在 keras 中制作自定义损失函数

Posted

技术标签:

【中文标题】在 keras 中制作自定义损失函数【英文标题】:Make a custom loss function in keras 【发布时间】:2018-02-08 05:28:11 【问题描述】:

您好,我一直在尝试在 keras 中为 dice_error_coefficient 制作自定义损失函数。它在 tensorboard 中有实现,我尝试在带有 tensorflow 的 keras 中使用相同的函数,但是当我使用 model.train_on_batch 时它一直返回 NoneTypemodel.fit,因为它在模型中的指标中使用时会给出正确的值。有人可以帮我解决我该怎么做吗?我曾尝试关注 ahunt 的 Keras-FCN 等库,他在其中使用了自定义损失函数,但似乎都不起作用。代码中的目标和输出分别是 keras 中的 loss.py 文件中使用的 y_true 和 y_pred。

def dice_hard_coe(target, output, threshold=0.5, axis=[1,2], smooth=1e-5):
    """References
    -----------
    - `Wiki-Dice <https://en.wikipedia.org/wiki/Sørensen–Dice_coefficient>`_
    """

    output = tf.cast(output > threshold, dtype=tf.float32)
    target = tf.cast(target > threshold, dtype=tf.float32)
    inse = tf.reduce_sum(tf.multiply(output, target), axis=axis)
    l = tf.reduce_sum(output, axis=axis)
    r = tf.reduce_sum(target, axis=axis)
    hard_dice = (2. * inse + smooth) / (l + r + smooth)
    hard_dice = tf.reduce_mean(hard_dice)
    return hard_dice

【问题讨论】:

【参考方案1】:

在 Keras 中实现参数化自定义损失函数有两个步骤。首先,为系数/度量编写一个方法。其次,编写一个包装函数来按照 Keras 需要的方式格式化。

    对于像 DICE 这样的简单自定义损失函数,直接使用 Keras 后端而不是 tensorflow 实际上要干净得多。这是以这种方式实现的系数示例:

    import keras.backend as K
    def dice_coef(y_true, y_pred, smooth, thresh):
        y_pred = y_pred > thresh
        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)
    

    现在是棘手的部分。 Keras 损失函数只能以 (y_true, y_pred) 作为参数。所以我们需要一个单独的函数来返回另一个函数。

    def dice_loss(smooth, thresh):
      def dice(y_true, y_pred)
        return -dice_coef(y_true, y_pred, smooth, thresh)
      return dice
    

最后,你可以在Keras编译中如下使用它。

# build model 
model = my_model()
# get the loss function
model_dice = dice_loss(smooth=1e-5, thresh=0.5)
# compile model
model.compile(loss=model_dice)

【讨论】:

'def dice(y_true, y_pred): return -dice_coef(y_true, y_pred, 1e-5, 0.5) def dice_coef(y_true, y_pred, smooth, thresh): y_pred = K.cast(y_pred > thresh ,dtype=tf.float32) y_true = K.cast(y_true > thresh, dtype=tf.float32) y_true_f = K.flatten(y_true) y_pred_f = K.flatten(y_pred) 交点 = K.sum(y_true_f * y_pred_f ) return (2. * intersection + smooth) / (K.sum(y_true_f) + K.sum(y_pred_f) + smooth) Final_Model.compile(optimizer=opt, loss=dice,metrics=['acc'])' this给我一个错误'试图将'x'转换为张量并失败。错误:不支持任何值。' 您是否在将 dice 实例传递给您的模型之前调用它? dice_fn = dice(smooth=1e-5, thresh=0.5)Final_Model.compile(optimizer=opt, loss=dice_fn) 按你说的方式工作。问题是输出不能以这种方式转换为 1,0。所以它返回一个无值。在删除那部分它完美地工作。谢谢你的帮助。 嗨,这里有人可以帮忙解答我的问题吗:***.com/questions/53650690/… 谢谢, 有人可以确认这是否有效吗? ypred 和 ytrue 是张量,所以 ypred = ypred &gt; ytrue 会失败。在我的情况下,对 ypred 和 ytrue 的任何计算都失败了。【参考方案2】:

根据documentation,您可以像这样使用自定义损失函数:

任何带有签名loss_fn(y_true, y_pred) 的可调用函数返回一组损失(输入批次中的样本之一),都可以作为损失传递给compile()。请注意,任何此类损失都会自动支持样本加权。

举个简单的例子:

def my_loss_fn(y_true, y_pred):
    squared_difference = tf.square(y_true - y_pred)
    return tf.reduce_mean(squared_difference, axis=-1)  # Note the `axis=-1`

model.compile(optimizer='adam', loss=my_loss_fn)

完整示例:

import tensorflow as tf
import numpy as np

def my_loss_fn(y_true, y_pred):
    squared_difference = tf.square(y_true - y_pred)
    return tf.reduce_mean(squared_difference, axis=-1)  # Note the `axis=-1`

model = tf.keras.Sequential([
    tf.keras.layers.Dense(8, activation='relu'),
    tf.keras.layers.Dense(16, activation='relu'),
    tf.keras.layers.Dense(1)])

model.compile(optimizer='adam', loss=my_loss_fn)

x = np.random.rand(1000)
y = x**2

history = model.fit(x, y, epochs=10)

【讨论】:

以上是关于在 keras 中制作自定义损失函数的主要内容,如果未能解决你的问题,请参考以下文章

Keras 中基于输入数据的自定义损失函数

在具有条件的 keras 中实现自定义损失函数

Keras 中的自定义损失函数(IoU 损失函数)和梯度误差?

Keras 自定义损失函数 - 生存分析截尾

如何在 Keras 自定义损失函数中使用张量?

如何在 tf.keras 自定义损失函数中触发 python 函数?