为Scipy Basinhopping配置自定义局部极小化方法遇阻求助
为Scipy Basinhopping配置自定义局部极小化方法的问题
我尝试为Scipy的Basinhopping算法配置自定义局部极小化方法,理解Basinhopping的流程为:从初始条件出发,用局部方法极小化,再通过Basinhopping调整参数,重复局部极小化。已知Basinhopping自带若干局部极小化方法,但自定义方法时遇到参数传递问题。
可运行的最小复现示例(MVE)
以下代码运行正常,能得到低chi²的优质解:
import scipy.optimize as so import numpy as np from scipy.optimize import basinhopping from scipy.optimize import OptimizeResult data_set=[np.array([0.01252837, 0.00994032, 0.02607758, 0.02938639, 0.03470389, 0.0393117 , 0.05045751, 0.05288866]), np.array([0.01096586, 0.0093723 , 0.02996665, 0.0490254 , 0.06359686, 0.07470107, 0.07533133, 0.10770218]), np.array([0.0108 , 0.01922004, 0.0290243 , 0.03236109, 0.00761577, 0.05216742, 0.05526853, 0.06572701]), np.array([0.01744162, 0.02563377, 0.03473111, 0.04372516, 0.05533209, 0.06429533, 0.06852919, 0.08112336]), np.array([0.01664812, 0.03377632, 0.04334155, 0.05260618, 0.06893069, 0.07831481, 0.08656102, 0.0999732 ]), np.array([0.01933805, 0.02861486, 0.04197618, 0.05017609, 0.06353904, 0.07471151, 0.08393098, 0.09447883])] prot,lig=np.array([0.28, 0.26, 0.25, 0.23, 0.21, 0.19, 0.18, 0.15]), np.array([0.14, 0.26, 0.37, 0.47, 0.63, 0.77, 0.88, 1.1 ]) def global_fun(par,protein,ligand,csp_list): kd,wmax=par chi2=0 for csp in csp_list: model=wmax*((protein+ligand+kd-np.sqrt(((protein+ligand+kd)**2)-(4*protein*ligand)))/(2*protein)) chi2+=np.sum((csp-model)**2) return chi2 sol=basinhopping(global_fun, minimizer_kwargs={'args':(prot,lig,data_set), 'options':{'maxiter':100000}, 'bounds':((0,np.inf),)*2, 'method':'Nelder-Mead'}, x0=[1,0.01])
运行结果:
fun: 0.00879004731452548 lowest_optimization_result: final_simplex: (array([[3.20231857, 0.33548486], [3.20238274, 0.33549024], [3.20240774, 0.33549202]]), array([0.00879005, 0.00879005, 0.00879005])) fun: 0.00879004731452548 message: 'Optimization terminated successfully.' nfev: 66 nit: 34 status: 0 success: True x: array([3.20231857, 0.33548486]) message: ['requested number of basinhopping iterations completed successfully'] minimization_failures: 0 nfev: 8794 nit: 100 x: array([3.20231857, 0.33548486])
错误的自定义局部求解器尝试
我尝试编写自定义局部求解器,但配置存在错误,不清楚如何传递minimizer_kwargs中的参数,也不知道Basinhopping迭代后的x0如何同步给局部求解器:
def custom_method(args=(args,bounds,options)): local_so=so.minimize(args=args,bounds=bounds,options=options,method='Nelder-Mead') return OptimizeResult(x=local_so.x,fun=local_so.fun,success=local_so.success) sol=basinhopping(global_fun, minimizer_kwargs={'args':(prot,lig,data_set), 'options':{'maxiter':100000}, 'bounds':((0,np.inf),)*2, 'method':custom_method}, x0=[1,0.01])
修正方案
自定义局部求解器的签名必须与scipy.optimize.minimize的接口对齐,Basinhopping会自动将目标函数、当前迭代的x0以及minimizer_kwargs中的参数传递给它。正确的自定义方法如下:
正确的自定义局部求解器
def custom_method(fun, x0, args=(), bounds=None, options=None): # 调用内置Nelder-Mead方法执行局部极小化 local_res = so.minimize(fun, x0, args=args, bounds=bounds, options=options, method='Nelder-Mead') # 返回符合要求的OptimizeResult对象,需包含关键字段 return OptimizeResult( x=local_res.x, fun=local_res.fun, success=local_res.success, message=local_res.message, nit=local_res.nit, nfev=local_res.nfev )
修正后的Basinhopping调用
sol = basinhopping(global_fun, x0=[1, 0.01], minimizer_kwargs={ 'args': (prot, lig, data_set), 'options': {'maxiter': 100000}, 'bounds': ((0, np.inf),)*2, 'method': custom_method })
关键说明
- 自定义方法的第一个参数是目标函数
fun,第二个参数是Basinhopping当前迭代的初始点x0,后续参数需与scipy.optimize.minimize的参数匹配(或用**kwargs接收所有参数) - Basinhopping每次迭代都会自动把更新后的
x0传入自定义方法,无需手动处理 - 必须返回
OptimizeResult对象,至少包含x(极小值点)、fun(极小值)、success(是否成功)三个核心字段,其他字段如nit、nfev可按需添加,用于Basinhopping记录迭代信息
内容的提问来源于stack exchange,提问作者samman
相关产品推荐
相关产品推荐

