不是二进制交叉熵中的二进制地面实况标签?
Posted
技术标签:
【中文标题】不是二进制交叉熵中的二进制地面实况标签?【英文标题】:Not binary ground truth labels in binary crossentropy? 【发布时间】:2020-08-27 12:21:10 【问题描述】:对二元交叉熵不使用二元基本真值是否有意义?有什么正式的证明吗?
看起来像在实践中使用:例如在https://blog.keras.io/building-autoencoders-in-keras.html 中,即 mnist 图像不是二进制图像,而是灰色图像。
这里是代码示例:
1.正常情况:
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.非二元真实值情况:
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.[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_1
和 test_3
中的丢失是相同的,可能是因为将 [-2, 2] 裁剪为 [0, 1] 但我在 Keras 代码中看不到裁剪代码。
同样有趣的是,test_1
和 test_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)
【问题讨论】:
【参考方案1】:是的,它“有道理”,因为交叉熵是概率分布之间差异的度量。也就是说,any 分布(当然是在相同的样本空间上)——目标分布是 one-hot 的情况实际上只是一种特殊情况,尽管它在机器学习中的使用频率很高。
一般来说,如果p
是您的真实分布并且q
是您的模型,则q = p
的交叉熵最小化。因此,使用交叉熵作为损失将鼓励模型向目标分布收敛。
关于情况1和2的区别:交叉熵不是对称的。它实际上等于真实分布p
的熵加上p
和q
之间的KL 散度。这意味着p
更接近均匀(更少“单热”),它通常会更大,因为这样的分布具有更高的熵(我认为 KL 散度也会不同,因为它不是对称的)。
至于案例3:这实际上是使用0.5作为output
的神器。事实证明,在交叉熵公式中,项将完全以这样一种方式抵消,即无论标签如何,您总是得到相同的结果 (log(2)
)。当您使用输出时,这将改变!= 0.5;在这种情况下,不同的标签会给你不同的交叉熵。例如:
output
0.3, target
2.0 给出 2.0512707 的交叉熵
output
0.3, target
-2.0 给出 -1.3379208 的交叉熵
第二种情况实际上给出了一个负输出,这是没有意义的。恕我直言,该函数允许 [0,1] 范围之外的目标是一个疏忽;这应该会导致崩溃。交叉熵公式工作得很好,但结果毫无意义。
我还建议阅读 the wikipedia article 关于交叉熵。它很短,包含一些有用的信息。
【讨论】:
以上是关于不是二进制交叉熵中的二进制地面实况标签?的主要内容,如果未能解决你的问题,请参考以下文章
np.dot 和 np.multiply 与 np.sum 在二进制交叉熵损失计算中的区别
具有对数损失的 TensorFlow 单 sigmoid 输出与具有稀疏 softmax 交叉熵损失的两个线性输出,用于二进制分类