【问题标题】:logistic / sigmoid function implementation numerical precision逻辑/sigmoid函数实现数值精度
【发布时间】:2016-09-01 15:44:54
【问题描述】:

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

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

但是,我已经看到了其他语言/框架的实现

1 / (1 + exp(-x))

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

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

【问题讨论】:

  • 似乎给出的答案都没有真正解决这个问题。 1 / (1 + exp(-x)) 准确与否?

标签: python scipy floating-point precision sigmoid


【解决方案1】:

这实际上只是为了稳定 - 输入数量级非常大的值可能会返回意想不到的结果。

如果expit1 / (1 + exp(-x)) 一样实现,那么将-710 的值放入函数将返回nan,而-709 将给出接近于零的值。这是因为exp(710) 太大而不能成为双倍。

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

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

【讨论】:

  • 我不确定我是否遵循您的观点...稳定性被认为是this GitHub thread 中代码的动机。
  • 我想说的是,1 / (1 + exp(-710)) 不返回 NaN,它在 IEEE 标准中返回 0 作为 1 / Inf = 0。在 numpy 1 / (1 + np.exp(-710)) == 0 中也是如此
  • 但问题肯定出在expit(x) 上,其中x 是一个较大的值。比如expit(-710)需要计算正数710的指数,即exp(+710)。我认为源代码中的exp 指的是您系统的C 数学库exp(不是ufunc np.exp),如果检测到溢出,它将引发错误,就像这里的情况一样.
【解决方案2】:

似乎使用起来会更有效率:

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

【讨论】:

  • 没有必要,因为exp(710) 计算为无穷大,1 / (1 + inf) = 0 计算为浮点数
【解决方案3】:

另一种方法是

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)),但对于负值更稳定

【讨论】:

    猜你喜欢
    • 2018-01-20
    • 2020-03-18
    • 2018-10-20
    • 2021-08-07
    • 1970-01-01
    • 1970-01-01
    • 2014-02-25
    • 2015-04-06
    • 1970-01-01
    相关资源
    最近更新 更多