4. 主流深度学习IR介绍

在自动驾驶模型部署工程中,中间表示(Intermediate Representation,IR)是连接训练框架与车载推理引擎的“通用语言”。不同 IR 的设计目标差异很大:有的强调跨框架互操作,有的强调图级优化,有的强调多后端代码生成,有的则试图成为编译器基础设施。理解它们的抽象层级、算子表达能力和部署链路位置,是做出正确技术选型的前提。

一、核心原理:五种IR的抽象层级与定位

ONNX 是一种开放的模型交换格式,以 protobuf 描述计算图,节点为算子,边为张量,强调“一次导出、多引擎加载”。TorchScript 是 PyTorch 的序列化图表示,通过 trace 或 script 将动态图固化为可独立执行的 IR,天然贴近 PyTorch 语义。TensorFlow GraphDef 是 TensorFlow 1.x 的计算图序列化格式,节点与属性描述完整,但生态绑定较强。TVM Relay 是 TVM 的高层函数式 IR,面向张量计算与自动调度,强调从图到硬件代码的端到端编译。MLIR 则是可扩展的编译器基础设施,通过多层 dialect 表达从高层算子到硬件指令的渐进下降。

关键判断:ONNX 解决“交换”,TorchScript 解决“PyTorch 固化”,GraphDef 解决“TF 图持久化”,Relay 解决“图到硬件的编译”,MLIR 解决“多层抽象的统一编译框架”。

五种主流深度学习IR:抽象层级与部署链路定位 高层语义 / 框架绑定 低层硬件 / 指令级 ONNX 模型交换格式 跨框架互操作 TorchScript PyTorch 图固化 trace / script GraphDef TF 计算图序列化 节点 + 属性 TVM Relay 函数式张量IR 自动调度编译 MLIR 多层 dialect 渐进式下降 PyTorch / TF 导出 onnx.export() torch.jit.trace torch.jit.script tf.GraphDef freeze_graph relay.frontend from_onnx / from_tf mlir-opt / iree dialect 转换 图优化:常量折叠 算子融合:有限 Grappler 优化 AutoTVM / Ansor Pass Pipeline TensorRT / OpenVINO ONNX Runtime LibTorch Torch-TensorRT TF-TRT TFLite CUDA / OpenCL ARM CPU / NPU LLVM / SPIR-V 自定义后端

二、方法流程:从训练框架到车载推理引擎

以典型的自动驾驶感知模型为例,部署流程通常包含导出、优化、量化、编译和运行五个阶段。不同 IR 在流程中的位置不同,决定了它们的适用边界。

  1. 导出阶段:PyTorch 模型通过 torch.onnx.export 生成 ONNX,或通过 torch.jit.trace 生成 TorchScript;TensorFlow 模型通过 freeze_graph 生成 GraphDef。
  2. 图优化阶段:ONNX 可借助 onnx-simplifier 做常量折叠与算子简化;GraphDef 使用 Grappler 做布局优化与算子融合;Relay 使用 FoldConstant、FuseOps 等 Pass。
  3. 量化阶段:ONNX 支持 QDQ 格式量化;TorchScript 支持 torch.quantization;Relay 支持 relay.quantize;MLIR 通过量化 dialect 表达。
  4. 编译阶段:Relay 通过 AutoTVM/Ansor 生成调度并编译为 CUDA 或 ARM 代码;MLIR 通过 Pass Pipeline 逐步下降至 LLVM IR。
  5. 运行阶段:ONNX 由 TensorRT、OpenVINO 或 ONNX Runtime 加载;TorchScript 由 LibTorch 或 Torch-TensorRT 执行;GraphDef 由 TF-TRT 或 TFLite 执行。
# ONNX 导出示例
torch.onnx.export(
    model, dummy_input, "perception.onnx",
    opset_version=13,
    input_names=["camera"], output_names=["boxes", "scores"],
    dynamic_axes={"camera": {0: "batch"}}
)

# TorchScript 导出示例
scripted = torch.jit.script(model)
scripted.save("perception.pt")

# Relay 加载 ONNX 并编译
mod, params = relay.frontend.from_onnx(onnx_model, shape_dict)
with tvm.transform.PassContext(opt_level=3):
    lib = relay.build(mod, target="cuda", params=params)

三、案例/场景:自动驾驶中的典型选型

在量产自动驾驶项目中,选型往往由芯片工具链决定。若目标芯片是 NVIDIA Orin,TensorRT 对 ONNX 的支持最成熟,因此 ONNX 常作为首选交换格式;若团队以 PyTorch 为主且需要保留动态控制流,TorchScript 更合适;若使用 TensorFlow 训练且部署到 TFLite,GraphDef 是自然选择;若需要针对自研 NPU 做深度算子调度,TVM Relay 提供了从图到硬件的完整编译能力;若芯片厂商提供 MLIR 后端,则 MLIR 可作为统一接入层。

场景提示:多传感器融合模型常包含动态 shape 和自定义算子。ONNX 对动态 shape 支持较好,但自定义算子需要注册;TorchScript 对控制流支持更自然;Relay 和 MLIR 则允许通过自定义 dialect 或 intrinsic 表达专有算子。

四、对比清单:五种IR的适用性对比

IR 抽象层级 核心优势 主要局限 自动驾驶适用场景
ONNX 算子图 跨框架交换、生态广 自定义算子支持弱、opset 版本碎片化 TensorRT/OpenVINO 部署、多框架模型统一
TorchScript 框架图 保留 PyTorch 语义、支持控制流 跨框架能力弱、优化空间有限 PyTorch 原生部署、Torch-TensorRT 链路
GraphDef 框架图 TF 生态完整、Grappler 优化成熟 生态绑定强、新框架支持弱 TF-TRT、TFLite 车载部署
TVM Relay 函数式张量IR 自动调度、多后端代码生成 算子覆盖需补齐、调试门槛高 自研 NPU、异构芯片深度优化
MLIR 多层 dialect 可扩展、渐进下降、统一编译框架 学习曲线陡、生态仍在演进 芯片厂商编译器、统一接入层

五、误区与复盘

常见误区一:认为 ONNX 是“万能格式”。实际上 ONNX 的算子集由 opset 决定,不同推理引擎对同一 opset 的支持程度不同,导出后必须做算子兼容性校验。

常见误区二:忽视 TorchScript 的 trace 与 script 差异。trace 会丢失数据依赖的控制流,script 才能保留 if/for 等动态逻辑,自动驾驶中的后处理逻辑应优先使用 script。

常见误区三:把 Relay 和 MLIR 当作同类工具。Relay 是 TVM 的高层 IR,面向张量计算与调度;MLIR 是编译器基础设施,Relay 本身也可以作为 MLIR 的一个 dialect 存在,二者是不同层面的抽象。

复盘来看,IR 选型应遵循“芯片工具链优先、算子覆盖其次、团队熟悉度再次”的原则。ONNX 适合作为跨团队交换格式,TorchScript 适合 PyTorch 原生链路,GraphDef 适合 TF 存量项目,Relay 适合需要深度调度的自研芯片,MLIR 适合作为长期编译器基础设施。理解每种 IR 的抽象层级和部署链路位置,才能在自动驾驶多芯片、多框架的工程现实中做出稳健决策。