一文弄懂LogSumExp技巧

网友投稿 493 2022-09-22

一文弄懂LogSumExp技巧

引言

今天来学习下LogSumExp(LSE)​​1​​​技巧,主要解决计算Softmax或CrossEntropy​​2​​时出现的上溢(overflow)或下溢(underflow)问题。

我们知道编程语言中的数值都有一个表示范围的,如果数值过大,超过最大的范围,就是上溢;如果过小,超过最小的范围,就是下溢。

什么是LSE

为什么需要LSE

我们通过实例来理解一下。

def bad_softmax(x): y = np.exp(x) return y / y.sum() x = np.array([1, -10, 1000])print(bad_softmax(x))

... RuntimeWarning: overflow encountered in exp... RuntimeWarning: invalid value encountered in true_dividearray([ 0., 0., nan])

接下来进行上面的优化,并进行测试:

def softmax(x): b = x.max() y = np.exp(x - b) return y / y.sum() print(softmax(x))

array([0., 0., 1.])

我们再看下是否会出现下溢:

x = np.array([-800, -1000, -1000])print(bad_softmax(x))# array([nan, nan, nan])print(softmax(x))# array([1.00000000e+00, 3.72007598e-44, 3.72007598e-44])

嗯,看来解决了这个两个问题。

等等,不是说LSE吗,怎么整了个什么归一化技巧。

好吧,回到LSE。

那我们是使用exp-normalize还是使用LogSumExp呢?

怎么实现LSE

实现LSE就很简单了,我们通过代码实现一下。

def logsumexp(x): b = x.max() return b + np.log(np.sum(np.exp(x - b))) def softmax_lse(x): return np.exp(x - logsumexp(x))

上面是基于LSE实现了Softmax,下面测试一下:

> x1 = np.array([1, -10, 1000])> x2 = np.array([-900, -1000, -1000])> softmax_lse(x1)array([0., 0., 1.])> softmax(x1)array([0., 0., 1.])> softmax_lse(x2)array([1.00000000e+00, 3.72007598e-44, 3.72007598e-44])> softmax(x2)> array([1.00000000e+00, 3.72007598e-44, 3.72007598e-44])

最后我们看一下数值稳定版的Sigmoid函数

数值稳定的Sigmoid函数

# 原来的做法def sigmoid_naive(x): return 1 / (1 + math.exp(-x)) # 优化后的做法def sigmoid(x): if x < 0: return math.exp(x) / (1 + math.exp(x)) else: return 1 / (1 + math.exp(-x))

然后用不同的数值进行测试:

> sigmoid_naive(2000)1.0> sigmoid(2000)1.0> sigmoid_naive(-2000)OverflowError: math range error> sigmoid(-2000)0.0

References

​​The Log-Sum-Exp Trick ​​​ ​​↩︎​​​​一文弄懂交叉熵损失 ​​​ ​​↩︎​​​​Exp-normalize trick​​​ ​​↩︎​​

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:vue3.0 2021-05-16
下一篇:狗狗狂奔十几公里为女主人送亲走红抖音,网友:看哭了!
相关文章

 发表评论

暂时没有评论,来抢沙发吧~