首页 / PyTorch 入门教程 / 推理加速:TensorRT 与量化部署概念

PyTorch 入门教程

推理加速:TensorRT 与量化部署概念

本教程共 60 篇 · 第 52 篇 · 更新于 2026-08-17 · 约 4 分钟阅读

PyTorchTensorRT推理加速量化PTQQAT模型部署

本节目标:了解推理优化的常用手段,理解 TensorRT 的优化思路与部署链路,认识量化(PTQ/QAT)的基本概念。

训练和推理是两码事

训练追求吞吐量:一次喂一堆数据,跑几天几夜没关系。推理(Inference)追求另外三样:延迟(Latency)要低、成本要省、设备要小。手机上分类一张图,用户最多等 100 毫秒。需求不同,优化手段也不同。

一条典型的部署链路长这样:

训练(PyTorch)
   ↓ 导出
ONNX / ExportedProgram
   ↓ 优化编译
TensorRT engine(GPU)/ ONNX Runtime(通用)
   ↓ 服务化
TorchServe / FastAPI / C++ 服务

优化手段归纳起来三招:图优化(算子融合、常量折叠)、低精度(FP16/INT8)、内核自动调优。NVIDIA 的 TensorRT 三招全占,这一章就围着它转。

先各自展开一点。图优化里最常见的是算子融合:把相邻几步计算合成一步,中间结果不再落显存。常量折叠则是把编译期就能算出来的部分提前算掉,比如归一化的均值和方差,训完就是常数,没必要每次推理都算一遍。低精度是把数值从 4 字节缩到 2 字节(FP16)甚至 1 字节(INT8),内存带宽是 GPU 推理的常见瓶颈,数据变小,搬运就快。内核自动调优则是同一个算子有多个实现版本,编译时挨个试跑,选最快的那个固定下来。

这三招之间不冲突,可以叠加使用。TensorRT 厉害之处就在于把这套流程封装得足够自动化。

TensorRT:NVIDIA 的推理引擎

TensorRT 是 NVIDIA 的推理优化器和运行时。它吃进 ONNX 模型(或 ExportedProgram),吐出「引擎」(engine),在 NVIDIA GPU 上跑得飞快。它的三板斧:

  1. 层融合:把 conv + BatchNorm + ReLU 这种三步连招合成一个内核。数据原来要在显存里进进出出三趟,融合后一趟搞定,带宽省了,延迟降了;
  2. 精度选择:FP32 太浪费,可以整体或逐层换成 FP16、INT8。INT8 算得快、带宽省,代价是精度略有损失;
  3. 内核自动调优:同一层卷积有好几种实现,TensorRT 挨个试,挑当前硬件上最快的。

关键代价:engine 绑定硬件。一块 GPU 上编译出来的 engine,换到另一型号可能跑不了。所以 engine 一般在部署现场生成,或按机器型号预生成好分发。

Note

层融合这件事,PyTorch 的 Inductor 也在做。区别在于 TensorRT 是 NVIDIA 的专用运行时,针对自家硬件优化得更深;而 Inductor 是通用编译后端,不挑厂商。

上手:trtexec 与 Python API

最省事的入口是命令行工具 trtexec(装 TensorRT 自带),一条命令把 ONNX 转成 engine:

trtexec --onnx=resnet50.onnx --saveEngine=resnet50.engine --fp16

--fp16 表示启用半精度。想开动态 batch,再加 --minShapes--optShapes--maxShapes 三个参数指定范围。

如果不用命令行,Python API 的完整流程是四步:建 logger、解析 ONNX 生成网络定义、用 builder 构建 engine、把 engine 序列化成文件。构建这一步最耗时,大模型可能要跑几十分钟——所以构建通常放在部署前的构建阶段,运行时只加载现成的 engine 文件:

import tensorrt as trt

logger = trt.Logger(trt.Logger.WARNING)
with open("resnet50.engine", "rb") as f, trt.Runtime(logger) as runtime:
    engine = runtime.deserialize_cuda_engine(f.read())
context = engine.create_execution_context()   # 拿到这个才能推理

推理时输入输出都待在 GPU 显存里。NumPy 数组要先 cuda.memcpy_htod 拷进显存,算完再 cuda.memcpy_dtoh 拷回来(PyCUDA 或 cuda-python 都能干)。这套「拷进、跑、拷出」的手续是 GPU 推理的通用姿势,ONNX Runtime 的 GPU provider 内部也是这么干的。

不想离开 PyTorch 生态的话,还有 Torch-TensorRT:torch_tensorrt.compile(model, inputs=[...], enabled_precisions={torch.float16}) 一行编译,体验和 torch.compile 类似。

量化:用精度换速度

模型参数默认 FP32 存储,一个数占 4 字节。量化(Quantization)就是把它们换成低位宽的表示,最常见的是 INT8(1 字节)。数据量缩到四分之一,带宽压力骤减;很多芯片还有专门的 INT8 计算单元,算得更快。省内存、提速度,代价是数值变粗,准确率可能掉一点。

按「什么时候量化」分三种:

  • PTQ(训练后量化,Post-Training Quantization):模型训完直接量化。用一小批校准数据(calibration data)跑一遍前向,统计各层激活的数值范围,定好缩放系数就完事。最省事,主流选择,适合精度冗余大的模型;
  • QAT(量化感知训练,Quantization-Aware Training):训练时就模拟量化误差,让模型学会「适应」INT8。精度最稳,但要重训一轮,成本高。对量化敏感的模型就得走这条;
  • 动态量化:只量化权重,激活值在推理时临时算范围。改动最小,适合 LSTM 这类权重占带宽、激活难量化的模型。

量化掉多少精度,跟模型和任务都有关系。图像分类这类任务对量化很宽容,掉零点几个百分点很正常;检测、分割这些精细任务就要小心了。好在决定不贵:先把 PTQ 跑出来实测一遍,不行再换 QAT,最多损失点时间。

Note

量化怎么做、精度掉了怎么救,下一章有专门展开。这里先混个脸熟——这套概念是全行业通用的,TensorRT、ONNX Runtime、PyTorch 原生量化工具用的都是同一套话术。

选择有个朴素的顺序:先试 PTQ,精度掉太多再上 QAT。

服务化:让模型变成 API

优化完的 engine 还得包装成服务才能被人调用。两条常见路:

  1. TorchServe:PyTorch 官方服务框架。用 torch-model-archiver 把模型和处理逻辑打包成 .mar 文件,一条命令起服务,自带版本管理和 A/B 测试;
  2. FastAPI 自建:自己写 REST 接口,把预处理、推理、后处理串在一个 handler 里。灵活可控,但并发、监控都要自己操心。

部署环境建议用 Docker 固化,CUDA 版本、依赖库全部锁死,避免「在我机器上明明好好的」的悲剧。上线之后还有两件事值得上心:性能监控和版本管理。延迟、吞吐量、显存占用这些指标接进 Prometheus 之类的监控系统,模型一退化立刻能发现;TorchServe 自带模型版本管理,新老版本可以 A/B 对比着切换,出问题随时回滚。这些是生产环境的日常功课,现在知道有这么回事就行。

小结

这一章把「模型怎么落地」的拼图拼齐了:导出得到标准格式,TensorRT 榨出硬件性能,量化在精度与速度之间做取舍,服务框架把模型变成 API。第九部分到此收尾。下一章开始,我们进入量化的深水区:PTQ 和 QAT 到底怎么做。