【问题标题】:pyomo seems very slow to write modelspyomo 写模型似乎很慢
【发布时间】:2018-12-18 13:01:38
【问题描述】:

我有一个相当大的模型(大约 500 万个变量和约束)。

构建时间是几分钟,求解时间也是几分钟(使用 gurobi)

但是写模型需要很长时间(大约2小时)

如果我使用model.write('model.lp', io_options={'symbolic_solver_labels': True}) 可以记录它,这是时候

如果我直接使用pyomo的模型SolverFactorysolve,时间差不多

这里有一个小样本,我知道这个模型对于 gurobi 来说是微不足道的,所以我没有在这里比较求解时间和构建时间,但我不明白为什么它这么长,我认为问题可能来自磁盘写入速度,但似乎磁盘从不超载,几乎没有使用

import pyomo.environ as pyo
import time

size = 500000

model = pyo.ConcreteModel()
model.set = pyo.RangeSet(0, size)
model.x = pyo.Var(model.set, within=pyo.Reals)
model.constrList = pyo.ConstraintList()
for i in range(size):
    model.constrList.add(expr = model.x[i] >= 1)
model.obj = pyo.Objective(expr=sum(model.x[i] for i in range(size)), sense=pyo.minimize)

opt = pyo.SolverFactory('gurobi')

_time = time.time()
res = opt.solve(model)
print(">>> total time () in {:.2f}s".format(time.time() - _time))

print(res)

结果是整个求解函数的时间为27 s,而gurobi的求解时间仅为4 s。

【问题讨论】:

    标签: pyomo


    【解决方案1】:

    检查您是否安装了最新版本的 pyomo 也是值得的。我最近从 v 5.5.0 更新到 5.6.8,发现构建 + 解决时间从 5 秒减少到 1 秒(对于一个明显比你的问题小得多的问题!)。

    【讨论】:

      【解决方案2】:

      从我加快 pyomo 模型生成的轨迹来看,您需要首先对进程的哪个部分减慢它进行基准测试。 (这确实是性能调优的一般建议)

      所以我把你的代码放到一个函数中:

      def main():
          size = 500000
      
          model = pyo.ConcreteModel()
          model.set = pyo.RangeSet(0, size)
          model.x = pyo.Var(model.set, within=pyo.Reals)
          model.constrList = pyo.ConstraintList()
          for i in range(size):
              model.constrList.add(expr = model.x[i] >= 1)
          model.obj = pyo.Objective(expr=sum(model.x[i] for i in range(size)), sense=pyo.minimize)
          return model
      

      所以我可以通过 ipython 中的 line profiler 运行:

      In [1]: %load_ext line_profiler                                                                                                                                                                         
      
      In [2]: import test_pyo                                                                                                                                                                                 
      
      In [3]: %lprun -f test_pyo.main test_pyo.main()
      

      这说明大部分时间都花在了model.constrList.add(expr = model.x[i] >= 1)上。

      将其移入基于规则的约束中并没有看到太大的改进,因此我决定尝试手动构建表达式,就像在PyPSA code 中一样。

      import pyomo.environ as pyo
      import time
      from pyomo.core.expr.numeric_expr import LinearExpression
      from pyomo.core.base.constraint import _GeneralConstraintData
      from pyomo.core.base.numvalue import NumericConstant
      
      def main():
          size = 500000
      
          model = pyo.ConcreteModel()
          model.set = pyo.RangeSet(0, size)
          model.x = pyo.Var(model.set, within=pyo.Reals)
          setattr(model, "constraint", pyo.Constraint(model.set, noruleinit=True))
          v = getattr(model, "constraint")
          for i in v._index:
              v._data[i] = _GeneralConstraintData(None, v)
              expr = LinearExpression()
              expr.linear_vars = [model.x[i]]
              expr.linear_coefs = [1]
              expr.constant = 0
              v._data[i]._body = expr
              v._data[i]._equality = False
              v._data[i]._lower = NumericConstant(1)
              v._data[i]._upper = None
      
          model.obj = pyo.Objective(expr=pyo.quicksum(model.x[i] for i in range(size)), sense=pyo.minimize)
          return model
      

      这似乎产生了大约 50% 的性能提升。线分析器显示,现在花费大量时间来创建集合、空 LinearExpression 对象以及创建目标。调整目标可能会使事情变得更好。

      【讨论】:

      • 事实证明,如果您还手动为目标创建 LinearExpression,您可以获得另一个小的改进
      【解决方案3】:

      我认为你的隐含问题是“我怎样才能让它更快?”

      如果写入时间有问题,您可以查看 Gurobi SolverFactory('gurobi', io_format='python') 的直接 python 接口。将symbolic_solver_labels 标志设置为True 几乎总是会增加模型的写入时间,因为组件名称查找可能很昂贵。

      【讨论】:

      • 感谢您的回答,io_format='python' 似乎对速度影响不大,对于符号标签,我通常只为调试编写模型,所以我需要标签
      • 啊,所以您的首要任务是能够写出整个模型以进行调试?或者您只是想检查模型的某个部分?
      • 编写模型时我并不关心速度,因为我只是在调试时使用它。直接从 pyomo 解决时,我的问题更多,我期望模型的构建时间在求解时间旁边可以忽略不计,但反过来,这就是我不明白的地方
      猜你喜欢
      • 2021-12-11
      • 1970-01-01
      • 1970-01-01
      • 2015-02-16
      • 1970-01-01
      • 1970-01-01
      • 2016-09-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多