RTX 2080 Ti上ONNX与TensorRT的精度和性能对比

本文由AI辅助编写

同一个YOLOv8检测模型导出为ONNX和TensorRTEngine后,在RTX 2080 Ti上比较了FP32、FP16和INT8。结果基本确认了TensorRT的速度优势,但也暴露出两个不能忽略的问题:INT8Engine的精度损失较大,ONNX INT8在两套测试中的耗时相差悬殊。

这组数据只适用于当时的模型和环境。测试使用CUDA11.8、cuDNN8.9.7和ONNXRuntimeGPU1.16.3,TensorRT版本、输入尺寸和完整硬件状态没有记录,因此不适合拿这些数字预测其他机器的性能。

单图推理耗时

性能脚本对同一张图片预热10轮,再执行100轮。表中的FPS是按平均推理耗时换算的数值,不是包含图片读取、预处理和后处理的端到端吞吐量。

格式 加载耗时(ms) 平均耗时(ms) P50(ms) P95(ms) P99(ms) 换算FPS
ONNX FP32 47.08 10.80 9.05 18.07 24.07 92.58
ONNX FP16 49.74 11.30 9.78 19.77 23.76 88.46
ONNX INT8 40.28 13.33 12.14 21.54 27.04 75.02
Engine FP32 67.73 7.89 6.51 15.48 17.23 126.79
Engine FP16 47.65 5.51 4.36 14.01 15.37 181.59
Engine INT8 39.42 4.21 3.92 5.63 7.89 237.44

在这次单图测试中,三个TensorRTEngine都比对应精度的ONNX模型快。FP32、FP16和INT8的平均耗时分别下降26.9%、51.2%和68.4%。这个百分比描述的是延迟下降;如果用吞吐量比值表达,则分别约为1.37倍、2.05倍和3.17倍,两种口径不能混用。

ONNX的结果并没有随着数值精度降低而变快,INT8反而最慢。仅凭这组输出不能把原因归结为ONNXRuntime的量化开销:还需要检查量化方式、节点分配、CUDAExecutionProvider是否完整接管计算,以及基准脚本是否包含额外的数据转换。

完整数据集上的精度

精度测试使用同一套图片和标签,并记录mAP、Precision、Recall与平均推理耗时。数据集规模和类别分布没有留在记录里,因此这里看同一测试集内的相对变化,不把指标外推到其他数据。

模型 mAP@0.5 mAP@0.5:0.95 Precision Recall F1 推理(ms) 换算FPS
PyTorch FP32 0.9070 0.6080 0.8962 0.9394 0.9173 10.2 98.3
ONNX FP32 0.9070 0.6083 0.8966 0.9392 0.9174 12.3 81.2
ONNX FP16 0.9069 0.6079 0.8967 0.9389 0.9173 13.4 74.6
ONNX INT8 0.5687 0.2509 0.5098 0.8854 0.6470 91.4 10.9
Engine FP32 0.9070 0.6083 0.8966 0.9392 0.9174 8.7 115.4
Engine FP16 0.9069 0.6084 0.8969 0.9391 0.9175 6.0 165.4
Engine INT8 0.7480 0.5036 0.9782 0.7783 0.8668 5.5 180.2

FP32和FP16的精度几乎没有变化,TensorRTEngine的耗时更低。其中FP16Engine相对PyTorch基线降低了41.2%的推理耗时,mAP和F1仍在同一水平,是这组模型里更稳妥的部署选择。

INT8Engine虽然最快,但代价很明显。它的mAP@0.5比PyTorch基线低0.1590,Recall低0.1611;Precision升至0.9782,并不能说明模型整体更准,而是漏检增加后留下的预测更保守。对检测任务来说,这种变化不能只靠更高的FPS抵消。

ONNX INT8结果不能直接采用

ONNX INT8在单图测试中的平均耗时是13.33ms,在完整数据集测试中却变成91.4ms,同时精度也远低于其他格式。两次测试不是同一测量路径,差异已经大到不能当作普通波动处理。

重新导出后数据仍然异常,但当时没有继续定位到具体原因。因此这项结果只能标记为异常,不能据此得出“ONNX INT8天然更慢”或“ONNXRuntime不适合INT8”的结论。继续排查时至少需要固定以下条件:

  • 使用完全相同的输入尺寸、预处理和后处理;
  • 记录每个ExecutionProvider实际承接的节点,确认没有意外回退到CPU;
  • 分开统计模型推理、量化转换和数据复制耗时;
  • 保存量化方式、校准集、算子类型以及导出日志;
  • 在同一数据集上重复测试,并同时观察GPU利用率和显存占用。

基于现有数据,FP16Engine应作为优先选择。INT8Engine只有在重新校准并确认Recall下降可以接受后才值得采用,ONNX INT8则需要先把精度和耗时异常查清楚。