如何在 keras 中创建自定义损失函数? (自定义加权二元交叉熵)

Posted

技术标签:

【中文标题】如何在 keras 中创建自定义损失函数? (自定义加权二元交叉熵)【英文标题】:How can I create a custom loss function in keras ? (Custom Weighted Binary Cross Entropy) 【发布时间】:2021-01-20 08:59:14 【问题描述】:

我正在创建一个完全卷积的神经网络,它给定输入中的图像,能够识别其中的区域(黑色,0),还可以识别背景(白色,255)。 我的目标是二值化图像(范围 0-255),我想在我的两个语义类(0 或 255)之间取得一些平衡。 事实上,我得到的“特殊”区域 (0) 是背景区域 (255) 的 1.8 倍,所以我需要抵消这种影响,我想更多地惩罚在背景上犯错误的事实,以避免仅预测特殊区域。

我尝试关注一些关于它的主题,这似乎并不难,但我在我的实施中陷入困境,我真的不知道为什么。

每次我的实现在编译阶段工作,但只有在拟合步骤中它才会返回错误。 到目前为止,这是我尝试过的:

import keras.backend as kb    
def custom_binary_crossentropy(y_true, y_pred):
        """
        Used to reequilibrate the data, as there is more black (0., articles), than white (255., non-articles) on the pages.
        """
        if y_true >=128:   # Half the 0-255 range
            return -1.8*kb.log(y_pred/255.)
        else:
            return -kb.log(1-(y_pred/255.))

但它返回了:

InvalidArgumentError:  The second input must be a scalar, but it has shape [16,256,256]
     [[node gradient_tape/custom_binary_crossentropy/cond/StatelessIf/gradient_tape/custom_binary_crossentropy/weighted_loss/Mul/_17]] [Op:__inference_train_function_24327]

Function call stack:
train_function

我不太明白这个错误。

我之前尝试过:

def custom_binary_crossentropy(y_true, y_pred):
    """
    Used to reequilibrate the data, as there is more black (0., articles), than white (255., non-articles) on the pages.
    """
    if y_true >=128:   # Half the 0-255 range
        return 1.8*keras.losses.BinaryCrossentropy(y_true, y_pred)
    else:
        return keras.losses.BinaryCrossentropy(y_true, y_pred)

但我得到了:

TypeError: in user code:

    /Users/axeldurand/opt/anaconda3/lib/python3.7/site-packages/tensorflow/python/keras/engine/training.py:806 train_function  *
        return step_function(self, iterator)
    <ipython-input-67-7b6815236f63>:6 custom_binary_crossentropy  *
        return -1.8*keras.losses.BinaryCrossentropy(y_true, y_pred)

    TypeError: unsupported operand type(s) for *: 'float' and 'BinaryCrossentropy'

我有点困惑,Keras 总是让它​​变得如此简单,我必须省略一些简单的东西,但我真的不明白。

【问题讨论】:

【参考方案1】:

非常感谢@qmeeus,您向我展示了成功之路! 我不知道 keras.losses.BinaryCrossentropy 和 keras.losses.binary_crossentropy 之间的区别,但它是一个主要的。

我是这样做的:

def custom_binary_crossentropy(y_true, y_pred):
    """
    Used to reequilibrate the data, as there is more black (0., articles),
    than white (255. (recalibrated to 1.), non-articles) on the pages.
    """
    # I put 0 so that the shape is (batch_size, 256, 256)
    # and not (batch_size, 256, 256, 1)
    is_white = y_true[:,:,:,0]>=0.5 
    white_error = 1.8*keras.losses.binary_crossentropy(y_true, y_pred)
    black_error = keras.losses.binary_crossentropy(y_true, y_pred)
    # Returns the right loss for each type of error.
    # We do make twice the calculation but I did not find a better way for now
    return tf.where(is_white, white_error, black_error)

我不知道 tf.where 的用途,但它非常有用。 我在 Aurélien Géron 的优秀著作《使用 Keras 和 TensorFlow 进行机器学习》中看到了本教程。

只需使用下一个:

# Compiling using this function
model.compile(optimizer="rmsprop", loss=custom_binary_crossentropy)

然后使用您的数据和最喜欢的超参数拟合您的模型,一切顺利!

【讨论】:

【参考方案2】:

您以错误的方式使用keras.losses.BinaryCrossentropy。你实际上想要这个损失的函数版本,即tf.keras.losses.binary_crossentropy

见https://www.tensorflow.org/api_docs/python/tf/keras/losses/BinaryCrossentropy和https://www.tensorflow.org/api_docs/python/tf/keras/losses/binary_crossentropy

【讨论】:

以上是关于如何在 keras 中创建自定义损失函数? (自定义加权二元交叉熵)的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Keras 中创建这个自定义损失函数并确保它是可微的?

如何在 Android Studio 中创建自定义图像按钮?

如何在 Keras 中创建一个依赖于纪元数的损失函数参数?

在 pytorch 中创建自定义梯度下降

如何在 Blend 中创建自定义列表

使用 Keras 为损失函数构建自定义指标,但有错误