SciPy Optimize使用NonlinearConstraint时Hessian报缺少参数v问题咨询
报错原因分析
直接报错的核心原因是混淆了目标函数的Hessian和非线性约束的Hessian的定义与传入位置:
- 你定义的
cons_H是给非线性约束使用的Hessian,要求接收拉格朗日乘子参数v,这部分你已经正确传给了NonlinearConstraint的hess参数,逻辑无误。 - 但你错误将
cons_H同时传给了optimize.minimize的hess参数,该位置要求传入的是目标函数自身的Hessian函数,仅需接收输入变量x作为唯一参数,调用时不会传入v,因此触发参数缺失的报错。
除此之外代码还存在3个配套错误,不修正依然无法正常运行:
- 维度不匹配:你定义的变量上下界
bounds是3个变量的约束,但初始值x0只有2个元素,和变量维度不匹配。 - 目标函数梯度传入错误:你把约束的雅可比
cons_J传给了minimize的jac参数,目标函数的梯度和约束的雅可比是完全独立的计算逻辑,不可混用。 - 约束Hessian返回格式错误:你定义的
cons_H返回的是一维数组,而Hessian要求返回n×n的二维矩阵(n为变量维度)。
解决方法
按以下步骤修改代码即可正常运行:
- 单独定义目标函数的梯度(jac)和Hessian,不要和约束的对应计算函数混用
- 修正约束的Hessian返回符合要求的二维矩阵
- 调整初始值
x0为3维,和变量维度匹配 - 调用
minimize时,传入目标函数专属的梯度和Hessian
修改后的可运行代码如下:
import numpy as np from scipy import optimize from scipy.optimize import NonlinearConstraint # 目标函数定义 def fun(x): return x[0]**2 + x[1]**2 - 8*x[1] + 16 # 目标函数梯度 def fun_jac(x): return np.array([2*x[0], 2*x[1] - 8, 0.0]) # 目标函数Hessian def fun_hess(x): return np.array([ [2.0, 0.0, 0.0], [0.0, 2.0, 0.0], [0.0, 0.0, 0.0] ]) bounds = optimize.Bounds([0,0,0],[np.inf,np.inf,np.inf]) # 约束相关定义 def cons_f(x): return x[0]**2 + x[1]**2 + x[2] def cons_J(x): return [2*x[0], 2*x[1], 1] def cons_H(x,v): # 返回3x3的约束Hessian矩阵 return v[0] * np.array([ [2.0, 0.0, 0.0], [0.0, 2.0, 0.0], [0.0, 0.0, 0.0] ]) nonlinear_constraint = optimize.NonlinearConstraint(cons_f, -np.inf, 6, jac=cons_J, hess=cons_H) # 修正初始值为3维 x0 = [1, 1, 1] res = optimize.minimize(fun, x0, method='trust-constr', jac=fun_jac, hess=fun_hess, constraints=[nonlinear_constraint], options={'verbose': 1}, bounds=bounds) print("最优解:", res.x)
运行后可以得到符合约束的最优解,无报错。
内容的提问来源于stack exchange,提问作者Félix Fombellida
相关产品推荐
相关产品推荐

