引言
今天来学习下LogSumExp(LSE)1技巧,主要解决计算Softmax或CrossEntropy2时出现的上溢(overflow)或下溢(underflow)问题。
我们知道编程语言中的数值都有一个表示范围的,如果数值过大,超过最大的范围,就是上溢;如果过小,超过最小的范围,就是下溢。
什么是LSE
LSE被定义为参数指数之和的对数:
输入可以看成是一个n维的向量,输出是一个标量。
为什么需要LSE
在机器学习中,计算概率输出基本都需要经过Softmax函数,它的公式应该很熟悉了吧
但是Softmax存在上溢和下溢大问题。如果太大,对应的指数函数也非常大,此时很容易就溢出,得到nan
结果;如果太小,或者说负的太多,就会导致出现下溢而变成0,如果分母变成0,就会出现除0的结果。
此时我们经常看到一个常见的做法是(其实用到的是指数归一化技巧, exp-normalize3),先计算中的最大值,然后根据
这种转换是等价的,经过这一变换,就避免了上溢,最大值变成了;同时分母中也会有一个1,就避免了下溢。
我们通过实例来理解一下。
接下来进行上面的优化,并进行测试:
我们再看下是否会出现下溢:
嗯,看来解决了这个两个问题。
等等,不是说LSE吗,怎么整了个什么归一化技巧。
好吧,回到LSE。
我们对Softmax取对数,得到:
因为上面最后一项也有上溢的问题,所以应用同样的技巧,得
同样是取中的最大值。
这样,我们就得到了LSE的最终表示:
此时,Softmax也可以这样表示:
对LogSumExp求导就得到了exp-normalize(Softmax)的形式,
那我们是使用exp-normalize还是使用LogSumExp呢?
如果你需要保留Log空间,那么就计算,此时使用LogSumExp技巧;如果你只需要计算Softmax,那么就使用exp-normalize技巧。
怎么实现LSE
实现LSE就很简单了,我们通过代码实现一下。
上面是基于LSE实现了Softmax,下面测试一下:
最后我们看一下数值稳定版的Sigmoid函数
数值稳定的Sigmoid函数
我们知道Sigmoid函数公式为:
对应的图像如下:
其中包含一个,我们看一下的图像:
从上图可以看出,如果很大,会非常大,而很小就没事,变成无限接近。
当Sigmoid函数中的负的特别多,那么就会变成,就出现了上溢;
那么如何解决这个问题呢?可以表示成两种形式:
当时,我们根据的图像,我们取的形式;
当时,我们取
然后用不同的数值进行测试:
References
- The Log-Sum-Exp Trick ↩︎
- 一文弄懂交叉熵损失 ↩︎
- Exp-normalize trick ↩︎