交叉熵损失分析
分类任务是训练神经网络最常用的任务之一。对于分类任务来说,它的损失函数一般采用交叉熵损失函数。至于为什么这样做,本博客在此进行简单的分析。
平方损失函数
在分类任务上,类别往往属于离散的整形数据(integer)。最直观的想法就是直接使用平方损失函数: L = 1 2 ∑ i = 1 N ( y i − t i ) 2 L=\frac{1}{2}\sum_{i=1}^N(y_i-t_i)^2 L=21∑i=1N(yi−ti)2。这里假设 y i y_i yi为第i个样本网络的输出结果, t i t_i ti为该样本对应的标签。
使用平方损失虽然简单,但是缺点也很明显:
- 例如:在二分类任务中,如果使用最后一层sigmoid激活以后的结果作为类别( y = s i g m o i d ( z ) , L = 1 2 ( y − t ) 2 y=sigmoid(z), L=\frac{1}{2}(y-t)^2 y=sigmoid(z),L=21(y−t)2),如果网络输出了0.000001,那么在softmax这块( d L d z = ( y − t ) ∗ y ∗ ( 1 − y ) \frac{dL}{dz} = (y-t)*y*(1-y) dzdL=(y−t)∗y∗(1−y)),导数基本很小,导致无法反向更新。对于logistic function都会存在这些问题。
- 一般分类任务中,类别之间是互斥的。那么所有类别对应的概率之和应该等于1。平方损失无法体现出该点。
Softmax损失函数
Softmax函数解决了互斥类别中各个类的概率之和等于1的问题。该函数定义如下:
p i = e a i ∑ k = 1 N e a k p_i = \frac{e^{a_i}}{\sum_{k=1}^N e^{a_k}} pi=∑k=1Neakeai
在numpy中,softmax函数可以通过如下实现:
def softmax(X):
exps = np.exp(X)
return exps / np.sum(exps)
但是这里有坑需要注意, e x e^x ex很容易出现数值溢出,返回nan的错误。
所以需要对softmax实现进行以下优化:
p i = e a i ∑ k = 1 N e a k = C e a i C ∑ k = 1 N e a k = e a i + l o g ( C ) ∑ k = 1 N e a k + l o g ( C ) p_i = \frac{e^{a_i}}{\sum_{k=1}^N e^{a_k}} = \frac{Ce^{a_i}}{C\sum_{k=1}^N e^{a_k}}=\frac{e^{a_i + log(C)}}{\sum_{k=1}^N e^{a_k+log(C)}} pi=∑k=1Neakeai=C∑k=1NeakCeai=∑k=1Nea