Scipy minimize SLSQP退出模式3求助:大模型优化失败
带不等式约束的多变量优化问题故障排查
问题背景
使用Scipy的minimize结合SLSQP求解带不等式约束的多变量优化问题:目标为最小化f(a),约束条件g(a) ≤ SIGMA。6维a向量的小模型运行正常,但476维的大模型运行时出现错误。
错误信息
More than 3*n iterations in LSQ subproblem (Exit mode 3) Current function value: 1543.3839071145048 Iterations: 1 Function evaluations: 268 Gradient evaluations: 1
代码及小模型输入
核心代码
import numpy as np import scipy.optimize as op SIGMA = 0.2 * (10 ** 6) Y_MOD = 210. * (10 ** 6) RHO = 7.850 GRAVITY_ACC = 9.81 A_MIN = 0.05 ** 2 A_MAX = 0.25 ** 2 def w(x, adj, a): return GRAVITY_ACC * RHO * np.sqrt(np.sum((x[adj[:, 1]] - x[adj[:, 0]]) ** 2, axis=1)) * a def f(x, adj, a): return np.sum(w(x, adj, a)) def g(x, adj, a, s, pw, pl): nk = len(x) ne = len(adj) dof = nk * 3 dir_vec = x[adj[:, 1], :] - x[adj[:, 0], :] lengths = np.sqrt(np.sum(dir_vec ** 2, axis=1)) stiff = Y_MOD * (a / lengths) fw = 0.5 * w(x, adj, a) cosines = dir_vec / lengths[:, None] Ks = np.zeros((dof, dof), dtype=np.float32) K_mats = np.empty((ne, 6, 6), dtype=np.float32) pg = np.zeros((dof,), dtype=np.float32) T_mats = np.empty((ne, 2, 6), dtype=np.float32) for e in range(ne): k_mat = np.array([[-stiff[e], stiff[e]], [stiff[e], -stiff[e]]]) cx, cy, cz = cosines[e] T_mats[e] = np.array([ [cx, cy, cz, 0, 0, 0], [0, 0, 0, cx, cy, cz]]) K_mats[e] = T_mats[e].T @ k_mat @ T_mats[e] i, j = adj[e] for h, x_idx in [(0, i * 3), (3, j * 3)]: for k, y_idx in [(0, i * 3), (3, j * 3)]: Ks[x_idx: x_idx + 3, y_idx:y_idx + 3] += K_mats[e, h:h + 3, k:k + 3] pg[i * 3 + 2] += fw[e] pg[j * 3 + 2] += fw[e] p = (pg + pw.flatten() + pl.flatten()) vec_mask = np.logical_not(s).flatten() d = np.zeros(dof, dtype=np.float32) d[vec_mask] = np.linalg.solve(Ks[vec_mask, :][:, vec_mask], p[vec_mask]) tensions = np.empty(ne, dtype=np.float32) b = np.array([1, -1], dtype=np.float32) for e in range(ne): i, j = adj[e] * 3 tensions[e] = (Y_MOD / lengths[e]) * (b @ T_mats[e] @ d[[i, i + 1, i + 2, j, j + 1, j + 2]]) return np.abs(tensions) def optimizeFullProfiles(x, adj, x0, s, pw, pl): nlc = op.NonlinearConstraint( fun=lambda a: g(x, adj, a, s, pw, pl), lb=0., ub=SIGMA) bounds = op.Bounds(A_MIN, A_MAX) res = op.minimize(fun=lambda a: f(x, adj, a), x0=x0, method='slsqp', bounds=bounds, constraints=[nlc], tol=1e-6, options={'disp': True, 'maxiter': 1000})
小模型输入
x = np.array([[0. 0. 0. ], [2. 0. 0. ], [2. 1. 0. ], [0. 0.9 0. ], [0.6 0.5 0.9]], dtype=np.float32) adj = np.array([[0 4], [1 4], [2 4], [3 4], [1 2], [1 3]], dtype=int) x0 = np.array([0.0625, 0.0625, 0.0625, 0.0625, 0.0625, 0.0625], dtype=np.float32) s = np.array([[1 1 1], [0 0 1], [1 1 1], [1 1 1], [0 0 0]], dtype=int) pw = np.array([[0. 0. 0.], [0. 0. 0.], [0. 0. 0.], [0. 0. 0.], [0. 0. 0.]], dtype=np.float32) pl = np.array([[ 0. 0. 0.], [ 0. 0. 0.], [ 0. 0. 0.], [ 0. 0. 0.], [ 0. 0. 500.]], dtype=np.float32)
故障原因及解决办法
原因分析
Exit mode 3对应SLSQP求解子问题时迭代次数超过阈值,本质是高维场景下数值稳定性下降,核心诱因包括:
- 梯度缺失:未提供目标函数和约束的解析梯度,Scipy只能用有限差分近似,高维下近似误差大,导致优化方向混乱。
- 矩阵病态:大模型中刚度矩阵
Ks可能出现条件数过大的情况,np.linalg.solve求解时数值不稳定,误差传递到约束计算,干扰优化过程。 - 初始点不合理:476维
x0全设为相同值,可能远离最优解区域,导致子问题快速陷入迭代僵局。
解决步骤
提供解析梯度
手动推导并实现目标函数和约束的梯度,替换有限差分近似,大幅提升高维优化稳定性:- 目标函数梯度:
f(a)是线性求和,df/da的每个分量直接为GRAVITY_ACC * RHO * 对应单元的长度。 - 约束梯度:利用结构力学伴随法推导张力对
a的导数,避免直接求导的复杂度。
- 目标函数梯度:
优化矩阵求解稳定性
替换np.linalg.solve为带正则项的最小二乘求解,处理病态矩阵:# 替换原solve代码块 K_sub = Ks[vec_mask, :][:, vec_mask] p_sub = p[vec_mask] # 添加小正则项避免矩阵奇异 d[vec_mask], _, _, _ = np.linalg.lstsq(K_sub + 1e-8 * np.eye(len(K_sub)), p_sub, rcond=None)调整初始点与优化参数
- 初始点
x0根据单元负载分配设置,受载大的单元初始值适当提高,避免全相同值。 - 调整SLSQP选项,增加子问题迭代次数、调整容差:
options={'disp': True, 'maxiter': 1000, 'maxls': 100, 'ftol': 1e-5}
- 初始点
尝试替代优化方案
若模型规模过大,可考虑分区域优化,或换用更适合高维问题的trust-constr优化器。
内容的提问来源于stack exchange,提问作者user22086025
相关产品推荐
相关产品推荐

