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 实现并发。
构建期:ONNX → Parser → Network → Builder → Serialized Engine
运行期: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。

构建期(离线) 运行期(在线) ONNX 模型 .onnx ONNX Parser 算子映射 / Shape 推断 Network 计算图定义 Builder 优化 / 精度 / 内核选择 Serialized Engine .engine / .plan 二进制 Runtime 反序列化 / 资源管理 Engine 优化后的推理计划 ExecutionContext 绑定地址 / 动态 Shape CUDA Stream 异步执行 多 Context 并发 共享 Engine,独立输入输出与流 序列化 Engine 是构建期与运行期的分界

四、典型场景:自动驾驶多路推理

以 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、插件开发和性能调优,都是在这条链的某个环节上做文章。