共计 2793 个字符,预计需要花费 7 分钟才能阅读完成。
背景痛点:为什么需要 TensorRT?
在实时视频分析、自动驾驶等延迟敏感场景中,直接用 PyTorch 或 TensorFlow 原生框架推理会遇到明显瓶颈:

- 计算图解释开销大(每次推理都要解析网络结构)
- 缺乏针对 NVIDIA GPU 的指令级优化
- 显存利用率低(框架本身占用过多资源)
实测 PyTorch 直接运行 ResNet50,在 T4 显卡上 batch_size= 1 时延迟高达 15ms,而业务需求通常要求 <5ms。
技术选型:为什么是 TensorRT?
横向对比主流推理加速方案:
- TensorFlow Lite
- 优势:移动端支持好,Android 生态完善
-
劣势:GPU delegate 功能有限,无法发挥 CUDA 核心能力
-
OpenVINO
- 优势:Intel CPU 优化极致,支持异构计算
-
劣势:对 NVIDIA 显卡优化不如 TensorRT 深入
-
TensorRT
- 杀手锏:层融合(Layer Fusion)、内核自动调优(Kernel Auto-Tuning)
- 实测同硬件下比原生框架快 3 - 8 倍
完整实现路径
第一步:模型导出为 ONNX
PyTorch 模型导出关键参数(以 ResNet50 为例):
torch.onnx.export(
model,
dummy_input,
"resnet50.onnx",
opset_version=13, # 必须 >=11
input_names=["input"],
output_names=["output"],
dynamic_axes={"input": {0: "batch"}, # 支持动态 batch
"output": {0: "batch"}
}
)
常见坑点:
- 遇到不支持的算子时,用
torch.nn.functional替代 - 导出后立即用
onnxruntime验证模型正确性
第二步:生成 TRT 引擎
推荐使用官方 trtexec 工具(已包含在 TensorRT 安装包中):
trtexec --onnx=resnet50.onnx \
--saveEngine=resnet50.trt \
--fp16 \
--workspace=2048 \
--minShapes=input:1x3x224x224 \
--optShapes=input:8x3x224x224 \
--maxShapes=input:32x3x224x224
参数说明:
--fp16:启用 FP16 量化--workspace:显存工作区大小(MB)min/opt/maxShapes:动态 shape 配置
第三步:C++ 加载引擎
核心代码结构(完整示例见后文):
// 初始化运行时
nvinfer1::IRuntime* runtime = nvinfer1::createInferRuntime(logger);
// 反序列化引擎
std::ifstream engineFile("resnet50.trt", std::ios::binary);
engineFile.seekg(0, std::ios::end);
size_t engineSize = engineFile.tellg();
engineFile.seekg(0, std::ios::beg);
std::vector<char> engineData(engineSize);
engineFile.read(engineData.data(), engineSize);
nvinfer1::ICudaEngine* engine =
runtime->deserializeCudaEngine(engineData.data(), engineSize);
深度优化技巧
量化方案对比
| 精度 | 延迟(ms) | 显存占用(MB) | 精度损失(%) |
|---|---|---|---|
| FP32 | 6.2 | 1200 | 0 |
| FP16 | 3.1 | 600 | <0.5 |
| INT8 | 1.8 | 300 | 1-2 |
INT8 量化需要校准集(约 500 张图片):
// 构建校准器
nvinfer1::IInt8Calibrator* calibrator =
new MyCalibrator(calibData, batchSize);
// 构建配置
builder->setInt8Mode(true);
builder->setInt8Calibrator(calibrator);
动态 Batch 处理
推荐方式:
- 构建时设置多个 profile
- 推理时根据实际 batch 选择最优 profile
auto profile = builder->createOptimizationProfile();
profile->setDimensions(
"input",
nvinfer1::OptProfileSelector::kMIN,
nvinfer1::Dims4(1,3,224,224));
// ... 设置 OPT/MAX 维度
config->addOptimizationProfile(profile);
避坑指南
内存泄漏检测
结合 Valgrind 和 NVTX 标记:
valgrind --tool=memcheck \
--leak-check=full \
--show-leak-kinds=all \
--track-origins=yes \
./your_inference_app
在代码中标记关键区域:
#include <nvtx3/nvToolsExt.h>
nvtxRangePushA("create_engine");
// 创建引擎代码...
nvtxRangePop();
多线程安全
每个线程需要独立的 CUDA 上下文:
class ThreadSafeEngine {
public:
void infer() {cudaSetDevice(deviceId);
thread_local std::unique_ptr<nvinfer1::IExecutionContext> ctx(engine->createExecutionContext());
// 推理代码...
}
private:
nvinfer1::ICudaEngine* engine;
};
性能验证
基准测试脚本要点:
- 预热(Warm Up)运行 100 次
- 统计 1000 次推理的指标
import numpy as np
latencies = []
for _ in range(1000):
start = time.time()
trt_model(inputs)
latencies.append(time.time() - start)
print(f"P99 延迟: {np.percentile(latencies, 99)*1000:.2f}ms")
print(f"吞吐量: {1000/np.sum(latencies):.2f}FPS")
开放问题
INT8 量化在实际项目中需要权衡:
– 业务能容忍多大精度损失?
– 是否有领域特定的校准方法?(如人脸识别可用 LFW 数据集校准)
建议方案:
1. 对分类任务,Top- 5 准确率下降 <3% 可接受
2. 检测 / 分割任务需逐层分析敏感度
完整代码示例见 GitHub 仓库:[示例链接]
正文完
