gurobi优化器常见问题与调试方法

本文整理自官方教程,是对多份官方资料学习所得笔记。

目录

优化失败

常见原因

诊断步骤

原因排查

独立于代码测试模型

优化异常

常见异常

常见原因

原因排查

log日志

模型统计数据

检查LP文件

测试已知解

MIP 最优性

可行性

不可行诊断工具infeasibility detection tools

不可约不一致子系统(IIS)

约束放松feasRelax

优化缓慢

常见原因

原因排查

导致性能降低的情况

算法瓶颈

性能调优

常用方法

一般方法

模型初始化

语法

内存

预计算

连续优化

整数优化


优化失败

常见原因

  • 代码问题
  • 无法捕获异常
  • 无法测试解的状态
  • 许可证
  • 数据错误
  • 内存满了、硬件故障

诊断步骤

  1. 什么错误?
  2. 你需要做什幺才能让它失败?什么操作导致的?
  3. 可复现性?你能可靠地复现它还是只能随机复现它?
  4. 代码中的哪个位置失败?
    • 模型创建
    • 求解
    • 回调
    • 检索解决方案值

原因排查

  1. 捕获异常Catch exceptions
  2. 使用系统分析工具:System Monitor, top, Activity Monitor, profiler in compiler
  3. 独立于代码测试模型
  4. 换用云端的不同硬件

独立于代码测试模型

  1. 将模型导出为MPS文件。
