當前位置: 首頁>>代碼示例 >>用法及示例精選 >>正文


Python SciPy optimize.basinhopping用法及代碼示例


本文簡要介紹 python 語言中 scipy.optimize.basinhopping 的用法。

用法:

scipy.optimize.basinhopping(func, x0, niter=100, T=1.0, stepsize=0.5, minimizer_kwargs=None, take_step=None, accept_test=None, callback=None, interval=50, disp=False, niter_success=None, seed=None, *, target_accept_rate=0.5, stepwise_factor=0.9)#

使用basin-hopping 算法查找函數的全局最小值。

Basin-hopping 是一種two-phase 方法,它將全局步進算法與每一步的局部最小化相結合。旨在模擬原子簇能量最小化的自然過程,它適用於“funnel-like,但崎嶇不平”的能量景觀[5]的類似問題。

由於step-taking、步進接受、最小化方法都是可定製的,因此該函數也可以用於實現其他two-phase方法。

參數

func 可調用f(x, *args)

函數有待優化。args可以作為字典中的可選項目傳遞minimizer_kwargs

x0 array_like

初步猜測。

niter 整數,可選

basin-hopping 迭代次數。本地最小化器將總共運行niter + 1

T 浮點數,可選

用於接受或拒絕標準的 “temperature” 參數。較高的 “temperatures” 意味著將接受函數值的較大跳躍。為了獲得最佳結果,T 應與局部最小值之間的間隔(函數值)相當。

stepsize 浮點數,可選

用於隨機位移的最大步長。

minimizer_kwargs 字典,可選

要傳遞給本地最小化器的額外關鍵字參數 scipy.optimize.minimize 一些重要的選項可能是:

method str

The minimization method (e.g. "L-BFGS-B")

args tuple

Extra arguments passed to the objective function (func) and its derivatives (Jacobian, Hessian).

take_step 可調用 take_step(x) ,可選

將此例程替換為默認的 step-taking 例程。默認的 step-taking 例程是坐標的隨機位移,但其他 step-taking 算法對於某些係統可能更好。take_step可以選擇具有該屬性take_step.stepsize。如果這個屬性存在,那麽basinhopping會調整take_step.stepsize以嘗試優化全局最小搜索。

accept_test 可調用,accept_test(f_new=f_new, x_new=x_new, f_old=fold, x_old=x_old), 可選的

定義一個測試,用於判斷是否接受該步驟。除了基於 “temperature” 的 Metropolis 測試之外,還將使用此測試T。可接受的返回值為 True、False 或"force accept"。如果任何測試返回 False,則該步驟將被拒絕。如果是後者,那麽這將覆蓋任何其他測試以接受該步驟。例如,這可以用來強製逃離局部最小值basinhopping被困在.

callback 可調用,callback(x, f, accept),可選

將為找到的所有最小值調用的回調函數。xf是試驗最小值的坐標和函數值,以及accept是該最低限度是否被接受。例如,這可用於保存找到的最低 N 最小值。還,打返回可用於通過選擇返回 True 來指定用戶定義的停止標準以停止basinhopping常規。

interval 整數,可選

更新步長的頻率間隔

disp 布爾型,可選

設置為 True 以打印狀態消息

niter_success 整數,可選

如果該迭代次數的全局最小候選者保持不變,則停止運行。

seed {無,int, numpy.random.Generator numpy.random.RandomState },可選

如果種子是無(或np.random), 這numpy.random.RandomState使用單例。如果種子是一個 int,一個新的RandomState使用實例,播種種子.如果種子已經是一個Generator或者RandomState實例然後使用該實例。指定種子用於可重複的最小化。用這個種子生成的隨機數隻影響默認的 Metropolisaccept_test和默認take_step.如果您提供自己的take_stepaccept_test,並且這些函數使用隨機數生成,那麽這些函數負責它們的隨機數生成器的狀態。

target_accept_rate 浮點數,可選

用於調整步長的目標接受率。如果當前接受率大於目標,則增加步長。否則,它會減少。範圍是 (0, 1)。默認值為 0.5。

stepwise_factor 浮點數,可選

