不是二元交叉熵中的二元基本事实标签吗?

Not binary ground truth labels in binary crossentropy?

二元交叉熵不使用二元地面真值有意义吗?有正式证明吗?

看起来像在实践中使用:例如在https://blog.keras.io/building-autoencoders-in-keras.html中,即mnist图像不是二值图像,而是灰度图像。

这是代码示例:

1.Normal 案例:

def test_1():
    print('-'*60)

    y_pred = np.array([0.5, 0.5])
    y_pred = np.expand_dims(y_pred, axis=0)
    y_true = np.array([0.0, 1.0])
    y_true = np.expand_dims(y_true, axis=0)

    loss = keras.losses.binary_crossentropy(
        K.variable(y_true),
        K.variable(y_pred)
    )

    print("K.eval(loss):", K.eval(loss))

输出:

K.eval(loss): [0.6931472]

2.Not 二元地面真值案例:

def test_2():
    print('-'*60)

    y_pred = np.array([0.0, 1.0])
    y_pred = np.expand_dims(y_pred, axis=0)
    y_true = np.array([0.5, 0.5])
    y_true = np.expand_dims(y_true, axis=0)

    loss = keras.losses.binary_crossentropy(
        K.variable(y_true),
        K.variable(y_pred)
    )

    print("K.eval(loss):", K.eval(loss))

输出:

K.eval(loss): [8.01512]

3.Ground 超出 [0,1] 范围的真值:

def test_3():
    print('-'*60)

    y_pred = np.array([0.5, 0.5])
    y_pred = np.expand_dims(y_pred, axis=0)
    y_true = np.array([-2.0, 2.0])
    y_true = np.expand_dims(y_true, axis=0)

    loss = keras.losses.binary_crossentropy(
        K.variable(y_true),
        K.variable(y_pred)
    )

    print("K.eval(loss):", K.eval(loss))

输出:

K.eval(loss): [0.6931472]

出于某种原因,test_1test_3 中的损失是相同的,可能是因为将 [-2, 2] 剪切为 [0, 1] 但我看不到剪切代码喀拉斯代码。 同样有趣的是,test_1test_2 损失值有很大差异,但在第一种情况下我们有 [0.5, 0.5] 和 [0.0, 1.0],在第二种情况下我们有 [0.0, 1.0] 和[0.5, 0.5],这是相同的值,但顺序相反。

在 Keras 中 binary_crossentropy 定义为:

def binary_crossentropy(y_true, y_pred):
    return K.mean(K.binary_crossentropy(y_true, y_pred), axis=-1)


def binary_crossentropy(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 = _to_tensor(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)

是的,它 "makes sense" 因为交叉熵是概率分布之间差异的度量。也就是说,any 分布(当然是在同一个样本 space 上)——目标分布是 one-hot 的情况实际上只是一个特例,尽管频率很高它用于机器学习。

一般来说,如果 p 是您的真实分布并且 q 是您的模型,则 q = p 的交叉熵最小化。因此,使用交叉熵作为损失将鼓励模型向目标分布收敛。

关于情况1和情况2的区别:交叉熵不是对称的。它实际上等于真实分布的熵p加上pq之间的KL散度。这意味着它通常会更大 p 更接近均匀(更少 "one-hot"),因为这样的分布具有更高的熵(我想 KL 散度也会不同,因为它不是对称的)。

至于case 3:这其实是把0.5当成output的神器。事实证明,在交叉熵公式中,项将以完全相同的方式抵消,无论标签如何,您总是会得到相同的结果 (log(2))。当您使用 output != 0.5; 时,这会发生变化;在这种情况下,不同的标签会给你不同的交叉熵。例如:

  • output 0.3,target 2.0 给出交叉熵 2.0512707
  • output 0.3, target -2.0 给出 -1.3379208
  • 的交叉熵

第二种情况实际上给出了负输出,这没有任何意义。恕我直言,该函数允许 [0,1] 范围之外的目标是一种疏忽;这应该会导致崩溃。交叉熵公式工作得很好,但结果没有意义。

我还建议阅读 the wikipedia article 关于交叉熵的内容。它很短,但包含一些有用的信息。