如何加速含交互变量的多方程Gekko最小化求解?
缩短Gekko (IMODE=3)大规模多项式拟合求解时间的策略
我使用Gekko以IMODE=3模式求解14个优化变量,目标是最小化约10000个平方误差方程(每个方程为训练数据第i行响应y与多项式模型输出的平方差eq[i] = (y[i] - model[i]) ** 2)。每行多项式包含10-100个项,变量间交互性强(多变量多次相乘),以下是可复现的简化拟合示例:
from gekko import GEKKO import numpy as np m = GEKKO() # 实例化Gekko模型 # 定义优化变量 a = m.FV(lb=0, ub=2) a.STATUS = 1 b = m.FV(lb=0, ub=2) b.STATUS = 1 c = m.FV(lb=0, ub=2) c.STATUS = 1 n_eqs1 = 1000 # 数据集1的方程数量 n_eqs2 = 500 # 数据集2的方程数量 n_terms = 12 # 每个方程的项数 noise_scl = 1 # 噪声标准差 # 训练数据集 x = { "dataset1": np.arange(n_eqs1)[:, np.newaxis] + np.random.normal(loc=0, scale=noise_scl, size=(n_eqs1, n_terms)), "dataset2": np.arange(n_eqs2)[:, np.newaxis] + np.random.normal(loc=0, scale=noise_scl, size=(n_eqs2, n_terms)), } # 响应值 y = np.arange(n_eqs1) for x_ds in x.values(): for i in range(x_ds.shape[0]): # 最小化平方误差 m.Minimize( ( y[i] - ( x_ds[i, 0] * a + x_ds[i, 1] * a**2 + x_ds[i, 2] * a * b + x_ds[i, 3] * a * (b**2) + x_ds[i, 4] * (a**2) * b + x_ds[i, 5] * (a**2) * (b**2) + x_ds[i, 6] * c + x_ds[i, 7] * (c**2) + x_ds[i, 8] * c * b + x_ds[i, 9] * c * (b**2) + x_ds[i, 10] * (c**2) * b + x_ds[i, 11] * (c**2) * (b**2) ) / n_terms ) ** 2 ) m.options.IMODE = 3 m.solve(disp=True) # 噪声合理时,优化值应趋近于1 print(f"a = {a.value[0]:3f}\n" f"b = {b.value[0]:3f}\n" f"c = {c.value[0]:3f}")
缩短求解时间的关键策略
合并目标函数调用:避免循环创建10000个独立的
m.Minimize(),改为计算所有平方误差的总和后一次性传入。Gekko支持向量化运算,这样能大幅减少模型构建的开销,同时让求解器更高效地处理整体目标。切换高效求解器:IMODE=3默认使用APOPT,对于大规模非线性最小二乘问题,切换到IPOPT(
m.options.SOLVER = 3)或BPOPT(m.options.SOLVER = 2)更合适。IPOPT在处理稀疏大规模问题时,迭代效率和内存占用表现更优。利用稀疏矩阵特性:你的多项式模型每个方程仅涉及10-100个项,雅可比矩阵天然稀疏。确保求解器启用稀疏处理(IPOPT、APOPT默认支持),避免稠密矩阵运算带来的性能损耗。
优化变量初始化与边界:
- 先用Scipy的
least_squares等工具快速得到一个初始解,将其作为Gekko变量的初始值(a.value = initial_a),减少求解器的迭代次数。 - 根据先验知识收紧变量的上下界(lb/ub),缩小求解器的搜索空间。
- 先用Scipy的
简化模型计算:
- 引入中间变量缓存重复计算的项,比如先定义
a2 = m.Intermediate(a**2)、b2 = m.Intermediate(b**2),后续直接引用这些中间变量,避免重复计算高次幂和交互项。 - 通过相关性分析或正则化方法,剔除对响应y影响极小的多项式项,减少每个方程的计算量。
- 引入中间变量缓存重复计算的项,比如先定义
启用并行计算:使用IPOPT时,可通过以下设置开启并行模式,利用多核CPU加速线性代数运算:
m.options.IPOPT_OPTIONS = {'linear_solver': 'ma57', 'parallel': 'yes'}调整求解器收敛参数:
- 如果对精度要求不是极高,可适当放宽收敛阈值,比如将
m.options.RTOL和m.options.ATOL从默认的1e-6调整为1e-4,减少迭代次数。 - 为IPOPT指定更高效的稀疏线性求解器,如
ma57、ma97,替代默认的mumps,提升大规模问题的求解速度。
- 如果对精度要求不是极高,可适当放宽收敛阈值,比如将
内容的提问来源于stack exchange,提问作者Florent H
相关产品推荐
相关产品推荐

