【问题标题】:Avoiding numerical instability when computing 1/(1+exp(x)) python计算 1/(1+exp(x)) python 时避免数值不稳定
【发布时间】:2015-11-25 15:36:04
【问题描述】:

我想为(可能很大)x 计算 1/(1+exp(x))。这是一个介于 0 和 1 之间的表现良好的函数。我可以这样做

import numpy as np
1.0/(1.0+np.exp(x))

但在这个幼稚的实现中,np.exp(x) 可能只会返回 0 或大 x 的无穷大,具体取决于符号。 python中是否有可以帮助我的功能?

我正在考虑实现系列扩展和系列加速,但我想知道这个问题是否已经解决。

【问题讨论】:

  • 您能否举例说明您获得较差输出的输入,以及您希望为这些输入获得的输出?对于几乎所有x,您给出的表达式实际上在数值上表现得相当好。 (我能想到的唯一困难的地方是np.exp(x) 只是溢出了一个双精度值,你最终会得到零而不是正确的次正常值。)

标签: python numpy floating-point scipy expansion


【解决方案1】:

您可以使用scipy.special.expit(-x)。它将避免1.0/(1.0 + exp(x))产生的溢出警告。

【讨论】:

  • 很好 - expit 也适用于 np.longdouble,并且在 x 的值比我的天真回答稍大时溢出。
  • @ali_m 感谢您的检查。我从答案中删除了“仍然是 64 位浮点”。
  • 谢谢,我不知道scipy.special.expit(-x)的存在。很棒的发现!
【解决方案2】:

从根本上说,您受到浮点精度的限制。例如,如果您使用 64 位浮点数:

fmax_64 = np.finfo(np.float64).max  # the largest representable 64 bit float
print(np.log(fmax_64))
# 709.782712893

如果 x 大于大约 709,那么您将无法使用 64 位浮点数表示 np.exp(x)(或 1. / (1 + np.exp(x)))。

您可以使用扩展精度浮点数(即np.longdouble):

fmax_long = np.finfo(np.longdouble).max
print(np.log(fmax_long))
# 11356.5234063

np.longdouble 的精度可能因您的平台而异 - on x86 it is usually 80 bit,这将允许您使用高达约 11356 的 x 值:

func = lambda x: 1. / (1. + np.exp(np.longdouble(x)))
print(func(11356))
# 1.41861159972e-4932

除此之外,您还需要重新考虑如何计算扩展,或者使用支持任意精度算术的 mpmath 之类的东西。然而,与 numpy 相比,这通常以运行时性能更差为代价,因为不再可能进行矢量化。

【讨论】:

  • 谢谢,我去看看 mpmath。我必须弄清楚我的任务真正需要什么样的精度。
  • 如果您问另一个问题来解释您要解决的全部问题,您可能会得到一个更有帮助的答案 - 也许有一种方法可以完全避免计算 exp(x)
猜你喜欢
  • 2021-06-09
  • 1970-01-01
  • 1970-01-01
  • 2011-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-09
  • 1970-01-01
相关资源
最近更新 更多