2017-03-16 72 views
2

在最小化問題和他們的雅可比行列式的約束條件之間存在相當多的共享計算,直到我幾乎可以免費獲得雅可比行列式。有什麼辦法可以分享計算嗎?scipy.optimize.minimize,一次性計算約束條件和他們的雅可比行程

+0

你可以添加一個例子嗎? – Cleb

+0

由於函數是python中的一等公民,我想你可以嘗試定義一個函數來處理jacobian和constraint,並使用實例屬性來存儲常用的東西。但是,那麼你將不得不首先處理哪一個......也許通過設置一個帶有「回調」的標誌?我只是在猜測,我從來沒有做過類似的事情。 –

回答

2

由於約束條件和雅各布可能並不總是一起評估,所以您只能期待較小的改進。

import scipy.optimize as opt 
from functools import lru_cache 

# only for the dummy example: 
import scipy as sp 
from time import sleep 

def cost(x): 
    '''dummy cost function to minimize on [1,11]''' 
    return sp.log(x) 

@lru_cache(maxsize=None) # careful with this choice 
def heavy_stuff(x): 
    '''idle computation representing common work in constraint and jacobian''' 
    sleep(0.1) 
    return 0 

def constraint(x): 
    '''constraint for [1,11], with simulated idle work''' 
    # the following only works for 1d arrays, needs more work for nd 
    throwaway = heavy_stuff(tuple(x)) 
    return 5 - abs(6 - x) # non-negative between 1 and 11 

def jacobian(x): 
    '''return the jacobiam with the same simulated idle work''' 
    throwaway = heavy_stuff(tuple(x)) 
    return 1/x 

x0 = 11 
tol = 0 
opts = {'disp': True} 
cons = {'type': 'ineq', 'fun': constraint} 
kwargs = {'method':'SLSQP', 'constraints': cons, 
      'jac': jacobian, 'tol': tol, 'options': opts} 
res = opt.minimize(cost,x0,**kwargs) 
print(heavy_stuff.cache_info()) 

上述嘗試啞例子在減少log(x):但是,如果你可以把常見的計算成一個單獨的函數/方法,你可以讓你不需要以後重新計算其cache其返回值區間[1,11]。我不定義界限,而是定義了一個給我們間隔的約束,這樣我就可以顯示我對你的問題的意思。

constraintjacobian都做同樣的工作,這是你想在多個評估發生同樣的論點時想要的。您必須將所有這些常用計算放入一個常用函數(這裏命名爲heavy_stuff),並使用constraintjacobian中的返回值。

我的觀點是,你應該使用functools.lru_cache來記憶沉重的東西。通過設置適當的緩存大小,使用相同的x的多個評估heavy_stuff將立即爲您提供先前計算的返回值,而不必重新計算。

如果我的懷疑是正確的,maxsize=1可能就足夠了lru_cache裝飾者。設置maxsize=None(沒有上限)會造成失去太多內存的危險,因爲沒有理由。你應該試驗一下,看看是否有多個記憶值是必要的,或者是少數還是隻有一個就足夠了。

但是,請注意,lru_cache使用一個詞典來查找先前計算的結果,其中鍵是裝飾函數的輸入參數。這意味着輸入參數必須是可哈希的,這實際上意味着它們應該是不可變的。 Numpy數組與列表非常相似,它們同樣是而不是可哈希。這就是爲什麼我們使用tuple(x)heavy_stuff稱爲:1d數組輸入被轉換爲元組。如果x是一個多維數組,則每一層的嵌套都必須轉換爲一個元組。更糟的是,heavy_stuff幾乎肯定必須將元組轉換回numpy ndarrays才能完成繁重的工作。但是,如果計算雅可比/約束實際上是CPU密集型的,那麼你總體上可能還是更好。

如果你想評估你的緩存的性能,你應該仔細看看最後打印的heavy_stuff.cache_info()。它會告訴你使用緩存值的頻率,以及需要計算新值的次數。