在Keras中使用类权重为U-net自定义损失函数:不支持3维以上的目标

这是我正在使用的代码(大部分来自Kaggle):

inputs = Input((IMG_HEIGHT, IMG_WIDTH, IMG_CHANNELS))...outputs = Conv2D(4, (1, 1), activation='sigmoid') (c9)model = Model(inputs=[inputs], outputs=[outputs])model.compile(optimizer='adam', loss='dice', metrics=[mean_iou])results = model.fit(X_train, Y_train, validation_split=0.1, batch_size=8, epochs=30, class_weight=class_weights)

我有四个非常不平衡的类。类A占70%,类B占15%,类C占10%,类D占5%。然而,我最关心的是类D。因此,我进行了如下类型的计算: D_weight = A/D = 70/5 = 14,类B和A的权重也是如此计算的。(如果有更好的选择这些权重的方法,请随时提出)

在最后一行,我试图正确设置类权重,我的做法是这样的: class_weights = {0: 1.0, 1: 6, 2: 7, 3: 14}

然而,当我这样做时,我得到了以下错误。

class_weight 不支持3维以上的目标。

是否可以在我最后的层之后添加一个密集层,并将其用作虚拟层,以便我可以传递类权重,然后仅使用最后的Conv2D层的输出进行预测?

如果这不可行,我该如何修改损失函数?(我知道这个帖子,然而,仅仅将权重传递给损失函数是不够的,因为损失函数是为每个类别单独调用的)目前,我使用的是以下损失函数:

def dice_coef(y_true, y_pred):    smooth = 1.    y_true_f = K.flatten(y_true)    y_pred_f = K.flatten(y_pred)    intersection = K.sum(y_true_f * y_pred_f)    return (2. * intersection + smooth) / (K.sum(y_true_f) + K.sum(y_pred_f) + smooth)def bce_dice_loss(y_true, y_pred):    return 0.5 * binary_crossentropy(y_true, y_pred) - dice_coef(y_true, y_pred)

但我看不出有什么办法可以输入类权重。如果有人想要完整的工作代码,请查看这个帖子。但请记住,将最后的Conv2D层的类别数更改为4而不是1。


回答:

你总是可以自己应用权重。

下面的originalLossFunc可以从keras.losses导入。
weightsList是你按类别排序的权重列表。

def weightedLoss(originalLossFunc, weightsList):    def lossFunc(true, pred):        axis = -1 #如果通道在最后         #axis=  1 #如果通道在最前        #argmax返回具有最大值的元素的索引        #在类轴上执行,返回类索引            classSelectors = K.argmax(true, axis=axis)             #如果你的损失是稀疏的,只使用true作为classSelectors        #考虑到权重是按类别排序的,对于每个类别        #如果类索引等于权重索引,则为true(1)           classSelectors = [K.equal(i, classSelectors) for i in range(len(weightsList))]        #将布尔值转换为浮点数以进行计算          #列表中的每个张量在真实类等于其索引的地方包含1         #如果你将所有这些相加,你将得到一个充满1的张量         classSelectors = [K.cast(x, K.floatx()) for x in classSelectors]        #对于上述每个选择,乘以它们各自的权重        weights = [sel * w for sel,w in zip(classSelectors, weightsList)]         #总和所有选择        #结果是一个张量,其中包含预测中每个元素的相应权重        weightMultiplier = weights[0]        for i in range(1, len(weights)):            weightMultiplier = weightMultiplier + weights[i]        #确保你的originalLossFunc只折叠类轴        #你需要保持其他轴完好无损以乘以权重张量        loss = originalLossFunc(true,pred)         loss = loss * weightMultiplier        return loss    return lossFunc

compile中使用这个方法:

model.compile(loss= weightedLoss(keras.losses.categorical_crossentropy, weights),               optimizer=..., ...)

直接在输入数据上改变类别平衡

你也可以改变输入样本的平衡。

例如,如果你有5个来自类别1的样本和10个来自类别2的样本,可以在输入数组中将类别5的样本传递两次。

.

使用sample_weight参数

你也可以“按样本”而不是“按类别”工作。

为输入数组中的每个样本创建一个权重数组: len(x_train) == len(weights)

并将此数组传递给fitsample_weight参数。
(如果是fit_generator,生成器将必须与训练/真实对一起返回权重: return/yield inputs, targets, weights

Related Posts

如何使用Google Protobuf解析、编辑和生成object_detection/pipeline.config文件

我在一个常见的集成学习范式中训练多个模型,目前我在处理…

我的GridSearchCV不起作用,我不知道为什么

大家好,我在使用GridSearchCV时遇到了问题,…

Keras: 两个同时进行的层,其中一个对前一层的输出进行卷积

我想实现这样的模型连接: 输入图像1 -> 卷积层1 …

如何将行数据转换为列数据而不使用独热编码

我有一个如下所示的数据集。 MonthDate Day…

使用 ML Kit 与 NNAPI

我正在尝试在运行 Android 9 的设备上使用新的…

Vowpal Wabbit 可能的哈希冲突

我在VW中生成了一个模型,并且在相同的数据上生成了两个…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注