加权二元交叉熵损失——Keras 实现

数据挖掘 喀拉斯 张量流 阶级失衡
2021-10-11 15:28:15

我有一个高度不平衡数据的二进制分割问题,因此每个第一类样本都有近 60 个零类样本。为了解决这个问题,我在 Keras 中编写了一个简单的加权二元交叉熵损失函数,并以 Tensorflow 作为后端。

def weighted_bce(y_true, y_pred):
  weights = (y_true * 59.) + 1.
  bce = K.binary_crossentropy(y_true, y_pred)
  weighted_bce = K.mean(bce * weights)
  return weighted_bce

我想问一下这个实现是否正确,因为我是 Keras/Tensorflow 的新手,优化器很难优化它。损失从 1.5 到 0.4 并且没有进一步下降。如果我将它长时间训练到过度拟合的程度,正常的二元交叉熵会表现得更好。在有人问之前,我不能使用 class_weight,因为我正在训练一个完全卷积的网络。

3个回答

代码是正确的。正常二元交叉熵表现更好的原因是它不会像加权情况那样严重惩罚较小类别的错误。可以肯定的是,这种方法适合您,在验证数据上评估较小和较大类的 f1 指标是合理的。它可能表明较小类的性能变得更好。训练时间可能会增加,因为模型被迫区分不同类别的对象并学习重要的模式来做到这一点。

对于不平衡的数据,准确性不再是一个足够好的指标。

简单示例:对于异常检测,您通常会发现自己的“正常”案例比异常多得多。假设您有 98% 的时间好案例和 2% 的时间“异常”,您只需将所有案例预测为“正常”,您将有 98% 的准确率(非常好,对吗?)

现在假设您的模型是防止信用卡欺诈,您认为 2% 的错误就足够了吗?不是真的,你会失去很多客户。在这种情况下,您需要使用替代指标:

  • 记起
  • F1分数

评估您的模型性能。我建议您在替代指标上比较模型性能(与您的传统损失和修改损失),您会看到改进。

这是我的实现,希望对你有帮助。这是针对图像分割问题(​​二元分类)。地面实况图像大小为 (512,512,1):

def weighted_BCE_loss(y_true, y_pred, positive_weight=5):
    # y_true: (None,None,None,None)     y_pred: (None,512,512,1)
    y_pred = K.clip(y_pred, min_value=1e-12, max_value=1 - 1e-12)
    weights = K.ones_like(y_pred)  # (None,512,512,1)
    weights = tf.where(y_pred < 0.5, positive_weight * weights, weights)
    # weights[y_pred<0.5]=positive_weight
    out = keras.losses.binary_crossentropy(y_true, y_pred)  # (None,512,512)
    out = K.expand_dims(out, axis=-1) * weights  # (None,512,512,1)* (None,512,512,1)
    return K.mean(out)```