Pyomo调用CBC求解器仅迭代一次未寻优的问题求助
问题
使用Pyomo进行最小化寻优时,求解器仅执行一次迭代就停止,未尝试寻找极小值点。
问题代码
import pyomo.environ as pyo model = pyo.ConcreteModel() model.x = pyo.Var([0, 1], domain = pyo.NonNegativeIntegers, initialize = [10, 3]) def loss(args): a, b = args[0].value, args[1].value return (a - 30) ** 2 + (b - 5) ** 2 model.obj = pyo.Objective(expr = loss((model.x[0], model.x[1])), sense = pyo.minimize) model.c1 = pyo.Constraint(expr = model.obj >= 0.0) solver_options = pyo.SolverFactory("cbc").options solver_options["max_iter"] = 10 solver_options["tolerance"] = 0.000001 solver_options["max_seconds"] = 10 results = pyo.SolverFactory("cbc").solve(model, options = solver_options) results.write()
求解输出
# ========================================================== # = Solver Results = # ========================================================== # ---------------------------------------------------------- # Problem Information # ---------------------------------------------------------- Problem: - Name: unknown Lower bound: 404.0 Upper bound: 404.0 Number of objectives: 1 Number of constraints: 2 Number of variables: 1 Number of nonzeros: 0 Sense: minimize # ---------------------------------------------------------- # Solver Information # ---------------------------------------------------------- Solver: - Status: ok User time: -1.0 System time: 0.0 Wallclock time: 0.0 Termination condition: optimal Termination message: Model was solved to optimality (subject to tolerances), and an optimal solution is available. Statistics: Branch and bound: Number of bounded subproblems: None Number of created subproblems: None Black box: Number of iterations: 0 Error rc: 0 Time: 0.008995532989501953 # ---------------------------------------------------------- # Solution Information # ---------------------------------------------------------- Solution: - number of solutions: 0 number of solutions displayed: 0
核心原因
代码的致命问题是:定义目标函数时直接调用了loss()函数并获取变量的当前值。这会让Pyomo将目标函数固定为初始化变量时计算出的常量(这里是(10-30)² + (3-5)² = 404),而非构建与model.x变量关联的动态表达式。
从求解器输出也能验证:问题信息里显示Number of variables: 1(实际应为2个变量),目标函数是常量,所以求解器直接判定已达最优,停止计算。
解决方案
根据场景分为两种处理方式:
场景1:函数可转化为Pyomo表达式(示例场景)
如果损失函数能用Pyomo变量表达式表示,直接在Objective中定义关联表达式,不要调用.value获取变量当前值:
import pyomo.environ as pyo model = pyo.ConcreteModel() model.x = pyo.Var([0, 1], domain=pyo.NonNegativeIntegers, initialize=[10, 3]) # 用Pyomo变量构建目标函数表达式 def loss_expr(model): return (model.x[0] - 30)**2 + (model.x[1] - 5)**2 model.obj = pyo.Objective(rule=loss_expr, sense=pyo.minimize) model.c1 = pyo.Constraint(expr=model.obj >= 0.0) solver = pyo.SolverFactory("cbc") solver.options["max_iter"] = 10 solver.options["tolerance"] = 1e-6 solver.options["max_seconds"] = 10 results = solver.solve(model) results.write() # 查看最优解 print(f"最优x0: {pyo.value(model.x[0])}, 最优x1: {pyo.value(model.x[1])}")
这种方式下,Pyomo能正确识别变量与目标函数的依赖关系,求解器会正常迭代寻优。
场景2:使用依赖外部包的复杂黑箱函数
如果损失函数依赖外部库、无法转化为Pyomo表达式,需要使用支持黑箱优化的求解器,或通过Pyomo的ExternalFunction包装函数。
方法:用ExternalFunction包装黑箱函数
import pyomo.environ as pyo from pyomo.core.expr.external import ExternalFunction model = pyo.ConcreteModel() model.x = pyo.Var([0, 1], domain=pyo.NonNegativeIntegers, initialize=[10, 3]) # 模拟依赖外部包的复杂黑箱函数 def black_box_loss(a, b): # 替换为你的实际复杂逻辑 return (a - 30)**2 + (b - 5)**2 # 注册外部函数 model.loss_fn = ExternalFunction(black_box_loss) # 用外部函数定义目标函数 model.obj = pyo.Objective(expr=model.loss_fn(model.x[0], model.x[1]), sense=pyo.minimize) model.c1 = pyo.Constraint(expr=model.obj >= 0.0) # 使用支持黑箱优化的求解器,比如bonmin(支持混合整数黑箱优化) solver = pyo.SolverFactory("bonmin") solver.options["max_iter"] = 100 results = solver.solve(model) results.write() print(f"最优x0: {pyo.value(model.x[0])}, 最优x1: {pyo.value(model.x[1])}")
注意事项
- CBC是线性/整数规划求解器,不支持黑箱优化,需更换为
ipopt(连续变量)或bonmin(混合整数变量)这类求解器。 - 确保已安装对应的求解器(可通过
conda install -c conda-forge ipopt bonmin安装)。
内容的提问来源于stack exchange,提问作者olivaw
相关产品推荐
相关产品推荐