每次更新時,步長乘以或除以該逐步因子。範圍是 (0, 1)。默認值為 0.9。

返回

res OptimizeResult

優化結果表示為 OptimizeResult 對象。重要屬性包括:x 解數組、fun 解中函數的值以及說明終止原因的 message。由選定的最小值返回的 OptimizeResult 對象也包含在該對象中,並且可以通過 lowest_optimization_result 屬性進行訪問。有關其他屬性的說明,請參閱 OptimizeResult

注意

Basin-hopping 是一種隨機算法,試圖找到一個或多個變量的平滑標量函數的全局最小值 [1] [2] [3] [4]。 David Wales 和 Jonathan Doye [2] http://www-wales.ch.cam.ac.uk/ 說明了當前形式的算法。

該算法是迭代的,每個循環由以下特征組成

  1. 坐標的隨機擾動

  2. 局部最小化

  3. 根據最小化函數值接受或拒絕新坐標

這裏使用的驗收測試是標準蒙特卡羅算法的 Metropolis 標準,盡管還有許多其他可能性 [3]。

這種全局最小化方法已被證明對於物理和化學中的各種問題非常有效。當函數具有許多由大障礙分隔的最小值時,它特別有用。請參閱Cambridge Cluster Database,了解主要使用basin-hopping 優化的分子係統數據庫。該數據庫包括超過 300 個自由度的最小化問題。

請參閱免費軟件程序GMIN,了解 basin-hopping 的 Fortran 實現。該實現具有上述過程的許多變體,包括更先進的步驟采取算法和替代接受標準。

對於隨機全局優化,無法確定是否確實找到了真正的全局最小值。相反,作為一致性檢查,可以從多個不同的隨機起點運行該算法,以確保每個示例中找到的最低最小值已收斂到全局最小值。為此原因,basinhopping默認情況下隻會運行迭代次數並返回找到的最低最小值。由用戶來確保這實際上是全局最小值。

選擇一步的大小: 這是一個很重要的參數basinhopping並取決於要解決的問題。在每個維度中,步長在從 x0-stepsize 到 x0+stepsize 的區域中統一選擇。理想情況下,它應該與正在優化的函數的局部最小值之間的典型分離(以參數值表示)相當。basinhopping默認情況下會調整一步的大小找到最佳值,但這可能需要多次迭代。如果您設置一個合理的初始值,您將獲得更快的結果stepsize.

選擇T:參數T是 Metropolis 標準中使用的“temperature”。如果滿足以下條件,則始終接受盆地跳躍步驟:func(xnew) < func(xold)。否則,它們被概率接受:

exp( -(func(xnew) - func(xold)) / T )

因此,為了獲得最佳結果,T 應該與局部最小值之間的典型差異(函數值)相當。 (局部最小值之間“walls”的高度無關緊要。)

如果T為0,則算法變為單調Basin-Hopping,其中所有增加能量的步驟都被拒絕。

參考

[1]

威爾士,大衛 J. 2003,能源景觀,劍橋大學出版社,英國劍橋。

[2] (1,2)

Wales, D J 和 Doye J P K,Basin-Hopping 的全局優化和包含多達 110 個原子的 Lennard-Jones 簇的最低能量結構。物理化學學報 A, 1997, 101, 5111。

[3] (1,2)

Li, Z. 和 Scheraga, H. A.,Monte Carlo-minimization 解決蛋白質折疊中multiple-minima 問題的方法,Proc。國家石油公司。學院派。科學。美國, 1987, 84, 6611。

[4]

Wales, D. J. 和 Scheraga, H. A.,簇、晶體和生物分子的全局優化,科學,1999, 285, 1368。

[5]

Olson, B.、Hashmi, I.、Molloy, K. 和 Shehu1, A.,盆地跳躍作為生物大分子表征的通用和多函數優化框架,人工智能進展,2012 年(2012 年)卷,文章 ID 674832, DOI:10.1155/2012/674832

例子

以下示例是一維最小化問題,許多局部最小值疊加在拋物線上。

