scipy.optimize.

最小化#

scipy.optimize.minimize(fun, x0, args=(), method=None, jac=None, hess=None, hessp=None, bounds=None, constraints=(), tol=None, callback=None, options=None)[源代码][源代码]#

最小化一个或多个变量的标量函数。

参数:
有趣可调用

要最小化的目标函数。

fun(x, *args) -> float

其中 x 是一个形状为 (n,) 的一维数组,而 args 是一个包含完全指定函数所需固定参数的元组。

x0ndarray, 形状 (n,)

初始猜测。大小为 (n,) 的实数元素数组,其中 n 是独立变量的数量。

参数tuple, 可选

传递给目标函数及其导数(funjachess 函数)的额外参数。

方法str 或 callable,可选

求解器类型。应为以下之一

如果没有指定,将根据问题是否有约束或边界,选择为 BFGSL-BFGS-BSLSQP 之一。

jac{callable, ‘2-point’, ‘3-point’, ‘cs’, bool}, 可选

计算梯度向量的方法。仅适用于 CG、BFGS、Newton-CG、L-BFGS-B、TNC、SLSQP、dogleg、trust-ncg、trust-krylov、trust-exact 和 trust-constr。如果它是一个可调用对象,它应该是一个返回梯度向量的函数:

jac(x, *args) -> array_like, shape (n,)

其中 x 是一个形状为 (n,) 的数组,args 是一个包含固定参数的元组。如果 jac 是一个布尔值且为 True,则假定 fun 返回一个包含目标函数和梯度的元组 (f, g)。方法 ‘Newton-CG’, ‘trust-ncg’, ‘dogleg’, ‘trust-exact’, 和 ‘trust-krylov’ 要求要么提供一个可调用对象,要么 fun 返回目标函数和梯度。如果为 None 或 False,将使用绝对步长的两点有限差分估计来估计梯度。或者,可以使用关键字 {‘2-point’, ‘3-point’, ‘cs’} 来选择相对步长的有限差分方案,以进行梯度的数值估计。这些有限差分方案遵守任何指定的 bounds

hess{callable, ‘2-点’, ‘3-点’, ‘cs’, HessianUpdateStrategy}, 可选

计算Hessian矩阵的方法。仅适用于Newton-CG、dogleg、trust-ncg、trust-krylov、trust-exact和trust-constr。如果它是可调用的,它应该返回Hessian矩阵:

hess(x, *args) -> {LinearOperator, spmatrix, array}, (n, n)

其中 x 是一个 (n,) 的 ndarray,而 args 是一个包含固定参数的元组。关键字 {‘2-point’, ‘3-point’, ‘cs’} 也可以用来选择有限差分方案,以进行数值估计的 Hessian。或者,可以使用实现 HessianUpdateStrategy 接口的对象来近似 Hessian。实现此接口的可用拟牛顿法有:

并非所有选项对每种方法都可用;有关可用性,请参阅注释。

hessp可调用,可选

目标函数的 Hessian 矩阵乘以任意向量 p。仅适用于 Newton-CG、trust-ncg、trust-krylov、trust-constr。只需提供 hessphess 中的一个。如果提供了 hess,则 hessp 将被忽略。hessp 必须计算 Hessian 矩阵乘以任意向量:

hessp(x, p, *args) ->  ndarray shape (n,)

其中 x 是一个形状为 (n,) 的 ndarray,p 是一个维度为 (n,) 的任意向量,而 args 是一个包含固定参数的元组。

bounds : 序列或 Bounds, 可选序列或

Nelder-Mead、L-BFGS-B、TNC、SLSQP、Powell、trust-constr、COBYLA 和 COBYQA 方法的变量边界。指定边界有两种方式:

  1. Bounds 类的实例。

  2. x 中每个元素的 (最小值, 最大值) 对序列。使用 None 表示无界限。

约束{约束, 字典} 或 {约束, 字典} 的列表, 可选

约束定义。仅适用于COBYLA、COBYQA、SLSQP和trust-constr。

对于 ‘trust-constr’ 和 ‘cobyqa’ 的约束条件定义为一个对象或指定优化问题约束的对象列表。可用的约束条件有:

COBYLA 和 SLSQP 的约束条件定义为一个字典列表。每个字典包含以下字段:

类型str

约束类型:’eq’ 表示相等,’ineq’ 表示不等。

乐趣可调用

定义约束的函数。

jac可调用,可选

fun 的雅可比矩阵(仅适用于SLSQP)。

参数序列,可选

传递给函数和雅可比的额外参数。

等式约束意味着约束函数的结果应为零,而不等式约束意味着结果应为非负。请注意,COBYLA 仅支持不等式约束。

tolfloat, 可选

