我必须为我的项目计算以下数组的指数:
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“,这是我想要避免的。
但是相对误差太大了。
如果可能的话,你能帮我解决这个问题吗?
发布于 2019-11-10 18:16:42
只有显着的扩展或任意的精确包才能处理数字上的巨大差异。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
发布于 2019-11-10 18:33:50
如果在最终结果中,由于附加项的数量级有很大的不同而导致数字松动的问题并不令人担心,我们也可以通过以下方式从数学上将和的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(v-m)))
在数字上是零的,因为最大数的指数完全支配这里的和。
发布于 2019-11-10 18:05:09
Numpy有一个名为logaddexp的函数,它计算
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
https://stackoverflow.com/questions/58789663
复制相似问题