簡體   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