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

Scipy SLSQP优化算法返回错误解的问题咨询

Scipy SLSQP约束优化问题求解异常分析与解决

问题描述

刚接触Scipy优化模块,用SLSQP方法求解简单约束优化问题时,算法要么找不到约束区域内的全局最优,要么返回看似不可行的点。尝试过禁用部分约束、调整边界,都没解决问题。只有当初始点设为[5,4]时返回该点(附带Positive directional derivative for linesearch (Exit mode 8)提示),初始点[0,0]返回可行但非最优解,其他初始点返回[8.16230102 10.]。

优化问题代码

from scipy.optimize import minimize
import numpy as np
from scipy.optimize import Bounds

def simpleFunction(x):
    x1 = float(x[0])
    x2 = float(x[1])
    return x2*(x1-x2)

def g1(x):
    x1 = float(x[0])
    x2 = float(x[1])
    return (x1-5)**2 - x2

def g2(x):
    x1 = float(x[0])
    x2 = float(x[1])
    return (x2+x1) - 10

def g3(x):
    x1 = float(x[0])
    x2 = float(x[1])
    return x2-0.8*x1

g1_ineq = {'type': 'ineq', 'fun': g1}
g2_ineq = {'type': 'ineq', 'fun': g2}
g3_ineq = {'type': 'ineq', 'fun': g3}

x0 = np.array([5 ,8])
bnds = Bounds([5, 3], [10, 10])
cons = ([g1_ineq, g2_ineq, g3_ineq])
res = minimize(simpleFunction, x0, method='SLSQP',
                constraints=cons,
                options={'disp': True},
               bounds=bnds)
print(res.x)
print(simpleFunction(res.x))
print(simpleFunction([5, 4]))
print(res.x)
print(simpleFunction(res.x))
print(simpleFunction([5, 4])) # 你认为的真实最小值点

# 不同初始点的结果:
# [0, 0] -> [5. 3.] -> 6.0
# [5, 4] -> [5, 4] -> 4.0
# [5, 5] -> [ 8.16230102 10.] -> -18.376
# [6, 6] -> [ 8.16230102 10.] -> -18.376
# [10, 10] -> [ 8.16230102 10.] -> -18.376
# [5 ,8] -> [ 8.16230102 10.] -> -18.376

图形化验证代码(原版本存在约束不一致问题)

from scipy.optimize import minimize
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import Bounds
from typing import List, Set, Dict, Tuple

def simpleFunction(x1, x2):
    return x2*(x1-x2)

def g1(x1, x2):
    return (x1-5)**2 - x2

def g2(x1, x2):
    return -x1 +5  # 此处与优化代码的g2约束完全不一致

def g3(x1, x2):
    return x2-0.8*x1

def g4(x1, x2):
    return -x2 +3

def g5(x1, x2):
    return (x2+x1) - 10

Z1 = 0

functions = [
    (lambda x1, x2: g1(x1,x2), Z1,'g1'), 
    (lambda x1, x2: g2(x1,x2), Z1,'g2'), 
    (lambda x1, x2: g3(x1,x2), Z1,'g3'), 
    (lambda x1, x2: g4(x1,x2), Z1,'g1'), 
    (lambda x1, x2: g3(x1,x2), Z1,'g1'),
]
X, Y = np.meshgrid(np.linspace(0, 10, 1000), np.linspace(0, 10, 1000))

for f, z,name in functions:
    plt.contour(X, Y, f(X, Y), levels = [0], colors='black')
    plt.contourf(X, Y, f(X, Y), [0, 1000], colors='blue', alpha=0.1)

plt.contour(X, Y, simpleFunction(X, Y), levels=100, linestyles='dashed', colors='black')
plt.title('feasible region')
plt.xlim(0, 10)
plt.ylim(0, 10)
plt.xlabel('x1')
plt.ylabel('x2')
plt.show()

可行区域示意图

可行区域示意图


问题核心原因

  1. 约束方向完全搞反:
    Scipy的ineq约束要求fun(x) >= 0时才属于可行区域。你的优化代码中g2定义为x1+x2-10,意味着只有x1+x2≥10的点才是可行点,但你误以为[5,4]是可行点——代入g2计算得5+4-10=-1<0,明显不满足约束,属于不可行点。
    同时你的图形化代码中g2定义为-x1+5,对应x1≤5的约束,和优化代码的约束完全冲突,导致你对可行区域的理解完全错误。

  2. 对SLSQP算法的局限性认知不足:
    SLSQP是局部优化算法,只能找到初始点附近的局部最优解。如果目标函数在可行区域内有多个局部最优,不同初始点会收敛到不同结果。

  3. 最优解判断错误:
    你认为[5,4]是全局最小值,但该点本身不可行;而算法返回的[8.16230102,10]是满足所有约束的:

    • g1=(8.1623-5)²-10≈10-10=0≥0
    • g2=8.1623+10-10=8.1623≥0
    • g3=10-0.8*8.1623≈3.47≥0
    • 边界x1∈[5,10]、x2∈[3,10]也满足
      该点的函数值-18.376远小于[5,4]的4.0,是当前约束下的更优解。

解决建议

  1. 修正约束定义:
    如果你实际想要的约束是x1+x2 ≤10,需要把g2改为10 - x1 -x2,这样g2≥0就对应x1+x2≤10,符合Scipy的约束规则。

  2. 同步图形化代码与优化代码的约束:
    修改图形化代码中的g2,使其和优化代码一致,这样才能正确可视化可行区域,辅助判断最优解。

  3. 处理局部最优问题:
    若需要找到全局最优解,可尝试使用Scipy的全局优化算法,比如dual_annealing、shgo等,或者多设置几个不同的初始点,对比结果后选择最优的可行解。

  4. 理解Exit mode 8的含义:
    当初始点设为[5,4]时出现的Exit mode 8提示,是因为该点不可行,算法在搜索方向上无法找到可行的步长,所以直接返回初始点。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 23:35:54