概述
转:
https://zhuanlan.zhihu.com/p/27223959
目录
背景与定义
导数
softmax的计算与数值稳定性
Loss function
对数似然函数
交叉熵
Loss function求导
Softmax函数
背景与定义
在Logistic regression二分类问题中,我们可以使用sigmoid函数将输入映射到区间中,从而得到属于某个类别的概率。将这个问题进行泛化,推广到多分类问题中,我们可以使用softmax函数,对输出的值归一化为概率值。
这里假设在进入softmax函数之前,已经有模型输出值,其中是要预测的类别数,模型可以是全连接网络的输出,其输出个数为,即输出为。
所以对每个样本,它属于类别的概率为:
通过上式可以保证,即属于各个类别的概率和为1。
导数
对softmax函数进行求导,即求
第项的输出对第项输入的偏导。
代入softmax函数表达式,可以得到:
用我们高中就知道的求导规则:对于
它的导数为
所以在我们这个例子中,
上面两个式子只是代表直接进行替换,而非真的等式。
(即)对进行求导,要分情况讨论:
- 如果,则求导结果为
- 如果,则求导结果为
再来看对求导,结果为。
所以,当时:
当时:
其中,为了方便,令
对softmax函数的求导,我在两年前微信校招面试基础研究岗位一面的时候,就遇到过,这个属于比较基础的问题。
softmax的计算与数值稳定性
在Python中,softmax函数为:
def softmax(x):
exp_x = np.exp(x)
return exp_x / np.sum(exp_x)
传入[1, 2, 3, 4, 5]的向量
>>> softmax([1, 2, 3, 4, 5])
array([ 0.01165623,
0.03168492,
0.08612854,
0.23412166,
0.63640865])
但如果输入值较大时:
>>> softmax([1000, 2000, 3000, 4000, 5000])
array([ nan,
nan,
nan,
nan,
nan])
这是因为在求exp(x)时候溢出了:
import math
math.exp(1000)
# Traceback (most recent call last):
#
File "<stdin>", line 1, in <module>
# OverflowError: math range error
一种简单有效避免该问题的方法就是让exp(x)中的x值不要那么大或那么小,在softmax函数的分式上下分别乘以一个非零常数:
这里是个常数,所以可以令它等于。加上常数之后,等式与原来还是相等的,所以我们可以考虑怎么选取常数。我们的想法是让所有的输入在0附近,这样的值不会太大,所以可以让的值为:
这样子将所有的输入平移到0附近(当然需要假设所有输入之间的数值上较为接近),同时,除了最大值,其他输入值都被平移成负数,为底的指数函数,越小越接近0,这种方式比得到nan的结果更好。
def softmax(x):
shift_x = x - np.max(x)
exp_x = np.exp(shift_x)
return exp_x / np.sum(exp_x)
>>> softmax([1000, 2000, 3000, 4000, 5000])
array([ 0.,
0.,
0.,
0.,
1.])
当然这种做法也不是最完美的,因为softmax函数不可能产生0值,但这总比出现nan的结果好,并且真实的结果也是非常接近0的。
UPDATE(2017-07-07):
有同学问这种近似会不会影响计算结果,为了看原来的softmax函数计算结果怎么样,尝试计算`softmax([1000, 2000, 3000, 4000, 5000])`的值。由于numpy是会溢出的,所以使用Python中的bigfloat库。
import bigfloat
def softmax_bf(x):
exp_x = [bigfloat.exp(y) for y in x]
sum_x = sum(exp_x)
return [y / sum_x for y in exp_x]
res = softmax_bf([1000, 2000, 3000, 4000, 5000])
print('[%s]' % ', '.join([str(x) for x in res]))
结果:
[6.6385371046556741e-1738, 1.3078390189212505e-1303, 2.5765358729611501e-869, 5.0759588975494576e-435, 1.0000000000000000]
可以看出,虽然前四项结果的量级不一样,但都是无限接近于0,所以加了一个常数的softmax对原来的结果影响很小。
Loss function
对数似然函数
机器学习里面,对模型的训练都是对Loss function进行优化,在分类问题中,我们一般使用最大似然估计(Maximum likelihood estimation)来构造损失函数。对于输入的,其对应的类标签为,我们的目标是找到这样的使得最大。在二分类的问题中,我们有:
其中,是模型预测的概率值,是样本对应的类标签。
将问题泛化为更一般的情况,多分类问题:
由于连乘可能导致最终结果接近0的问题,一般对似然函数取对数的负数,变成最小化对数似然函数。
交叉熵
说交叉熵之前先介绍相对熵,相对熵又称为KL散度(Kullback-Leibler Divergence),用来衡量两个分布之间的距离,记为
这里是的熵。
假设有两个分布和,它们在给定样本集上的交叉熵定义为:
从这里可以看出,交叉熵和相对熵相差了,而当已知的时候,是个常数,所以交叉熵和相对熵在这里是等价的,反映了分布和之间的相似程度。关于熵与交叉熵等概念,可以参考该博客再做了解。
回到我们多分类的问题上,真实的类标签可以看作是分布,对某个样本属于哪个类别可以用One-hot的编码方式,是一个维度为的向量,比如在5个类别的分类中,[0, 1, 0, 0, 0]表示该样本属于第二个类,其概率值为1。我们把真实的类标签分布记为,该分布中,当属于它的真实类别。同时,分类模型经过softmax函数之后,也是一个概率分布,因为,所以我们把模型的输出的分布记为,它也是一个维度为的向量,如[0.1, 0.8, 0.05, 0.05, 0]。
对一个样本来说,真实类标签分布与模型预测的类标签分布可以用交叉熵来表示:
可以看出,该等式于上面对数似然函数的形式一样!
最终,对所有的样本,我们有以下loss function:
其中是样本属于类别的概率,是模型对样本预测为属于类别的概率。
Loss function求导
对单个样本来说,loss function对输入的导数为:
上面对求导结果已经算出:
当时:
当时:
所以,将求导结果代入上式:
最后
以上就是优秀中心为你收集整理的softmax loss函数和求导以及数值稳定性讨论的全部内容,希望文章能够帮你解决softmax loss函数和求导以及数值稳定性讨论所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复