这是我正在使用的代码(大部分来自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)
并将此数组传递给fit
的sample_weight
参数。
(如果是fit_generator
,生成器将必须与训练/真实对一起返回权重: return/yield inputs, targets, weights
)