终止容差。当指定 tol 时,所选的最小化算法会将一些相关的求解器特定容差设置为 tol。如需详细控制,请使用求解器特定的选项。

选项dict, 可选

求解器选项的字典。除 TNC 外的所有方法都接受以下通用选项:

maxiter整数

要执行的最大迭代次数。根据方法的不同,每次迭代可能使用多次函数求值。

对于 TNC 使用 maxfun 而不是 maxiter

disp布尔

设置为 True 以打印收敛消息。

对于特定方法的选项,请参阅 show_options

回调可调用,可选

在每次迭代后调用的可调用对象。

除了 TNC、SLSQP 和 COBYLA 之外的所有方法都支持具有以下签名的可调用对象:

callback(intermediate_result: OptimizeResult)

其中 intermediate_result 是一个包含 OptimizeResult 的关键字参数,该 OptimizeResult 具有属性 xfun,分别表示参数向量和目标函数的当前值。请注意,参数的名称必须为 intermediate_result,以便回调函数能够接收到 OptimizeResult。如果回调函数引发 StopIteration,这些方法也将终止。

除 trust-constr 之外的所有方法(也)支持以下签名:

callback(xk)

其中 xk 是当前的参数向量。

内省用于确定调用上述哪个签名。

返回:
res优化结果

优化结果表示为一个 OptimizeResult 对象。重要属性包括:x 解数组,success 一个布尔标志,指示优化器是否成功退出,以及 message 描述终止原因。有关其他属性的描述,请参见 OptimizeResult

参见

minimize_scalar

单变量标量函数的最小化算法接口

show_options

求解器接受的附加选项

注释

本节描述了可以通过 ‘method’ 参数选择的可用求解器。默认方法是 BFGS

无约束最小化

方法 CG 使用 Polak 和 Ribiere 提出的非线性共轭梯度算法,这是 [5] pp.120-122 中描述的 Fletcher-Reeves 方法的一个变体。仅使用一阶导数。

方法 BFGS 使用 Broyden, Fletcher, Goldfarb 和 Shanno (BFGS) [5] 第136页的拟牛顿法。它仅使用一阶导数。BFGS 已被证明即使在非光滑优化中也有良好的性能。此方法还会返回 Hessian 逆的近似值,存储在 OptimizeResult 对象的 hess_inv 中。

方法 Newton-CG 使用了一个 Newton-CG 算法 [5] pp. 168(也称为截断牛顿法)。它使用 CG 方法来计算搜索方向。另请参阅 TNC 方法,该方法适用于具有类似算法的箱约束最小化。适用于大规模问题。

方法 dogleg 使用狗腿信赖域算法 [5] 进行无约束最小化。该算法需要梯度和Hessian;此外,Hessian需要是正定的。

方法 trust-ncg 使用牛顿共轭梯度信赖域算法 [5] 进行无约束最小化。该算法需要梯度和海森矩阵或一个计算海森矩阵与给定向量乘积的函数。适用于大规模问题。

方法 trust-krylov 使用 Newton GLTR 信赖域算法 [14], [15] 进行无约束最小化。该算法需要梯度和 Hessian 矩阵或一个计算 Hessian 矩阵与给定向量乘积的函数。适用于大规模问题。在不定问题上,它通常比 trust-ncg 方法需要更少的迭代次数,并推荐用于中等和大规模问题。

方法 trust-exact 是一种用于无约束最小化的信赖域方法,其中二次子问题几乎被精确求解 [13]。该算法需要梯度和Hessian矩阵(不需要是正定的)。在许多情况下,它是牛顿法,能够在更少的迭代次数内收敛,并且对于中小规模问题最为推荐。

边界约束最小化

方法 Nelder-Mead 使用单纯形算法 [1][2]。该算法在许多应用中都很稳健。然而,如果可以信任数值计算的导数,那么使用一阶和/或二阶导数信息的其他算法通常可能因其更好的性能而被优先选择。

方法 L-BFGS-B 使用 L-BFGS-B 算法 [6][7] 进行边界约束最小化。

方法 Powell 是对 Powell 方法 [3][4] 的一种改进,这是一种共轭方向方法。它在方向集的每个向量上执行顺序的一维最小化(optionsinfo 中的 direc 字段),该方向集在主最小化循环的每次迭代中更新。该函数不需要可微分,也不需要计算导数。如果没有提供边界,则将使用无界线搜索。如果提供了边界并且初始猜测在边界内,那么在整个最小化过程中,每次函数评估都将在边界内。如果提供了边界,初始猜测在边界外,并且 direc 是满秩的(默认情况下是满秩的),那么在第一次迭代期间,某些函数评估可能会超出边界,但在第一次迭代之后的每次函数评估都将保持在边界内。如果 direc 不是满秩的,那么某些参数可能不会被优化,并且解不能保证在边界内。

