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

如何使shgo算法结合COBYLA成功收敛并适配约束与边界?

问题:SHGO结合COBYLA优化时参数越界崩溃,换L-BFGS-B无法得到全局最优

我用SHGO算法做黑箱模拟的全局最大化(目标函数负责运行并评估模拟),设置了5个输入变量,需要通过边界和约束限制几何参数。SHGO本应是适合带约束全局优化的选择,但目前无法让它正确处理边界与约束并收敛。

我的优化代码

bnds = [(50*1e-9,500*1e-9), (50*1e-9,500*1e-9), (1,20), (20*1e-9,80*1e-9), (250*1e-9,800*1e-9)]

def constraint1(x):
    return x[4]-50*1e-9-2*x[0] # x[4] ≤ 2*x[0] - 50nm(阈值)
def constraint2(x):
    return x[1]-x[3]-20*1e-9 # x[1]-x[3] ≥ 20nm(阈值) 
def constraint3(x):
    return x[0]-(x[1]/2)*(2.978/x[2])-20*1e-9

cons = ({'type': 'ineq', 'fun': constraint1},
        {'type': 'ineq', 'fun': constraint2},
        {'type': 'ineq', 'fun': constraint3})

minimizer_kwargs = {'method':'COBYLA',
                    'bounds': bnds,
                    'constraints':cons}   

opts = {'disp':True}

res_shgo =  shgo(objective, 
                 bounds=bnds, 
                 constraints=cons, 
                 sampling_method='sobol', 
                 minimizer_kwargs=minimizer_kwargs, 
                 options=opts)

遇到的问题1:COBYLA作为局部优化器时参数越界

全局评估完成33轮后启动极小值池:

Evaluations completed.
Search for minimiser pool
--- Starting minimization at [3.3828125e-07 4.6484375e-07 1.1984375e+01 6.7812500e-08 7.5703125e-07]...

用COBYLA做局部极小化时,几轮后参数就超出边界,直接导致模拟崩溃。

遇到的问题2:换L-BFGS-B能收敛但无全局最优

将局部优化器改为L-BFGS-B:

minimizer_kwargs = {'method':'L-BFGS-B'}

算法能收敛,但结果不是全局极小值,输出如下:

lres =       fun: -20.247226776119533
 hess_inv: <5x5 LbfgsInvHessProduct with dtype=float64>
      jac: array([ 1.70730429e+09,  1.22968297e+09,  0.00000000e+00, -1.82566323e+09,
        1.83071706e+09])
  message: 'CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL'
     nfev: 6
      nit: 0
     njev: 1
   status: 0
  success: True
        x: array([2.43359375e-07, 2.99609375e-07, 1.48046875e+01, 7.01562500e-08,
       6.23828125e-07])
Minimiser pool = SHGO.X_min = []
Successfully completed construction of complex.

现在需要解决的是:如何让SHGO结合COBYLA成功终止,同时保证参数不越界?


解决方案建议

1. 修正COBYLA的约束与边界处理逻辑

COBYLA不原生支持bounds参数,你在minimizer_kwargs里传入bounds是无效的,这就是参数越界的核心原因。必须把边界条件转换成不等式约束,和现有约束合并后传给COBYLA:

# 生成边界约束:将上下界转为COBYLA可识别的不等式约束
bound_cons = []
for idx, (low, high) in enumerate(bnds):
    # 下界约束:x[idx] ≥ low → 返回值≥0为可行
    bound_cons.append({'type': 'ineq', 'fun': lambda x, idx=idx, low=low: x[idx] - low})
    # 上界约束:x[idx] ≤ high → 返回值≥0为可行
    bound_cons.append({'type': 'ineq', 'fun': lambda x, idx=idx, high=high: high - x[idx]})

2. 修正约束函数的逻辑(关键!)

COBYLA要求不等式约束的返回值≥0时,参数处于可行域。你的constraint1逻辑写反了:

# 原约束1逻辑错误,修正后:
def constraint1(x):
    return (2*x[0] - 50*1e-9) - x[4]  # 满足x[4] ≤ 2*x[0]-50nm时,返回值≥0

constraint2逻辑正确,constraint3需要你确认预期的约束方向,确保返回值≥0对应可行区域。

3. 调整SHGO与COBYLA的参数配置

  • 给COBYLA设置匹配参数尺度的初始步长(rhobeg)和收敛阈值,避免大步跳出可行域
  • 增加SHGO的初始采样数(n),提升全局探索能力
  • 限制总评估次数,适配黑箱模拟的计算成本

调整后的完整代码示例

from scipy.optimize import shgo

bnds = [(50*1e-9,500*1e-9), (50*1e-9,500*1e-9), (1,20), (20*1e-9,80*1e-9), (250*1e-9,800*1e-9)]

# 修正后的约束函数
def constraint1(x):
    return (2*x[0] - 50*1e-9) - x[4]  # x[4] ≤ 2*x[0]-50nm → 返回≥0为可行
def constraint2(x):
    return x[1] - x[3] -20*1e-9  # x[1]-x[3]≥20nm → 返回≥0为可行
def constraint3(x):
    return x[0] - (x[1]/2)*(2.978/x[2]) -20*1e-9  # 确认约束方向:返回≥0对应可行域

# 生成边界约束
bound_cons = []
for idx, (low, high) in enumerate(bnds):
    bound_cons.append({'type': 'ineq', 'fun': lambda x, idx=idx, low=low: x[idx] - low})
    bound_cons.append({'type': 'ineq', 'fun': lambda x, idx=idx, high=high: high - x[idx]})

# 合并所有约束
all_constraints = (
    {'type': 'ineq', 'fun': constraint1},
    {'type': 'ineq', 'fun': constraint2},
    {'type': 'ineq', 'fun': constraint3}
) + tuple(bound_cons)

# COBYLA参数配置:去掉无效的bounds,增加步长和迭代控制
minimizer_kwargs = {
    'method': 'COBYLA',
    'constraints': all_constraints,
    'options': {
        'maxiter': 200,
        'rhobeg': 1e-10,  # 初始步长匹配纳米级参数
        'tol': 1e-12
    }
}

# SHGO全局优化配置
shgo_options = {
    'disp': True,
    'maxfev': 500  # 限制总评估次数,适合黑箱模拟
}

res_shgo = shgo(
    objective,
    bounds=bnds,
    constraints=all_constraints,
    sampling_method='sobol',
    n=100,  # 增加初始采样数,提升全局探索能力
    minimizer_kwargs=minimizer_kwargs,
    options=shgo_options
)

print(res_shgo)

为什么L-BFGS-B没得到全局最优?

L-BFGS-B是局部优化器,只会在初始采样点附近收敛。如果SHGO的初始采样未覆盖全局最优区域,局部搜索只能得到局部解。而COBYLA在正确配置约束后,能在可行域内更灵活地搜索,配合SHGO的全局采样,更有机会找到全局最优。

内容的提问来源于stack exchange,提问作者loco39

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 16:10:26