You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 16:14:54