方法 TNC 使用截断牛顿算法 [5], [8] 来最小化一个受边界约束的变量函数。该算法使用梯度信息;它也被称为牛顿共轭梯度。它与上述 Newton-CG 方法的不同之处在于它封装了一个 C 实现,并允许为每个变量指定上下界。

约束最小化

方法 COBYLA 使用线性近似约束优化(COBYLA)方法 [9][10][11]。该算法基于目标函数和每个约束的线性近似。该方法包装了算法的FORTRAN实现。约束函数 ‘fun’ 可以返回单个数字或数字数组或列表。

方法 COBYQA 使用约束优化通过二次近似 (COBYQA) 方法 [18]。该算法是一种基于二次近似目标函数和每个非线性约束的无导数信赖域 SQP 方法。边界被视为不可放松的约束,即算法在整个优化过程中始终遵守这些约束。

方法 SLSQP 使用顺序最小二乘编程来最小化具有任意组合的边界、等式和不等式约束的多个变量的函数。该方法包装了最初由Dieter Kraft实现的SLSQP优化子程序 [12]。注意,包装器通过将它们转换为大浮点值来处理边界中的无限值。

方法 trust-constr 是一个用于约束优化的信赖域算法。它根据问题定义在两种实现之间切换。它是 SciPy 中实现的最通用的约束最小化算法,最适合大规模问题。对于等式约束问题,它是 Byrd-Omojokun 信赖域 SQP 方法的实现,描述在 [17][5],第 549 页。当施加不等式约束时,它会切换到 [16] 中描述的信赖域内点方法。这个内点算法通过引入松弛变量并解决一系列等式约束障碍问题来解决不等式约束,障碍参数的值逐渐减小。先前描述的等式约束 SQP 方法用于以越来越高的精度解决子问题,因为迭代更接近解。

有限差分选项

对于方法 trust-constr ,可以使用三种有限差分方案来近似梯度和Hessian:{‘2-点’, ‘3-点’, ‘cs’}。方案 ‘cs’ 可能是最准确的,但它要求函数能够正确处理复数输入并在复平面上可微。方案 ‘3-点’ 比 ‘2-点’ 更准确,但需要两倍的操作次数。如果通过有限差分估计梯度,则必须使用一种拟牛顿策略来估计Hessian。

`hess` 关键字的特定方法选项

方法/Hess

可调用

‘2-point/’3-point’/’cs’

HUS

Newton-CG

x

(n, n) LO

x

x

dogleg

(n,n)

trust-ncg

(n,n)

x

x

trust-krylov

(n,n)

x

x

trust-exact

(n,n)

trust-constr

x

(n, n) LO sp

x

x

其中 LO=线性算子, sp=稀疏矩阵, HUS=海森更新策略

自定义最小化器

传递自定义的最小化方法可能是有用的,例如在使用 scipy.optimize.basinhopping 或其他库的前端时。你可以简单地将一个可调用对象作为 method 参数传递。

可调用对象被调用为 method(fun, x0, args, **kwargs, **options),其中 kwargs 对应于传递给 minimize 的任何其他参数(如 callbackhess 等),除了 options 字典,其内容也按对传递为 method 参数。此外,如果 jac 作为布尔类型传递,jacfun 会被处理,使得 fun 仅返回函数值,而 jac 被转换为返回雅可比矩阵的函数。该方法应返回一个 OptimizeResult 对象。

提供的 method 可调用对象必须能够接受(并可能忽略)任意参数;minimize 接受的参数集可能会在未来的版本中扩展,届时这些参数将被传递给该方法。你可以在 scipy.optimize 教程中找到一个示例。

参考文献

[1]

Nelder, J A, 和 R Mead. 1965. 一种用于函数最小化的单纯形法. 计算机杂志 7: 308-13.

[2]

Wright M H. 1996. 直接搜索方法:曾经被轻视,现在值得尊敬,在数值分析1995:1995年邓迪数值分析双年会议论文集(编辑:D F Griffiths 和 G A Watson)。Addison Wesley Longman,英国哈洛。191-208。

[3]

Powell, M J D. 1964. 一种在不计算导数的情况下寻找多元函数最小值的高效方法。计算机杂志 7: 155-162.

[4]

Press W, S A Teukolsky, W T Vetterling 和 B P Flannery。数值秘笈(任何版本),剑桥大学出版社。

[5] (1,2,3,4,5,6,7,8)

Nocedal, J, 和 S J Wright. 2006. 数值优化. Springer 纽约.

[6]

Byrd, R H 和 P Lu 以及 J. Nocedal. 1995. 一种用于边界约束优化的有限内存算法。SIAM 科学和统计计算杂志 16 (5): 1190-1208.

