当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


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。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。