model.update(); 
model.write("test.mps”);

导出参数配置,可以导出以下几个配置文件:

  • 非默认参数放在.prm后缀的文档
  • MIP初值放在.mst后缀的文档
  • 初始 LP线性规划基础放在.bas后缀的文档
model.update(); 
model.write("test.mps"); 
model.write("test.prm"); 
model.write("test.mst");
  1. 在命令行/gurobi自己的shell界面运行gurobi
#命令行 
gurobi_cl test.mps
#或者gurobi自己的shell界面 
model=read("test.mps") model.optimize()

使用文档写入和读取参数,热启动:

#命令行 
gurobi_cl 
inputfile=test.prm inputfile=test.mst test.mps 

#或者gurobi自己的shell界面 
model=read("test.mps") 
model.read("test.prm") 
model.read("test.mst") model.optimize()

优化异常

常见异常

  • 模型不可行infeasible
  • 已知的解决方案不可行not feasible
  • 解决方案欠优suboptimal
  • 解决方案违反已知约束violates some known constraints
  • 数值稳定性问题

常见原因

  • 模型错误
  • 输入数据异常
  • 其它数字问题

原因排查

  • 检查log日志,和模型统计数据
  • 检查LP文件
  • 测试已知解
  • 尝试不可行诊断infeasibility detection

log日志

 

模型文档中的问题仅在使用 MPS 或 LP 文档时显示

MPS 和 LP 格式未完全指定

模型统计数据

统计数据如下,比较模型规模是否符合预期。

 

0

检查LP文件

输出 LP 格式文件。 LP 格式文件是最接近数学模型表达式的格式,每写一步程序,就可以输出为 LP 文件。打开后和手写的模型做对比,来检查程序是否正确。

对于 C, C++, C#, Python, Java, R, Matlab 这些 Gurobi 直接支持的语言,输出LP 文件可以用 model.write 命令;

测试已知解

MIP 最优性

把前一步的解作为初值带入,再次优化。看有没有提升

m=read("test.mps") 
m.read("test.mst") 
m.optimize()
可行性

对优化变量增加约束。通过约束增减来判断。

对复杂问题的不可行进行溯源,是一项繁琐的工作,计算量不亚于求解一个优化模型。如果以上方式无法在短时间找到源头,用户也可以通过逐步增加约束,边增加边判断的方式发现问题的源头

m=read("test.mps") 
x=m.getVarByName("x") 
x.setAttr("LB", 1.0) 
x.setAttr("UB", 1.0)

不可行诊断工具infeasibility detection tools

主要有不可约不一致子系统 Irreducible Inconsistent Subsystem (IIS),和约束放松feasRelax两个方法。

不可约不一致子系统(IIS)

功能:

  • 查找相互冲突的约束的最小集合
  • 指示无法满足的属性
  • 适用于模型开发

Gurobi 9.5 版本允许用户为变量的上下界、线性约束、二次约束、 SOS 约束、非线性约束单独设置 IIS Force 属性,也就是 IISConstrForce, IISLBForce, IISUBForce, IISSOSForce, IISQConstrForce, and IISGenConstrForce 属性。

如果这些属性值设置为 1(默认值为-1),那么就要求 Gurobi 必须将这些变量上下界和约束包含到 IIS 计算当中。

这个属性的最大作用,就是当一个可行模型在添加新的约束和变量上下界之后,变得不可行, 需要溯源哪些新的变化造成了模型不可行。

这种情况下,用户可以将原模型中的变量边界和约束的 Force 属性设定为 1,然后运行 ComputeIIS(),那么 Gurobi 只会专注在新增加的约束和变量边界上,不但溯源的时间会更短,而且提供的信息可以更容易让用户发现问题。 但需要注意这种方式获得的 IIS 集合不一定是最小集合。

约束放松feasRelax

功能:

  • 找到有最少的约束冲突的解
  • 检索人工添加的松弛变量以查找违规行为
  • 适用于已部署的应用

复杂问题 computeIIS() 时间长,或者输出的 ILP 冲突约束文件不容易看出来具体的错误源头。这时采用 Gurobi 的 feasRelaxS() 和feasRelax() 函数。其中, feasRelaxS() 是 feasRelax() 函数的简化,易用,我们以此为列来进行说明。

feasRelaxS() 和 feasRelax() 函数的功能,是在原有模型基础上,为变量和约束添加松弛变量,让松弛模型变得可行,然后通过最小化松弛量来获得一个最小违反变量和约束限制的模型。

用户可以观察优化后的松弛变量的数值是否为 0(全部松弛变量为 0 意味着模型有可行解),以及数值范围, 来初步了解哪些约束可能是问题的源头,以及冲突的程度。需要说明的是,任何模型不可能由单一约束或者单一变量边界造成不可行。不可行的模型往往存在若干个约束和变量边界一起发生冲突,导致最终不可行,因此导致冲突的原因可以有无穷多的解读和因果链条,并不存在唯一的化解方式,需要结合模型的应用场景来调整。

样例:feasopt.py

样例步骤:

  1. 用 m=read(“model.ilp”) 读入这个模型。 ILP 格式和 LP 格式一致。
  2. 用 m.feasRelaxS(0,False,False,True) 添加松弛变量。函数参数的具体含义请看参考手册。
  3. 用 m.optimize() 运行这个松弛模型。
  4. 用 m.write(“model.sol”) 将松弛模型的优化结果输出到 model.sol 文件。
  5. 用 m.write(“model.lp”) 将松弛模型输出到 model.lp 文件,这里面包含了松弛变量,以 Art 开头。 所有的松弛变量为非负。
  6. 打开 model.sol 文件, 我们可以忽略在 model.lp 中标记为 free 的那些变量,例如 C1126 等,这些变量无论取什么数值都和不可行无关。我们注意到松弛变量 ArtN_R10165 的数值不为 0,对应的 R10165 约束中另外一个松弛变量ArtP_R10165 为 0,就意味着约束 R10165 距离可行还相差 0.5605625。化解这个冲突可以有很多方法,要结合模型实际应用背景来处理,例如可以让 C8069的下界从原来的 0, 更改为-0.5605625;或者更改 C66 的边界值,等等。

我们以上的方法是将 feasRelaxS() 函数作用于 ILP 文件,也就是运行 ComputeIIS()之后的输出文件。用户也可以直接将 feasRelaxS()作用于原始 LP 文件,方法一致。作用于 ILP的好处就是排除不相关的约束,让分析更聚焦在冲突的约束上

优化缓慢

常见原因

  • 数值问题
  • 内存限制
  • 不切实际的容差值
  • 大型或困难的模型

原因排查

  • 导致性能降低的情况
  • 算法瓶颈
  • 参数调优工具 Parameter tuning tool
  • 性能指南
  • 将测试模型发送给Gurobi

导致性能降低的情况

  • 哪些数据导致缓慢
  • 缓慢是随机产生,还是可预测稳定产生?
  • 硬件原因

算法瓶颈

  • 模型初始化和解决方案检索。用gurobi_cl命令行工具检测.mps文件,查看速度是否提升
  • 求解过程。
    • 预解析
    • 求解(初始 LP)
    • MIP的节点0
    • MIP的其他节点
    • log日志显示预求解、LP 松弛、MIP 根、节点所花费的时间
  • 在log日志中查看各个部分的时间开销,查找代码瓶颈

性能调优

常用方法

  • 一般方法
  • 预计算
  • 连续优化
  • 整数优化
  • 约束简化

一般方法

模型初始化
  • 每个矩阵生成器都有自己的陷阱和最佳实践。有效地对 API 使用迭代器
  • 通过代码分析器查找:瓶颈
  • OO接口是C矩阵接口上的薄层
  • 使用Gurobi OO接口,利用延迟更新。仅在必要时调用更新函数以引用新对象
语法
  • c++循环的优化
  • 优化器模型的引用传参
  • 避免在一个语句中嵌入多个循环和条件定义,避免嵌套多个 sum (quicksum) 语句。对于新手而言,建议用多个独立循环,单独罗列条件来构造复杂的多个变量或者约束
内存
  • 内存不足会破坏性能
  • 通过磁盘的虚拟内存比 RAM 慢得多
  • 并行优化需要更多内存
  • 通过计算机上的系统监视器工具查找:内存使用情况。如:系统监视器、活动监视器
  • 参数
    • 减少线程数threads
    • 设置NodefileStart使用磁盘存储 MIP 节点信息
  • 内存可劲儿造

预计算

  • 意义:预先花时间,以简化模型。
  • 方法:预先查找有不同预计算参数的性能方案
  • 控制参数:Presolve

希望降低预计算时间,降低该参数;希望简化模型,增加该参数;

  • 附加参数:精细调节
参数名功能
PrePasses有空再补上这一行。下同
Aggregate
AggFill
PreSparsify
PreDual
PreDepRow

连续优化

等有空再补上这一段。

整数优化

等有空再补上这一段。

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值