交叉熵损失函数区别及应用场景
对于机器学习中常用的损失函数
tf.nn.sigmoid_cross_entropy_with_logits
(Binary Cross Entropy, BCE) 和
tf.nn.softmax_cross_entropy_with_logits_v2
(Cross Entropy, CE),
想必有过时间的同学都已经能都熟练描述出他们的运行原理。但是在什么场景,用哪个损失函数呢?在不同的场景,这两个交叉熵损失又有哪些区别和联系呢?
下面先附上 tensorflow v1.15
中的函数原型:
tf.nn.sigmoid_cross_entropy_with_logits(_sentinel=None, labels=None, logits=None, name=None)
tf.nn.softmax_cross_entropy_with_logits_v2(labels, logits, axis=None, name=None, dim=None)
1. 基本概念和公式
信息量
- 其中 $f(x)$ 是预测为正例的概率
熵
- 其中 $f(x)$ 是预测为正例的概率,熵其实是信息量的期望值,它是一个随机变量的确定性的度量。熵越大,变量的取值越不确定,反之就越确定。
相对熵(Relative Entropy,又称为KL散度Kullback-Leibler divergence)
- 是两个随机分布间距离的度量。记为 $DKL(p||q)$。它度量当真实分布为p时,假设分布q的无效性。
交叉熵(Cross-Entropy)
- 其中 $x$ 表示输入样本, $C$ 为待分类的类别总数, 以手写数字识别任务(MNIST)为例, 其输入出的类别数为10, 对应的C=10,$y_i$ 为第 $i$ 个类别对应的真实标签, $f_i(x)$ 为对应的模型输出值.
Binary-Cross-Entropy
- 其中 $ i \in [1, C ]$,即每个类别输出节点都对应一个BCE的值
- 所以其实 BCE 只是 CE 的一种当label是二分类的时候的一种特殊形式,个人认为是因为在实际的场景中由于二分类的任务比较多,为了方便和效率考虑,单独将 BCE 从 CE 中抽出来另外多实现了一个。
2. 应用场景分析
着重讨论以下三种场景:二分类、单标签多分类、多标签多分类(multi-label)。
2.1 二分类
首先在二分类的场景下,我们只有一个输出节点,其输出值 $f(x) \in \lbrace 0, 1 \rbrace$ 。
那么按照约定俗成的观点,应该使用sigmoid + BCE
作为最后的输出层配置。
由于只有一个分类输出,上式中的 $i$ 可以忽略。
那如果使用CE会怎样呢?由于输出类别数 $C = 1$,所以CE中的求和可以忽略:
$$ CE(x) = -y_i log f_i(x) $$可以看到,在这种情况下,两者都具有相同的部分,BCE仅在样本标签 $ y = 0 $ 时多了一个反向的损失函数因子。 这里存疑?
因此,只有对错分的正样本,CE损失函数的值才大于0,此时的网络权值才会得到调整,最终的结果是正样本预测精度会很高,但负样本基本上相当于随机猜测。而对应BCE而言,对错分的正负样本都会产生梯度,网络权值都会进行调整。所以,从直觉上来看,BCE的收敛会更快,学习出的weight也会更合理。
事实上,在keras的train模块中对categorical_crossentropy的使用进行了强制限制,如果输出标签维度为1,只能使用binary_crossentropy,否则程序会报错。为了验证上述推论,我们使用keras自带的imdb二分类例子进行试验,由于输出维度为1的情况下不能直接使用categorical_crossentropy,我们修改例子的代码,通过在自定义loss函数中直接调用backend.categorical_crossentropy函数的方法实验。
运行200个step后,binary_crossentropy已经明显收敛:
20000/25000 [==>……] - ETA: 1:53 - loss: 0.5104 - acc: 0.7282
而categorical_crossentropy却收敛缓慢:
20000/25000 [==>……] - ETA: 1:58 - loss: 5.9557e-08 - acc: 0.5005
可以看到,CE损失函数工作得很差,这与我们的推论相符。所以keras明确禁止了在这种情况下categorical_crossentropy的使用,现在看来也是很合理的。
2.2 单标签多分类
按约定俗成的观点,应该使用 softmax+CE
的方案,我们同样先把对应的两种损失函数写出来,
同样的,由于只有一个类别的真实标签 $ y_i = 1 $ ,对CE来说,可以将前边的求和符号去掉:
$$ CE(x) = -y_i log f_i (x) $$看到这里,大家可能会有个疑问,在CE中我们同样只计算了某个类别标签为1时的loss,而没有计算它为0时的loss,会不会也像二分类的场景那样,导致模型收敛缓慢? 但在这里答案是否定的,原因就在于前边的softmax函数具有“排它”性质,某一个输出增大,必然导致其它类别的输出减小,因为其进行了归一化操作,使得每个类别的预测输出概率加和必须为1。但好奇的读者可能又要问了,那使用BCE应该也可以吧?没错!理论上确实是可以。当然可以,因为二者本身就是一家人>
下面我们使用keras自带的mnist多分类例子进行实验:
运行100个step后,binary_crossentropy的结果如下:
100/600 [=>…………………….] - ETA: 19:58 - loss: 0.0945 - categorical_accuracy: 0.8137
categorical_crossentropy的结果如下:
100/600 [=>…………………….] - ETA: 18:36 - loss: 0.6024 - acc: 0.8107
可以看到,两者并没有太大差距,binary_crossentropy效果反而略好于categorical_crossentropy。注意这里的acc为训练集上的精度,训练步数也仅有100个step,读者如有兴趣,可以深入分析。但这里至少说明了一点,在单标签多分类的情况下BCE同样是适用的。
2.3 多标签多分类
多标签多分类(multi-label)由于假设每个标签的输出是相互独立的,因此常用配置是 sigmoid + BCE
, 其中每个类别输出对应一个sigmoid。
如果读者仔细看了前面两个小节,相信不用分析,也可以自行得出结果,即这种场景下使用CE将难以收敛,
原因跟2.1中的分析类似—-我们只计算了某个类别标签为1时的loss及梯度,而忽略了为0时的loss,而每个输出又相互独立,不像softmax函数那样有归一化的限制。
所以multi-label是一定不能使用CE作为loss函数的。
3. 其他
“CE用于多分类, BCE适用于二分类”其实大部分都是正确的, 唯一有待商榷的部分在于多分类(单标签)其实也可以使用BCE,而对于multi-label的多分类,则不能使用CE。
另外有同学提到,BCE是CE的一种特殊情况,
- 对于正例,则 $loss = -y_postive log f(x)$, 其中 $f(x)$ 是预测为正例的概率;
- 对于负例,则 $loss = -(1 - y_negative)log (1 - f(x))$, 其中 $f(x)$ 还是预测为正例的概率,$1 - f(x)$ 则是预测为负例的概率;
- 所以,交叉熵(Cross Entropy)一直都是 $-y log f(x)$,其中 $f(x)$ 是预测为正例的概率;