4、模型转换入门:使用trtexec工具转换ONNX模型、TensorRT的精度模式(FP32/FP16/INT8)
好,咱们今天聊聊模型转换。说实话,这是很多刚接触TensorRT的同学最容易卡住的一步。你想想看,辛辛苦苦训练好的模型,怎么才能让它跑在嵌入式设备上?答案就是——转成TensorRT能吃的格式。
我个人习惯用trtexec这个工具。它虽然是个命令行工具,但功能非常强大。说白了,它就是TensorRT官方给我们的一把瑞士军刀,既能做模型转换,又能做性能测试。
4.1 准备工作:拿到你的ONNX模型
在开始之前,你得先有个ONNX模型。我建议你从PyTorch或者TensorFlow导出ONNX时,注意以下几点:
- 固定输入尺寸:虽然ONNX支持动态尺寸,但TensorRT对固定尺寸的优化更好。我在项目中遇到过,动态尺寸的模型在Jetson Nano上推理速度慢了将近一倍。
- 算子兼容性:不是所有ONNX算子TensorRT都支持。嗯,这里要注意,像
Resize、ScatterND这些算子,在旧版TensorRT里可能有问题。 - 简化模型:用
onnx-simplifier把模型过一遍,去掉那些冗余的节点。
opset_version设为11或13,这两个版本在TensorRT里兼容性最好。
4.2 初识trtexec:一行命令搞定转换
trtexec的使用方式非常简单。最基本的命令长这样:
trtexec --onnx=model.onnx --saveEngine=model.engine
就这么一行,就能把ONNX模型转成TensorRT的引擎文件。但实际项目中,我们很少用这么简单的命令。为什么?因为你需要指定精度模式。
4.3 精度模式:FP32、FP16、INT8怎么选?
这是面试时经常被问到的问题。我直接给你一张表,一目了然:
| 精度模式 | 存储大小 | 推理速度 | 精度损失 | 适用场景 |
|---|---|---|---|---|
| FP32 | 基准(100%) | 基准(1x) | 无 | 精度要求极高的场景 |
| FP16 | 约50% | 约1.5~2x | 几乎无感 | 大多数嵌入式场景 |
| INT8 | 约25% | 约2~4x | 1%~3% | 对带宽敏感、精度容忍度高的场景 |
你可能会问:「那我是不是直接上INT8就完事了?」别急,听我说完。
4.4 FP32模式:最稳妥的选择
FP32模式不需要任何额外参数。直接用:
trtexec --onnx=model.onnx --saveEngine=model_fp32.engine --fp32
其实--fp32是默认的,不写也行。但我个人习惯还是加上,显得专业嘛。
FP32的好处是零精度损失。如果你的模型在GPU上跑FP32精度是99.2%,转成TensorRT后还是99.2%。我在做医疗影像项目时,客户要求精度不能掉0.1%,那就只能用FP32。
4.5 FP16模式:嵌入式平台的黄金选择
FP16是我用得最多的模式。命令也很简单:
trtexec --onnx=model.onnx --saveEngine=model_fp16.engine --fp16
你想想看,在Jetson Nano上,FP16比FP32快了将近一倍,但精度几乎看不出差别。我做过一个分类模型,FP32精度是92.3%,FP16是92.1%,只掉了0.2%。这点损失换来的速度提升,太值了。
4.6 INT8模式:性能怪兽,但需要校准
INT8模式就有点讲究了。它需要你提供校准数据:
trtexec --onnx=model.onnx --saveEngine=model_int8.engine --int8 --calib=calibration_data
校准数据是什么?说白了,就是一小批有代表性的输入数据。我建议你用验证集里的几百张图片就够了。注意,校准数据要覆盖模型可能遇到的各种情况,不能全是同一类图片。
我曾经踩过一个坑:用全黑图片做校准,结果模型推理结果全乱了。后来才发现,校准数据分布太偏,导致量化参数算错了。
4.7 实战:三步完成模型转换
好,咱们来走一遍完整的流程。假设你有一个resnet50.onnx模型:
- 第一步:检查模型
trtexec --onnx=resnet50.onnx --shapes=input:1x3x224x224 --verbose
这个命令会检查ONNX模型能不能被TensorRT解析。如果报错,别慌,看日志里提示哪个算子不支持。
- 第二步:生成FP16引擎
trtexec --onnx=resnet50.onnx --saveEngine=resnet50_fp16.engine --fp16 --workspace=1024
--workspace参数指定了TensorRT在构建引擎时能用的最大显存,单位是MB。我一般设1024,够用。
- 第三步:验证引擎
trtexec --loadEngine=resnet50_fp16.engine --shapes=input:1x3x224x224
这个命令会加载引擎并跑一次推理,看看有没有报错。同时它还会输出推理延迟,你可以看看是不是达到了预期。
4.8 常见问题与避坑指南
我整理了几个新手最容易遇到的问题:
- 「明明转成功了,但推理结果全是错的」:这通常是输入输出的数据排布问题。检查一下你的输入是NCHW还是NHWC,TensorRT默认用NCHW。
- 「转换时提示显存不足」:增大
--workspace参数,或者换个更大的GPU来转。转完的引擎文件可以在小显存设备上跑。 - 「INT8模式精度掉得厉害」:试试用更多的校准数据,或者改用
--int8 --fp16混合模式,让TensorRT自己决定哪些层用INT8。
好了,模型转换这块就聊到这儿。下一章咱们会深入讲讲如何用C++ API加载和运行这些引擎文件。到时候你会发现,trtexec只是开胃菜,真正的硬核内容还在后面。