一般的方法是使用定製的callback。
回調:可調用,可選
每次迭代後調用,如回調(XK),其中XK是當前的參數矢量。
現在使用,因爲這是很容易:
history = []
def callback(x):
fobj = rosen(x)
history.append(fobj)
result = minimize(rosen, x0, method='Nelder-Mead', tol=1e-6, callback=callback)
print(history)
但作爲率先在上述評論這兩個環節中的評論中提到(好!鏈接),這種方法是使用額外功能-evaluations! (這顯然是基於經典軟件開發設計的原理 - 原理問題:要使用多少抽象?)
根據您的任務,函數評估可能代價高昂(如果不是,則忽略以下內容)!
在這種情況下,您可以使用memoization來緩存先前計算的值,並且不要一直重新計算它們。
現在至少你的優化,「內爾德 - 米德,無梯度優化的一個,你會需要你緩存多個值是媲美沒有回調的解決方案(因爲不知何故需要更老的值)。這可能取決於選擇的最小化方法(以及一些內部方法)。
scipy使用一些記憶漸變,當使用數值微分,因爲這是非常昂貴的。但是這個代碼只緩存最後一個值,這對你的情況不起作用(NM是不同的)。
因此,我們可以建立我們自己的memoization緩存,基於函數只(沒有梯度因爲沒有使用):
import numpy as np
from scipy.optimize import minimize, rosen, rosen_der
""" Memoization of function-values -> don't recompute """
class Memoize(object):
""" Modified from https://github.com/scipy/scipy/blob/c96c5294ca73586cadd6f4c10f26b6be5ed35045/scipy/optimize/optimize.py#L53 """
def __init__(self, fun, n, cache_size=8):
self.n = n
self.c_n = cache_size
self.fun = fun
self.fobj = np.full((self.c_n), np.inf)
self.x = np.full((self.c_n, self.n), np.inf)
self.pos = 0 # circular-like buffer; next to replace = oldest
def __call__(self, x, *args):
# Check cache
cands = np.all(x == self.x, axis=1).nonzero()[0]
if cands.size:
return self.fobj[cands]
else:
fobj = self.fun(x)
self.fobj[self.pos] = fobj
self.x[self.pos] = x
self.pos = (self.pos + 1) % self.c_n
return fobj
""" rosen-wrapper to check function-evaluations """
nfev = 0
def rosen_wrapper(x):
global nfev
nfev += 1
return rosen(x)
x0 = [1.3, 0.7, 0.8, 1.9, 1.2]
mem_rosen = Memoize(rosen_wrapper, len(x0))
""" Callback storing history """
history = []
def callback(x):
fobj = mem_rosen(x)
history.append(fobj)
result = minimize(mem_rosen, x0, method='Nelder-Mead', tol=1e-6, callback=callback)
print(result)
print('iteration fun(x)')
print(history[::50]) # every 50th
print(nfev)
與回調和緩存大小爲8叫:
final_simplex: (array([[ 1.00000002, 1.00000002, 1.00000007, 1.00000015, 1.00000028],
[ 0.99999999, 0.99999996, 0.99999994, 0.99999986, 0.99999971],
[ 1.00000005, 1.00000007, 1.00000017, 1.00000031, 1.00000063],
[ 1.00000004, 1.00000008, 1.00000013, 1.00000025, 1.00000047],
[ 0.99999999, 0.99999996, 0.99999994, 0.99999984, 0.99999963],
[ 1.00000005, 1.00000004, 1.00000003, 1.00000003, 1.00000004]]), array([ 1.94206402e-13, 2.44964782e-13, 3.10422870e-13,
3.37952410e-13, 5.52173609e-13, 7.16586838e-13]))
fun: 1.9420640199868412e-13
message: 'Optimization terminated successfully.'
nfev: 494
nit: 295
status: 0
success: True
x: array([ 1.00000002, 1.00000002, 1.00000007, 1.00000015, 1.00000028])
iteration fun(x)
[array([ 516.14978061]), array([ 1.16866125]), array([ 0.00135733]), array([ 6.48182410e-05]), array([ 1.03326372e-06]), array([ 7.12094933e-10])]
504
緩存的24(不推薦;僅用於演示目的):
nfev: 494
nit: 295
status: 0
success: True
...
494
現在這裏顯然是一個權衡,因爲我們st礦石的高速緩存大小:
C_SIZE * N
#X-載體
C_SIZE * 1
#好玩值
而我們在每個呼叫計算上C_SIZE * N
線性操作。
如果這能夠回報,並且如何選擇緩存大小取決於您的函數,最小化器以及可能還有您的參數。
請記住,所選擇的方法是基於這樣的想法:numpy-based計算的線性數量可能比使用基於純python的(或類似)算法更快!
(memoization的代碼未進行廣泛檢查!)
的可能的複製[如何顯示scipy.optimize功能的進步?](https://stackoverflow.com/questions/16739065/how-to-display -scipy-optimize-function) – DavidW
或https://stackoverflow.com/questions/27564436/print-currently-evaluated-params-during-scipy-minimization – DavidW