2012-03-04 26 views
17

使用numpy的有,我有一個函數的定義是:新政使用numpy的溢出EXP

def powellBadlyScaled(X): 
    f1 = 10**4 * X[0] * X[1] - 1 
    f2 = numpy.exp(-numpy.float(X[0])) + numpy.exp(-numpy.float(X[1])) - 1.0001 
    return f1 + f2 

該功能上評價最優化過程的時間數量巨大。它經常會引起異常:

RuntimeWarning: overflow encountered in exp 

我知道操作數不能存儲在分配的空間中。但是我怎樣才能克服這個問題呢?

+2

您需要修改算法。如果價值不適合,它不適合。找到一種不同的方式來表達不會溢出的計算。 – 2012-03-04 22:22:25

+1

你可以做的唯一明智的事情是看你的函數的漸近行爲。如果這是明智的,那麼高於某個閾值,則可以用漸近值替換顯式計算。如果漸近值不明智,那麼問題很可能出現在您選擇的算法中,而不是代碼中。 – DaveP 2012-03-04 23:38:18

+1

DaveP,exp的漸近行爲是exp ... – 2012-03-05 12:29:30

回答

16

您可以使用bigfloat軟件包。它支持任意精確的浮點操作。

http://packages.python.org/bigfloat/

import bigfloat 
bigfloat.exp(5000,bigfloat.precision(100)) 
# -> BigFloat.exact('2.9676283840236670689662968052896e+2171', precision=100) 

您是否使用了功能優化框架?他們通常實施價值邊界(使用懲罰條款)。試試看。相關的價值是否真的如此極端?在優化中,將log(f)最小化並不罕見。 (大概的對數似然等等)。您確定要優化該exp值,而不是log(exp(f))== f。 ?

看一看我回答這個問題:logit and inverse logit functions for extreme values

順便說一句,如果你要做的就是儘量減少powellBadlyScaled(X,Y),則最低爲x - > + INF和y - > + INF,所以不需要數字。

+1

確切的說,在優化上下文中,並且就Powell Badly Scaled函數用於測試而言,我施加了一些框約束。我第一次運行溢出的腳本考慮了初始化的限制(在授權框中進行一些抽樣),但沒有在主例程中(我沒有再檢查框限制)。考慮到約束條件,操作數不會溢出。無論如何,我會盡量嘗試大流量。謝謝! – octoback 2012-03-05 12:27:12

1

也許你可以通過檢查哪些區域會得到警告(可能會爲X [0],X [1])某些值並用一個非常大的數字替換結果來改進算法。你需要看看你的功能如何表現,我應該檢查例如exp(-x)+exp(-y)+x*y

0

根據您的具體需求,將輸入參數裁剪爲exp()可能會很有用。如果你真的想要得到一個inf如果它溢出或你想得到荒謬的巨大數字,那麼其他答案會更合適。

def powellBadlyScaled(X): 
    f1 = 10**4 * X[0] * X[1] - 1 
    f2 = numpy.exp(-numpy.float(X[0])) + numpy.exp(-numpy.float(X[1])) - 1.0001 
    return f1 + f2 


def powellBadlyScaled2(X): 
    f1 = 10**4 * X[0] * X[1] - 1 
    arg1 = -numpy.float(X[0]) 
    arg2 = -numpy.float(X[1]) 
    too_big = log(sys.float_info.max/1000.0) # The 1000.0 puts a margin in to avoid overflow later 
    too_small = log(sys.float_info.min * 1000.0) 
    arg1 = max([min([arg1, too_big]), too_small]) 
    arg2 = max([min([arg2, too_big]), too_small]) 
    # print(' too_small = {}, too_big = {}'.format(too_small, too_big)) # Uncomment if you're curious 
    f2 = numpy.exp(arg1) + numpy.exp(arg2) - 1.0001 
    return f1 + f2 

print('\nTest against overflow: ------------') 
x = [-1e5, 0] 
print('powellBadlyScaled({}) = {}'.format(x, powellBadlyScaled(x))) 
print('powellBadlyScaled2({}) = {}'.format(x, powellBadlyScaled2(x))) 

print('\nTest against underflow: ------------') 
x = [0, 1e20] 
print('powellBadlyScaled({}) = {}'.format(x, powellBadlyScaled(x))) 
print('powellBadlyScaled2({}) = {}'.format(x, powellBadlyScaled2(x))) 

結果:

Test against overflow: ------------ 
*** overflow encountered in exp 
powellBadlyScaled([-100000.0, 0]) = inf 
powellBadlyScaled2([-100000.0, 0]) = 1.79769313486e+305 

Test against underflow: ------------ 
*** underflow encountered in exp  
powellBadlyScaled([0, 1e+20]) = -1.0001 
powellBadlyScaled2([0, 1e+20]) = -1.0001 

注意powellBadlyScaled2沒有溢出/下溢當原始powellBadlyScaled做,但修改後的版本給1.79769313486e+305而不是inf在測試中的一個。我想有很多應用程序,其中1.79769313486e+305幾乎是inf,這將是罰款,甚至是首選,因爲1.79769313486e+305是一個實數,而inf不是。