>>> import numpy as np
>>> from scipy.optimize import basinhopping
>>> func = lambda x: np.cos(14.5 * x - 0.3) + (x + 0.2) * x
>>> x0 = [1.]

Basinhopping 在內部使用局部最小化算法。我們將使用參數minimizer_kwargs告訴盆地跳躍要使用哪種算法以及如何設置該最小化器。該參數將被傳遞給scipy.optimize.minimize.

>>> minimizer_kwargs = {"method": "BFGS"}
>>> ret = basinhopping(func, x0, minimizer_kwargs=minimizer_kwargs,
...                    niter=200)
>>> print("global minimum: x = %.4f, f(x) = %.4f" % (ret.x, ret.fun))
global minimum: x = -0.1951, f(x) = -1.0009

接下來考慮一個二維最小化問題。另外,這一次,我們將使用梯度信息來顯著加快搜索速度。

>>> def func2d(x):
...     f = np.cos(14.5 * x[0] - 0.3) + (x[1] + 0.2) * x[1] + (x[0] +
...                                                            0.2) * x[0]
...     df = np.zeros(2)
...     df[0] = -14.5 * np.sin(14.5 * x[0] - 0.3) + 2. * x[0] + 0.2
...     df[1] = 2. * x[1] + 0.2
...     return f, df

我們還將使用不同的局部最小化算法。此外,我們必須告訴最小化器我們的函數返回能量和梯度(雅可比)。

>>> minimizer_kwargs = {"method":"L-BFGS-B", "jac":True}
>>> x0 = [1.0, 1.0]
>>> ret = basinhopping(func2d, x0, minimizer_kwargs=minimizer_kwargs,
...                    niter=200)
>>> print("global minimum: x = [%.4f, %.4f], f(x) = %.4f" % (ret.x[0],
...                                                           ret.x[1],
...                                                           ret.fun))
global minimum: x = [-0.1951, -0.1000], f(x) = -1.0109

這是使用自定義step-taking 例程的示例。想象一下,您希望第一個坐標比其餘坐標采取更大的步驟。這可以像這樣實現:

>>> class MyTakeStep:
...    def __init__(self, stepsize=0.5):
...        self.stepsize = stepsize
...        self.rng = np.random.default_rng()
...    def __call__(self, x):
...        s = self.stepsize
...        x[0] += self.rng.uniform(-2.*s, 2.*s)
...        x[1:] += self.rng.uniform(-s, s, x[1:].shape)
...        return x

自從MyTakeStep.stepsize存在盆地跳躍將調整的幅度一步的大小以優化搜索。我們將使用與之前相同的二維函數

>>> mytakestep = MyTakeStep()
>>> ret = basinhopping(func2d, x0, minimizer_kwargs=minimizer_kwargs,
...                    niter=200, take_step=mytakestep)
>>> print("global minimum: x = [%.4f, %.4f], f(x) = %.4f" % (ret.x[0],
...                                                           ret.x[1],
...                                                           ret.fun))
global minimum: x = [-0.1951, -0.1000], f(x) = -1.0109

現在,讓我們使用自定義回調函數來做一個示例,該函數打印找到的每個最小值的值

>>> def print_fun(x, f, accepted):
...         print("at minimum %.4f accepted %d" % (f, int(accepted)))

這次我們將隻運行 10 個盆地跳躍步驟。

>>> rng = np.random.default_rng()
>>> ret = basinhopping(func2d, x0, minimizer_kwargs=minimizer_kwargs,
...                    niter=10, callback=print_fun, seed=rng)
at minimum 0.4159 accepted 1
at minimum -0.4317 accepted 1
at minimum -1.0109 accepted 1
at minimum -0.9073 accepted 1
at minimum -0.4317 accepted 0
at minimum -0.1021 accepted 1
at minimum -0.7425 accepted 1
at minimum -0.9073 accepted 1
at minimum -0.4317 accepted 0
at minimum -0.7425 accepted 1
at minimum -0.9073 accepted 1

-1.0109 處的最小值實際上是全局最小值,已在第 8 次迭代中找到。

相關用法


注:本文由純淨天空篩選整理自scipy.org大神的英文原創作品 scipy.optimize.basinhopping。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。