端侧模型部署一般流程

端侧模型部署一般流程

model_optimizer 结合开源模型端侧框架,分析端侧模型部署的一般流程,技术细节,关键流程

本文总结 LLM / VLM / VLA 在嵌入式设备(Jetson Orin、Drive Thor、边缘 GPU、BPU 等)上的 通用部署流水线 ,不绑定具体工具链。文中 §3.1 量化 · §3.2 导出/重写 · §3.3 编译 · §3.5 精度验证 可独立阅读;三项目(TensorRT-Edge-LLM、model_optimizer、Chamleon)对照见各节附录表。


1. 与数据中心 serving 的根本差异

维度 端侧 onboard 数据中心 serving
Batch ≈1,形状可静态化 连续 batching、动态并发
内存 8--32GB 统一内存,须 可预算 大显存 + paged KV 池化
延迟 单次推理 尾延迟 优先 吞吐、多租户优先
编译 AOT(TRT engine / 厂商 blob) 常保留 PyTorch / 动态图
Runtime C++ 为主,Python 仅开发态 Python API + 调度器
KV Linear / 固定槽位 或 stage 间 handoff Paged attention、跨请求复用

不宜照搬 onboard 的路径:vLLM/sglang 式 continuous batching、TensorRT-LLM paged KV + in-flight batching、动态 seq len 多用户调度。


2. 通用流水线总览

#mermaid-svg-3eaf55ljlfD7J5I6{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-3eaf55ljlfD7J5I6 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-3eaf55ljlfD7J5I6 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-3eaf55ljlfD7J5I6 .error-icon{fill:#552222;}#mermaid-svg-3eaf55ljlfD7J5I6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-3eaf55ljlfD7J5I6 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-3eaf55ljlfD7J5I6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-3eaf55ljlfD7J5I6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-3eaf55ljlfD7J5I6 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-3eaf55ljlfD7J5I6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-3eaf55ljlfD7J5I6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-3eaf55ljlfD7J5I6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-3eaf55ljlfD7J5I6 .marker.cross{stroke:#333333;}#mermaid-svg-3eaf55ljlfD7J5I6 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-3eaf55ljlfD7J5I6 p{margin:0;}#mermaid-svg-3eaf55ljlfD7J5I6 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-3eaf55ljlfD7J5I6 .cluster-label text{fill:#333;}#mermaid-svg-3eaf55ljlfD7J5I6 .cluster-label span{color:#333;}#mermaid-svg-3eaf55ljlfD7J5I6 .cluster-label span p{background-color:transparent;}#mermaid-svg-3eaf55ljlfD7J5I6 .label text,#mermaid-svg-3eaf55ljlfD7J5I6 span{fill:#333;color:#333;}#mermaid-svg-3eaf55ljlfD7J5I6 .node rect,#mermaid-svg-3eaf55ljlfD7J5I6 .node circle,#mermaid-svg-3eaf55ljlfD7J5I6 .node ellipse,#mermaid-svg-3eaf55ljlfD7J5I6 .node polygon,#mermaid-svg-3eaf55ljlfD7J5I6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-3eaf55ljlfD7J5I6 .rough-node .label text,#mermaid-svg-3eaf55ljlfD7J5I6 .node .label text,#mermaid-svg-3eaf55ljlfD7J5I6 .image-shape .label,#mermaid-svg-3eaf55ljlfD7J5I6 .icon-shape .label{text-anchor:middle;}#mermaid-svg-3eaf55ljlfD7J5I6 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-3eaf55ljlfD7J5I6 .rough-node .label,#mermaid-svg-3eaf55ljlfD7J5I6 .node .label,#mermaid-svg-3eaf55ljlfD7J5I6 .image-shape .label,#mermaid-svg-3eaf55ljlfD7J5I6 .icon-shape .label{text-align:center;}#mermaid-svg-3eaf55ljlfD7J5I6 .node.clickable{cursor:pointer;}#mermaid-svg-3eaf55ljlfD7J5I6 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-3eaf55ljlfD7J5I6 .arrowheadPath{fill:#333333;}#mermaid-svg-3eaf55ljlfD7J5I6 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-3eaf55ljlfD7J5I6 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-3eaf55ljlfD7J5I6 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3eaf55ljlfD7J5I6 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-3eaf55ljlfD7J5I6 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3eaf55ljlfD7J5I6 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-3eaf55ljlfD7J5I6 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-3eaf55ljlfD7J5I6 .cluster text{fill:#333;}#mermaid-svg-3eaf55ljlfD7J5I6 .cluster span{color:#333;}#mermaid-svg-3eaf55ljlfD7J5I6 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-3eaf55ljlfD7J5I6 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-3eaf55ljlfD7J5I6 rect.text{fill:none;stroke-width:0;}#mermaid-svg-3eaf55ljlfD7J5I6 .icon-shape,#mermaid-svg-3eaf55ljlfD7J5I6 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3eaf55ljlfD7J5I6 .icon-shape p,#mermaid-svg-3eaf55ljlfD7J5I6 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-3eaf55ljlfD7J5I6 .icon-shape .label rect,#mermaid-svg-3eaf55ljlfD7J5I6 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3eaf55ljlfD7J5I6 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-3eaf55ljlfD7J5I6 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-3eaf55ljlfD7J5I6 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 4. 部署
3. 验证
2. 编译前端

  1. 优化
  2. 准备
    训练 checkpoint
    tokenizer / 前后处理资产
    校准数据 可选
    量化 PTQ 可选
    权重 layout repack 可选
    Stage 拆分 + 图导出
    Sidecar metadata
    平台编译 build
    Profiling / 算力估算
    精度对拍
    Runtime 编排
    应用集成

硬分离原则(业界常见做法):

  • Host / 开发机:量化、图导出、部分编译(视平台而定)
  • 目标板:最终 engine build(SM / BPU 精确匹配)、集成测试、OTA 发布
  • Sidecar 与 engine 分离 :tokenizer、embedding、quant config 等 不进不全进 编译产物,便于热更新

3. 各阶段说明

3.0 准备

输入 说明
Checkpoint FP16/BF16 或预量化权重(safetensors 等)
模型配置 层数、head、RoPE、多模态子模块
前后处理资产 tokenizer、chat template、norm stats(VLA)、图像 resize 规则
校准集 量化用代表性样本(文本 / 图文 / 机器人 observation)

产出:可加载的 训练语义一致 的推理输入规范(I/O 契约)。


3.1 量化(可选)

目的 :在精度可接受前提下,压缩 权重 / 激活 / KV,使模型放进显存并降低带宽。

对象 典型手段 主要收益
权重 INT4 AWQ、NVFP4、FP8 显存、权重带宽
激活 NVFP4、FP8 W8A8 算力与激活带宽
KV Cache FP8 KV 长上下文显存与 attention 带宽
大表 FP8 embedding、缩词表 词表显存

端侧量化的核心设计原则:量化数学(PTQ 校准)与 IR 导出 / kernel layout 解耦 ------先得到带 scale 的量化 checkpoint 或 fake-quant 模型,再在 export 阶段按 metadata 选择 Linear 实现类 、emit 对应 ONNX 子图,必要时 repack 权重字节序。详见下文 §3.1.3--§3.1.5。
#mermaid-svg-vo1b63I9UxnLlOFz{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-vo1b63I9UxnLlOFz .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-vo1b63I9UxnLlOFz .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-vo1b63I9UxnLlOFz .error-icon{fill:#552222;}#mermaid-svg-vo1b63I9UxnLlOFz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-vo1b63I9UxnLlOFz .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-vo1b63I9UxnLlOFz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-vo1b63I9UxnLlOFz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-vo1b63I9UxnLlOFz .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-vo1b63I9UxnLlOFz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-vo1b63I9UxnLlOFz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-vo1b63I9UxnLlOFz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-vo1b63I9UxnLlOFz .marker.cross{stroke:#333333;}#mermaid-svg-vo1b63I9UxnLlOFz svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-vo1b63I9UxnLlOFz p{margin:0;}#mermaid-svg-vo1b63I9UxnLlOFz .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-vo1b63I9UxnLlOFz .cluster-label text{fill:#333;}#mermaid-svg-vo1b63I9UxnLlOFz .cluster-label span{color:#333;}#mermaid-svg-vo1b63I9UxnLlOFz .cluster-label span p{background-color:transparent;}#mermaid-svg-vo1b63I9UxnLlOFz .label text,#mermaid-svg-vo1b63I9UxnLlOFz span{fill:#333;color:#333;}#mermaid-svg-vo1b63I9UxnLlOFz .node rect,#mermaid-svg-vo1b63I9UxnLlOFz .node circle,#mermaid-svg-vo1b63I9UxnLlOFz .node ellipse,#mermaid-svg-vo1b63I9UxnLlOFz .node polygon,#mermaid-svg-vo1b63I9UxnLlOFz .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-vo1b63I9UxnLlOFz .rough-node .label text,#mermaid-svg-vo1b63I9UxnLlOFz .node .label text,#mermaid-svg-vo1b63I9UxnLlOFz .image-shape .label,#mermaid-svg-vo1b63I9UxnLlOFz .icon-shape .label{text-anchor:middle;}#mermaid-svg-vo1b63I9UxnLlOFz .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-vo1b63I9UxnLlOFz .rough-node .label,#mermaid-svg-vo1b63I9UxnLlOFz .node .label,#mermaid-svg-vo1b63I9UxnLlOFz .image-shape .label,#mermaid-svg-vo1b63I9UxnLlOFz .icon-shape .label{text-align:center;}#mermaid-svg-vo1b63I9UxnLlOFz .node.clickable{cursor:pointer;}#mermaid-svg-vo1b63I9UxnLlOFz .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-vo1b63I9UxnLlOFz .arrowheadPath{fill:#333333;}#mermaid-svg-vo1b63I9UxnLlOFz .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-vo1b63I9UxnLlOFz .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-vo1b63I9UxnLlOFz .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vo1b63I9UxnLlOFz .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-vo1b63I9UxnLlOFz .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vo1b63I9UxnLlOFz .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-vo1b63I9UxnLlOFz .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-vo1b63I9UxnLlOFz .cluster text{fill:#333;}#mermaid-svg-vo1b63I9UxnLlOFz .cluster span{color:#333;}#mermaid-svg-vo1b63I9UxnLlOFz div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-vo1b63I9UxnLlOFz .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-vo1b63I9UxnLlOFz rect.text{fill:none;stroke-width:0;}#mermaid-svg-vo1b63I9UxnLlOFz .icon-shape,#mermaid-svg-vo1b63I9UxnLlOFz .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vo1b63I9UxnLlOFz .icon-shape p,#mermaid-svg-vo1b63I9UxnLlOFz .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-vo1b63I9UxnLlOFz .icon-shape .label rect,#mermaid-svg-vo1b63I9UxnLlOFz .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vo1b63I9UxnLlOFz .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-vo1b63I9UxnLlOFz .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-vo1b63I9UxnLlOFz :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} FP16/BF16 checkpoint
Recipe / quant_cfg
校准 forward 收集 amax
mtq.quantize PTQ
量化 checkpoint 或 fake-quant 模型
Stage export
权重 repack 可选
ONNX Q-DQ / custom op
Compile

3.1.1 通用 PTQ 流水线

无论具体工具链,端侧 训练后量化(PTQ) 通常遵循固定步骤:

