Python 数值稳定的softmax
有没有一种数值稳定的方法来计算下面的softmax函数? 我得到的值在神经网络代码中变成了NaNPython 数值稳定的softmax,python,numpy,nan,scientific-computing,softmax,Python,Numpy,Nan,Scientific Computing,Softmax,有没有一种数值稳定的方法来计算下面的softmax函数? 我得到的值在神经网络代码中变成了NaN np.exp(x)/np.sum(np.exp(y)) 按照您的情况计算softmax函数没有什么错。问题似乎来自于爆发的梯度或您的训练方法的此类问题。关注那些“剪裁值”或“选择正确的权重初始分布”的问题softmax exp(x)/sum(exp(x)实际上在数值上表现良好。它只有正项,所以我们不必担心显著性的损失,分母至少和分子一样大,所以结果保证在0到1之间 唯一可能发生的意外是指数型流动过
np.exp(x)/np.sum(np.exp(y))
按照您的情况计算softmax函数没有什么错。问题似乎来自于爆发的梯度或您的训练方法的此类问题。关注那些“剪裁值”或“选择正确的权重初始分布”的问题softmax exp(x)/sum(exp(x)实际上在数值上表现良好。它只有正项,所以我们不必担心显著性的损失,分母至少和分子一样大,所以结果保证在0到1之间 唯一可能发生的意外是指数型流动过度或不足。x的单个元素溢出或所有元素下溢将使输出或多或少无用 但是,通过使用标识softmax(x)=softmax(x+c)很容易防止这种情况,该标识适用于任何标量c:从x减去max(x)会留下一个只有非正项的向量,排除溢出和至少一个为零的元素,排除消失分母(某些但并非所有条目中的下溢是无害的) 脚注:从理论上讲,灾难性事故的总数是可能的,但你需要一个荒谬的数字。例如,即使使用只能解析3位小数的16位浮点运算——与“正常”64位浮点运算的15位小数相比——我们也需要在2^1431(~6 x 10^431)和2^1432之间才能得到一个和,也就是说。谢谢解释,但我想知道为什么我们需要减去max(x)。因此,我找到了更详细的信息,希望能对那些和我有同样问题的人有所帮助。 请参阅以下链接文章中的“最大减法是怎么回事?”一节
Softmax功能容易出现两个问题:溢出和下溢 溢出:当非常大的数字近似为
无穷大
下溢:当非常小的数字(在数字行中接近零)被近似(即四舍五入)为零
在进行softmax计算时,为了解决这些问题,一个常见的技巧是通过从所有元素中减去输入向量中的最大元素来移动输入向量。对于输入向量x
,定义z
,以便:
z = x-max(x)
然后取新(稳定)向量的softmaxz
例如:
def stable_softmax(x):
z = x - max(x)
numerator = np.exp(z)
denominator = np.sum(numerator)
softmax = numerator/denominator
return softmax
# input vector
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])
# input vector with really large number, prone to overflow issue
In [269]: vec = np.array([12345, 67890, 99999999])
In [270]: stable_softmax(vec)
Out[270]: array([ 0., 0., 1.])
在上述情况下,我们使用stable\u softmax()
有关更多详细信息,请参阅一书中的一章。扩展@kmario23的答案以支持1维或2维numpy数组或列表(如果您通过softmax函数传递一批结果,则此选项很常见):
此处的答案显示了计算softmax的更好方法:@ajcr此链接上接受的答案实际上是糟糕的建议。阿披舍克,OP所做的事情,尽管他们一开始似乎不明白为什么是正确的。在softmax中,除了溢出,没有数字上困难的步骤。因此,在数学上相等的情况下,将所有输入向左移动,消除了溢出的可能性,因此在数值上是一种改进。是的,尽管该公认答案的作者在评论中承认,减去最大值不会引入“必要项”,但实际上提高了数值稳定性(也许这个答案应该被编辑…)。无论如何,数值稳定性的问题在其他几个答案中都有提到。@AbhishekBhatia:你认为这个链接能令人满意地回答你的问题吗,或者一个新的答案会对你有好处吗?“按照你的情况计算softmax函数没有错。”尝试使用它计算
softmax(800)
。在该范围内执行任何操作都会导致“inf”。如果您尝试在该范围内工作,python中的任何东西都是不稳定的。对于meI来说,这仍然是不稳定的。我已经使用它很长一段时间了,没有任何问题。您确定没有输入NaN或inf吗?我现在明白了-np.seterr(all='raise')
会抱怨大值的下溢,即使函数工作正常。这确实是最好的解决方案。
import numpy as np
def stable_softmax(x):
z = x - np.max(x, axis=-1, keepdims=True)
numerator = np.exp(z)
denominator = np.sum(numerator, axis=-1, keepdims=True)
softmax = numerator / denominator
return softmax
test1 = np.array([12345, 67890, 99999999]) # 1D
test2 = np.array([[12345, 67890, 99999999], [123, 678, 88888888]]) # 2D
test3 = [12345, 67890, 999999999]
test4 = [[12345, 67890, 999999999]]
print(stable_softmax(test1))
print(stable_softmax(test2))
print(stable_softmax(test3))
print(stable_softmax(test4))
[0. 0. 1.]
[[0. 0. 1.]
[0. 0. 1.]]
[0. 0. 1.]
[[0. 0. 1.]]