2017-10-08 26 views
0

如果我們考慮從文檔的例子:如何呈現的結果Scipy.optimize.minimize

from scipy.optimize import minimize, rosen, rosen_der 
x0 = [1.3, 0.7, 0.8, 1.9, 1.2] 
result = minimize(rosen, x0, method='Nelder-Mead', tol=1e-6) 
print(result) 

我們得到以下結果

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]) 

,你可以看到,迭代次數是295.我的問題是如何在每次迭代中獲得x的值?

+2

的可能的複製[如何顯示scipy.optimize功能的進步?](https://stackoverflow.com/questions/16739065/how-to-display -scipy-optimize-function) – DavidW

+2

或https://stackoverflow.com/questions/27564436/print-currently-evaluated-params-during-scipy-minimization – DavidW

回答

1

一般的方法是使用定製的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的代碼未進行廣泛檢查!)