TensorRT 到底是什么?—— 一个推理引擎的自白

说实话,刚接触 TensorRT 那会儿,我也挺困惑的。它跟 PyTorch、TensorFlow 这些训练框架到底啥关系?是不是又一个深度学习框架?

嗯,这里要澄清一下。TensorRT 不是训练框架,它是个推理优化引擎。说白了,就是把你训练好的模型,拿来“精加工”一下,让它跑得更快、占内存更少。

我习惯这么理解:训练框架是“造车厂”,TensorRT 是“改装车间”。车造好了,你要上赛道(部署到工业现场),就得找改装车间调教一下,把不必要的零件拆掉,发动机调得更猛。

推理引擎 vs 训练框架:到底差在哪?

很多同学问我:“我直接用 PyTorch 推理不行吗?干嘛非要折腾 TensorRT?”

行,当然行。但你在工业现场试试看?

我去年在一个质检项目里,客户要求检测速度 30 FPS,用 PyTorch 直接推理,一张 2048×2048 的 PCB 图像要跑 80 毫秒,死活达不到。换成 TensorRT 优化后,直接压到 25 毫秒。这就是差距。

来看看它们核心的区别:

对比维度 训练框架(PyTorch/TF) 推理引擎(TensorRT)
核心目标 灵活定义网络、计算梯度 极致加速前向推理
支持算子 几百个,甚至自定义算子 精选高频算子,深度优化
动态性 支持动态图,随时改结构 静态图为主,图结构固定
精度控制 默认 FP32,训练必须高精度 FP32/FP16/INT8 可选
部署形态 依赖 Python 运行时,环境重 轻量引擎文件,C++/Python 均可
典型场景 模型研发、实验调参 工业产线、边缘设备、车端

一句话总结:训练框架要“灵活”,TensorRT 要“快”。两者不是替代关系,是上下游关系。

核心三件套:Builder、Engine、Context

TensorRT 的工作流程,说白了就是三个角色在干活。我刚开始学的时候,老把 Engine 和 Context 搞混,后来踩了坑才明白。

1. Builder(构建器)—— 总设计师

Builder 负责把你的模型“翻译”成 TensorRT 能理解的东西,然后做各种优化决策。

  • 网络定义:把 ONNX 或自定义网络解析成 TensorRT 的 Network 对象
  • 配置策略:设置工作空间大小、精度模式、动态形状范围
  • 编译优化:执行层融合、内存复用、内核自动调优

我记得第一次用 Builder 时,忘了设置最大工作空间,结果 INT8 校准一直报 OOM。后来养成习惯,上来先设 setMemoryPoolLimit。

2. Engine(引擎)—— 编译好的“可执行文件”

Builder 优化完,产出的就是 Engine。你可以把它理解成一个高度优化的、序列化后的推理程序。

  • 序列化:可以保存成 .engine 或 .plan 文件,下次直接加载
  • 平台绑定:Engine 跟 GPU 架构绑定(比如 A100 的 Engine 不能在 T4 上用)
  • 不可变:一旦生成,网络结构就固定了,不能再改

避坑指南:我曾经在开发机上用 RTX 3090 生成 Engine,部署到产线的 RTX 3060 上直接报错。因为 Compute Capability 不一样。记住:Engine 在哪台 GPU 上生成,最好就在同架构的 GPU 上跑。

3. Context(执行上下文)—— 真正的“干活的人”

Engine 是蓝图,Context 才是真正执行推理的实例。一个 Engine 可以创建多个 Context,实现多路并行推理。

  • 执行推理:调用 enqueueV2() 或 executeV2() 跑前向
  • 绑定输入输出:通过 Binding Index 把 GPU 显存地址传进去
  • 管理中间结果:每个 Context 有自己的工作空间,互不干扰

这里有个细节:一个 Engine 创建多个 Context 时,显存是共享的。我有个项目需要同时处理 4 路相机,一开始每个流都单独创建 Engine,显存直接爆了。后来改成 1 个 Engine + 4 个 Context,稳得很。

精度模式:FP32、FP16、INT8 怎么选?

这是工业检测里最纠结的问题。精度和速度,就像鱼和熊掌。我直接说结论:

精度模式 存储/计算位宽 理论加速比 精度损失 工业检测适用性
FP32 32-bit 1×(基准) 无 高精度缺陷检测(如晶圆缺陷)
FP16 16-bit 1.5× ~ 2× 极小(通常 <0.1% mAP) 90% 的工业场景首选
INT8 8-bit 3× ~ 4× 中等(需校准数据集) 对速度要求极高、精度容忍度高的场景

FP32:保底方案

如果你对精度零容忍,比如检测 0.1mm 的划痕,那就老老实实用 FP32。但说实话,现在支持 Tensor Core 的 GPU,FP16 几乎无损,我很少用纯 FP32 部署了。

FP16:我的首选

我个人习惯,工业检测项目上来先试 FP16。为什么?

  • 精度损失微乎其微,肉眼几乎看不出来
  • 速度提升明显,尤其是有 Tensor Core 的 GPU(Turing 架构以上)
  • 不需要额外校准数据,直接转换就行

我做过一个手机中框划痕检测,YOLOv5s 模型,FP32 推理 45 FPS,FP16 直接干到 78 FPS,mAP 只掉了 0.3%。客户根本看不出来。

INT8:双刃剑

INT8 加速是真猛,但坑也是真多。

我的经验:INT8 必须做校准(Calibration),而且校准数据集要跟实际产线数据分布一致。我曾经用公开数据集做校准,到产线上一测,漏检率直接翻倍。后来老老实实从产线抽了 1000 张图做校准,才把精度拉回来。

INT8 适合的场景:

  • 检测目标比较大(比如 50×50 像素以上)
  • 对召回率要求不是极端苛刻
  • GPU 算力有限,比如 Jetson 边缘设备

一张图看懂 TensorRT 工作流

说了这么多,不如画个图直观。下面是我自己总结的 TensorRT 核心流程:

TensorRT 核心工作流与组件关系 训练模型 (ONNX/PyTorch) Builder(构建器) • 解析网络结构 • 设置精度/工作空间 • 层融合 + 内核调优 Engine(引擎) • 序列化 .engine 文件 • 平台绑定,结构固定 Context(执行上下文) • 执行 enqueueV2() 推理 精度模式选择 ▸ FP32:无损,基准速度 ▸ FP16:推荐,几乎无损 ▸ INT8:需校准,加速最大 ⚠ 工业检测首选 FP16 ⚠ INT8 需产线数据校准 关键特性 ▸ 层融合(Layer Fusion) ▸ 内存复用(Memory Reuse) ▸ 内核自动调优(Auto Tuning) ▸ 量化校准(INT8 Calib) ▸ 动态形状(Dynamic Shape)

总结一下

TensorRT 不是个黑盒子,它的逻辑其实很清晰:

  • Builder 负责“编译优化”,把模型变成高效的引擎
  • Engine 是“编译结果”,可以序列化保存和加载
  • Context 是“执行者”,真正跑推理
  • 精度选择 是工程权衡,工业检测我推荐 FP16 起步

嗯,这一章的概念比较多,但都是后面实战的基础。你想想看,如果连 Builder 和 Context 都分不清,后面做 INT8 量化校准的时候肯定要懵。我当初就是吃了这个亏,花了一周才把校准流程跑通。