交叉熵(cross entropy)是深度学习中常用的一个概念,一般用来求目标与预测值之间的差距。以前做一些分类问题的时候,没有过多的注意,直接调用现成的库,用起来也比较方便。最近发现自己对交叉熵的理解有些模糊,不够深入。
信息论
交叉熵是信息论中的一个概念,要想了解交叉熵的本质,需要先从最基本的概念讲起。
1.信息量
如果说概率P是对确定性的度量,那么信息就是对不确定性的度量 举个例子: 事件A:巴西队进入了2018世界杯决赛 事件B:中国对进入了2018世界杯决赛 凭直觉来说,事件B的信息量比事件A的信息量大,究其原因,是因为事件A发生的概率很大,事件B发生的概率很小。所以当越不可能发生的事件发生了,我们获取到的信息量就越大。那么信息量应该和事件发生的概率有关,信息量的大小和事件发生的概率成反比。具体的数学表示如下:
假设X是一个离散型随机变量,其取值集合为χ,概率分布函数p(x)=P(X=x),xϵχ,则定义事件X=x0的信息量为: I(x0)=−log(p(x0))
2.熵
考虑另一个问题,对于某个事件,有n种可能性,每一种可能性都有一个概率p(xi),这样就可以计算出某一种可能性的信息量
序号 | 事件 | 概率P | 信息量 |
---|---|---|---|
A | 电脑正常 | 0.7 | −log(p(A))=0.36 |
B | 电脑死机 | 0.2 | −log(p(b))=1.61 |
C | 电脑爆炸 | 0.1 | −log(p(c))=2.30 |
现在有了信息量的定义,而熵用来表示所有信息量的期望,即: H(X)=−n∑i=1p(xi)log(p(xi)) 其中n代表所有的n中可能性,所以上面的结果就是: H(X)=−[p(A)log(p(A))+p(B)log(p(B))+p(C))log(p(C))] =0.7×0.36+0.2×1.61+0.1×2.30 =0.804
然而一些比较特殊的问题,比如投掷硬币只有两种可能,买彩票只有两种可能,我们称之为0-1分布问题,对于这类问题,熵的计算方法可以简化为如下计算: H(X)=−n∑i=1p(xi)log(p(xi)) =−p(x)log(p(x))−(1−p(x))log(1−p(x))
3.相对熵(KL散度)
相对熵又称KL散度,如果我们对于同一个随机变量 x 有两个单独的概率分布 P(x) 和 Q(x),我们可以使用 KL 散度(Kullback-Leibler (KL) divergence)来衡量这两个分布的差异。 如果用P来描述目标问题,而不是用Q来描述目标问题,得到的信息增量,<font color='red'>在机器学习中,P往往用来表示样本的真实分布,比如[1,0,0]表示当前样本属于第一类。Q用来表示模型所预测的分布,比如[0.7,0.2,0.1] </font>。 直观的理解就是如果用P来描述样本,那么就非常完美。而用Q来描述样本,虽然可以大致描述,但是不是那么的完美,信息量不足,需要额外的一些“信息增量”才能达到和P一样完美的描述。如果我们的Q通过反复训练,也能完美的描述样本,那么就不再需要额外的“信息增量”,Q等价于P。KL散度的计算公式: DKL(p||q)=n∑i=1p(xi)log(p(xi)q(xi)) n为事件的所有可能性,DKL的值越小,表示q分布和p分布越接近
4.交叉熵
对上式KL散度变形可以得到: DKL(p||q)=n∑i=1p(xi)log(p(xi))−n∑i=1p(xi)log(q(xi)) =−H(p(x))+[−n∑i=1p(xi)log(q(xi))]
等式的前一部分正是p的熵,等式的后一部分,就是交叉熵: H(p,q)=−n∑i=1p(xi)log(q(xi))
在机器学习中,我们需要评估label和predict之间的差距,使用KL散度刚刚好,即:DKL(y||ˆy),由于KL散度中的前一部分−H(y)不变,故在优化过程中,只需要关注交叉熵就可以了。
机器学习中交叉熵的应用
1.为什么要用交叉熵做loss函数?
在逻辑回归问题中,常常使用MSE(Mean Squared Error)作为loss函数,如: loss=12mm∑i=1(yi−^yi)2
这里的m表示m个样本,loss为m个样本loss的均值。MSE在逻辑回归问题中比较好用,那么在分类问题中还是如此么?
2.交叉熵在单分类问题中的使用
这里的单分类是指,每一张图像样本只能有一个类别,比如只能是狗或者只能是猫。交叉熵在单分类问题上的标配方法是: loss=−n∑i=1yilog(^yi)
这个式子为计算一张样本的loss,n表示有n中类别,每个样本只属于其中一种,举例说明:
* | 猫 | 狗 | 兔 |
---|---|---|---|
Label | 0 | 1 | 0 |
Pred | 0.3 | 0.6 | 0.1 |
那么loss为: loss=−(0×log(0.3)+1×log(0.6)+0×log(0.1) =−log(0.6)
对应一个batch的loss就是: loss=−1mm∑j=1n∑i=1yjilog(^yji)
m为当前batch的样本数
3.交叉熵在多分类问题中的使用
这里的多类别是指,每一张图像样本可以由多个类别,比如同时包含一只猫和一只狗,和单分类问题的标签不同,多分类的标签是n-hot的。比如一张图里面既有猫,又有狗,那么具体看例子:
* | 猫 | 狗 | 兔 |
---|---|---|---|
Label | 1 | 1 | 0 |
Pred | 0.8 | 0.7 | 0.1 |
值得注意的是,这里的Pred不再是通过softmax计算的了,这里采用的是sigmoid激活函数,将每一个节点的输出归一化到0-1之间。所有Pred值的和也不再是1,换句话说,就是每一个Label都是独立分布的,相互之间没有影响。所以交叉熵在这里是单独对每一个节点进行计算,每一个节点只有两种可能值,所以是一个二项分布。对于这种只有两个结果0,1的分布,熵的计算可以进行简化,同样的,交叉熵的计算也可以简化,即: loss=−ylog(ˆy)−(1−y)log(1−ˆy) 注意,上面式子只是针对一个节点的计算公式,这一点要和单分类的loss区分开来,例子中可以计算为: loss猫=−1×log(0.8)−(1−1)log(1−0.8)=−log(0.8) loss狗=−1×log(0.7)−(1−1)log(1−0.7)=−log(0.7) loss兔=−0×log(0.1)−(1−0)log(1−0.1)=−log(0.9) 单张样本的loss即为loss=loss猫+loss狗+loss兔 每一个batch的loss就是: loss=m∑j=1n∑i=1−yjilog(^yji)−(1−yji)log(1−^yji) 式中m为当前batch的样本数量,n为类别数。
补充(sigmoid与softmax)
1. 作用
sigmoid是一个激活函数,输入数据进行完线性变换后,都要进行一个非线性变换,原理就是计算sigmoid函数值,常用的激活函数还有tanh,relu等,sigmoid函数公式为:f(x)=11+e−x,作用时将数值归一化到0-1之间。
tensorflow中的接口示例如下:
1 | import tensorflow as tf |
softmax是网络结构输出层的一层,计算输出层的值。主要用于神经网络最后一层,作为输出层进行多分类,是Logistic二分类的推广。在Logistic回归中,loss函数是sigmoid交叉熵,所以loss公式为: H(X)=−p(x)log(p(x))−(1−p(x))log(1−p(x))
其中p(x)为f(x)=11+e−θTx。 在softmax回归中,我们解决的事多分类问题,它的本质就是将一个K维的任意实数向量压缩(映射)成另一个K维的实数向量,其实向量中的每个元素取值都介于(0,1)之间,softmax函数形式如下: Si=eVi∑jeVj
也就是说,是该元素的指数与所有元数指数的比值,这个定义非常直观,还有很多优点。
- 计算与标注样本的差距
在神经网络的计算当中,我们经常需要计算按照神经网络的正向传播计算的分数S1,和按照正确标注计算的分数S2,之间的差距,计算Loss,才能应用反向传播。Loss定义为交叉熵: loss=−n∑i=1yjilog(^yji)
其中ˆy就是softmax计算结果,这样的话,它占的比重越大,这个样本的Loss也就越小,这种定义符合我们的要求
- 计算上非常的方便
我们对分类的Loss进行改进的时候,我们要通过梯度下降,每次优化一个step大小的梯度,我们应用链式法则对loss进行求导,最后的形式非常简单,过程如下,我们重新定义loss,a为拟合值,是关于参数输出zi的函数,y为真实标签,则: C=−∑iyilogai
我们的目标是,求loss对于zi的梯度:∂C∂zi,根据链式法则: ∂C∂zi=∂C∂aj∂aj∂zi
有个人可能有疑问了,这里为什么是aj而不是ai,这里要看一下softmax的公式了,因为softmax公式的特性,它的分母包含了所有神经元的输出,所以,对于不等于i的其他输出里面,也包含着zi,所有的a都要纳入到计算范围中,并且后面的计算可以看到需要分为i=j和i≠j两种情况求导。 下面我们一个一个推: ∂C∂aj=∂(−∑jyjlogaj)∂aj=−∑jyj1aj
第二个稍微复杂一点:(除法的导数公式uv=u′v−uv′v2)
- 如果 i=j:
∂ai∂zi=∂(ezi∑kezk)∂zi=∑kezkezi−(ezi)2(∑kezk)2=(ezi∑kezk)(1−ezi∑kezk)=ai(1−ai)
- 如果 i≠j:
∂aj∂zi=∂(ezj∑kezk)∂zi=−ezj(1∑kezk)2ezi=−aiaj
ok,所有我们把上面的组合连起来: ∂C∂zi=(−∑jyj1aj)∂aj∂zi=−yiaiai(1−ai)+∑j≠iyjajaiaj=−yi+yiai+∑j≠iyjai=−yi+ai∑jyj 最后的结果看起来简单了很多,最后针对分类问题,我们给定的yi只会是0或者1,因此,对于分类问题,这个梯度等于: ∂C∂zi=ai−yi
举个例子,通过若干层的计算,最后得到的某个训练样本的向量的分数是*[ 1, 5, 3 ],那么概率分别就是[ 0.015, 0.866, 0.117],如果这个样本正确的分类是第二个的话,那么计算出来的偏导就是[0.015,0.866−1,0.117]=[0.015,−0.134,0.117]*,!然后再根据这个进行back propagation就可以了。
tensorflow中关于softmax的使用:
1 | import tensorflow as tf |