Mini-Infer (20): 优化器的骨架 — `Pass Manager` 架构设计
Mini-Infer (20): 优化器的骨架 — Pass Manager 架构设计
1. 设计哲学:像编译器一样思考
在编译器领域(如 LLVM),优化通常被组织成一系列的 Pass (遍)。每一个 Pass 只做一件特定的事情(比如“死代码消除”),然后优化器(Pass Manager)按顺序执行这些 Pass。
Mini-Infer 借鉴了这种设计,同时也参考了 TensorRT 的 IOptimizationProfile 概念。
我们需要两个核心组件:
OptimizationPass: 定义“怎么优化”的接口(策略模式)。GraphOptimizer: 定义“何时优化”的管理器(执行管线)。
2. 定义契约:OptimizationPass
首先,我们定义所有优化算法必须遵守的基类。
1 | // mini_infer/graph/graph_optimizer.h |
这个接口非常简单但强大:
apply: 这是唯一需要实现的方法。具体的优化逻辑(比如遍历图、查找模式、修改节点)都在这里实现。num_modifications: 这是一个关键的反馈机制。如果返回0,说明图结构已经稳定,或者该优化不适用。这为未来的“定点迭代”(反复优化直到不再变化)提供了基础。
3. 调度中心:GraphOptimizer
有了 Pass,我们需要一个容器来管理它们的执行顺序,并提供日志和统计功能。
1 | // mini_infer/graph/graph_optimizer.h |
实现逻辑 (graph_optimizer.cpp)
optimize 函数不仅是简单的循环调用,它还集成了日志记录和统计,这对于调试复杂的图优化非常重要。
1 | core::Status GraphOptimizer::optimize(Graph* graph) { |
4. 为什么要这样设计?
这种 Pass Manager 架构带来了极大的灵活性:
- 解耦 (Decoupling):
GraphOptimizer不需要知道具体的优化算法(Fusion, DCE 等)。添加新的优化只需要写一个新的OptimizationPass子类并注册即可。 - 可配置性 (Configurability):我们可以根据不同的硬件后端(CPU vs GPU)注册不同的 Pass 列表。例如,某些 GPU 特有的融合策略在 CPU 上可能并不适用。
- 可观测性 (Observability):通过
Statistics和日志,我们可以清楚地看到每个 Pass 到底做了什么。如果模型跑得慢,我们可以检查是不是“算子融合”Pass 没有生效(修改数为 0)。
5. 总结与展望
本篇我们构建了图优化的“骨架”。我们现在拥有了一个能够调度、执行和监控优化的系统。
但是,目前的优化器还是“空转”的,因为它还没有注册任何具体的 Pass。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 James的成长之路!
评论