步骤 动作 产出
1. 选 recipe 指定算法(max / AWQ / SmoothQuant 等)与目标格式(FP8、INT4、NVFP4...) quant_cfg 或 CLI 参数
2. 准备校准集 代表性样本(文本 / 图文 / 机器人 observation);VLM 须含图像 才能标定 visual 激活 DataLoader
3. 结构替换 nn.Linear 等替换为带 TensorQuantizer 的量化模块,按 recipe 配置 bit/axis/block fake-quant 图
4. 校准 forward forward_loop,收集各层 amax 或 AWQ/SQ 专用统计量 scale / zero-point
5. 固化量化参数 执行 algorithmmaxawq_litesmoothquant...) 量化权重 + metadata
6. 导出 checkpoint(可选) export_hf_checkpoint → safetensors + hf_quant_config.json 可 OTA 的量化权重
7. 下游 export trace ONNX;NVFP4 另做 ONNX 图后处理 (见 §3.1.8);Edge-LLM 在 export 做 PyTorch repack stage.onnx

注意 :步骤 1--6 在 Host / GPU 开发机 完成,不依赖 TRT plugin;步骤 7 才与 §3.2 模型重写、custom op 交汇。

3.1.2 ModelOpt 两阶段机制(业界主流实现)

Workspace 内 TensorRT-Edge-LLMmodel_optimizer 均基于 NVIDIA Model Optimizer(ModelOpt)mtq.quantize(model, config, forward_loop) 在语义上固定为两阶段:

text 复制代码
阶段 A --- apply_mode("quantize"):
  nn.Linear → QuantLinear + TensorQuantizer(weight / input / output)
  set_quantizer_by_cfg(quant_cfg)   # 通配符匹配各量化器属性

阶段 B --- calibrate(algorithm):
  forward_loop 跑校准集 → 收集 amax → 固化 scale → 开启 fake quant 仿真

quant_cfg 是支持 多种方案并存 的核心数据结构(见 §3.1.3)。algorithm 常见取值:

algorithm 典型格式 校准特点
max FP8、NVFP4、FP8 KV per-tensor / per-block amax
awq_lite INT4 AWQ W4A16 搜索 pre_quant_scale,保精度
smoothquant INT8 W8A8 平滑激活离群值后量化

校准 forward 的 根模块 有约束:含 *_bmm_quantizer(FP8 KV)时,mtq.quantize 的根须为 HuggingFace PreTrainedModel ,否则 attention BMM 量化器不会注册------pi0.5 的 Pi05DenoiseStep 等 wrapper 须把 gemma_expert 作为 quantize root,校准经 forward_context 走完整 denoise forward(见 §3.1.5)。

3.1.3 如何在模型中支持不同量化方案(三层架构)

多种量化方案并非靠 if/else 散落在业务代码,而是通过 recipe → 模块分发 → IR 发射 三层解耦:

text 复制代码
┌─────────────────────────────────────────────────────────────┐
│  Layer 1 --- Recipe(quant_cfg)                               │
│  通配符 / 模块路径 → QuantizerAttributeConfig                  │
│  例:*weight_quantizer、*layers.11.*.input_quantizer           │
└──────────────────────────┬──────────────────────────────────┘
                           ▼
┌─────────────────────────────────────────────────────────────┐
│  Layer 2 --- 模块分发(export 时选 Linear 类)                  │
│  Edge-LLM: make_linear(module_name, config) → FP8/NVFP4/AWQ... │
│  ModelOpt: QuantLinear.forward → TensorQuantizer fake quant   │
└──────────────────────────┬──────────────────────────────────┘
                           ▼
┌─────────────────────────────────────────────────────────────┐
│  Layer 3 --- IR / Kernel(ONNX 子图 + plugin)                  │
│  FP8: QuantizeLinear + DQ + MatMul                          │
│  NVFP4: nvfp4_act_qdq + nvfp4_dequantize + MatMul            │
│  INT4: int4_groupwise_gemm custom op                         │
│  FP8 KV: attention_plugin(enable_fp8_kv_cache=True)          │
└─────────────────────────────────────────────────────────────┘
(1)Recipe 层:quant_cfg 通配符与子模块覆盖

quant_cfg模块名模式 → 量化器属性 的字典。键支持通配(*)、层级路径(*layers.{i}.mlp.gate_proj.weight_quantizer)、以及 按类名 匹配。"default" 为未命中时的默认。

支持多方案的方式

手段 示例 效果
全局 recipe NVFP4_DEFAULT_CFGFP8_DEFAULT_CFG 主体统一 W4A4 / W8A8
子模块禁用 "lm_head": {"enable": False} LM head 保持 FP16
逐层覆盖 *layers.11-17.* → FP8 quantizer NVFP4 body + 高层 FP8 混合
按算子跳过 denoise:action_in_proj.*_quantizer → disable 时间/动作投影保持 FP32
KV 独立 merge update_quant_cfg_with_kv_cache_quant + FP8_KV_CFG 权重量化与 KV 量化正交组合
AdaRMS / norm input_layernorm / post_attention_layernorm → disable 纯 RMSNorm 无量化器;AdaRMS 的 dense 走 Linear 规则

