数值稳定的softmax

问题描述 投票:8回答:4

下面有一个数值稳定的方法来计算softmax函数吗?我在神经网络代码中获得的值变为Nans。

np.exp(x)/np.sum(np.exp(y))
python numpy nan scientific-computing softmax
4个回答
29
投票

softmax exp(x)/ sum(exp(x))实际上在数值上表现良好。它只有正项,所以我们不必担心重要性的损失,分母至少与分子一样大,所以结果保证在0到1之间。

可能发生的唯一事故是指数过度或不足。 x的所有元素的单个或下溢的溢出将使输出或多或少无用。

但是很容易通过使用标识softmax(x)= softmax(x + c)来保护任何标量c:从x减去max(x)只留下一个只有非正条目的向量,排除了溢出并且至少有一个零元素排除了消失的分母(某些但不是所有条目的下溢都是无害的)。

注意:从理论上讲,总和中的灾难性事故是可能的,但是你需要一些荒谬的术语并且是荒谬的不幸。此外,numpy使用相对强大的成对求和。


6
投票

Softmax功能容易出现两个问题:溢出和下溢

溢出:当非常大的数字近似为infinity时发生

下溢:当非常小的数字(数字线中接近零)被近似(即舍入为)时发生,如zero

为了在进行softmax计算时解决这些问题,常见的技巧是通过从所有元素中减去输入向量中的最大元素来移位输入向量。对于输入向量x,定义z,使得:

z = x-max(x)

然后采用新(稳定)矢量z的softmax


例:

In [266]: def stable_softmax(x):
     ...:     z = x - max(x)
     ...:     numerator = np.exp(z)
     ...:     denominator = np.sum(numerator)
     ...:     softmax = numerator/denominator
     ...:     return softmax
     ...: 

In [267]: vec = np.array([1, 2, 3, 4, 5])

In [268]: stable_softmax(vec)
Out[268]: array([ 0.01165623,  0.03168492,  0.08612854,  0.23412166,  0.63640865])

In [269]: vec = np.array([12345, 67890, 99999999])

In [270]: stable_softmax(vec)
Out[270]: array([ 0.,  0.,  1.])

有关更多详细信息,请参阅Numerical Computation一书中的deep learning一章。


1
投票

感谢Paul Panzer's的解释,但我想知道为什么我们需要减去max(x)。因此,我发现了更详细的信息,并希望它对与我有同样问题的人有所帮助。请参阅以下链接文章中的“最大减法是什么?”部分。

https://nolanbconaway.github.io/blog/2017/softmax-numpy


0
投票

计算softmax函数没有任何问题,就像你的情况一样。问题似乎来自于爆炸梯度或您的训练方法的这类问题。用“削减值”或“选择正确的权重初始分布”来关注那些问题。

© www.soinside.com 2019 - 2024. All rights reserved.