首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >numpy.exp()中的溢出

numpy.exp()中的溢出
EN

Stack Overflow用户
提问于 2019-11-10 14:35:20
回答 3查看 2.1K关注 0票数 2

我必须为我的项目计算以下数组的指数:

代码语言:javascript
运行
复制
w  = [-1.52820754859, -0.000234000845064, -0.00527938881237, 5797.19232191, -6.64682108484,
       18924.7087966, -69.308158911, 1.1158892974, 1.04454511882, 116.795573742]

但是由于号码18924.7087966,我一直在溢水。

这样做的目的是避免使用额外的包,例如bigfloat (除了"numpy"),并得到一个接近的结果(这有一个小的相对错误)。

1.到目前为止,我尝试使用更高的精度(即float128):

代码语言:javascript
运行
复制
def getlogZ_robust(w):

    Z = sum(np.exp(np.dot(x,w).astype(np.float128)) for x in iter_all_observations())
    return np.log(Z)

但我还是得到了"inf“,这是我想要避免的。

  1. 我尝试过使用nump.clip()来裁剪它: def getlogZ_robust(w):z=和(np.exp(np.clip(np.dot(x,w).astype(np.float128),-11000,11000)用于x in iter_all_observations()返回np.log(Z) )

但是相对误差太大了。

如果可能的话,你能帮我解决这个问题吗?

EN

回答 3

Stack Overflow用户

发布于 2019-11-10 18:16:42

只有显着的扩展或任意的精确包才能处理数字上的巨大差异。w中最大和最负数的指数相差8000 (!)数量级。float (即双精度)只有15位的精度(意味着1+1e-16在数字上等于1),因此将小数字添加到最大数的巨大指数中没有任何影响。事实上,exp(18924.7087966)是如此巨大,以至于它主宰了总数。下面是一个在mpmath中执行扩展精度和的脚本:指数与exp(18924.7087966)之和的比率基本上是1

代码语言:javascript
运行
复制
w  = [-1.52820754859, -0.000234000845064, -0.00527938881237, 5797.19232191, -6.64682108484,
       18924.7087966, -69.308158911, 1.1158892974, 1.04454511882, 116.795573742]

u = min(w)
v = max(w)

import mpmath
#using plenty of precision
mpmath.mp.dps = 32768
print('%.5e' % mpmath.log10(mpmath.exp(v)/mpmath.exp(u)))
#exp(w) differs by 8000 orders of magnitude for largest and smallest number

s = sum([mpmath.exp(mpmath.mpf(x)) for x in w])

print('%.5e' % (mpmath.exp(v)/s))
#largest exp(w) dominates such that ratio over the sums of exp(w) and exp(max(w)) is approx. 1
票数 4
EN

Stack Overflow用户

发布于 2019-11-10 18:33:50

如果在最终结果中,由于附加项的数量级有很大的不同而导致数字松动的问题并不令人担心,我们也可以通过以下方式从数学上将和的log变换成指数,从而避免大数的exp

代码语言:javascript
运行
复制
log(sum(exp(w)))
= log(sum(exp(w-wmax)*exp(wmax)))
= wmax + log(sum(exp(w-wmax)))

在python中:

代码语言:javascript
运行
复制
import numpy as np
v = np.array(w)
m = np.max(v)
print(m + np.log(np.sum(np.exp(v-m))))

注意,np.log(np.sum(np.exp(v-m)))在数字上是零的,因为最大数的指数完全支配这里的和。

票数 4
EN

Stack Overflow用户

发布于 2019-11-10 18:05:09

Numpy有一个名为logaddexp的函数,它计算

代码语言:javascript
运行
复制
logaddexp(x1, x2) == log(exp(x1) + exp(x2))

而不显式计算中间exp()值。这样就避免了溢出。因此,解决办法如下:

代码语言:javascript
运行
复制
def getlogZ_robust(w):

    Z = 0
    for x in iter_all_observations():
        Z = np.logaddexp(Z, np.dot(x,w))
    return Z
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58789663

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档