Machine learning TensorFlow:实现类加权交叉熵损失?

Machine learning TensorFlow:实现类加权交叉熵损失?,machine-learning,tensorflow,computer-vision,deep-learning,image-segmentation,Machine Learning,Tensorflow,Computer Vision,Deep Learning,Image Segmentation,假设在对用于分割的图像执行中值频率平衡后,我们有以下类别权重: class_weights = {0: 0.2595, 1: 0.1826, 2: 4.5640, 3: 0.1417, 4: 0.9051, 5: 0.3826, 6: 9.6446, 7: 1.

假设在对用于分割的图像执行中值频率平衡后,我们有以下类别权重:

class_weights = {0: 0.2595,
                 1: 0.1826,
                 2: 4.5640,
                 3: 0.1417,
                 4: 0.9051,
                 5: 0.3826,
                 6: 9.6446,
                 7: 1.8418,
                 8: 0.6823,
                 9: 6.2478,
                 10: 7.3614,
                 11: 0.0}
这个想法是创建一个权重掩码,这样它就可以被两个类的交叉熵输出相乘。要创建此权重掩码,我们可以根据地面真相标签或预测广播值。我的实现中的一些数学:

  • 标签和标签的形状均
    [批次大小、高度、宽度、数量等级]

  • 重量遮罩的形状
    [批次大小、高度、宽度,1]

  • 权重掩码被广播到logit的softmax和标签之间相乘的
    num\u类
    通道数,以给出
    [批次大小、高度、宽度、num\u类]
    的输出形状。在这种情况下,
    num_classes
    是12

  • 减少一批中每个示例的总和,然后对一批中的所有示例执行减少平均值,以获得单个损失标量值

  • 在这种情况下,我们应该根据预测或基本事实创建权重掩码吗?


    如果我们根据基本事实构建它,那么这意味着无论预测的像素标签是什么,它们都会根据类的实际标签受到惩罚,这似乎无法以合理的方式指导训练

    但是,如果我们基于预测构建它,那么对于生成的任何logit预测,如果预测标签(从logit的argmax中)占主导地位,那么该像素的logit值都将显著减少

    -->虽然这意味着最大logit仍然是最大值,因为12个通道中的所有logit都将按相同的值缩放,但预测的标签的最终softmax概率(缩放前后仍然相同)将低于缩放前(做了一些简单的数学估算)。-->预计损失较低

    但问题是:如果预测该权重会导致较低的损失,那么预测主导品牌会给你带来更大的损失这一观点是否与之相矛盾?

    我对这种方法的总体印象是:

  • 对于占主导地位的品牌,他们受到的惩罚和奖励要小得多
  • 对于不太占主导地位的品牌,如果预测正确,他们会得到高额奖励,但如果预测错误,他们也会受到严重惩罚
  • 那么,这有助于解决阶级平衡问题吗?我不太明白这里的逻辑


    实施

    这是我目前计算加权交叉熵损失的实现,尽管我不确定它是否正确

    def weighted_cross_entropy(logits, onehot_labels, class_weights):
        if not logits.dtype == tf.float32:
            logits = tf.cast(logits, tf.float32)
    
        if not onehot_labels.dtype == tf.float32:
            onehot_labels = tf.cast(onehot_labels, tf.float32)
    
        #Obtain the logit label predictions and form a skeleton weight mask with the same shape as it
        logit_predictions = tf.argmax(logits, -1) 
        weight_mask = tf.zeros_like(logit_predictions, dtype=tf.float32)
    
        #Obtain the number of class weights to add to the weight mask
        num_classes = logits.get_shape().as_list()[3]
    
        #Form the weight mask mapping for each pixel prediction
        for i in xrange(num_classes):
            binary_mask = tf.equal(logit_predictions, i) #Get only the positions for class i predicted in the logits prediction
            binary_mask = tf.cast(binary_mask, tf.float32) #Convert boolean to ones and zeros
            class_mask = tf.multiply(binary_mask, class_weights[i]) #Multiply only the ones in the binary mask with the specific class_weight
            weight_mask = tf.add(weight_mask, class_mask) #Add to the weight mask
    
        #Multiply the logits with the scaling based on the weight mask then perform cross entropy
        weight_mask = tf.expand_dims(weight_mask, 3) #Expand the fourth dimension to 1 for broadcasting
        logits_scaled = tf.multiply(logits, weight_mask)
    
        return tf.losses.softmax_cross_entropy(onehot_labels=onehot_labels, logits=logits_scaled)
    
    有人能验证我的加权损失概念是否正确,以及我的实现是否正确吗?这是我第一次熟悉一个类不平衡的数据集,所以如果有人能够验证这一点,我将不胜感激

    测试结果:在做了一些测试之后,我发现上面的实现导致了更大的损失。应该是这样吗?i、 这会使训练更加困难,但最终会产生更准确的模型吗


    类似线程

    注意,我在这里检查了一个类似的线程:

    但TF似乎只有样本权重,而没有类别权重


    非常感谢大家。

    以下是我自己使用TensorFlow后端在Keras中的实现:

    def class_weighted_pixelwise_crossentropy(target, output):
        output = tf.clip_by_value(output, 10e-8, 1.-10e-8)
        with open('class_weights.pickle', 'rb') as f:
            weight = pickle.load(f)
        return -tf.reduce_sum(target * weight * tf.log(output))
    
    其中,
    weight
    只是一个标准的Python列表,其权重索引与一个热向量中对应类的权重索引匹配。我将权重存储为pickle文件,以避免重新计算它们。这是一个改编的。第一行只是剪辑该值,以确保我们从不使用0的日志

    我不确定为什么人们会用预测而不是事实来计算权重;如果你提供进一步的解释,我可以更新我的回答

    编辑:使用此numpy代码了解其工作原理。同时,也要回顾定义


    “如果我们基于基本事实构建它,那么这意味着无论预测的像素标签是什么,它们都会根据类的实际标签受到惩罚,这似乎不能以合理的方式指导培训。”为什么?意思是说如果某个像素[x,y]应该标记为1,但是预测值可以是0到11之间的任何值,那么不管该标签的预测值是什么,应用于logit的特定像素的缩放比例将是相同的,不管logit预测值是什么。我认为这会很奇怪,因为我们想要自适应地惩罚预测的标签。你对此有什么见解吗?我知道你输入的形状是什么?该函数是否适用于4维的情况?事实上,对于权重计算,我也不是很确定,所以我猜测它可能是基于预测或地面真相。你有没有进一步的参考资料,让我读一读,以理解为什么它应该以事实真相为基础?另外,你知道有任何中值频率平衡的实现吗?重要的是输出。输入是形状(1024、512、3)的RGB图像,输出是形状(1024、512、1)的注释。这个函数应该适用于任何级别的输出。我相信如果你处理一批图像,也就是级别4,你应该在最后使用reduce mean。在您的情况下,您的类是1还是0?我一直认为对于多标签像素分类,输出应该有num classes通道。我不太明白目标的广播*权重如何取代目标是4级的,但权重只是1级-每个像素如何知道我们需要什么
    import numpy as np
    
    weights = [1,2]
    
    target = np.array([ [[0.0,1.0],[1.0,0.0]],
                        [[0.0,1.0],[1.0,0.0]]])
    
    output = np.array([ [[0.5,0.5],[0.9,0.1]],
                        [[0.9,0.1],[0.4,0.6]]])
    
    crossentropy_matrix = -np.sum(target * np.log(output), axis=-1)
    crossentropy = -np.sum(target * np.log(output))