[7]

Zhu, C 和 R H Byrd 和 J Nocedal. 1997. L-BFGS-B: 算法 778: L-BFGS-B, 用于大规模边界约束优化的 FORTRAN 程序. ACM 数学软件交易 23 (4): 550-560.

[8]

Nash, S G. 通过Lanczos方法的牛顿型最小化。1984年。SIAM数值分析杂志21: 770-778。

[9]

Powell, M J D. 一种通过线性插值建模目标和约束函数的直接搜索优化方法。1994年。《优化与数值分析进展》,S. Gomez 和 J-P Hennart 编,Kluwer Academic (Dordrecht),51-67。

[10]

Powell M J D. 直接搜索算法用于优化计算。1998年。Acta Numerica 7: 287-336.

[11]

Powell M J D. 无导数的优化算法观点. 2007.剑桥大学技术报告 DAMTP 2007/NA03

[12]

Kraft, D. 用于序列二次规划的软件包。1988年。技术报告 DFVLR-FB 88-28,德国航空航天中心 – 飞行力学研究所,德国科隆。

[13]

Conn, A. R., Gould, N. I., 和 Toint, P. L. 信赖域方法. 2000. Siam. 第169-200页.

[14]

F. Lenders, C. Kirches, A. Potschka: “trlib: A vector-free implementation of the GLTR method for iterative solution of the trust region problem”, arXiv:1611.04718

[15]

N. Gould, S. Lucidi, M. Roma, P. Toint: “Solving the Trust-Region Subproblem using the Lanczos Method”, SIAM J. Optim., 9(2), 504–525, (1999).

[16]

Byrd, Richard H., Mary E. Hribar, 和 Jorge Nocedal. 1999. 一种用于大规模非线性规划的内点算法. SIAM 优化杂志 9.4: 877-900.

[17]

Lalee, Marucha, Jorge Nocedal, 和 Todd Plantega. 1998. 关于大规模等式约束优化算法的实现. SIAM 优化杂志 8.3: 682-706.

[18]

Ragonneau, T. M. 基于模型的无导数优化方法与软件. 博士论文, 应用数学系, 香港理工大学, 中国香港, 2022. URL: https://theses.lib.polyu.edu.hk/handle/200/12294.

示例

让我们考虑最小化Rosenbrock函数的问题。这个函数(及其相应的导数)在 scipy.optimize 中的 rosen`(分别在 `rosen_derrosen_hess 中)实现。

>>> from scipy.optimize import minimize, rosen, rosen_der

Nelder-Mead 方法的一个简单应用是:

>>> x0 = [1.3, 0.7, 0.8, 1.9, 1.2]
>>> res = minimize(rosen, x0, method='Nelder-Mead', tol=1e-6)
>>> res.x
array([ 1.,  1.,  1.,  1.,  1.])

现在使用 BFGS 算法,使用一阶导数和一些选项:

>>> res = minimize(rosen, x0, method='BFGS', jac=rosen_der,
...                options={'gtol': 1e-6, 'disp': True})
Optimization terminated successfully.
         Current function value: 0.000000
         Iterations: 26
         Function evaluations: 31
         Gradient evaluations: 31
>>> res.x
array([ 1.,  1.,  1.,  1.,  1.])
>>> print(res.message)
Optimization terminated successfully.
>>> res.hess_inv
array([
    [ 0.00749589,  0.01255155,  0.02396251,  0.04750988,  0.09495377],  # may vary
    [ 0.01255155,  0.02510441,  0.04794055,  0.09502834,  0.18996269],
    [ 0.02396251,  0.04794055,  0.09631614,  0.19092151,  0.38165151],
    [ 0.04750988,  0.09502834,  0.19092151,  0.38341252,  0.7664427 ],
    [ 0.09495377,  0.18996269,  0.38165151,  0.7664427,   1.53713523]
])

接下来,考虑一个带有多个约束的最小化问题(即来自 [5] 的例 16.4)。目标函数是:

>>> fun = lambda x: (x[0] - 1)**2 + (x[1] - 2.5)**2

定义了三个约束条件:

>>> cons = ({'type': 'ineq', 'fun': lambda x:  x[0] - 2 * x[1] + 2},
...         {'type': 'ineq', 'fun': lambda x: -x[0] - 2 * x[1] + 6},
...         {'type': 'ineq', 'fun': lambda x: -x[0] + 2 * x[1] + 2})

并且变量必须是正的,因此有以下界限:

>>> bnds = ((0, None), (0, None))

优化问题使用 SLSQP 方法解决,如下所示:

>>> res = minimize(fun, (2, 0), method='SLSQP', bounds=bnds,
...                constraints=cons)

它应该收敛到理论解 (1.4, 1.7)。