logistic / sigmoid 函数实现数值精度

logistic / sigmoid function implementation numerical precision

scipy.special.expit中,逻辑函数实现如下:

if x < 0
    a = exp(x) 
    a / (1 + a) 
else 
    1 / (1 + exp(-x))

但是,我在其他 languages/frameworks 中看到了实现

1 / (1 + exp(-x))

我想知道 scipy 版本实际带来了多少好处。

对于非常小的x,结果接近于0。即使exp(-x)溢出到Inf也有效。

这实际上只是为了稳定性 - 否则输入非常大的值可能会 return 出乎意料的结果。

如果 expit 就像 1 / (1 + exp(-x)) 一样实现,那么将 -710 的值放入函数中将 return nan,而 -709 会像预期的那样给出接近于零的值。这是因为 exp(710) 太大而不能成为双数。

代码中的分支只是意味着避免了这种情况。

另请参阅 Stack Overflow 上的 this question and answer

似乎使用它会更有效率:

if x < -709
  sigmoid = 0.0
else
  sigmoid = 1.0 / (1.0 + exp(-x))

除非您需要精度为 10^-309 的数字(见下文),否则这似乎太过分了!

>>> 1 / (1 + math.exp(709.78))
5.5777796105262746e-309

另一种方法是

python np.where(x > 0, 1. / (1. + np.exp(-x)), np.exp(x) / (np.exp(x) + np.exp(0)))

因为 np.exp(x) / (np.exp(x) + np.exp(0)) 等同于 1. / (1. + np.exp(-x)) 但对于负值更稳定