3. TensorRT基础概念
在自动驾驶模型部署中,TensorRT 并不是一个“把 ONNX 丢进去就出结果”的黑盒。它把一次部署拆成若干职责明确的对象:Builder 负责构建与优化,Network Definition 描述计算图,ONNX 解析器把外部模型翻译成 TensorRT 网络,Engine 是序列化后的优化产物,Runtime 负责反序列化与资源管理,ExecutionContext 才是真正执行推理的上下文。理解这条对象链,是后续做 INT8 校准、动态 Shape、显存复用和多流并发的前提。
一、核心对象与职责边界
TensorRT 的部署流程可以概括为“构建期”和“运行期”两个阶段。构建期通常离线完成,耗时较长;运行期要求低延迟、可重复、可并发。
- Builder:构建器,负责创建 Network、配置 BuilderConfig、设置精度与显存上限,并调用 buildSerializedNetwork 生成序列化 Engine。
- Network Definition:计算图定义,包含输入输出张量、层、权重和动态 Shape 约束。它只描述“算什么”,不负责“怎么跑”。
- ONNX Parser:把 ONNX 的节点、初始化和算子属性映射为 TensorRT 层。遇到不支持的算子时,需要插件或回退。
- Engine:优化后的推理计划,包含层融合、内核选择、显存布局和序列化权重。Engine 与具体 GPU 架构、TensorRT 版本强相关。
- Runtime:运行期入口,负责反序列化 Engine、创建 ExecutionContext,并管理设备内存。
- ExecutionContext:一次推理的实际执行环境,绑定输入输出绑定地址、流和动态 Shape 的具体取值。同一 Engine 可创建多个 Context 实现并发。
运行期:Serialized Engine → Runtime → Engine → ExecutionContext → enqueueV3 / executeV2
二、ONNX 解析与序列化机制
ONNX 解析器的工作不是简单复制节点,而是做算子映射、常量折叠、Shape 推断和部分图优化。解析完成后,Network 中的层会经过 Builder 的优化器:层融合、精度选择、内核自动调优、显存复用。最终 Engine 被序列化为一个二进制 blob,可以落盘为 .engine 或 .plan 文件。
# 典型构建与序列化流程(Python 伪代码)
import tensorrt as trt
logger = trt.Logger(trt.Logger.WARNING)
builder = trt.Builder(logger)
network = builder.create_network(
1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH))
parser = trt.OnnxParser(network, logger)
with open("model.onnx", "rb") as f:
assert parser.parse(f.read())
config = builder.create_builder_config()
config.set_memory_pool_limit(trt.MemoryPoolType.WORKSPACE, 1 << 30)
config.set_flag(trt.BuilderFlag.FP16)
serialized_engine = builder.build_serialized_network(network, config)
with open("model.engine", "wb") as f:
f.write(serialized_engine)
运行期则相反:先反序列化,再创建 Context。注意 Engine 不能跨平台、跨 TensorRT 大版本随意复用,否则会出现反序列化失败或精度异常。
runtime = trt.Runtime(logger)
with open("model.engine", "rb") as f:
engine = runtime.deserialize_cuda_engine(f.read())
context = engine.create_execution_context()
context.set_input_shape("images", (1, 3, 640, 640))
context.set_tensor_address("images", d_input)
context.set_tensor_address("output", d_output)
context.execute_async_v3(stream_handle)
三、对象关系与数据流
下图展示从 ONNX 到推理执行的完整对象链。构建期与运行期以序列化 Engine 为分界:左侧是离线优化,右侧是在线执行。ExecutionContext 是唯一可以“多实例”的对象,因此多路摄像头并发时,通常共享一个 Engine,为每条流创建独立 Context。
四、典型场景:自动驾驶多路推理
以 BEV 感知模型为例,构建期在服务器上完成:导出 ONNX,设置 EXPLICIT_BATCH,开启 FP16 或 INT8,校准集准备 500 张代表性图像,构建出 engine 文件。运行期在车端 Orin 上加载 engine,为 6 路摄像头创建 6 个 ExecutionContext,每个 Context 绑定独立的输入输出显存和 CUDA Stream,实现流水线并发。
| 对象 | 生命周期 | 是否可多实例 | 自动驾驶中的典型用法 |
|---|---|---|---|
| Builder | 构建期 | 否 | 离线构建 engine,设置精度与 workspace |
| Network | 构建期 | 否 | 承载 ONNX 解析后的计算图 |
| Engine | 运行期常驻 | 否(可共享) | 车端加载一次,多路共享 |
| ExecutionContext | 运行期 | 是 | 每路摄像头一个,独立绑定与流 |
| Runtime | 运行期 | 否 | 反序列化 engine,创建 context |
五、常见误区与复盘
误区一:把 Engine 当模型文件随意拷贝。Engine 与 GPU 架构、TensorRT 版本、驱动版本强绑定。在 A100 上构建的 engine 拿到 Orin 上可能直接反序列化失败。
误区二:一个 Context 跑多路。Context 内部保存了绑定地址和动态 Shape 状态,多线程共用同一 Context 会导致数据竞争和结果错乱。正确做法是每路独立 Context。
误区三:忽略动态 Shape 的 profile。ONNX 中动态维度必须在 Builder 阶段设置 OptimizationProfile,否则运行期 set_input_shape 会失败。
复盘建议:把构建期和运行期严格分离。构建脚本记录 TensorRT 版本、GPU 型号、精度标志和校准集哈希;运行期只做反序列化和 Context 管理。这样当模型更新时,只需重新构建 engine,车端逻辑无需改动。
掌握 Builder、Network、Parser、Engine、Runtime、ExecutionContext 这条对象链,就掌握了 TensorRT 部署的骨架。后续的 INT8 校准、动态 Shape、插件开发和性能调优,都是在这条链的某个环节上做文章。