版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Katherine_hsr/article/details/81276021
在CNN中,全连接层后会加上softmax函数,并且一般用交叉熵函数作为损失函数。这篇文章主要记录softmax把CNN的输出变成概率的过程以及交叉熵如何为优化过程提供度量,并且用python实现。
softmax函数
softmax函数将一个N维向量的输入的每一维都转换成区间维(0,1)之间的一个实数,公式如下:
pi=eai∑Nk=1eak
softmax可以将全连接层的输出映射成一个概率分布,我们的训练目标是让属于第k类的样本经过softmax函数之后,第k类概率越大越好。
下面是使用python实现softmax函数:
def softmax(x):
exps = np.exp(x)
return exps / np.sum(exps)
由于numpy中浮点类型是有数值上的限制的,对于指数函数来说很容易打破上线返回nan。
为了避免出现nan这种情况,通常在分子和分母上同时乘一个常数C,表达式如下:
pj=eai∑Nk=1eak=CeaiC∑Nk=1eak=eai+log(C)∑Nk=1eak+log(C)
理论上我们可以选择任何一个值作为log(C),但是一般我们会选择log(C)=-max(a),通过这种方法可以使得原来非常大的指数结果变成0,避免出现nan的情况。
下面是用python实现改进后的softmax函数:
def stable_softmax(x):
exps = np.exp(x-np.max(x))
return exps / np.sum(exps)
softmax函数的导数推倒过程
softmax函数可以将样本输出变成概率密度函数,由于这一特性我们可以把它放到神经网络最后一层,最理想的输出就是样本类别one-hot的表现形式。我们接下来了解一下如何计算softmax函数的梯度,首先对softmax函数求导:
∂pj∂aj=∂eai∑Nk=1eak∂aj
根据求导法则
f(x)=g(x)h(x)
的导数为
f′(x)=g′(x)h(x)−h′(x)g(x)h(x)2
. 在softmax函数中,
g(x)=eai
,
h(x)=∑Nk=1eak
. 对于h(x)来说,
∂∂aj
都为
eaj
, 对于g(x)来说,当i=j的时候
∂∂aj
才是
eaj
。下面为softmax函数求导的具体过程:
if i=j:
∂eai∑Nk=1eak∂aj=eai∑Nk=1eak−eajeai(∑Nk=1eak)2(∑Nk=1eak)2=eai(∑Nk=1eak−eaj)(∑Nk=1eak)2=eaj∑Nk=1eak×(∑Nk=1eak−eaj)∑Nk=1eak=pi(1−pj)
if
i≠j
∂eai∑Nk=1eak∂aj=0−eajeai(∑Nk=1eak)2=−eaj∑Nk=1eak×eai∑Nk=1eak=−pj⋅pi
所以softmax函数可以表示成如下形式:
∂pj∂aj={pi(1−pj)ifi=j −pj⋅piifi≠j
交叉熵损失函数
交叉熵损失函数体现了模型输出的概率和样本真实概率之间的相似程度,它可以作为foftmax函数激活的神经网络的损失函数,定义如下:
H(y,p)=−∑iyilog(pi)
交叉熵损失函数的求导过程
L=−∑Iyilog(pi)
∂L∂oi=−∑kyk∂log(pk)∂oi=−∑kyk∂log(pk)∂pk×∂pk∂oi=−∑yk1pk×∂pk∂oi
加上softmax函数的导数:
∂L∂oi=−yi(1−pi)−∑k≠jyk1pk(−pkpi)=−yi(1−pi)+∑k≠1yk⋅pi=−yi+yipi+∑k≠1yk⋅pi=pi(yi+∑k≠1yk−yi)=pi(yi+∑k≠1yk)−yi
y代表标签的one-hot编码,因此
∑kyk=1
, 并且
yi+∑k≠1yk=1
。因此我们可以得到:
∂L∂oi=pi−yj