自定义 Keras binary_crossentropy 损失函数不起作用

Posted

技术标签:

【中文标题】自定义 Keras binary_crossentropy 损失函数不起作用【英文标题】:Custom Keras binary_crossentropy loss function not working 【发布时间】:2019-12-11 08:22:54 【问题描述】:

我正在尝试重新定义 keras 的 binary_crossentropy 损失函数,以便我可以自定义它,但它给我的结果与现有的不同。

我正在使用 TF 1.13.1 和 Keras 2.2.4。

我浏览了 Keras 的 github 代码。我的理解是 model.compile(optimizer='adam', loss='binary_crossentropy', metrics =['accuracy']) 中的 loss 是在 loss.py 中定义的,使用的是 tensorflow_backend.py 中定义的 binary_crossentropy。

我运行了一个虚拟数据和模型来测试它。以下是我的发现:

自定义损失函数输出与 keras 相同的结果 在 keras 模型中使用自定义损失会产生不同的准确度结果
from numpy.random import seed
seed(1)
from tensorflow import set_random_seed
set_random_seed(2)

import tensorflow as tf
from keras import losses
import keras.backend as K
import keras.backend.tensorflow_backend as tfb
from keras.layers import Dense
from keras import Sequential

#Dummy check of loss output
def binary_crossentropy_custom(y_true, y_pred):
    return K.mean(binary_crossentropy_custom_tf(y_true, y_pred), axis=-1)

def binary_crossentropy_custom_tf(target, output, from_logits=False):
    """Binary crossentropy between an output tensor and a target tensor.

    # Arguments
        target: A tensor with the same shape as `output`.
        output: A tensor.
        from_logits: Whether `output` is expected to be a logits tensor.
            By default, we consider that `output`
            encodes a probability distribution.

    # Returns
        A tensor.
    """
    # Note: tf.nn.sigmoid_cross_entropy_with_logits
    # expects logits, Keras expects probabilities.
    if not from_logits:
        # transform back to logits
        _epsilon = tfb._to_tensor(tfb.epsilon(), output.dtype.base_dtype)
        output = tf.clip_by_value(output, _epsilon, 1 - _epsilon)
        output = tf.log(output / (1 - output))

    return tf.nn.sigmoid_cross_entropy_with_logits(labels=target,
                                                   logits=output)

logits = tf.constant([[-3., -2.11, -1.22],
                     [-0.33, 0.55, 1.44],
                     [2.33, 3.22, 4.11]])

labels = tf.constant([[1., 1., 1.], 
                      [1., 1., 0.], 
                      [0., 0., 0.]])

custom_sigmoid_cross_entropy_with_logits = binary_crossentropy_custom(labels, logits)
keras_binary_crossentropy = losses.binary_crossentropy(y_true=labels, y_pred=logits)

with tf.Session() as sess:
    print('CUSTOM sigmoid_cross_entropy_with_logits: ', sess.run(custom_sigmoid_cross_entropy_with_logits), '\n')
    print('KERAS keras_binary_crossentropy: ', sess.run(keras_binary_crossentropy), '\n')

#CUSTOM sigmoid_cross_entropy_with_logits:  [16.118095 10.886106 15.942386] 

#KERAS keras_binary_crossentropy:  [16.118095 10.886106 15.942386] 

#Dummy check of model accuracy

X_train = tf.random.uniform((3, 5), minval=0, maxval=1, dtype=tf.dtypes.float32)
labels = tf.constant([[1., 0., 0.], 
                      [0., 0., 1.], 
                      [1., 0., 0.]])

model = Sequential()
#First Hidden Layer
model.add(Dense(5, activation='relu', kernel_initializer='random_normal', input_dim=5))
#Output Layer
model.add(Dense(3, activation='sigmoid', kernel_initializer='random_normal'))

#I ran model.fit for each model.compile below 10 times using the same X_train and provide the range of accuracy measurement
# model.compile(optimizer='adam', loss='binary_crossentropy', metrics =['accuracy']) #0.748 < acc < 0.779
# model.compile(optimizer='adam', loss=losses.binary_crossentropy, metrics =['accuracy']) #0.761 < acc < 0.778
model.compile(optimizer='adam', loss=binary_crossentropy_custom, metrics =['accuracy']) #0.617 < acc < 0.663

history = model.fit(X_train, labels, steps_per_epoch=100, epochs=1)

我希望自定义损失函数能够提供类似的模型精度输出,但事实并非如此。任何想法?谢谢!

【问题讨论】:

【参考方案1】:

Keras 会根据损失自动选择使用哪个accuracy 实现,如果您使用自定义损失,这将不起作用。但在这种情况下,您可以明确地使用正确的准确度,即binary_accuracy

model.compile(optimizer='adam', loss=binary_crossentropy_custom, metrics =['binary_accuracy'])

【讨论】:

以上是关于自定义 Keras binary_crossentropy 损失函数不起作用的主要内容,如果未能解决你的问题,请参考以下文章

在 Keras 中构建自定义损失函数

如何用Keras自定义层?

Keras 自定义目标需要张量评估

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

如何为 keras 模型使用 tensorflow 自定义损失?

Keras CIFAR-10分类 自定义simple CNN篇