还是废话不说,直接上峰神的链接
Softmax理解之Smooth程度控制
softmax交叉熵我们经常使用,但是为啥有的任务,用softmax交叉熵效果很好,有的任务用效果却不怎么样。在实际项目中,分析softmax交叉熵的缺点,才能知道,什么时候有用,失效的怎么去优化。
不要总是当个黑盒子,什么情况下都用,精度上不去的时候,又不知道怎么去优化。
softmax交叉熵为啥会有不管用的时候呢,原因很简单,因为它不是我们真正的目标函数,是目标函数smooth过来的,为了方便求导和计算,那么我们就要和真正的目标函数比较一下,到底是在哪个岔路口,softmax交叉熵和真正的目标函数走丢了呢?
我们重新再复述一遍:max是我们真正的目标函数,LogSumExp是max smooth化,softmax近似取到了one-hot max的作用
我们来看下面的例子,我在峰神的基础上,加入了方差和均值的计算,想看下,到底是什么影响着softmax
x= [1, 2, 3, 4]
max(x) = 4
softmax(x) = [0.0321, 0.0871, 0.2369, 0.6439]
LSE(x) = 4.4402
从上面的例子来看,LSE是4.4402,对max的近似效果不错;另外,本来1和4只差4倍,通过指数函数的放大作用,softmax之后相差大约20倍,但是0.6439对1的靠近效果不是很好。
放大10倍之后,LSE和softmax的近似效果都不错
x= [10, 20, 30, 40]
max(x) = 40
softmax(x) = [9.36e-14 2.06e-9 4.54e-5 1.00]
LSE(x) = 40.00
缩小10倍后,LSE和softmax效果都不是很好,LSE把最大值拉倒了1.6,是实际最大值的4倍,softmax 把x的数据拉的很紧,最大值是0.2887,是最小值的1倍,而实际上x中,最大值是最小值的4倍,另外,最大值离1.0还很远。
x = [0.1 0.2 0.3 0.4]
softmax(x) = [0.2138 0.2363 0.2612 0.2887]
LSE(x) = 1.6425
缩小10倍之后,出现这种情况可以这样理解,softmax函数中,唯一的非线性,是exp(x)函数引入的,其他操作都是线性的,exp(x)函数曲线如下:
最后峰神总结说:输入的logit分数 的幅度既不能过大、也不能过小,过小会导致近对目标函数近似效果不佳的问题;过大则会使类间的间隔趋近于0,影响泛化性能。
1、影响softmax拟合作用的是数据分布的方差
由于softmax有下面的性质,
s o f t m a x ( z i ) = e z i ∑ j = 1 k e z j = e z i ∗ e C ∑ j = 1 k e z j ∗ z C = e z i + C ∑ j = 1 k e z j + C softmax(z_i) = \frac{e^{z_i}}{\sum_{j = 1}^k e^{z_j}} = \frac{e^{z_i} * e^C}{\sum_{j = 1}^k e^{z_j} * z^C} = \frac{e^{z_i +C}}{\sum_{j = 1}^k e^{z_j+C}} softmax(zi)=∑j=1kezjezi=∑j=1kezj∗zCezi∗eC=∑j=1kezj+Cezi+C
所以,当我们把所有的输入数据,减去均值,变成均值为0的分布时,再次分析上面的例子:
x= [1, 2, 3, 4]
减去均值后变为:
x = [-1.5000, -0.5000, 0.5000, 1.5000]
var: 1.66
softmax: [0.0321, 0.0871, 0.2369, 0.6439]
x= [10, 20, 30, 40]
减去均值后变为:
x = [-15., -5., 5., 15.]
var: 166.66
softmax:[9.3572e-14, 2.0611e-09, 4.5398e-05, 9.9995e-01]
x = [0.1, 0.2, 0.3, 0.4]
减去均值后变为:
x = [-0.1500, -0.0500, 0.0500, 0.1500]
var: 0.016
softmax: [0.2138, 0.2363, 0.2612, 0.2887]
可以看到,我们把数据变成了均值为0,不影响softmax的值,发现,方差越大,softamx的拟合效果越好,其实不管数据分布在哪个数据段,不是大小的问题,是数据方差的问题
2、类别数增加时,会影响softmax的拟合作用
2.1、输入的数据范围固定时,类别数越多,softmax的近似效果越差
x = torch.linspace(-10, 10, 10)
lse = torch.logsumexp(x.unsqueeze(0), 1)
max = torch.max(x.unsqueeze(0), 1)[0]
y = F.softmax(x)
print ("max:", max.item())
print ("lse:", lse.item())
print ("softmax:", y[-1].item())
plt.plot(x,y)
plt.show()
x的输入范围一直是[-10, 10],当个数是10时,x的方差值为45.26,max函数值是10,LSE的函数值是10.114,softmax最大值的函数值是0.98,softmax和LSE的近似效果都不过;
当x的输入范围[-10, 10]不变,个数变为100是,x的方差值为34.35,max函数值是10,LSE的函数值是11.69,softmax最大的函数值是0.18;
当x的输入范围[-10, 10]不变,个数变为500是,x的方差值为33.53,max函数值是10,LSE的函数值是13.23,softmax最大的函数值是0.039;
输入的数据范围固定时,类别数越多,softmax的近似效果越差
2.2、类别数很多时,若想softmax的近似效果好,需要拉宽输入分数的范围
输入个数是500时,把输入的数据范围拉到 [-1000, 1000],x 的方差值为335340.0,softmax最大的函数值为0.9818,max值为1000,LSE的值为1000.018。