第 9 章 部署管线:ORT / TensorRT / OpenVINO
第 9 章 部署管线:ORT / TensorRT / OpenVINO
量化算法写完只是第一步。真正的战场是部署:把量化后的模型送进推理引擎,在目标硬件上拿到真实的加速。这一章是第 6 章"量化通路"的续篇——第 6 章把模型量化好,这一章把量化模型跑起来、跑得快、还能打包交付。
原书仓库 ch9/ 目录:ch9_ort_optimum_deployment.py、ch9_tensorrt_engines.py、ch9_openvino_deployment.py、ch9_packaging_serving.py。三个引擎、一条打包流水线。
9.1 关键前置知识:执行提供方(Execution Provider)
ONNX Runtime 有个核心概念叫 Execution Provider(EP,执行提供方)——同一个 ONNX 模型,可以选择不同的底层执行引擎。这一章的主线之一,就是验证"运行库 + EP 的组合决定了实际调度到哪个内核"。
# 来自 ch9/ch9_ort_optimum_deployment.py(结构)
def available_execution_providers(ort):
# 列出当前 ONNX Runtime 支持的所有 EP
...
def time_session(ort, model_path, providers, ...):
# 用指定 EP 创建 session,测延迟
...
def _try_preload_trt_libs():
# TensorRT EP 需要预加载动态库,否则报错
...ch9_ort_optimum_deployment.py 用 BERT 演示了同一模型在 CPU / CUDA / TensorRT 三种 EP 下的行为:
- CPU EP:默认,任何机器都能跑,INT8 内核依赖硬件指令(AVX2/AVX-512/VNNI,第 10 章展开)。
- CUDA EP:GPU 上的通用加速。
- TensorRT EP:调用 NVIDIA TensorRT 的深度优化引擎,通常最快,但需要模型是 TensorRT 能优化的图结构(QDQ 图),且需要预加载 TensorRT 动态库(
_try_preload_trt_libs)。
脚本里的 _produce_qdq_bert_int8 会在没有现成 INT8 模型时,用校准器(_BertCalibReader)现场生成一个带 QDQ 节点的 INT8 BERT——这串起了第 4 章的校准和第 6 章的 ONNX 通路。
9.2 TensorRT:真正的引擎构建
ch9_tensorrt_engines.py 深入了 NVIDIA TensorRT 的内部。TensorRT 和 ONNX Runtime 的 EP 不同——它不是"解释执行" ONNX 图,而是把模型编译成高度优化的引擎(engine)。
# 来自 ch9/ch9_tensorrt_engines.py(核心)
def build_trt_engine(trt, builder, logger, onnx_path, ...):
# 1. 解析 ONNX → TensorRT 网络
# 2. 设置精度(FP32 / FP16 / INT8)
# 3. INT8 需要校准器(_Int8EntropyCalib,熵校准,呼应第 4 章)
# 4. builder 优化网络 → 序列化成 engine
...
def bench_engine(engine_path, ...):
# 加载引擎,测延迟
...
def inspect_engine_layers(engine_path):
# 检查引擎里每一层实际跑在什么精度
...两个 TensorRT 的关键概念:
1. Implicit vs Explicit QDQ 图。
- Implicit(隐式):老式 API,你告诉 builder "用 INT8",它自己决定怎么量化。
- Explicit(显式):新式 API,模型图里已经带好了 QDQ 节点(第 6 章 ONNX 静态量化生成的),TensorRT 忠实执行这些节点的意图。现代部署几乎都用 Explicit QDQ——因为量化决策在 ONNX 阶段就由你的校准方法定好了,TensorRT 不自由发挥,行为更可预测。脚本里的
_strip_int32_dq处理了 QDQ 图里的一个坑(INT32 输入的 DQ 节点要特殊处理)。
2. INT8 校准器。
TensorRT 的 INT8 引擎在构建时需要校准数据(_Int8EntropyCalib)——这就是第 4 章熵校准在 TensorRT 世界的落地。校准数据决定了 scale,scale 决定了量化质量。
inspect_engine_layers 是一个很实用的调试工具:构建完引擎后,逐层检查它实际跑在 INT8 还是 FP16/FP32——有时候你以为全 INT8,实际某些层被 TensorRT 保留成 FP16,这会影响最终精度和速度。
9.3 OpenVINO:Intel 硅片上的部署
ch9_openvino_deployment.py 走的是 Intel 的推理栈 OpenVINO,展示了两种接入方式:
# 来自 ch9/ch9_openvino_deployment.py(核心)
def convert_onnx_to_ir(onnx_path, ir_xml_path, ...):
# ONNX → OpenVINO IR(中间表示),用 model optimizer
...
def quantize_with_nncf(calib_feeds, ...):
# 用 NNCF(Neural Network Compression Framework)做量化
# NNCF 是 Intel 的模型压缩库,支持 PTQ 和 QAT
...
def bench_ov_native(...):
# 方式一:纯 OpenVINO 运行时直接推理
...
def bench_ort_ov_ep(...):
# 方式二:ONNX Runtime 的 OpenVINO EP(用 ORT 接口调 OpenVINO)
...两条路径的本质区别:
- 原生 OpenVINO(方式一):模型转成 OpenVINO IR 后,用 OpenVINO 自己的 API 推理。对 Intel CPU/iGPU/NPU 的优化最深。
- ORT + OpenVINO EP(方式二):你写 ORT 的代码,底层调度到 OpenVINO。适合"已经在用 ORT,想换个执行后端"的场景,接口统一。
inspect_runtime_model 还能把编译后的 OpenVINO 模型逐算子打印出来——和 9.2 的 inspect_engine_layers 一样,都是为了验证"到底跑没跑在你以为的引擎上"。这是全书反复强调的工程态度:不轻信宣称,用工具看实际行为。
9.4 打包与交付:manifest、Triton、来源元数据
ch9_packaging_serving.py 是这一章最"生产"的脚本。它把前面产出的所有量化产物(ORT/OpenVINO/TensorRT 各一套)打包成可交付的制品(artifact),并附上三样东西:
# 来自 ch9/ch9_packaging_serving.py(核心)
class ArtifactSet:
# 一个模型的所有量化变体 + 配套文件
...
def hash_file(path): # 计算校验和,保证制品可追溯
...1. manifest.json:部署契约。
每个制品旁边生成一个 manifest,记录:
- 输入/输出签名与 dtype;
- 量化配方(scheme、校准方法、量化了哪些算子、排除了哪些、校准集指纹);
- 构建来源(工具版本、宿主机、时间戳);
- 运行时与硬件要求。
有了 manifest,别人拿到制品就知道"这个模型是怎么量化出来的、该用什么环境跑",避免"跑出来的结果和文档对不上"的灾难。
2. config.pbtxt:Triton 模型仓库配置。
为每个后端(onnxruntime / openvino / tensorrt)生成 NVIDIA Triton Inference Server 的模型仓库配置。Triton 是生产级推理服务器,config.pbtxt 声明模型的输入输出、动态 batch 等。这等于把第 9 章的量化模型直接接进了生产 serving 栈。
3. 兼容性矩阵图。 记录"哪个制品 + 哪个运行时 + 哪个硬件"的组合被实际验证过、跑出了什么性能。这是给团队/客户看的交付说明书。
9.5 部署选型的决策框架
graph LR
A[量化后的 ONNX 模型] --> B{目标硬件?}
B -->|NVIDIA GPU| C[TensorRT 引擎]
B -->|Intel CPU/iGPU/NPU| D[OpenVINO]
B -->|通用/多平台| E[ONNX Runtime + EP]
C --> F[打包: manifest + config.pbtxt]
D --> F
E --> F
F --> G[Triton / 生产服务]- NVIDIA GPU:TensorRT(显式 QDQ 图 + 熵校准)拿最大加速。
- Intel 硅片:OpenVINO 原生,或 ORT + OpenVINO EP 保持接口统一。
- 通用/多平台:ONNX Runtime + 合适的 EP,代码一套、EP 可换。
- 无论哪条路:制品必须带 manifest 和来源元数据,验证"实际跑在哪个引擎上",用 Triton 之类的生产服务器接进服务。
下一章转向一个被严重低估的推理场景——CPU 上的 LLM 服务。第 10 章把 GGUF 文件格式逐字节拆开,看 llama.cpp 如何让普通人用 CPU 跑 7B 模型。
作者: itech001 来源: 公众号:AI人工智能时代(the-ai-era) 网站: https://www.theaiera.top/ 关注每日最新AI新闻和技术博客,主页有更多的文章的AI 技术参考:https://www.theaiera.top
本文首发于 AI人工智能时代,转载请注明出处。