model_optimizer 在 config/quant/*.py 维护各 stage 的 recipe 文件(如 llm_quant_nvfp4_cfg.pydenoise_quant_fp8_cfg.py);CLI model-opt quantize --quantize_cfg <file> 加载后传给各 stage 的 Model.quantize()

(2)模块分发层:按 metadata 实例化不同 Linear

TensorRT-Edge-LLM自研 Module 树 构建时用 make_linear(config, in, out, module_name) 分发:

text 复制代码
module_quant_type(module_name, config)
  ├─ quant.excluded          → FP16Linear
  ├─ layer_overrides[name]   → 覆盖 dominant quant_type(混合精度)
  └─ quant.quant_type        → FP8 / NVFP4 / AWQ / GPTQ / MXFP8 / INT8SQ ...

每种 *Linearforward() 故意 emit 与 TRT 融合路径匹配的子图(调用 ops.py 中的 custom op 桩)。checkpoint 的 hf_quant_config.json 驱动 ModelConfig.quant,export 时 无需再跑 PTQ

model_optimizer(pi0.5) 在 export 前仍用 HF + ModelOpt QuantLinear :量化后 set_dynamic_quant(model, "bf16"|"fp16") 为 NVFP4 激活 quantizer 设置 _trt_high_precision_dtype_onnx_quantizer_type(动态激活 / 静态权重),使 ONNX QDQ 与 TRT 解析一致。embed_prefix 导出前另有 _patch_modelopt_quantizers_trt_hp_for_onnx,避免 FP8 符号与 TRT 高精度 dtype 冲突。

(3)IR / Export 层:量化方案如何进入 ONNX
方案 PyTorch 侧 ONNX / TRT 侧 额外后处理
FP8 W8A8 TensorQuantizer fake quant 标准 QuantizeLinear + DQ + MatMul set_dynamic_quant
NVFP4 W4A4 block FP4 + FP8 scale(ModelOpt QuantLinear 或 Edge NVFP4Linear nvfp4_act_qdq / nvfp4_dequantize custom op,或两级 DequantizeLinear MO 路径 :export 后 fp4qdq_to_2dqONNX 图改写 ,见 §3.1.8);Edge 路径 :load 后 apply_all_repackingPyTorch 权重 layout,见 §3.1.8)
INT4 AWQ W4A16 AWQ pre_quant_scale int4_groupwise_gemm custom op repacking.py nibble layout
FP8 KV *_bmm_quantizer on HF attention attention_plugin(enable_fp8_kv_cache=True) quantize root 须为 PreTrainedModel
FP8 Embedding 不在 PTQ 内 runtime lookup lang_embedding.safetensors sidecar

预量化社区权重 (AWQ/GPTQ/ModelOpt 已量化 checkpoint):跳过步骤 3--5,export 时直接 GPTQLinear / AWQLinear 加载 + repack。

3.1.4 混合精度与组件级组合

端侧常见 同一模型内多种精度并存,通过 recipe 与 metadata 组合实现,而非单一全局 bit-width:

组件 可独立配置 典型组合
Backbone fp8 / int4_awq / nvfp4 / mxfp8 / int8_sq Thor:nvfp4 主体
LM head 可与 backbone 不同 nvfp4 body + fp8 head(精度敏感)
KV cache fp8(与权重正交) nvfp4 + fp8 KV(长 context)
Visual / Audio tower fp8 VLM:语言 NVFP4 + 视觉 FP8
Embedding export 阶段 sidecar FP8 词表,不进 engine
Expert / denoise 投影 per-module disable expert FP8 + action_* FP32

平台约束 :Jetson Orin 以 FP16 / INT8 / INT4 为主;FP8 / NVFP4 / MXFP8 需 Blackwell 级(Thor) Tensor Core 路径。

LM head 配置陷阱 :在 layer_overrides 里对 lm_head 写 "default": {"enable": False}覆盖 body 已 enable 的 quantizer(历史 bug);应只对 lm_head 路径显式设精度。

3.1.5 量化与 Export 的衔接(pi0.5 要点)

各 stage 的 Model.quantize(quant_cfg, calib_data, export_dir) 遵循统一模式:

text 复制代码
calib_dataloader = get_calibrate_dataset(calib_data)
quantize_model(root_module, quant_cfg, calib_dataloader, forward_context=...)
set_dynamic_quant(self, dynamic_quant_dtype)
export(export_dir)                    # trace ONNX
[NVFP4, MO] fp4qdq_to_2dq(onnx)       # ONNX 图后处理,非 PyTorch repack(§3.1.8)
[denoise] apply_denoise_onnx_post_export_patches
Stage quantize root 校准 forward 特殊处理
llm GemmaModel(HF) model(**batch) AWQ 标定暂转 fp32;FP8 KV 需 HF root
expert gemma_expert expert forward 同 llm
denoise gemma_expert 或整 Pi05DenoiseStep forward_context 完整 denoise FP8 KV → expert root;AdaRMS 预计算:校准关、导出开
vit / embed_prefix SigLIP 子模块 图文样本 vision quant conv 禁 input quant

FlashRT 路径native_flashrt_decoder):不走 TRT denoise ONNX 量化链,而用 离线 NativeDecoderStatsCollector 收集激活 scale → NativeDecoderQuantSpec JSON,供手写 FVK 静态 FP8 布局(属 runtime/compile 侧,见 §3.2.5 附录)。

3.1.6 附录:三项目量化实现对照
维度 TensorRT-Edge-LLM model_optimizer(pi0.5) Chamleon
PTQ 入口 tensorrt-edgellm-quantize model-opt quantize --quantize_cfg chameleon quantizeQuantMethod 插件:int8/fp8/nvfp4/int4_awq 等 6 种)
底层引擎 ModelOpt mtq.quantize 同左(quantization_utils.quantize_model quantization/methods/modelopt_ptq.py 封装
Recipe 定义 quantization_configs.py + CLI config/quant/*.py per stage YAML quantize step + method 名
模块分发 自研 make_linear → 8 种 Linear HF QuantLinear + set_dynamic_quant 委托 adapter + ModelOpt PTQ
混合精度 QuantConfig.layer_overrides + module_quant_type quant_cfg 逐层通配覆盖 随 method / YAML
KV 量化 kv_cache_quant=fp8 + attention plugin flag FP8_KV_CFG merge 进 quant_cfg 随 method 配置
Embedding FP8 export --fp8-embedding fp8_lang_embedding sidecar 未默认接入
Export 后处理 export 前 PyTorch repacking.py;图内 custom op / 标准 DQ export 后 fp4qdq_to_2dq + denoise dtype patch 随 pi05 deploy 路径
预量化权重 AWQ/GPTQ/ModelOpt 直接 load 同左 ---
特殊模型 EAGLE/MTP draft、Phi4MM、Qwen3-ASR joint pi0.5 分 stage;AdaRMS 校准/导出分叉 薄编排,无量化自研

与 §3.2 模型重写的关系 :量化决定 checkpoint 里权重的数值表示与 scale ;模型重写决定 ONNX 里出现哪些算子节点 。二者在 export 交汇:make_linear / QuantLinearforward() 必须把量化数学 翻译成 TRT 可融合的 Q-DQ 子图或 custom op------因此 §3.2.2(4)量化感知 Linear 与 §3.1.3(2)模块分发是同一链路的两侧。

3.1.7 案例深入:pi0.5 denoise 的 FP8 recipe 如何定制

model_optimizer/config/quant/denoise_quant_fp8_cfg.py 为例,说明 Layer 1(recipe) 如何在单 stage 内混用多种精度策略:

python 复制代码
# 全局:FP8 W8A8(ModelOpt FP8_DEFAULT_CFG)
QUANT_CFG = FP8_DEFAULT_CFG

# 整类 norm 不参与量化(无 QuantLinear 子模块的纯 RMSNorm)
QUANT_CFG["quant_cfg"]["input_layernorm"] = {"enable": False}
QUANT_CFG["quant_cfg"]["post_attention_layernorm"] = {"enable": False}
QUANT_CFG["quant_cfg"]["norm"] = {"enable": False}

# 时间/动作投影保持全精度(与 flow 控制强相关、shape 小)
for name in ("action_in_proj", "action_out_proj", "time_mlp_in", "time_mlp_out"):
    QUANT_CFG["quant_cfg"][f"{name}.weight_quantizer"] = {"enable": False}
    QUANT_CFG["quant_cfg"][f"{name}.input_quantizer"] = {"enable": False}
    # ...

设计意图

模块 策略 原因
gemma_expert 内 Linear FP8 主体算力与带宽
input_layernorm disable 语言塔纯 RMSNorm 无可量化 Linear;AdaRMS 的 dense 若启用则单独走 Linear 规则
action_* / time_mlp_* disable 小矩阵、控制流敏感;denoise 后处理还须 MatMul/bias dtype 对齐(§3.2.5 denoise patch)
可选 FP8_KV_CFG merge *_bmm_quantizer KV 量化与权重 FP8 正交 ;quantize root 须为 gemma_expert(HF)

执行链Pi05DenoiseStep.quantize()quantize_model(gemma_expert, quant_cfg, calib, forward_context=self)set_dynamic_quantexportapply_denoise_onnx_post_export_patches。若同时开 AdaRMS 预计算 (§3.2.6),校准期 enable_adarms_precompute(False),导出期再打开------校准 batch 只有 timestep,没有 adarms_mod

Chamleon 侧 :YAML quantize step 选 method: fp8 等名称,由 ModelOptQuantMethod 映射到同名 FP8_DEFAULT_CFG;无 ModelOpt 时降级为 metadata-only(CPU 开发机可跑通流水线,权重仍 FP16)。

3.1.8 NVFP4:repackfp4qdq_to_2dq 各在哪一步?

一句话总结

  • NVFP4 的「量化数学」(FP4 数值 + block/global scale)在 PTQ(mtq.quantize)阶段完成。
  • PyTorch 权重 repack (layout / view / MoE pack)在 export 之前,主要是 Edge-LLM 路径。
  • fp4qdq_to_2dq 在 export 之后 :把 ONNX 里的 TRT_FP4QDQ 占位节点 展开成 两级 DequantizeLinear ,并把权重 真正写入FLOAT4E2M1 initializer (packed 字节)+ FLOAT8E4M3FN block scale ------不是 PyTorch repack,也 不是 简单的「INT8 改个 type 标签」。
权重 repack(PyTorch) fp4qdq_to_2dq(ONNX 后处理)
发生时机 checkpoint load 之后、trace export 之前 torch.onnx.export 完成之后、build 之前
操作对象 nn.Module 上的 weight buffer ONNX ModelProto(节点 + initializer)
改什么 字节 layout / dtype view(数值等价) 图结构 + 新建 FP4/FP8 initializer,删除旧权重
典型代码 Edge-LLM checkpoint/repacking.py::apply_all_repacking modelopt.onnx.quantization.qdq_utils.fp4qdq_to_2dq
pi0.5 MO 路径 一般不做 独立 repack 模块 NVFP4 必做 (各 stage _nvfp4_post_processing
text 复制代码
                    PTQ (ModelOpt mtq.quantize)
                              │
                              ▼
              量化 checkpoint:FP4 数值 + block/global scale
                              │
         ┌────────────────────┴────────────────────┐
         │                                         │
   Edge-LLM 路径                           model_optimizer 路径
         │                                         │
         ▼                                         ▼
  load_weights                           QuantLinear 保留 ModelOpt buffer
         │                                         │
         ▼                                         ▼
  apply_all_repacking  ◄── PyTorch repack         set_dynamic_quant
  · 稠密 NVFP4: uint8→int8 view                    │
  · MoE NVFP4: 专家 stack + interleave              ▼
    + N-major pack(Thor/GeForce)            torch.onnx.export
         │                              → TRT_FP4QDQ 融合节点
         ▼                                         │
  trace export (custom op / DQ)                    ▼
         │                              fp4qdq_to_2dq(onnx)  ◄── ONNX 图改写 + 权重落盘
         │                              · 删 TRT_FP4QDQ,拆两级 DequantizeLinear
         │                              · 新建 weight_f4 (FLOAT4E2M1) + f8_scale + f32_scale
         │                              · 删旧 FP16/BF16 权重 initializer;写 external data
         ▼                                         ▼
              llm_build / build_engine
PyTorch repack 做什么(Edge-LLM 为主)

loader.load_weights() 末尾调用 apply_all_repacking(model)

量化类型 repack 内容 不做会怎样
INT4 AWQ/GPTQ nibble swizzle、zero-point fold、Marlin/MoE stack plugin 读错通道 → 结果全错
NVFP4 稠密 Linear _cast_nvfp4_weightsuint8int8 view(比特不变,满足 ONNX importer) 部分路径 UINT8 initializer 解析失败
NVFP4 MoE decode → interleave(up,gate) → _nvfp4_pack_n_major fused MoE plugin 无法消费 HF 布局

注意 :稠密 NVFP4 的 repack 很轻(多为 view cast);重 repack 在 MoE / INT4 。这与 INT4「必须 swizzle 才能算对」不同量级,但仍在 export 前 的 PyTorch 侧完成。

fp4qdq_to_2dq 做什么(model_optimizer pi0.5 为主)

export 阶段留下了什么?

ModelOpt 对 静态权重weight_quantizer._onnx_quantizer_type = "static")export 时,并不直接在 ONNX 里写 FP4 字节,而是插入 占位 自定义节点:

text 复制代码
trt::TRT_FP4QDQ(weight_fp16/bf16, block_size=...)

此时 ONNX 里的 权重 initializer 仍是 FP16/BF16 (高精度浮点),TRT_FP4QDQ 在 trace 时只是「标记这里要做 NVFP4 静态双量化」。真正的 FP4 打包发生在 export 之后的 fp4qdq_to_2dq

fp4qdq_to_2dq 逐步做了什么?modelopt/onnx/quantization/qdq_utils.py

对每个 TRT_FP4QDQ 节点:

步骤 动作
1 从 initializer 读回权重 → read_f16_tensor_as_fp32(按 FP16/BF16 解释,再算 FP32)
2 计算 per-tensor global scale(get_weights_scaling_factor_2)与 per-block scale(get_weights_scaling_factor
3 按 block 做 NVFP4 量化 → _cast_fp4:两枚 FP4 nibble pack 进 1 byte (内部用 uint8 numpy 存 raw bytes)
4 block scale 写成 FP8 E4M3_cast_fp8 → initializer data_type = FLOAT8E4M3FN
5 新建 initializer:weight_f4ONNX 类型设为 FLOAT4E2M1make_tensor(..., data_type=Float4, vals=w_f4.tobytes(), raw=True)
6 删除TRT_FP4QDQ 节点与旧 FP16/BF16 权重 initializer
7 插入 两级 标准 DequantizeLinear(先 DQ block scale,再 DQ weight,带 axis=-1, block_size=...
8 对后续 MatMul/Gemm 的 activation 侧插入 Cast 到 FP16/BF16,保证与 DQ 输出 dtype 一致

图结构变化:

text 复制代码
# export 后(简化)
weight [FP16/BF16] ──► TRT_FP4QDQ ──► w_dq ──► MatMul

# fp4qdq_to_2dq 后
weight_f4 [FLOAT4E2M1, packed bytes]
weight_f8_scale [FLOAT8E4M3FN]     weight_f32_scale [FP32]
        │                │
        └─► DQ(scale) ──► sw_f32
                              │
weight_f4 ──► DQ(w_f4, sw_f32, block_size) ──► w_dq ──► MatMul
「INT8 → FLOAT4E2M1」到底指什么?

容易混淆的三件事:

说法 实际含义 发生在哪
INT8 → FLOAT4E2M1(类型标签) 部分文档/路径把 packed 字节 先用 INT8/UINT8 initializer 承载,TRT 解析前改为 ONNX 枚举 FLOAT4E2M1 Edge dynamo 注释中的 post-export 改写;或 packed raw bytes 的 ONNX 类型声明
_cast_fp4 输出 uint8 两 nibble 一字节的 物理存储 用 numpy uint8 数组;写入 ONNX 时 data_type 仍标为 FLOAT4E2M1,不是把 INT8 量化值语义改成 FP4 fp4qdq_to_2dq 内部
从 FP16/BF16 权重生成 FP4 读回高精度权重 → 按 block 重新量化 → pack → 写入新 initializer fp4qdq_to_2dq 主路径(pi0.5 MO)

因此:pi0.5 路径上,NVFP4 权重「变成 FP4 并落进 ONNX」主要是在 fp4qdq_to_2dq 里完成的 ------但输入是 export 留下的 FP16/BF16 initializer ,不是 PTQ 后再走一遍 INT8 整型权重。FLOAT4E2M1 是 ONNX 对 packed FP4 字节 的类型名;与 PyTorch repack 里的 uint8→int8 view(Edge export 前,比特不变)也不是同一步。

激活(activation)侧export_fp4onnx_quantizer_type == "dynamic" 时会直接 emit FP4 dynamic quant + DQ 子图, 经过 TRT_FP4QDQfp4qdq_to_2dq 主要处理 静态权重 节点。

pi0.5 调用链llm.py::_nvfp4_post_processing 等):

text 复制代码
onnx.load → fp4qdq_to_2dq(onnx_model)
         → 删掉 export_dir 里除 .json 外的旧文件
         → onnx.save_model(..., save_as_external_data=True, location="onnx_model.data")

Edge-LLM 若在 dynamo export 时已直接 emit 等价的两级 DequantizeLinear(不经过 TRT_FP4QDQ),则 不必 再跑 fp4qdq_to_2dq;pi0.5 走 HF QuantLinear + static weight export 时 必须 跑。

与 denoise dtype patch 的顺序(MO)
text 复制代码
export → [NVFP4] fp4qdq_to_2dq → apply_denoise_onnx_post_export_patches → build

dtype patch 解决 MatMul/bias 浮点 dtype 不一致 ;与 repack / fp4qdq_to_2dq 正交。

FlashRT 的「repack」是第三条线

repack_decoder_weights(FlashRT native decoder)在 runtime 初始化 把 HF expert 权重排成手写 FVK 布局,不属于 NVFP4 PTQ → ONNX 链路;与本文 §3.1.8 前两列无关。


3.2 导出(Graph Capture / Stage Export)

目的 :把训练栈上的模型变为 平台可编译的 IR (常见为 ONNX)。端侧路径里,这一步往往不只是「原样 trace」,而是 对模型重写(model rewrite) ------用与训练 数学等价、但图结构面向部署 的实现,替换 HuggingFace / PyTorch 原生模块。

3.2.1 模型重写:为何不直接 trace Transformers?

训练与推理栈通常共用 transformers 等现成实现;端侧 export 却常 ** deliberately 不用 HF forward trace**,而改为 自研推理图 + 直读 checkpoint 权重。主要动机如下:

动机 说明
图稳定、可 OTA HF 小版本升级常改模块命名、算子分解、控制流;trace 出的 ONNX 随版本漂移 。车载/机器人要求 10 年级 可回归的 export 图,须由部署代码 显式控制 forward 语义。
算子与 runtime 对齐 端侧 attention、INT4/NVFP4 GEMM、MoE 路由等依赖 TRT Plugin / 专用 kernel ;通用 MatMul+Softmax 分解图难以被编译器融合,也无法走 FP8 KV、XQA decode 等路径。
Prefill + Decode 统一 LLM 需 同一张 ONNX 通过 past_len=0/>0 与双 optimization profile 服务 prefill 与单 token decode;HF 模块默认不暴露这一 I/O 契约。
量化与 kernel layout 解耦 Checkpoint 可能是 AWQ/GPTQ/NVFP4 等多种 layout;需在 export 前 repack 成 plugin 期望字节序,而不是把 layout 问题留给 runtime。
融合与带宽 训练图偏「正确、可读」;端侧要 减 kernel launch、减 HBM 往返(fused MLP、fused MoE、RoPE+写 KV 合一)。
text 复制代码
训练侧:  HF Checkpoint(权重 + config)  →  transformers 训练/推理
端侧 export:同一 Checkpoint  →  自研 nn.Module(仅推理语义)  →  ONNX + custom op
                ↑ 只借权重与配置,不借 HF 计算图

与「直接用 optimum / torch.export trace HF」相比:数值对齐 HF 训练结果,但图结构是 deployment-native 的

3.2.2 重写时做的典型工作

模型重写不是单点技巧,而是 结构替换 + 算子替换 + 权重变换 + I/O 重设计 的组合。

(1)自研模块树(结构对齐、实现自有)
  • config.json 解析层数、head、RoPE、MoE / Mamba / GDN 等 层类型 ,在 models/<arch>/ 下用 自有 AttentionRMSNormDecoderLayer 等拼装网络。
  • 权重 key 与 HF 对齐loader.load_weights 填 buffer),必要时 key_remap(多模态嵌套 config、TTS talker 等)。
  • 不 import transformersforward,避免 hidden 依赖与版本绑定。
(2)Custom Op 三段式(export 桩 → ONNX → C++ Plugin)

端侧高性能算子无法在纯 ONNX 标准 op 中表达,采用固定模式:

text 复制代码
torch.library.custom_op   # export 时返回正确 shape 的 dummy tensor
        ↓ dynamo_translations / symbolic
ONNX Custom Node + schema   # llm_build 可识别
        ↓
TRT Plugin / CuTe kernel    # 板端实际执行

常见 custom op 类别:

类别 典型 op / 节点 解决的部署问题
Attention 统一 attention plugin(vanilla / FP8 KV / EAGLE tree) Prefill FMHA + decode XQA;Linear KV 原地更新;RoPE 融合
ViT Attention vit attention plugin 变长 cu_seqlens、双向 attention
量化 Linear INT4 groupwise GEMM、NVFP4/MXFP8 Q-DQ、INT8 SQ W4A16 / W4A4 / W8A8 走 Tensor Core 路径
MoE INT4 MoE plugin、NVFP4 MoE(prefill/decode/fused) 路由 + topk + 多专家 GEMM 单节点或融合 kernel
Hybrid 层 Gated Delta Net、Mamba causal conv + SSM update 非标准 Transformer 层的端侧 kernel
Action / 原生 TRT rope、kv_cache_update、attention(无 plugin 回退路径) 小模型 action head 等于 TRT 原生 op 即可

Attention 等 op 的 feature flag 必须显式传入 (如 enable_fp8_kv_cache),避免 dynamo 因默认值被优化掉而导致 ONNX 缺字段。

(3)子图融合(Fused MLP、Fused MoE 等)

不改变数学语义 的前提下合并算子,降低 权重带宽与 launch 次数

融合模式 原始(训练图) 重写后 收益
Fused MLP(SwiGLU/GeGLU) down(act(gate(x)) * up(x)) 两次 FC1 GEMM gate_up_proj 一次 GEMM + split + act + mul + down 少一次 FC1 权重读;更高算术强度
MoE gate+up 打包 每专家独立 gate/up/down export 前 stack + interleave 为 plugin 级 fc_gate_up_qweights 融合路由与分组 GEMM
Attention 内融合 RoPE、写 KV、FMHA/XQA 多 kernel AttentionPlugin 内 RoPE+WriteKV+FMHA 或 XQA 减中间 buffer;FP8 KV 直连
NVFP4 MoE 端到端 route → FC1 → act → quant → FC2 多步 单 fused MoE kernel(部分平台) decode/prefill 少 launch

Fused MLP 示例(Gemma / pi0.5 类 MLP)------纯图重写、零 plugin 也可成立:

text 复制代码
原:  g = x @ W_gate^T ;  u = x @ W_up^T ;  h = act(g) * u ;  y = h @ W_down^T
合:  [g;u] = x @ W_gu^T   (W_gu = concat(W_gate, W_up))
      h = act(g) * u ;  y = h @ W_down^T

可在 export 前 in-place 替换 GemmaMLPFusedGemmaMLP;ONNX 中为一次 MatMul + Split + 激活 + Mul + MatMul,TRT Myelin 可继续融合 down 前小算子。

(4)量化感知 Linear(make_linear 类模式)

同一层类型按 checkpoint metadata 分发 不同 Linear 实现,每种 forward() 故意 emit 与 TRT 融合路径匹配的子图(量化 recipe 与模块分发见 §3.1.3):

text 复制代码
QuantConfig → FP16Linear | FP8Linear | NVFP4Linear | AWQLinear | GPTQLinear | ...
                    ↓
            对应 Q-DQ-MatMul / int4_groupwise_gemm / nvfp4_act_qdq 等 ONNX 子图

LM head、MoE 专家、visual tower 可 与 backbone 不同精度(混合精度 export)。

(5)权重 Repack(layout 重写,非改数值)

量化 checkpoint 的 存储 layout 与 GPU plugin/kernel 期望 layout 可能不一致。在 PyTorch 侧、trace export 之前 做 repack(Edge-LLM:load_weightsapply_all_repacking):

  • INT4 :nibble swizzle、fold zero-point → plugin 约定 (nibble-8)*scale
  • MoE(INT4/NVFP4):逐专家 stack → N-major / Marlin / interleave(up,gate)
  • NVFP4 稠密层 :多为 uint8→int8 view cast(比特不变)

NVFP4 的 ONNX 图改写 fp4qdq_to_2dq 不是 repack ------发生在 export 之后 ,见 §3.1.8

INT4 不做 repack 会直接算错;NVFP4 稠密层不 view cast 可能导致 ONNX/TRT 解析问题;MoE 不做重 pack 则 plugin 无法加载。

(6)图级 I/O 与 sidecar 外置

重写还包括 什么进 ONNX、什么留 runtime

进 ONNX 图 外置 sidecar(不进 engine)
主干 MatMul/Attention/MoE embedding.safetensors(含 FP8 embedding)
KV cache I/O 绑定 tokenizer、chat_template
控制张量:context_lengthskvcache_start_index config.json、quant metadata
可选 external INT4 大权重 vocab_map、LoRA adapter 目录

Embedding lookup、采样循环、denoise 控制流 等常留在 C++ Orchestrator,不强行塞进单一 ONNX。

VLA denoise 中 AdaRMS modulation 可进一步外置为图输入 adarms_mod(host 按固定步调度预算),见 §3.2.6

(7)与 Stage 拆分的关系

模型重写发生在 每个 stage 的 export 内 ;stage 拆分(vit / llm / denoise)是 VLA 或多模态 在重写之后的 切图策略 ,见下节。LLM 单 backbone 可在 一次重写 中得到「prefill+decode 统一图」。
#mermaid-svg-JJdEugvOFyyYdEDa{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-JJdEugvOFyyYdEDa .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-JJdEugvOFyyYdEDa .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-JJdEugvOFyyYdEDa .error-icon{fill:#552222;}#mermaid-svg-JJdEugvOFyyYdEDa .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-JJdEugvOFyyYdEDa .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-JJdEugvOFyyYdEDa .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-JJdEugvOFyyYdEDa .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-JJdEugvOFyyYdEDa .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-JJdEugvOFyyYdEDa .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-JJdEugvOFyyYdEDa .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-JJdEugvOFyyYdEDa .marker{fill:#333333;stroke:#333333;}#mermaid-svg-JJdEugvOFyyYdEDa .marker.cross{stroke:#333333;}#mermaid-svg-JJdEugvOFyyYdEDa svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-JJdEugvOFyyYdEDa p{margin:0;}#mermaid-svg-JJdEugvOFyyYdEDa .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-JJdEugvOFyyYdEDa .cluster-label text{fill:#333;}#mermaid-svg-JJdEugvOFyyYdEDa .cluster-label span{color:#333;}#mermaid-svg-JJdEugvOFyyYdEDa .cluster-label span p{background-color:transparent;}#mermaid-svg-JJdEugvOFyyYdEDa .label text,#mermaid-svg-JJdEugvOFyyYdEDa span{fill:#333;color:#333;}#mermaid-svg-JJdEugvOFyyYdEDa .node rect,#mermaid-svg-JJdEugvOFyyYdEDa .node circle,#mermaid-svg-JJdEugvOFyyYdEDa .node ellipse,#mermaid-svg-JJdEugvOFyyYdEDa .node polygon,#mermaid-svg-JJdEugvOFyyYdEDa .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-JJdEugvOFyyYdEDa .rough-node .label text,#mermaid-svg-JJdEugvOFyyYdEDa .node .label text,#mermaid-svg-JJdEugvOFyyYdEDa .image-shape .label,#mermaid-svg-JJdEugvOFyyYdEDa .icon-shape .label{text-anchor:middle;}#mermaid-svg-JJdEugvOFyyYdEDa .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-JJdEugvOFyyYdEDa .rough-node .label,#mermaid-svg-JJdEugvOFyyYdEDa .node .label,#mermaid-svg-JJdEugvOFyyYdEDa .image-shape .label,#mermaid-svg-JJdEugvOFyyYdEDa .icon-shape .label{text-align:center;}#mermaid-svg-JJdEugvOFyyYdEDa .node.clickable{cursor:pointer;}#mermaid-svg-JJdEugvOFyyYdEDa .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-JJdEugvOFyyYdEDa .arrowheadPath{fill:#333333;}#mermaid-svg-JJdEugvOFyyYdEDa .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-JJdEugvOFyyYdEDa .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-JJdEugvOFyyYdEDa .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JJdEugvOFyyYdEDa .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-JJdEugvOFyyYdEDa .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JJdEugvOFyyYdEDa .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-JJdEugvOFyyYdEDa .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-JJdEugvOFyyYdEDa .cluster text{fill:#333;}#mermaid-svg-JJdEugvOFyyYdEDa .cluster span{color:#333;}#mermaid-svg-JJdEugvOFyyYdEDa div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-JJdEugvOFyyYdEDa .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-JJdEugvOFyyYdEDa rect.text{fill:none;stroke-width:0;}#mermaid-svg-JJdEugvOFyyYdEDa .icon-shape,#mermaid-svg-JJdEugvOFyyYdEDa .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JJdEugvOFyyYdEDa .icon-shape p,#mermaid-svg-JJdEugvOFyyYdEDa .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-JJdEugvOFyyYdEDa .icon-shape .label rect,#mermaid-svg-JJdEugvOFyyYdEDa .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JJdEugvOFyyYdEDa .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-JJdEugvOFyyYdEDa .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-JJdEugvOFyyYdEDa :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Checkpoint
自研 Module + custom op + 融合 + repack
Stage ONNX
Compile

3.2.3 为何要 Stage 拆分
模型形态 典型 stage 原因
LLM 单 backbone(或 + visual tower) Prefill/decode 可 同一 ONNX、双 profile
VLM visual + llm 视觉塔与语言塔 算力与 shape 不同
VLA vit → llm_prefix → action/denoise 一次 prefix + N 次 denoise;KV 须跨 stage 传递

整模型单 engine 在 VLA 上通常 不可行:denoise 环成为热点,且 prefix KV 须在 expert 阶段复用。

3.2.4 导出要点
  • 静态 shape 上界 :batch、seq_len、action_horizon、denoise 步数在 product 设计时 定 cap
  • Custom op → 后端 plugin :Attention、INT4 GEMM、NVFP4 MoE 等须在 IR 中显式出现(见 §3.2.2
  • Prefill + Decode 统一图 (LLM):单 ONNX 通过 I/O 区分 past_len=0 / past_len>0,compile 时建 双 optimization profile
  • Sidecar 同步写出 :runtime 需要的 config、tokenizer、embedding、quant flag------不宜全部 bake 进 engine

产物stage.onnx(每 stage 一个或多个)+ sidecar 目录 + Manifest / 血缘记录(版本、TRT 版本、quant spec)。

3.2.5 附录:三项目重写实例对照

§3.2.2 描述的是 通用重写模式 ;下表按 重写类型 列出三仓库中的 具体实现 ,便于查缺。按发生阶段分为:Export 图重写Export 后 ONNX patch权重 layout repackSidecar 外置Runtime 挂载(后两类严格说不算 export 重写,但与 pi0.5 路径强相关,一并列出)。

重写类型 TensorRT-Edge-LLM model_optimizer(pi0.5) Chamleon
自研 Module 树 + 不 trace HF 全架构 models/<arch>/loader.load_weights + 各模型 key_remap(Alpamayo、Talker/TTS、Phi4MM 等) 默认仍用 HF GemmaModel/GemmaDecoderEdge 路径 另建 GemmaModelEdgeOnnxExport deploy/pi05/* 薄包装 HF decoder(eager attention);自研 backbone
Attention custom op trt::attention_plugintrt::vit_attention_plugin;Action 小模型回退 trt::attention_onnx + rope_onnx + kv_cache_update_onnx llm_with_trtedgellm:包装 GemmaAttentionTrtEdge + 导出专用 forward 调 edge.forward;QKV layout 对齐 plugin 未接 Edge attention plugin;LLM stage 为 原生 MatMul+Softmax eager 图
独立 FMHA plugin (含于 attention_plugin 族) llm_with_cutedsltrt::FmhaD256AttentionPlugin(CuTe DSL,不依赖 Edge-LLM) kernels/fmha/fmha_d256.py 占位;未接入 export 主路径
Fused MLP(gate+up 合并) 部分架构 export 内融合 fused_mlp.install_fused_mlp;feature 注册于 llm.py / dit.py 未实现(expert/denoise 仍 HF MLP)
AdaRMS 预计算(图简化) --- dit.pyadarms_dense_precompute;导出时 timestepadarms_mod,forward hook 绕过 dense GEMM(详见 §3.2.6 未实现
量化 Linear / Q-DQ 子图 make_linear → FP16/FP8/NVFP4/AWQ/GPTQ/INT8SQ 等(详见 §3.1.3 ModelOpt 量化 + embed_prefix 的 TRT high-precision patch 依赖 ModelOpt(若走 reference quant 路径)
MoE / Hybrid 层 plugin int4_moe_pluginNvfp4MoePlugingated_delta_net、Mamba causal_conv1d/update_ssm_state pi0.5 无 MoE ---
INT4/NVFP4/MXFP8 辅助 op int4_groupwise_gemmnvfp4_act_qdqmxfp8_*fp8_quantize/dequantizegather_nd 经 ModelOpt QDQ + Edge plugin(Edge 路径) ---
权重 repack(layout) checkpoint/repacking.py(AWQ/GPTQ/NVFP4/MoE stack) FlashRT repack_decoder_weightsruntime/compile,非 ONNX 图) ---
Vocab reduction vocab_reduction/:repack 缩 lm_head 行;EAGLE draft 特例 --- ---
External weights 外置 externalize_weights 大权重不进 ONNX --- ---
LoRA insert_lora.py 图插入;merge_lora.py checkpoint 合并 --- ---
Spec decode / MTP 变体 EAGLE base/draft、MTP base/draft 分目录 export --- ---
多模态 sidecar 拆分 Talker codec embedding、lm_heads、small_to_mtp_projection;Alpamayo processor fp8_lang_embeddinglang_embedding.safetensorsembed_prefix 多相机 SigLIP 图 embed_prefix stage 未实现
Export 后 ONNX dtype patch --- denoise_onnx_post_export.py 四步:全局 bias、投影层、NVFP4 Gemm、FP8 Gemm dtype 对齐 未接(denoise 若走 MO 路径需同样 patch)
SigLIP / ViT 导出 patch 各 visual tower 自研 embed_prefix:vision quant conv 禁 input quant(TorchScript ONNX) export_vit 薄包装
Runtime engine 替换 C++ LLMEngineRunner 原生 pi05_trt_engine_setup.py:vit/llm/expert/denoise engine 挂载;fp8_lang_embedding runtime lookup deploy/pi05 + TRT build;编排层,无额外图重写
FlashRT 整循环 decoder --- native_flashrt_decoder:绕过 TRT denoise loop,手写 FVK + 静态 FP8 ---

覆盖度结论(相对 §3.2.2 通用模式):

项目 已写入 §3.2.2 的模式 本文附录补充、原文未逐项列出的
TensorRT-Edge-LLM 自研模块、custom op 全族、fused MLP/MoE、make_linear、repack、sidecar vocab reduction、external weights、LoRA 插入/合并、EAGLE/MTP、Alpamayo/Talker/Phi4MM key_remap、Action 原生 TRT op 回退
model_optimizer fused MLP、Attention plugin 对接思路、sidecar embedding GemmaModelEdgeOnnxExport 双 forward、CuTe FMHA、AdaRMS(§3.2.6)、denoise dtype patch、FlashRT;量化 recipe 见 §3.1.6--§3.1.7
Chamleon (几乎无独立重写,仅 stage 拆分) 明确:委托 MO 风格薄 export;LLM 走 Edge attention;embed_prefix 缺失;fmha 仅占位

pi0.5 路径差异要点 :model_optimizer 的 Edge/CuTe LLM 路径 与 Chamleon 默认 HF eager LLM export 不是同一张图;对比数值或 compile 结果时需先确认走的是哪条 export 后端。

3.2.6 案例深入:AdaRMS Dense 预计算(Pi0.5 denoise)

Pi0.5 VLA 的 denoise stage (action expert / DiT)使用 Adaptive RMSNorm(AdaRMS) :扩散时间步 t 经 MLP 变成条件向量,再经每个 norm 上的 densecond_dim → dim×3)生成 (scale, shift, gate),对 token 做仿射调制并返回 gate 供 gated residual 使用。

为何值得单独成节 :这是 §3.2.2「图级 I/O 重写」的典型实例------不是改数学,而是把 与推理输入无关、仅依赖固定步调度 的子图移出 engine,改由 host 预算后以张量注入;收益主要来自 少 launch + 图简化让 Myelin 融合更好 (model_optimizer / FlashRT 实测约 -5.5ms)。

背景:默认 denoise 图里有什么

条件链路(model_optimizer/models/pi05/dit.py):

text 复制代码
timestep [batch]
  └─ create_sinusoidal_pos_embedding(t)     # 仅依赖 t
       └─ time_mlp_in → SiLU → time_mlp_out → SiLU
            └─ adarms_cond [batch, cond_dim]
                 └─ 每个 AdaRMS:modulation = dense(adarms_cond)   # cond_dim → dim×3
                      └─ scale, shift, gate = chunk(modulation, 3)
                           └─ normed * (1+scale) + shift ;返回 gate

18 层 expert 有 37 个 AdaRMS (每层 input_layernorm + post_attention_layernorm,再加 final norm)。denoise 默认 10 步 → 每步 37 次 dense GEMM → 370 个小 GEMM / 次推理(launch-bound 段,算力本身极小)。

关键洞察adarms_cond 只依赖 timestep ,与 x_t、prefix KV、观测无关;flow-matching 的 num_steps / dt 在部署期固定;dense 权重冻结 ⇒ 每个 (step_k, norm_i) 的 modulation 是 常量,不必在 TRT 热路径里重复计算。

两种模式对比

渲染错误: Mermaid 渲染失败: Parse error on line 2: ...art TB subgraph default["默认模式:timest ----------------------^ Expecting 'SPACE', 'GRAPH', 'DIR', 'subgraph', 'end', 'AMP', 'COLON', 'START_LINK', 'STR', 'MD_STR', 'STYLE', 'LINKSTYLE', 'CLASSDEF', 'CLASS', 'CLICK', 'DOWN', 'UP', 'NUM', 'NODE_STRING', 'BRKT', 'MINUS', 'MULT', 'UNICODE_TEXT', got 'DEFAULT'

维度 默认模式 AdaRMS 预计算
第 5 个 ONNX 输入 timestep [batch] adarms_mod [num_norms, batch, dim×3]
图内 sinusoid / time_mlp
图内 37 个 dense
条件如何进 norm adarms_cond 传入 expert → 各层 dense(cond) Host 预算后 _inject_modulation;expert 传 adarms_cond=None
实现位置 openpi GemmaRMSNorm.forward dit.py 运行时替换为 _adarms_injected_forward(不改 modeling_gemma.py
预计算的三步机制

(1)替换 norm forwardenable_adarms_precompute):把 37 个 AdaRMS 的 forward monkey-patch 为注入版------读 self._injected_mod[batch, dim×3]),chunk 得 scale/shift/gate,做 normed*(1+scale)+shift不调用 self.dense

(2)Host 预算 modulationprecompute_adarms_modulation(timestep)):

text 复制代码
cond = _compute_adarms_cond(timestep)          # 完整 time 链路(PyTorch 全精度)
mods = [norm.dense(cond) for norm in norms]    # 仍用真实 dense 权重
adarms_mod = stack(mods, dim=0)              # [num_norms, batch, dim×3]

num_norms 顺序固定:layer[i].input_layernormlayer[i].post_attention_layernorm(i 递增)→ gemma_expert.norm。18 层时 num_norms=37dim×3 = hidden_size×3

(3)推理注入forward 预计算分支):_embed_action(x_t) 只做 action_in_proj(不算 time);_inject_modulation(adarms_mod) 给每个 norm 设 _injected_mod_run_expert(..., adarms_cond=None) 走 expert 主干。

ONNX 导出:输入 / 输出
名称 Shape(典型) 说明
prefix_pad_masks [batch, prefix_len] prefix 有效 mask
past_keys [L, batch, H_kv, prefix_len, D] LLM prefix KV(与 LLM stage 堆叠方式一致)
past_values past_keys
x_t [batch, action_horizon, action_dim] 当前步噪声动作
timestep adarms_mod [batch] [37, batch, dim×3] 第 5 输入名与 shape 随模式切换
v_t(输出) [batch, action_horizon, action_dim] flow 速度场

导出时(Pi05DenoiseStep.export):预计算模式用 adarms_mod 假输入 tracing,日志示例:[adarms] precompute export: 37 norms × dim*3=3072, dense GEMM 已移出图

量化注意 :ModelOpt 校准数据只含 timestep,故 quantize()临时关闭 预计算做标定,导出前再打开 ------校准走完整 time 链路,最终 ONNX 仍是 adarms_mod 图。

实际推理(TRT host 循环)

infer/pi05_adarms.py::AdaRmsModulator:用 非预计算 模式构建 Pi05DenoiseStep(保留原始 dense),按 timestep 调用 precompute_adarms_modulation,结果 fp32 缓存(固定 10 步最多 10 份)。

pi05_trt_engine_setup.py::install_denoise:若 denoise_adarms_precompute=true,每步:

text 复制代码
adarms_mod = AdaRmsModulator(timestep)   # Host:sinusoid + time_mlp + 37×dense
v_t = denoise_engine(..., adarms_mod=adarms_mod)   # Engine:仅仿射 + transformer 主干

一步 denoise 数据流:

text 复制代码
Host                          TRT denoise engine
────                          ──────────────────
timestep ──→ 预算 adarms_mod ──→ 注入式 AdaRMS(elementwise,无 dense)
x_t      ────────────────────→ action_in_proj → expert → v_t
past_kv  ────────────────────→ cross-attn with prefix
启用与三处一致性
阶段 开关
Export / quantize feature_config.features.adarms_dense_precompute=truePI05_ADARMS_PRECOMPUTE=1
Build ONNX 第 5 输入为 adarms_mod,shape 须与 export 日志中 N×dim×3 一致
Serve / infer tensorrt.denoise_adarms_precompute=true(或 onnxrt 同名项)

风险 :若运行时改变 num_stepsdt 或 sinusoid 参数(min_period=4e-3, max_period=4.0),须 重算 全部 step 的 modulation;开关前后应对 v_t 做逐步 cos 比对(建议 ≥ 0.999)。

与 FlashRT、Chamleon 的关系
model_optimizer(TRT 路径) FlashRT
预算 precompute_adarms_modulationadarms_mod 张量 precompute_adarms_stylessa/sf/fs 常量
注入 TRT 图输入 fused kernel 内消费
性质 编译器友好(图简化) 手写 FVK,整 10 步循环

Chamleon 默认 deploy/pi05/denoise 未接 此 feature;要走预计算须使用 model_optimizer 的 Pi05DenoiseStep + 上述三处开关对齐。

代码锚点model_optimizer/models/pi05/dit.py(export / inject / precompute)、infer/pi05_adarms.py(host 预算)、infer/tensorrt/pi05_trt_engine_setup.py(engine 喂入)。


3.3 编译(Build / Compile)

目的 :将 §3.2 产出的 ONNX(+ sidecar)在 目标 SM / 同架构 GPU 上编译为 可执行 engine ,并固化 shape 上界、optimization profile、plugin 注册、workspace 峰值
#mermaid-svg-CVMrEZuTWA8prYCU{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-CVMrEZuTWA8prYCU .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-CVMrEZuTWA8prYCU .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-CVMrEZuTWA8prYCU .error-icon{fill:#552222;}#mermaid-svg-CVMrEZuTWA8prYCU .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-CVMrEZuTWA8prYCU .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-CVMrEZuTWA8prYCU .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CVMrEZuTWA8prYCU .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CVMrEZuTWA8prYCU .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-CVMrEZuTWA8prYCU .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CVMrEZuTWA8prYCU .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CVMrEZuTWA8prYCU .marker{fill:#333333;stroke:#333333;}#mermaid-svg-CVMrEZuTWA8prYCU .marker.cross{stroke:#333333;}#mermaid-svg-CVMrEZuTWA8prYCU svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-CVMrEZuTWA8prYCU p{margin:0;}#mermaid-svg-CVMrEZuTWA8prYCU .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-CVMrEZuTWA8prYCU .cluster-label text{fill:#333;}#mermaid-svg-CVMrEZuTWA8prYCU .cluster-label span{color:#333;}#mermaid-svg-CVMrEZuTWA8prYCU .cluster-label span p{background-color:transparent;}#mermaid-svg-CVMrEZuTWA8prYCU .label text,#mermaid-svg-CVMrEZuTWA8prYCU span{fill:#333;color:#333;}#mermaid-svg-CVMrEZuTWA8prYCU .node rect,#mermaid-svg-CVMrEZuTWA8prYCU .node circle,#mermaid-svg-CVMrEZuTWA8prYCU .node ellipse,#mermaid-svg-CVMrEZuTWA8prYCU .node polygon,#mermaid-svg-CVMrEZuTWA8prYCU .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-CVMrEZuTWA8prYCU .rough-node .label text,#mermaid-svg-CVMrEZuTWA8prYCU .node .label text,#mermaid-svg-CVMrEZuTWA8prYCU .image-shape .label,#mermaid-svg-CVMrEZuTWA8prYCU .icon-shape .label{text-anchor:middle;}#mermaid-svg-CVMrEZuTWA8prYCU .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-CVMrEZuTWA8prYCU .rough-node .label,#mermaid-svg-CVMrEZuTWA8prYCU .node .label,#mermaid-svg-CVMrEZuTWA8prYCU .image-shape .label,#mermaid-svg-CVMrEZuTWA8prYCU .icon-shape .label{text-align:center;}#mermaid-svg-CVMrEZuTWA8prYCU .node.clickable{cursor:pointer;}#mermaid-svg-CVMrEZuTWA8prYCU .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-CVMrEZuTWA8prYCU .arrowheadPath{fill:#333333;}#mermaid-svg-CVMrEZuTWA8prYCU .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-CVMrEZuTWA8prYCU .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-CVMrEZuTWA8prYCU .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CVMrEZuTWA8prYCU .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-CVMrEZuTWA8prYCU .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CVMrEZuTWA8prYCU .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-CVMrEZuTWA8prYCU .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-CVMrEZuTWA8prYCU .cluster text{fill:#333;}#mermaid-svg-CVMrEZuTWA8prYCU .cluster span{color:#333;}#mermaid-svg-CVMrEZuTWA8prYCU div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-CVMrEZuTWA8prYCU .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-CVMrEZuTWA8prYCU rect.text{fill:none;stroke-width:0;}#mermaid-svg-CVMrEZuTWA8prYCU .icon-shape,#mermaid-svg-CVMrEZuTWA8prYCU .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CVMrEZuTWA8prYCU .icon-shape p,#mermaid-svg-CVMrEZuTWA8prYCU .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-CVMrEZuTWA8prYCU .icon-shape .label rect,#mermaid-svg-CVMrEZuTWA8prYCU .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CVMrEZuTWA8prYCU .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-CVMrEZuTWA8prYCU .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-CVMrEZuTWA8prYCU :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} stage.onnx + sidecar
build_cfg / llm_build 参数
加载 plugin .so
ONNX Parser
Optimization Profile
TRT Builder
.engine
Manifest / 血缘

硬约束(三项目共识)

约束 说明
板端 build Edge-LLM 官方要求 在 Edge 设备上 llm_build;pi0.5 亦应在部署 GPU 上 build
TRT 版本锁定 build 与 infer 的 TensorRT 主版本 必须一致
Export ↔ Build 对齐 输入 名称、秩、dtype 与 export 一致;动态轴用 min/opt/max 或 maxInputLen 等上界表达
Plugin 先于 Parser 自定义 op 须在 OnnxParser.parse 之前 ctypes.CDLL(..., RTLD_GLOBAL) 加载
Sidecar 随 engine 部署 config.json、tokenizer、FP8 embedding 等 bake 进 engine,须与 engine 目录一并拷贝
3.3.1 通用编译关注点
关注点 作用 典型参数
Optimization profile 约束 TRT 为 min/opt/max shape 选 kernel;决定 plugin getWorkspaceSize() 峰值 LLM:prefill 长 seq + decode seq=1 双 profile
Shape 上界 同时约束 KV 池大小scratch workspace maxInputLenmaxKVCacheCapacitymaxBatchSize
Precision / STRONGLY_TYPED 与 ONNX 浮点 dtype、custom plugin I/O 对齐 bf16 / fp16;含 Edge AttentionPlugin 时常需 FP16 ONNXstrongly_typed_network
Workspace pool Builder 临时融合缓冲 workspace_mb(Python 路径常见 8192)
Plugin 库 Attention、INT4 GEMM、NVFP4 MoE 等 plugin_lib_paths / Edge 内置 libNvInfer_edgellm_plugin.so
Debug 输出 逐 tensor 对齐 PyTorch debug_output_tensors(仅调试,engine 变大变慢)

产物.engine(每 stage 一个或多个)+ build 日志 + Manifest 记录(ONNX/engine 哈希、TRT 版本、build_cfg)。

3.3.2 TensorRT-Edge-LLM:C++ llm_build / visual_build

Edge-LLM 的编译是 专用 C++ Builder ,不是通用 trtexec 封装:

text 复制代码
onnx/ + config.json + tokenizer/ ...
        │
        ▼
llm_build --onnxDir ... --engineDir ...
           [--maxInputLen] [--maxKVCacheCapacity] [--maxBatchSize]
           [--maxLoraRank] [--specDraft|--specBase] [--profilingDetailed]
        │
        ▼
llm.engine + sidecar 复制到 engineDir
工具 模型 关键参数
llm_build LLM / Talker / Action expert ONNX maxInputLenmaxKVCacheCapacitymaxBatchSize;EAGLE --specDraft/--specBase
visual_build ViT / visual tower minImageTokensmaxImageTokens
action_build Alpamayo 等 action head 与 LLM 共享 maxKVCacheCapacity一致

LLM 双 optimization profile(Edge 精华)EngineExecutor同一 engine 上切换 context(prefill)generation(decode) profile------对应 export 时「单 ONNX、past_len=0/>0」契约。Build 期 maxInputLen / maxKVCacheCapacity 直接进入 AttentionPlugin 的 workspace 估算(prefill 长 seq 往往是 scratch 峰值来源)。

精度评测 build 建议examples/accuracy/README.md):accuracy 数据集 prompt 较长,宜 maxInputLen=8192maxKVCacheCapacity=10240;VLM 须 分别 build visual + text engine。

Runtime 衔接 :C++ LLMEngineRunner 使用 kUSER_MANAGED workspace + 多 engine 串行共享 scratch(setContextMemory);build 期 profile 越大,此处 getRequiredContextMemorySize() 越高。

3.3.3 model_optimizer:Python build_engine + build_cfg

pi0.5 每 stage 一份 Python build_cfgconfig/build_configs/*.py),经 model-opt build --build_cfg ... 调用 trt_build/build.py::build_engine

python 复制代码
# denoise_step_build_cfg.py 示例 --- 须与 dit.py export 的 input_names/shape 一致
build_cfg = {
    "precision": "bf16",
    "strongly_typed_network": True,
    "workspace_mb": 8192,
    "min_shapes": {"prefix_pad_masks": (1, 818), "past_keys": (18, 1, 818, 256), ...},
    "opt_shapes": { ... },
    "max_shapes": { ... },
}

build 流水线(5 步)

  1. validate_precision_matches_onnx :ONNX 主浮点 dtype 与 precision 不一致则 提前 fail(避免 TRT 选错 kernel、深层输出塌缩)
  2. trt.init_libnvinfer_plugins + plugin_lib_paths 预加载 Edge/CuTe 插件
  3. ONNX ParserEXPLICIT_BATCH;可选 STRONGLY_TYPED
  4. Optimization profilemin_shapes / opt_shapes / max_shapes输入名 绑定
  5. build_serialized_network → 写 .enginerecord_trt_build_artifact 写入血缘

与 export 对齐清单(常见踩坑)

开关 / 参数 export 侧 build 侧
AdaRMS 预计算 第 5 输入 adarms_mod [37,B,dim×3] denoise_*_adarms_build_cfg.py 改输入名与 shape
prefix 长度 export prefix_len / 假输入 _PREFIX_LEN / SEQ_LEN 一致
Edge Attention ONNX 插件 I/O 常为 FP16 precision="fp16" 或 bf16+插件报错时改 export dtype
NVFP4 denoise QDQ + 四步 dtype patch 后 strongly_typed_network=True;勿对 action_in_proj 强行 fp32 override(Add bias dtype 冲突)
CuTe LLM llm_cutedsl_build_cfg.py + FmhaD256 插件 so 独立 plugin 路径

Artifacts :build 结果记入 model_optimizer/artifacts,便于 CI 追溯 ONNX → engine 对应关系。

3.3.4 Chamleon:YAML 编排 + 复用 deploy build

Chameleon 提供 两条 compile 路径

路径 入口 说明
deploy.backend=pi05 run_deploy_buildbuild_pi05_stage_engine 复用 deploy/trt_build.py(与 model_optimizer 同构的 build_engine)+ deploy/build_cfg 解析
Reference adapter run_compileTensorRTCompiler 通用 ONNX Artifact → engine;cfg["profiles"] 支持 prefill/decode 双 profile 列表

Workflow YAML 示例动作序:quantize → export → compile → trt_profile → infercompile step 指定 stage 与 build_cfg 路径;infer.use_compiled_engines=true 时把 compile 产物注入 InferenceSession

Profiling 集成chameleon trt-profile 对已 build 的 engine 跑 trtexec --exportProfiledraw/trt_profile_viewer.py 解析 JSON 生成交互 layer 表------与 compile 解耦,属 build 后性能验证(见 §3.4)。

3.3.5 三项目编译对照
维度 TensorRT-Edge-LLM model_optimizer Chamleon
Build 入口 llm_build / visual_build C++ model-opt build + build_cfg.py chameleon compile / run_deploy_build
Profile 模型 C++ Builder 内建 LLM 双 profile 每输入 min/opt/max dict pi05:静态 shape cfg;reference:profiles[] 双 profile
Plugin 链接 Edge plugin 库 plugin_lib_paths 显式加载 同 MO + compile cfg
Precision 预检 Builder 内 validate_precision_matches_onnx 同 MO(deploy/trt_build.py
Sidecar export 目录复制到 engineDir export_dir JSON / safetensors Manifest Artifact 血缘
VLA 多 stage 分目录 build vit/llm/expert/denoise 各 *_build_cfg.py 同 pi05 deploy
Spec decode --specDraft/--specBase --- ---

LLM 单图双 profile vs pi0.5 多 engine :Edge-LLM LLM 用 一个 engine 两个 profile 服务 prefill/decode;pi0.5 用 多 stage 多 engine + host 环(denoise×N),compile 重点是 stage 间 KV handoff shape,不是 decode profile。


3.4 Profiling 与算力估算(Build 后、上车前)

Profiling 不替代精度验证,但应在 compile 通过后、task eval 前 完成,用于确认 latency 预算热点层

类型 工具 / 位置 作用
Layer profiling Edge:llm_build --profilingDetailed;Chamleon:trtexec --exportProfile + profile viewer 找 Attention / MoE / Myelin 融合块耗时
Stage latency Edge:llm_inference --dumpProfile;MO:serve / webui timing hooks vit / llm / denoise 各占 ms
Denoise 环 × num_steps(默认 10) 勿只 profile 单步 denoise engine
Workspace / 显存 getDeviceMemorySizeV2、Edge setContextMemory 多 engine 串行共享 scratch 峰值常由 LLM prefill profile 决定
理论 MACs 无 GPU 时粗算 判断是否可 onboard

VLA 注意 :若 denoise 图已含 expert,不要 再把 expert engine 与 denoise 单步 latency 相加;FlashRT 整循环 decoder 则 profile 整 10 步 FVK,与 TRT 单步 engine 不可直接对比。


3.5 精度验证

Compile 只保证 图可执行 ;精度验证保证 数值与任务语义可接受 。推荐 分层推进,避免一上来就跑完整 robot eval。
#mermaid-svg-1YdFSz1cMM3rhwRa{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-1YdFSz1cMM3rhwRa .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-1YdFSz1cMM3rhwRa .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-1YdFSz1cMM3rhwRa .error-icon{fill:#552222;}#mermaid-svg-1YdFSz1cMM3rhwRa .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-1YdFSz1cMM3rhwRa .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-1YdFSz1cMM3rhwRa .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-1YdFSz1cMM3rhwRa .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-1YdFSz1cMM3rhwRa .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-1YdFSz1cMM3rhwRa .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-1YdFSz1cMM3rhwRa .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-1YdFSz1cMM3rhwRa .marker{fill:#333333;stroke:#333333;}#mermaid-svg-1YdFSz1cMM3rhwRa .marker.cross{stroke:#333333;}#mermaid-svg-1YdFSz1cMM3rhwRa svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-1YdFSz1cMM3rhwRa p{margin:0;}#mermaid-svg-1YdFSz1cMM3rhwRa .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-1YdFSz1cMM3rhwRa .cluster-label text{fill:#333;}#mermaid-svg-1YdFSz1cMM3rhwRa .cluster-label span{color:#333;}#mermaid-svg-1YdFSz1cMM3rhwRa .cluster-label span p{background-color:transparent;}#mermaid-svg-1YdFSz1cMM3rhwRa .label text,#mermaid-svg-1YdFSz1cMM3rhwRa span{fill:#333;color:#333;}#mermaid-svg-1YdFSz1cMM3rhwRa .node rect,#mermaid-svg-1YdFSz1cMM3rhwRa .node circle,#mermaid-svg-1YdFSz1cMM3rhwRa .node ellipse,#mermaid-svg-1YdFSz1cMM3rhwRa .node polygon,#mermaid-svg-1YdFSz1cMM3rhwRa .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-1YdFSz1cMM3rhwRa .rough-node .label text,#mermaid-svg-1YdFSz1cMM3rhwRa .node .label text,#mermaid-svg-1YdFSz1cMM3rhwRa .image-shape .label,#mermaid-svg-1YdFSz1cMM3rhwRa .icon-shape .label{text-anchor:middle;}#mermaid-svg-1YdFSz1cMM3rhwRa .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-1YdFSz1cMM3rhwRa .rough-node .label,#mermaid-svg-1YdFSz1cMM3rhwRa .node .label,#mermaid-svg-1YdFSz1cMM3rhwRa .image-shape .label,#mermaid-svg-1YdFSz1cMM3rhwRa .icon-shape .label{text-align:center;}#mermaid-svg-1YdFSz1cMM3rhwRa .node.clickable{cursor:pointer;}#mermaid-svg-1YdFSz1cMM3rhwRa .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-1YdFSz1cMM3rhwRa .arrowheadPath{fill:#333333;}#mermaid-svg-1YdFSz1cMM3rhwRa .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-1YdFSz1cMM3rhwRa .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-1YdFSz1cMM3rhwRa .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1YdFSz1cMM3rhwRa .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-1YdFSz1cMM3rhwRa .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1YdFSz1cMM3rhwRa .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-1YdFSz1cMM3rhwRa .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-1YdFSz1cMM3rhwRa .cluster text{fill:#333;}#mermaid-svg-1YdFSz1cMM3rhwRa .cluster span{color:#333;}#mermaid-svg-1YdFSz1cMM3rhwRa div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-1YdFSz1cMM3rhwRa .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-1YdFSz1cMM3rhwRa rect.text{fill:none;stroke-width:0;}#mermaid-svg-1YdFSz1cMM3rhwRa .icon-shape,#mermaid-svg-1YdFSz1cMM3rhwRa .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1YdFSz1cMM3rhwRa .icon-shape p,#mermaid-svg-1YdFSz1cMM3rhwRa .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-1YdFSz1cMM3rhwRa .icon-shape .label rect,#mermaid-svg-1YdFSz1cMM3rhwRa .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1YdFSz1cMM3rhwRa .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-1YdFSz1cMM3rhwRa .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-1YdFSz1cMM3rhwRa :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Layer / Tensor 对拍
Stage 输出对拍
Pipeline PT vs TRT
Task / Benchmark

3.5.1 分层验证策略
层级 对象 指标 / 方法 典型门禁
L1 Tensor 单层或 debug engine 输出 cosine sim、L1 mean/max、MAE cos ≥ 0.999(AdaRMS 等图简化)
L2 Stage vit / llm / expert / denoise 各 stage Pi05Metric / compare_predictions 校准集上逐 key 对比
L3 Pipeline PyTorch vs TRT 同输入 WebUI vit_pt_trt_comparetrt_trt_compare、Polygraphy 子图 逐步 mse/mae 曲线
L4 Task 端到端能力 Edge:examples/accuracy;VLA:LeRobot success rate 业务阈值

原则

  • 先 FP16/BF16 engine 对拍,再量化 engine------分离 compile bug 与 quant 误差。
  • Export / quant / build 开关三角一致(如 AdaRMS 的 export 输入 = build shape = serve 喂入)。
  • 量化模型除 tensor 对拍外,须做 代表性 downstream eval(LLM:MMLU/MMMU;VLA:仿真或实机 episode)。
3.5.2 TensorRT-Edge-LLM:Benchmark 体系

examples/accuracy/ 提供三类评测:

类型 数据集示例 流程
Accuracy(选择题) MMLU、MMMU、MMStar、OmniBench prepare_datasetllm_inferencecalculate_correctness
ROUGE(生成质量) GSM8K、HumanEval、MTBench vLLM 生成 reference → Edge inference → ROUGE 对比
Audio Seed-TTS-eval、MiniMax WER + speaker similarity

要点

  • VLM 须 visual engine + text engine 联合推理(--multimodalEngineDir)。
  • Build 时用 大于产品 cap 的 seq len 做 accuracy,避免 benchmark 被截断。
  • CI 侧可从 llm_inference / llm_build stdout 解析 --dumpProfile 做 perf baseline(tests/defs/utils/baseline.py)。
3.5.3 model_optimizer:Stage val 与 Compare 工具链

量化前后 stage val (各 Model.quantize 内建):

text 复制代码
quantize 前:val_loop(original) → val_datas_before
quantize 后:val_loop(quantized) → val_datas_after
Pi05Metric.compare(before, after)  # Origin vs Quantized

PyTorch ↔ TRT 对拍evaluate/compare/utils.py):

  • compare_predictions(pred_trt, pred_pt) 逐输出 key 打印 cosine sim、L1 mean/max
  • model-opt evalrun_evalrecord_eval_artifact 写入 metrics 血缘
  • 部署 WebUI:vit_pt_trt_comparecompare_modetrt_trt_compare(两路 TRT 配置对比)、trt_ort_polygraphy_compare(子图 ONNX TRT vs ORT)

pi0.5 特殊项

场景 验证要点
NVFP4 export 后 fp4qdq_to_2dq + denoise dtype patch 后再 build;对拍失败先查 ONNX bias dtype
AdaRMS 预计算 开关前后 逐步 v_t cos ≥ 0.999
FP8 lang embedding sidecar 存在性 + runtime lookup 与 engine 一致
QDQ error quantize(..., measure_quant_error=True) 打印 top-K RMSE quantizer
3.5.4 Chamleon:Manifest 与 Workflow 验证

Chameleon 通过 Manifest 串联 quantize / export / compile / infer 血缘:

  • 每步产出 Artifact(kind=onnx|engine|quantized),记录 path、platform、metadata
  • WorkflowRunnerinfer.use_compiled_engines 时只注入 已 compile 的 stage engine
  • Reference 路径:run_compile 可在 compile 内嵌 capture→ONNX(与 pi05 deploy 导出分离)

CPU 开发机无 TRT 时:ModelOptQuantMethod metadata-only 量化、TensorRTCompiler 抛出清晰 on-device 说明------流水线可跑通,精度验证须上 GPU

3.5.5 三项目精度验证对照
维度 TensorRT-Edge-LLM model_optimizer Chamleon
Tensor 对拍 C++ inference + 自定义脚本 compare_predictions、Polygraphy 随 infer session / 待扩展
Stage metric --- Pi05Metric per stage 委托 MO eval
Task benchmark MMLU/MMMU/ROUGE/TTS 全套 LeRobot WebUI / sim eval YAML infer step
Quant 前后 量化 checkpoint 独立 eval val() before/after quantize quantize Manifest
Artifacts 记录 手工 / CI baseline record_eval_artifact Manifest
推荐门禁 数据集 accuracy 不降超阈值 cos ≥ 0.999(stage);task SR Manifest 哈希 + stage 对拍

上车前 Checklist(通用)

  1. Export ONNX 与 build_cfg 输入名/shape/dtype 一致(含 AdaRMS、FP8 embedding sidecar)
  2. FP16/BF16 engine 与 PyTorch L2 stage 对拍通过
  3. 量化 engine 与 FP16 engine(或 golden)cos / MAE 过线
  4. Profiling 满足 latency 预算(denoise×steps、首 token、 sustained FPS)
  5. Manifest / artifact 记录 engine 哈希 + TRT 版本 + quant recipe 便于 OTA 回归

3.6 Runtime 部署

目的 :在设备上 串行或分 stage 调用 编译产物,完成一次端到端推理。

3.6.1 两层结构
text 复制代码
┌─────────────────────────────────────────┐
│ 编排层 Orchestrator                      │
│  · 前后处理(tokenize / 图像 / state)    │
│  · stage 调用顺序                        │
│  · KV / hidden state handoff             │
│  · VLA:denoise 环控制流                 │
├─────────────────────────────────────────┤
│ 执行层 Engine Executor                   │
│  · 单 stage enqueue / run                │
│  · profile 切换、I/O 绑定                │
│  · 可选 CUDA Graph                       │
└─────────────────────────────────────────┘

开发态可用 Python 编排 + C++/TRT 执行 ;生产态目标为 C++ 编排 + C++ 执行,无 PyTorch 依赖。

3.6.2 内存模型(须分开规划)
类型 内容 生命周期
权重 常驻 engine constant 或 sidecar 加载 进程级
KV Cache Attention 历史 K/V(或 VLA prefix 输出) 跨 prefill/decode 或跨 stage
I/O 激活 logits、embeddings、action tensor stage 间传递或预分配 buffer
Scratch / workspace TRT context memory、plugin 临时区 单次 enqueue;多 engine 可串行共享

显存预算公式(粗算):

text 复制代码
峰值 ≈ 权重 + KV池 + max(stage_workspace) + 激活峰值 + 前后处理缓冲
3.6.3 LLM / VLM 推理时序

采样 LLM Engine Visual 可选 Runtime 应用 采样 LLM Engine Visual 可选 Runtime 应用 #mermaid-svg-bXItCyEkuPoP3MxW{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-bXItCyEkuPoP3MxW .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-bXItCyEkuPoP3MxW .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-bXItCyEkuPoP3MxW .error-icon{fill:#552222;}#mermaid-svg-bXItCyEkuPoP3MxW .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-bXItCyEkuPoP3MxW .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-bXItCyEkuPoP3MxW .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-bXItCyEkuPoP3MxW .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-bXItCyEkuPoP3MxW .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-bXItCyEkuPoP3MxW .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-bXItCyEkuPoP3MxW .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-bXItCyEkuPoP3MxW .marker{fill:#333333;stroke:#333333;}#mermaid-svg-bXItCyEkuPoP3MxW .marker.cross{stroke:#333333;}#mermaid-svg-bXItCyEkuPoP3MxW svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-bXItCyEkuPoP3MxW p{margin:0;}#mermaid-svg-bXItCyEkuPoP3MxW .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-bXItCyEkuPoP3MxW text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-bXItCyEkuPoP3MxW .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-bXItCyEkuPoP3MxW .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-bXItCyEkuPoP3MxW .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-bXItCyEkuPoP3MxW .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-bXItCyEkuPoP3MxW #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-bXItCyEkuPoP3MxW .sequenceNumber{fill:white;}#mermaid-svg-bXItCyEkuPoP3MxW #sequencenumber{fill:#333;}#mermaid-svg-bXItCyEkuPoP3MxW #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-bXItCyEkuPoP3MxW .messageText{fill:#333;stroke:none;}#mermaid-svg-bXItCyEkuPoP3MxW .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-bXItCyEkuPoP3MxW .labelText,#mermaid-svg-bXItCyEkuPoP3MxW .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-bXItCyEkuPoP3MxW .loopText,#mermaid-svg-bXItCyEkuPoP3MxW .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-bXItCyEkuPoP3MxW .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-bXItCyEkuPoP3MxW .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-bXItCyEkuPoP3MxW .noteText,#mermaid-svg-bXItCyEkuPoP3MxW .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-bXItCyEkuPoP3MxW .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-bXItCyEkuPoP3MxW .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-bXItCyEkuPoP3MxW .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-bXItCyEkuPoP3MxW .actorPopupMenu{position:absolute;}#mermaid-svg-bXItCyEkuPoP3MxW .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-bXItCyEkuPoP3MxW .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-bXItCyEkuPoP3MxW .actor-man circle,#mermaid-svg-bXItCyEkuPoP3MxW line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-bXItCyEkuPoP3MxW :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} opt 多模态 loop 自回归 decode 请求 prompt + 可选 image visual forward image tokens / embeds prefill 写 KV generation profile 单 token logits 采样 输出 tokens / 文本

常见优化:System prompt KV 缓存、投机解码(EAGLE/MTP)、decode CUDA Graph、FP8/NVFP4 权重与 FP8 KV。

3.6.4 VLA 推理时序

Denoise / Action LLM prefix Vision Orchestrator 应用 Denoise / Action LLM prefix Vision Orchestrator 应用 #mermaid-svg-0Ja6Om8Su5FdqFBF{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-0Ja6Om8Su5FdqFBF .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-0Ja6Om8Su5FdqFBF .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-0Ja6Om8Su5FdqFBF .error-icon{fill:#552222;}#mermaid-svg-0Ja6Om8Su5FdqFBF .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-0Ja6Om8Su5FdqFBF .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-0Ja6Om8Su5FdqFBF .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-0Ja6Om8Su5FdqFBF .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-0Ja6Om8Su5FdqFBF .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-0Ja6Om8Su5FdqFBF .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-0Ja6Om8Su5FdqFBF .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-0Ja6Om8Su5FdqFBF .marker{fill:#333333;stroke:#333333;}#mermaid-svg-0Ja6Om8Su5FdqFBF .marker.cross{stroke:#333333;}#mermaid-svg-0Ja6Om8Su5FdqFBF svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-0Ja6Om8Su5FdqFBF p{margin:0;}#mermaid-svg-0Ja6Om8Su5FdqFBF .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-0Ja6Om8Su5FdqFBF text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-0Ja6Om8Su5FdqFBF .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-0Ja6Om8Su5FdqFBF .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-0Ja6Om8Su5FdqFBF .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-0Ja6Om8Su5FdqFBF .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-0Ja6Om8Su5FdqFBF #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-0Ja6Om8Su5FdqFBF .sequenceNumber{fill:white;}#mermaid-svg-0Ja6Om8Su5FdqFBF #sequencenumber{fill:#333;}#mermaid-svg-0Ja6Om8Su5FdqFBF #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-0Ja6Om8Su5FdqFBF .messageText{fill:#333;stroke:none;}#mermaid-svg-0Ja6Om8Su5FdqFBF .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-0Ja6Om8Su5FdqFBF .labelText,#mermaid-svg-0Ja6Om8Su5FdqFBF .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-0Ja6Om8Su5FdqFBF .loopText,#mermaid-svg-0Ja6Om8Su5FdqFBF .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-0Ja6Om8Su5FdqFBF .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-0Ja6Om8Su5FdqFBF .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-0Ja6Om8Su5FdqFBF .noteText,#mermaid-svg-0Ja6Om8Su5FdqFBF .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-0Ja6Om8Su5FdqFBF .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-0Ja6Om8Su5FdqFBF .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-0Ja6Om8Su5FdqFBF .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-0Ja6Om8Su5FdqFBF .actorPopupMenu{position:absolute;}#mermaid-svg-0Ja6Om8Su5FdqFBF .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-0Ja6Om8Su5FdqFBF .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-0Ja6Om8Su5FdqFBF .actor-man circle,#mermaid-svg-0Ja6Om8Su5FdqFBF line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-0Ja6Om8Su5FdqFBF :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Euler / flow-matching 更新 x_t loop denoise num_steps 次 obs image + lang + state vit / embed_prefix 视觉 token prefix forward 一次 KV cache past_key_values x_t + time + prefix KV v_t 或 delta action chunk

关键契约

  • Prefix 只算一次 ;denoise 复用同一份 KV(layout 与层数须在 export 时约定)
  • Denoise 环是 延迟热点:优先 CUDA Graph、单步小 engine、专用 kernel(或融合 decoder)
  • 停止条件 / 特殊 token(若 LLM 段含 CoT)须在编排层 显式定义,不能照搬 chat EOS

3.7 评测与上线

阶段 内容
离线 benchmark 延迟分 stage、显存峰值、功耗
任务 eval 机器人 benchmark、ASR WER、LLM 基准
Manifest 归档 checkpoint 版本、quant、engine、TRT/NPU 版本、精度结果
OTA engine + sidecar 分包;export 图稳定可回归

4. 按模型类型的流程差异

类型 Stage 数 编译重点 Runtime 重点
纯 LLM 1 双 profile;Linear KV 容量 Prefill + decode 循环;采样
VLM 2(visual + llm) 变长 image token;共享 workspace 多 engine 串行;MRoPE 等
VLA 3+(vit / llm / denoise) denoise 静态 shape;KV I/O 对齐 Orchestrator + denoise×N
MoE LLM 1(含 MoE 层) 专家权重 layout;prefill/decode MoE kernel 路由 + 分组 GEMM

5. 端到端检查清单

text 复制代码
□ Checkpoint 与训练推理语义一致(dtype、norm、tokenizer)
□ 量化 metadata 与 compile/runtime 对齐(含 repack)
□ 每 stage ONNX I/O 名称/shape 与 Orchestrator 契约一致
□ LLM build:context + generation 双 profile(若含 decode)
□ max_kv / max_seq 与 product 规格一致
□ 编译与运行环境 TensorRT(或等价工具链)版本一致
□ 逐 stage 数值对拍通过
□ 全链路 latency:denoise×N 单独达标
□ 显存:权重 + KV + max(workspace) 低于设备上限
□ Manifest 记录血缘,便于 OTA 回滚

6. 文档说明

本文自成体系,覆盖端侧 LLM/VLM/VLA 从准备、量化、导出、编译、验证到 Runtime 的通用流程,并在各节附录中对照 TensorRT-Edge-LLM、model_optimizer、Chamleon 三项目实现差异。代码路径以各仓库内 tensorrt_edgellm/model_optimizer/chameleon/ 为准。