c语言sscanf函数的用法是什么
493
2022-09-22
一文弄懂LogSumExp技巧
引言
今天来学习下LogSumExp(LSE)1技巧,主要解决计算Softmax或CrossEntropy2时出现的上溢(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小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~