20 框架前端与模型格式洞察
- 章节编号:20
- 所属层:M 模型层 / C 编译器前端(承接 15 章 IR 栈;喂 21 章具身模型)
- 关联 ADR:ADR-071(主前端:torch-mlir + IREE Turbine)、ADR-072(ONNX/StableHLO 边界)、ADR-073(LeRobot manifest 与版本兼容)、ADR-074(自定义 op / 控制流扩展)
- 上游依赖:15(MLIR 前端)、16(lowering)、21(具身模型/LeRobot)、Demo
03-mlir-compiler
学习目标
- 前置知识:读过 15 章(MLIR 前端与 IR 栈)与 16 章(lowering)的开篇,知道「dialect / lowering / codegen」三段式;读过 19 章(压缩量化)了解 INT4/per-channel scale;读过 21 章的具身模型族画像(VLA / 流匹配动作头 / 双系统)。会写基础 PyTorch,能看懂
torch.export大致在做什么即可,无需 MLIR 编译器开发经验。 - 学完产出:① 能画出一张「PyTorch → 捕获(torch.export)→ torch dialect → linalg → vmfb」的前端管线图,并说清每一跳丢了什么、保留了什么;② 能解释为什么「动态 shape / 控制流 loop」在
PyTorch → ONNX → 后端这条链上最容易被抹平,以及 torch-mlir 路线如何把它保住;③ 能把 LeRobot manifest 讲成「部署契约(deployment contract)」——它约束了编译器、runtime、量化三方对同一个模型的理解,而不只是一个配置文件;④ 能对比 MLIR 路线(torch-mlir+IREE) 与 国产非 MLIR 路线(华为 CANN 的 OM / torch_npu) 在「制品可版本化、生态复用、自主可控」三个维度上的取舍;⑤ 亲手把一段带 while-loop 的流匹配伪代码,对照说清「过早 unroll」会让下游 16/17 章丢掉哪些优化机会。 - 阅读姿势:盯住一条主线——「前端的唯一使命,是把上层框架里那些'高层语义'(动态 shape、控制流循环、量化意图、模块边界)完整、无损地搬进编译器 IR,而不是急着把它们碾平成一堆标量算子」。凡是在 import 阶段被抹掉的语义,下游 16/17/18 章就再也拿不回来——这就是「前端决定了编译器天花板」的根因。
1. 范围与目标
本章定义 PyTorch/ONNX/StableHLO 等如何进入 MLIR/IREE 管线,以及 LeRobot manifest、版本 pinning、自定义 op 的兼容策略。不含训练框架(仅推理 import + AOT export)。
核心问题
- 主路径是 torch-mlir 还是 ONNX-mlir 还是 StableHLO?
- π0/OpenVLA/GR00T 的
torch.export/torch.fx如何稳定导入? - flow loop / while / cross-attn 等控制流如何保留到 16/17 章?
- TOP 厂商(PyTorch 原生、TensorRT、QNN、CANN)前端策略于我们有何借鉴?
- LeRobot manifest 作为 SSOT 如何绑定编译产物?
2. 需求洞察(具身驱动)
2.1 具体场景/任务
| 场景 | 前端压力 | 来源 |
|---|---|---|
| π0 / OpenVLA 导入 | torch.export + 动态 shape + while(flow) | 21 章 |
| GR00T 混合 | PyTorch backbone + AOT DiT 分模块 export | 17 章 |
| 客户 ONNX 遗留 | ONNX opset 17+;ControlFlow | POC |
| LeRobot 一键部署 | manifest → compile recipe | 21 ADR-046 |
| QAT/蒸馏后权重 | 量化 scale 随 graph 导入 | 19 章 |
2.2 硬性指标
- P0 模型 import 成功率 100%(π0 子集、OpenVLA INT4、Diffusion Policy)。
- import→vmfb ≤30min/模型(CI);增量 ≤5min(改 manifest 字段)。
- torch 2.x + Python 3.10/3.11 支持;版本 pinning 文档化。
- 未支持 op → 明确 error + 决策树(17 章),非 silent CPU fallback。
2.3 端 / 边 / 中心
| 形态 | 前端 |
|---|---|
| 端侧 | PyTorch/LeRobot 主;ONNX 兼容 |
| 边缘 | 同 + 批量 compile farm |
| 中心 | StableHLO/JAX 可选;非 扩展阶段 |
3. 技术现状与趋势(点名 + 来源)
3.1 MLIR 前端光谱(承接 15 章 3.1)
| 前端 | 入口 | 优点 | 缺点 |
|---|---|---|---|
| torch-mlir | torch.export / Dynamo / fx | PyTorch 原生;→ Linalg/TOSA/StableHLO | 动态 shape 演进中 |
| IREE Turbine | PyTorch AOT | IREE 官方;--iree-input-type=torch | 复杂模型用 advanced API |
| onnx-mlir | ONNX | 客户遗留 | VLA 控制流/自定义 op 弱 |
| StableHLO | JAX/XLA export | 云生态 | 具身 custom op 不成熟(IREE RFC) |
| TOSA | 移动端 | 规范稳定 | 大模型表达力弱 |
IREE RFC 结论:StableHLO 对 custom op/类型/路径 不成熟;torch-mlir 子集集成 IREE 为实际选择。
3.2 框架前端全景:一次「语义搬运」的四跳(新增)
在钻进各家对比之前,先建立一张统一的心智图——把「模型从框架到芯片」看成一条语义逐级下沉、每跳都可能丢信息的流水线,前端的价值恰在于决定哪些高层语义能活到 codegen:
读这张图的一句话:前端不是「格式转换器」,而是「语义守门员」——每一跳都在做减法,前端的工程质量 = 尽量把减法推迟到编译器真正需要具体化的那一刻。凡是「后端制品不可 git diff、控制流被抹平、动态 shape 被冻死」的方案,本质都是在过早的一跳做了不可逆的减法。
3.3 TOP 级推理芯片/框架前端策略横向对比(2025–2026)
| 公司/栈 | 主前端 | 中间格式 | 捕获 API | 具身/VLA | 优势 | 劣势 |
|---|---|---|---|---|---|---|
| NVIDIA | PyTorch → TensorRT / Edge-LLM | ONNX 可选;engine blob | torch→ONNX→TRT;ModelOpt | GR00T ModelOpt→TRT;Cosmos | 极致 ms;fusion+precision 一体 | 闭源;engine 不可 git diff |
| IREE + Turbine(我们) | torch-mlir / Turbine | MLIR Linalg | torch.export | SDXL;VLA 待建 | 开源同源;vmfb+spec 可版本化 | DSA 前端投入大 |
| ExecuTorch 1.0(2025 GA) | PyTorch native | .pte | torch.export→partitioner | VLM/LLM Meta 量产;QNN delegate | 零格式转换;12+ backend | 非 MLIR 全栈;VLA control flow 弱于编译器 |
| Qualcomm QNN | ONNX/TFLite/PyTorch | QNN graph | AI Hub 编译 | QIRP;ExecuTorch QnnPartitioner | Hexagon Perf/W;车规 | 封闭 IR;custom op 慢 |
| 华为 CANN | PyTorch/ONNX adapter | OM(GE) | torch_npu | π0 430ms | 国产生态 | 非 MLIR;与 IREE 分叉 |
| Google XLA/PJRT | JAX/PyTorch(XLA) | StableHLO/HLO | jax.export / torch_xla | 云 TPU 为主 | StableHLO composite SDPA | 端侧 VLA custom op 弱 |
| ONNX Runtime | ONNX | ORT graph | onnx | 泛化 EP | EP 生态广 | VLA while/动态 shape 痛苦 |
| LeRobot | PyTorch checkpoint | Python runtime | 无 AOT | π0/OpenVLA 入口 | manifest 统一 | 无编译 SSOT |
| Physical Intelligence | PyTorch eager | — | — | π0 硬件中立 | 客户面最广 | 需第三方 AOT |
横评一句话:全表可按「后端制品能不能被 git diff / 语义能不能保住」二分为两派——**MLIR 派(torch-mlir+IREE、部分 StableHLO)**制品是文本 IR + 可版本化 spec,黑盒派(TensorRT engine、QNN graph、CANN OM)制品是二进制 blob,性能极致但不可审计。我们选 MLIR 派的核心动机不是「性能一定更高」,而是制品可审计 + 全栈同源(详见 §3.6a 思考题 3)。
3.3a 代表方案深度对比
IREE Turbine + torch-mlir(我们的主线)
| 维度 | 内容 |
|---|---|
| 优势 | 与 15/16/18 同一 MLIR 树;--iree-input-type=torch;tuning spec 可 git;IREE RFC 已验证集成路径 |
| 劣势 | 动态 shape 仍演进;复杂 VLA 需 Turbine advanced API;社区小于 ExecuTorch |
| 适用 | DSA 全栈、需 loop 融合/INT4 codegen 的 π0/GR00T DiT |
ExecuTorch 1.0 + QNN(Qualcomm / Plan B)
| 维度 | 内容 |
|---|---|
| 方案 | torch.export → to_edge_transform_and_lower → .pte;QnnPartitioner 上 Hexagon |
| 优势 | 2025 GA;Meta 数十亿用户 验证;Qualcomm 称 LLM/VLM +30–92% vs CPU;一行换 backend |
| 劣势 | 分区边界 黑盒;大 VLA while-loop 难整体 delegate;非 IREE/MLIR |
| 适用 | 客户已有 PyTorch、Quick POC、QIRP IQ10 绑定场景(09/12 Plan B) |
NVIDIA TensorRT + ModelOpt(GR00T 标杆)
| 维度 | 内容 |
|---|---|
| 方案 | ModelOpt nvfp4/fp8 → TRT engine;PyTorch backbone 可 eager |
| 优势 | GR00T 92ms 公开;Builder 自动 fusion+tactic |
| 劣势 | engine opaque;CUDA 绑定;混合 PyTorch+TRT 双 runtime |
| 我们可借鉴 | 分模块 export + link metadata(17/22);quant 与 compile 一体 |
StableHLO / torch_xla export(观察轨)
| 维度 | 内容 |
|---|---|
| 优势 | stablehlo.composite 保留 SDPA 等高层 op;JAX 云生态 |
| 劣势 | IREE RFC:custom op/路径不成熟;VLA 演进快需 torch.library |
| 判断 | 扩展阶段 不为主路径;watch composite 是否进入 IREE |
华为 CANN:torch_npu + OM(国产非 MLIR 路线)(新增)
| 维度 | 内容 |
|---|---|
| 方案 | PyTorch 侧经 torch_npu 适配层接管算子分发 → GE(Graph Engine) 构图下沉 → OM(Offline Model) 离线模型;推理走 ACL / MindIE |
| 优势 | 国产自主可控全栈;昇腾硬件深度协同(对齐 L1.1 达芬奇 Cube/Vector/Scalar);LeRobot 上已有 π0 端侧真机(310P) 落地 |
| 劣势 | 非 MLIR 树,与 IREE 生态分叉,长尾/自定义 op 需手写 Ascend C;OM 为二进制离线模型,不可 git diff;torch.export 适配演进中 |
| 载体标注 | 昇腾 310P 上 π0(LeRobot,FP16,310P 无 BF16)公开 ~430ms/推理——具体载体/功耗档以官方为准,该数值随芯片型号(310P vs 910)、精度、batch、去噪步数显著变化,不可直接外推到其它昇腾 SKU |
3.3b 前端能力矩阵(具身 VLA 专项)
| 能力 | torch-mlir+IREE | ExecuTorch | TensorRT | ONNX-mlir | LeRobot |
|---|---|---|---|---|---|
torch.export | ✅ | ✅ | △(via ONNX) | △ | ❌ |
| while(flow loop) | ✅(保留 IR) | △ | △ | ❌ | ✅ eager |
| 动态 shape | △ bucket | △ | ❌ 需 profile | △ | ✅ |
| INT4 感知 import | ✅(19) | ✅ quantizer | ✅ ModelOpt | △ | △ bitsandbytes |
| 可 git 制品 | ✅ spec/vmfb | △ .pte | ❌ engine | △ | ❌ ckpt |
| 自定义 op 扩展 | ✅ ADR-028 | △ delegate | △ plugin | ❌ | ✅ Python |
3.4 torch-mlir → IREE 工作流(重点)
- 捕获:
torch.export.export(model, args)→ExportedProgram - Import: Turbine /
fx_importer→torchdialect MLIR - Lower: torch → linalg-on-tensors (+ bufferization)
- Compile: IREE
--iree-input-type=torch→ vmfb
控制流:flow matching while-loop 须保留至 16 章 loop tiling / 1-NFE 分支(17) —— import 阶段 禁止过早 unroll。
动态 shape:OpenVLA/π0 的 batch=1、变长 prompt —— Turbine dynamic dim 与 tuning spec shape 库(18)联动。
3.5 LeRobot manifest 作为 SSOT(衔接 21 ADR-046)
# 概念字段(非最终 schema)
model_id: pi0.7
framework: lerobot
checkpoint: ...
chunk_size: 50
n_action_steps: 10
flow_steps: 10 # → 18 spec 选择
quant_scheme: int4 # → 19 + compile flags
power_profile: sustained # → 11 ADR-070
cameras: [head, wrist] # → 17 multi-camera
编译器输入 = manifest + checkpoint → reproducible recipe(hash 锁定)。
为什么把 manifest 抬到「契约」高度:同一个 π0 checkpoint,编译器要知道 flow_steps(选 loop tiling 还是 1-NFE 快路径)、runtime 要知道 chunk_size / n_action_steps(配双缓冲)、量化要知道 quant_scheme(选 INT4 kernel)、功耗层要知道 power_profile(11 章 DVFS)。这些字段分散在四个团队手里,若各自约定,version bump 时必然漂移。manifest 把它们收敛成一份 versioned、hash-locked 的单一事实源(SSOT)——这正是「部署契约」的含义:详见 §3.6a 深入思考第 2 题。
3.6 自定义 op 与扩展(ADR-074)
| 具身特有 | 处理 |
|---|---|
| cross-attn mask(blockwise) | torch 原语 或 torch.library custom → 15 ADR-028 |
| flow matching step | while-loop IR 原语 |
| action chunk reshape | linalg 可表达 |
| RTC 双缓冲 | Runtime(12),非前端 |
3.6a 深入思考
下面 三题每题先给题干,再用
<details>折叠一份图文并茂的参考答案。建议先合上答案自己想 3 分钟,再展开对照。
思考题 1:PyTorch → ONNX → 后端为何会丢动态 shape
一个 π0 类模型 batch=1、prompt 变长、动作 chunk 长度可配,你先用 torch.onnx.export 导成 ONNX 再喂给某后端,结果发现推理时换个 prompt 长度就要重新编译 engine。结合 §3.2 语义搬运四跳,论证「PyTorch → ONNX → 后端 这条链上,动态 shape 与控制流 loop 为什么最容易在中间那一跳被抹平」,以及 torch-mlir 路线凭什么能保住它。
展开参考答案(含 shape 抹平路径图 + 对比表)
结论:ONNX 是「以静态图为默认、动态维度靠 symbolic dim 打补丁」的中间格式,导出时 tracer 走的是「喂一组样例输入、录下这一次的形状」——除非显式声明 dynamic_axes,变长维度会被这一次的具体值冻死;而 torch.export 捕获的是带 SymInt 的 ExportedProgram,dynamic dim 与 while-loop 作为一等公民保留进 torch dialect,直到 16/17 章才具体化,所以语义不会在中间那一跳丢。
用一个具体例子对照算一遍:设 prompt 长度可取 {16, 32, 64, 128} 四档,动作头 flow-loop 步数 flow_steps 可取 {1, 5, 10}。
- 路径 A(ONNX trace,未声明 dynamic_axes):tracer 只见到导出那一次的输入(如 prompt=64、flow=10),ONNX 图里 sequence 维被写死成 64、loop 被展开成 10 个静态块。上线换 prompt=32 → 形状不匹配 → 要么报错要么触发后端 重新编译;换 flow=5 → 展开块数不对 → 又一次重编。4 × 3 = 12 种组合,最坏要维护 12 份 engine。
- 路径 B(torch.export + torch-mlir):prompt 维标 SymInt、flow-loop 保留为
scf.while语义,一份 torch dialect 覆盖全部动态。到 IREE 编译时,18 章 shape 库把 prompt 归成少数几个 bucket(如 ≤32 / ≤64 / ≤128 三桶),flow_steps 走 manifest 分支 → 3 份 bucket + 参数化 loop,而非 12 份死 engine。
| 对比维度 | 路径 A(ONNX trace) | 路径 B(torch.export→torch-mlir) |
|---|---|---|
| 动态维度默认行为 | 按样例冻死,需手动 dynamic_axes 补 | SymInt 标注,默认保留 |
| 控制流 while | 常被 trace 展开(unroll) | scf.while 保留至 16/17 章 |
| 换 shape 代价 | 重编译新 engine | 命中已编 bucket,零重编 |
| 制品数量(上例) | 最坏 12 份 engine | 3 桶 + 参数化 loop |
| 后续融合空间 | loop 已展平,难再融合 | loop 一等公民,可 tiling/1-NFE |
要点:「动态 shape 丢失」不是 ONNX 本身不能表达(opset 支持 symbolic dim),而是导出这一跳的默认行为是 trace 一次形状——工程上极易在样例输入处把动态性烙死。torch.export 把「动态是一等公民」做成默认,把「何时具体化」推迟到编译器真正需要的一刻——这正是 §3.2 主线「把减法推迟」的直接体现。(回链:见 §3.2 语义搬运四跳、§3.4 torch-mlir 工作流)
思考题 2:manifest 如何做为部署契约
你把 π0.7 的 flow_steps 从 10 改成 1(上了 1-NFE 快路径),结果编译器还在按 10 步 loop tiling、runtime 双缓冲深度没变、功耗层 DVFS 档位也没调——三个团队各跑各的。结合 §3.5,论证「为什么 LeRobot manifest 要被抬到'部署契约'的高度,而不只是一个配置 YAML」,以及缺了它会引发怎样的跨团队漂移。
展开参考答案(含 manifest 契约辐射图 + 对比表)
结论:manifest 是编译器、runtime、量化、功耗四方对同一个模型的唯一共享事实源;它把原本散落在四个团队各自约定里的关键字段(flow_steps / chunk_size / quant_scheme / power_profile)收敛成一份 versioned、hash-locked 的契约,任何一方读到的都是同一份、同一版——缺了它,一次字段变更就会在四个团队间产生不一致,且因为无 hash 锁定而无法复现、无法追责。
用一次变更算一遍漂移代价:把 flow_steps: 10 改成 flow_steps: 1(π0.7 上 1-NFE)。
- 有契约(manifest 为 SSOT):改一处字段 → version bump → recipe hash 变化 → CI 触发四方同步重跑:编译器切 1-NFE 快路径、runtime 收缩双缓冲、量化保持 INT4、功耗按新算力密度调 DVFS。产物
vmfb + tuning spec与 hash 一一对应,可复现、可回滚。 - 无契约(各团队各自约定):算法侧改了训练脚本的 flow_steps,但编译器 CI 里硬编码的还是 10 → 仍按 10 步 tiling;runtime 双缓冲深度是另一个团队半年前拍的常数;功耗档位没人通知。结果:推理时 loop 只跑 1 步但 tiling 按 10 步排布 → 大量空转,双缓冲白占内存,DVFS 不匹配 → 现场 ms 与预期对不上,且因为没有 hash 无法定位是哪次改动引入的。
| 维度 | 有 manifest 契约 | 无契约(各自约定) |
|---|---|---|
| 字段变更传播 | 一处改,四方同步重跑 | 各团队异步、易漏 |
| 复现性 | recipe hash 锁定,可回滚 | 无锚点,难复现 |
| 责任边界 | schema 明确谁读哪个字段 | 口头约定,扯皮 |
| 版本漂移 | semver + CI pin 拦截 | LeRobot 一升级就崩 |
| 长尾扩展 | 保留扩展字段(Gemini/GR00T) | 硬编码,加字段即破坏 |
要点:契约(contract)与配置(config)的区别在于是否被多方共同信任并强制对齐。manifest 之所以是契约,是因为它同时约束了四个下游团队、被 hash 锁定、走 semver + CI pin——它是「模型这一侧对整个软件栈的承诺」。这也是 ADR-073 把 manifest schema 冻结列为不可逆点的原因(§7)。(回链:见 §3.5 manifest SSOT、§5 LeRobot 版本漂移风险、ADR-073)
思考题 3:国产生态(OM/torch_npu)非 MLIR 路线的取舍
华为昇腾走的是 torch_npu → GE → OM 的非 MLIR 路线,我们主线是 torch-mlir → IREE。结合 §3.3a CANN 深度对比 与 §3.2 主线,分析:在「制品可版本化 / 生态复用 / 自主可控」三个维度上,选 MLIR 与选 OM 各自的优势与代价是什么?为什么这决定了「同一个 π0,在昇腾上跑通」与「在我们自研 DSA 上跑通」是两套截然不同的工程投入?
展开参考答案(含两条前端路线取舍图 + 三维对比表)
结论:MLIR 路线(torch-mlir+IREE)拿到的是文本 IR + 可 git 的 tuning spec,制品可审计、可增量 diff、与上游 15/16/18 章同源,代价是 DSA 前端要从头建、社区比 CANN/ExecuTorch 小;OM 路线(torch_npu+GE)拿到的是昇腾深度协同、国产自主可控的成熟全栈与已落地的 π0 端侧,代价是 OM 为二进制离线模型不可 git diff、与 MLIR 生态分叉、长尾算子要手写 Ascend C——两条路的移植成本压在完全不同的层。
三维度对比:
| 维度 | MLIR(torch-mlir+IREE) | OM(torch_npu+GE) |
|---|---|---|
| 制品可版本化 | 高:vmfb + tuning spec 是文本 / 可 hash,能 git diff、能回滚定位 | 低:OM 为二进制离线模型,只能整包替换,难做语义级 diff |
| 生态复用 | 高:与 15/16/18 章同一 MLIR 树,pass / dialect / 社区 codegen 可复用 | 中:昇腾生态内自洽,但与 MLIR 上游分叉,长尾 op 需在 CANN 内单独建设 |
| 自主可控 | 中:开源同源但依赖 LLVM/IREE 上游节奏 | 高:全栈国产、软硬协同(对齐 L1.1 达芬奇架构),不受外部生态卡脖子 |
为什么「同一个 π0 两套投入」:模型最终都要落成针对特定硬件的算子 + 制品。
- 走 OM:π0 经 torch_npu 分发 → GE 构图下沉 OM,昇腾上已有 310P FP16 ~430ms 的公开真机落地(具体载体/TDP 以官方为准,该值随 SKU、精度、batch、去噪步数变化,不可外推)。投入压在「昇腾长尾算子补齐 + CANN 版本适配」,好处是站在成熟全栈的肩膀上。
- 走 自研 DSA + MLIR:要把 π0 的 flow-loop / cross-attn / INT4 codegen 一路从 torch dialect 建到自研 DSA HAL,投入压在「前端到后端的整条 MLIR 管线自建」,好处是制品可审计、全栈同源、每一跳可复现。
要点:这不是「谁更快」的问题,而是「把工程债押在哪一层」的问题。OM 路线把债押在生态分叉与制品黑盒,换来成熟与自主可控;MLIR 路线把债押在前端自建与社区规模,换来可审计与同源复用。我们选后者,恰因 §3.2 主线要求「语义无损、制品可审计」——但对昇腾等已建成栈的国产伙伴,OM 路线是理性且已被 π0 端侧验证的选择。(回链:见 §3.3a CANN 深度对比、§3.2 语义搬运四跳、L1.1 达芬奇 DSA)
3.7 趋势
- torch.export 统一捕获(PyTorch 2.x)——TorchScript 边缘化。
- IREE Turbine 与 ExecuTorch 1.0 GA(2025) 并列成为 PyTorch 端 侧 两大出口——前者编译器栈,后者 runtime 分区。
- manifest 驱动编译——LeRobot →
dsa-compile --manifest。 - StableHLO composite(SDPA)——观察是否减少手写 fusion。
- 双栈过渡:GR00T 式 PyTorch backbone + AOT 动作头 成行业默认,前端须 分模块 export。π0.7 / GR00T N1.7 等新代次已陆续 GA,前端 op 覆盖与 manifest 字段须随之 version bump;路线图项(StableHLO composite 进 IREE、torch_npu 的
torch.export适配深度)均以官方为准。
3b. 由演进反推的诉求
| 演进 | 前端响应 |
|---|---|
| π0.7 Gemma3 | 更新 op 覆盖;manifest version bump |
| 1-NFE | flow_steps: 1 manifest 分支 |
| 双模型 GR00T | 分模块 export + link metadata |
| 客户 ONNX | onnx-mlir 兼容层,非主线 |
4. 候选方案与对比矩阵
| 候选 | 生态 | VLA 控制流 | 成本 | 可驾驭度 | 小结 |
|---|---|---|---|---|---|
| A. torch-mlir + IREE Turbine(主) | 5 | 4 | 4 | 4 | 建议方案 |
| B. ONNX-mlir(主) | 4 | 2 | 3 | 4 | 兼容层 only |
| C. StableHLO(主) | 3 | 2 | 3 | 3 | 暂不选 |
| D. 自研 PyTorch trace | 2 | 3 | 1 | 2 | 禁止 |
倾向:A 主 + B 兼容;ExecuTorch 作客户 Plan B(09/12)。
5. 关键权衡、风险与依赖
- torch-mlir 动态 shape 成熟度 → M2 可能需 shape bucket 编译(18 shape 库)。
- LeRobot 版本漂移 → manifest schema semver + CI pin(Demo
03-mlir-compiler)。 - GR00T 混合:backbone 可暂留 PyTorch;DiT 必须 AOT(17)。
6. 结论与待决项
6.1 初步结论
- 主前端:torch-mlir + IREE Turbine;
--iree-input-type=torch。 - ONNX 作客户遗留 兼容 import;StableHLO 观察,非 扩展阶段 主路径。
- LeRobot manifest = 编译 SSOT;recipe hash 锁定 vmfb + tuning spec。
- 控制流/flow loop 保留至 16/17;import 阶段不盲目 unroll。
- 对标 IREE Turbine + LeRobot;ExecuTorch 作 Qualcomm/快速 POC Plan B(ADR-071 补充)。
6.2 待决项
- Turbine 与 upstream torch-mlir submodule 策略(IREE plugin vs 独立)。
- OpenVLA 7B 全量 import M3 还是 π0 子集优先。
6.3 ADR 候选
- ADR-071 主前端: torch-mlir + IREE Turbine;PyTorch 2.x torch.export;IREE input type torch;禁止自研 trace 前端。
- ADR-072 ONNX/StableHLO 边界:ONNX 兼容 import(onnx-mlir);StableHLO 不为主路径;JAX 客户需求 case-by-case。
- ADR-073 LeRobot manifest:定义 manifest schema(versioned);compile CLI 读 manifest;checkpoint+recipe hash 锁定;CI 版本 pin。
- ADR-074 自定义 op/控制流:具身 while(flow)/cross-attn 保留 IR;扩展走 torch.library + 15 ADR-028;未支持 op fail fast。
7. 端→边→中心演进影响
- 边缘:compile farm 批量跑同一 Turbine 管线;manifest 批量。
- 不可逆点:manifest schema 字段随 SDK 冻结 → semver + 扩展字段。
附:信息来源
区分公开/估计;参考时间 2026-06。
- torch-mlir architecture:github.com/llvm/torch-mlir docs/architecture.md。[公开]
- IREE Turbine:github.com/iree-org/iree-turbine;iree.dev。[公开]
- IREE RFC torch-mlir integration:iree-discuss 2024。[公开]
- PyTorch StableHLO export:PyTorch/XLA docs 2025。[公开]
- LeRobot:github.com/huggingface/lerobot;21 章。[公开]
- ExecuTorch 1.0 GA:pytorch.org blog 2025;github.com/pytorch/executorch。[公开]
- Qualcomm ExecuTorch QNN delegate:docs.pytorch.org/executorch/1.0/android-qualcomm.html。[公开]
- 华为 CANN / torch_npu / GE-OM:gitee.com/ascend/pytorch;昇腾社区 CANN 文档;昇腾 310P π0 LeRobot 部署(~430ms FP16,载体/TDP 以官方为准):devpress.gitcode.com;21 章。[公开]