加权分类交叉熵语义分割

时间:2018-07-16 12:02:56

标签: python tensorflow keras deep-learning

我想使用FCN(一种U-Net)来进行语义分割。 我使用基于Tensorflow后端的Python和Keras进行了此操作。现在,我取得了良好的结果,我正在尝试改善它们,我认为做到这一点的一种方法是改善损失计算。 我知道在我的输出中,几个类是不平衡的,使用默认的categorical_crossentropy函数可能是个问题。 我的模型输入和输出均为float32格式,输入为channel_first,输出为channel_last(在模型末尾完成排列) 在二进制情况下,当我只想细分一个类时,我以这种方式更改了损失函数,因此它可以根据输出内容逐个添加权重:

def weighted_loss(y_true, y_pred):
    def weighted_binary_cross_entropy(y_true, y_pred):
        w = tf.reduce_sum(y_true)/tf_cast(tf_size(y_true), tf_float32)
        real_th = 0.5-th 
        tf_th = tf.fill(tf.shape(y_pred), real_th) 
        tf_zeros = tf.fill(tf.shape(y_pred), 0.)
        return (1.0 - w) * y_true * - tf.log(tf.maximum(tf.zeros, tf.sigmoid(y_pred) + tf_th)) +
               (1- y_true) * w * -tf.log(1 - tf.maximum(tf_zeros, tf.sigmoid(y_pred) + tf_th))
    return weighted_binary_coss_entropy

请注意,th是激活阈值,默认情况下为1 / nClasses,我已对其进行了更改,以查看哪个值能给我带来最佳效果 你怎么看待这件事? 对其进行更改,以便能够计算加权分类交叉熵(在多类情况下)

1 个答案:

答案 0 :(得分:0)

您的实现将适用于二进制类,对于多类,它将只是

  -y_true * tf.log(tf.sigmoid(y_pred)) 

并使用内置的张量流方法来计算类别熵,因为它避免了y_pred <0

的溢出

您可以查看此答案Unbalanced data and weighted cross entropy,它说明了加权分类交叉熵的实现。

categorical_crossentropy的唯一变化是

def weighted_loss(y_true, y_pred):
    def weighted_categorical_cross_entropy(y_true, y_pred):
        w = tf.reduce_sum(y_true)/tf_cast(tf_size(y_true), tf_float32)
        loss = w * tf.nn.softmax_cross_entropy_with_logits(onehot_labels, logits)
        return loss
    return weighted_categorical_cross_entropy

提取单个班级的预测

def loss(y_true, y_pred):
    s = tf.shape(y_true)

    # if number of output classes  is at last
    number_classses = s[-1]

    # this will give you one hot code for your prediction
    clf_pred = tf.one_hot(tf.argmax(y_pred, axis=-1), depth=number_classses, axis=-1)

    # extract the values of y_pred where y_pred is max among the classes
    prediction = tf.where(tf.equal(clf_pred, 1), y_pred, tf.zeros_like(y_pred))

    # if one hotcode == 1 then class1_prediction == y_pred  else class1_prediction ==0
    class1_prediction = prediction[:, :, :, 0:1]
    # you can compute your loss here on individual class and return the loss ,just for simplicity i am returning the class1_prediction
    return class1_prediction

模型输出

y_pred = [[[[0.5, 0.3, 0.7],
   [0.6, 0.3, 0.2]]
,
  [[0.7, 0.9, 0.6],
   [0.3 ,0.9, 0.3]]]]

相应的地面真相

y_true =  [[[[0,  1, 0],
   [1 ,0, 0]]
,
  [[1,0 , 0],
   [0,1, 0]]]]

第1类的预测

prediction = loss(y_true, y_pred)
# prediction =  [[[[0. ],[0.6]],[0. ],[0. ]]]]