繁体   English   中英

numpy.exp() 中的溢出

[英]Overflow in numpy.exp()

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

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):

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 = sum(np.exp(np.clip(np.dot(x,w).astype(np.float128),-11000, 11000)) for x in iter_all_observations()) return np.log(Z)

但是相对误差太大了。

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

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

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

如果由于添加项的数量级差异很大而导致最终结果中丢失数字的问题不值得关注,则还可以通过以下方式在数学上转换指数和的对log ,从而避免大数的exp

log(sum(exp(w)))
= log(sum(exp(w-wmax)*exp(wmax)))
= wmax + log(sum(exp(w-wmax)))

在 python 中:

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(vm)))在数值上为零,因为这里最大数的指数完全支配总和。

Numpy 有一个名为logaddexp的 function 计算

logaddexp(x1, x2) == log(exp(x1) + exp(x2))

无需显式计算中间 exp() 值。 这样就避免了溢出。 所以这里是解决方案:

def getlogZ_robust(w):

    Z = 0
    for x in iter_all_observations():
        Z = np.logaddexp(Z, np.dot(x,w))
    return Z

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM