Keras:binary_crossentropy& categorical_crossentropy confusion

时间:2017-12-18 22:03:34

标签: python tensorflow keras classification cross-entropy

使用TensorFlow已经有一段时间了,我已经阅读了一些Keras教程并实现了一些示例。我找到了几个使用keras.losses.binary_crossentropy作为损失函数的卷积自动编码器教程。

我认为binary_crossentropy应该是一个多类丢失函数,很可能会使用二进制标签,但事实上Keras(TF Python后端)调用tf.nn.sigmoid_cross_entropy_with_logits,实际上,它适用于具有互斥的多个独立类的分类任务。

另一方面,我对categorical_crossentropy的期望是针对多类分类,其中目标类彼此具有依赖关系,但不一定是单热编码

然而,Keras文件指出:

  

(...)当使用categorical_crossentropy损失时,你的目标应该是分类格式(例如,如果你有10个类,每个样本的目标应该是全零预期的10维向量对于与样本类对应的索引处的1。

如果我没有记错,这只是单热编码分类任务的特例,但潜在的交叉熵损失也适用于概率分布(“多类”,依赖标签)?

此外,Keras使用tf.nn.softmax_cross_entropy_with_logits(TF python后端)进行实现,其本身states

  

注意:虽然这些类是互斥的,但他们的概率不一定是。所需要的只是每行标签是有效的概率分布。如果不是,则梯度的计算将是不正确的。

如果我错了,请纠正我,但在我看来Keras文档至少 - 不是非常“详细”?!

那么,Keras命名损失函数背后的想法是什么?文档是否正确?如果二进制交叉熵真的依赖于二进制标签,它应该适用于自动编码器,对吧?! 同样,分类交叉熵:如果文档正确,应该只适用于单热编码标签吗?!

3 个答案:

答案 0 :(得分:5)

通过定义每种损失适用的区域,你是正确的:

  • binary_crossentropy(以及tf.nn.sigmoid_cross_entropy_with_logits)是二元多标签分类(标签是独立的)。
  • categorical_crossentropy(以及引擎盖下的tf.nn.softmax_cross_entropy_with_logits)用于多级分类(类是独占的)。

另见this question中的详细分析。

我不确定你的意思是什么,所以无法评论binary_crossentropy是否是自动编码器的好或坏选择。

至于命名,这是绝对正确和合理的。或者您认为sigmoidsoftmax名称听起来更好?

因此,您问题中唯一的混淆是categorical_crossentropy文档。请注意,已声明的所有内容都是正确的:损失支持单热表示。这个函数确实适用于标签的任何概率分布(除了一个热矢量),在张量流后端的情况下,可以包含在doc中,但这不是对我来说看起来很重要。此外,需要检查其他后端,theano和CNTK是否支持软类。请记住,keras试图是最简单的,并且是大多数流行用例的目标,因此我可以理解这里的逻辑。

答案 1 :(得分:1)

不确定这是否能回答你的问题,但对于softmax损失,输出层需要是概率分布(即总和为1),对于二进制的交叉熵损失则不然。就那么简单。 (二进制并不意味着只有2个输出类,它只是意味着每个输出都是二进制的。)

答案 2 :(得分:0)

文档中没有提到BinaryCrossentropy可用于多标签分类,这可能会造成混淆。但是它也可以用于二进制分类器(当我们只有2个排它类,例如猫和狗)时-请参见经典example。但是在这种情况下,我们必须设置n_classes=1

tf.keras.layers.Dense(units=1)

BinaryCrossentropytf.keras.losses.binary_crossentropy的行为也不同。

让我们看一下文档中的示例,以证明它实际上是用于多标签分类的。

y_true = tf.convert_to_tensor([[0, 1], [0, 0]])
y_pred = tf.convert_to_tensor([[0.6, 0.4], [0.4, 0.6]])

bce = tf.keras.losses.BinaryCrossentropy()
loss1 = bce(y_true=y_true, y_pred=y_pred)
# <tf.Tensor: shape=(), dtype=float32, numpy=0.81492424>

loss2 = tf.keras.losses.binary_crossentropy(y_true, y_pred)
# <tf.Tensor: shape=(2,), dtype=float32, numpy=array([0.9162905 , 0.71355796], dtype=float32)>

np.mean(loss2.numpy())
# 0.81492424

scce = tf.keras.losses.SparseCategoricalCrossentropy()
y_true = tf.convert_to_tensor([0, 0])
scce(y_true, y_pred)
# <tf.Tensor: shape=(), dtype=float32, numpy=0.71355814>
y_true = tf.convert_to_tensor([1, 0])
scce(y_true, y_pred)
# <tf.Tensor: shape=(), dtype=float32, numpy=0.9162907>
相关问题