news 2026/9/18 7:13:08

SuperGradients YOLO-NAS 基准测试完整指南:从 ONNX 导出到 INT8 TensorRT 引擎与性能剖析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SuperGradients YOLO-NAS 基准测试完整指南:从 ONNX 导出到 INT8 TensorRT 引擎与性能剖析

SuperGradients YOLO-NAS 基准测试完整指南:从 ONNX 导出到 INT8 TensorRT 引擎与性能剖析

【免费下载链接】super-gradientsEasily train or fine-tune SOTA computer vision models with one open source training library. The home of Yolo-NAS.项目地址: https://gitcode.com/GitHub_Trending/su/super-gradients

导读

本文是围绕 SuperGradients 仓库中 BenchmarkingYoloNAS.md 展开的深度实战指南,核心解决一个典型痛点:在 RTX 4090 上跑 YOLO-NAS 只拿到 10 FPS 时,如何通过"正确的导出姿势"把量化模型编译成 INT8 TensorRT 引擎,从而真正发挥模型的推理潜力。读完本文,你将掌握三大能力:① 正确导出经 PTQ/QAT 量化后的 YOLO-NAS 到 ONNX(理解prep_model_for_conversion与 QARepVGG 分支融合的底层原理);② 使用trtexec构建 INT8 TensorRT 引擎并解读关键参数;③ 读懂trtexec基准输出中的吞吐量、端到端延迟、H2D/D2H 传输耗时,并据此定位性能瓶颈。

背景:为什么 YOLO-NAS 需要"正确"的基准测试

YOLO-NAS 是一个兼顾精度与效率的目标检测架构。要让它在资源受限的端侧设备(以及追求极致吞吐的云端 GPU)上发挥全部潜力,通常需要经过 后训练量化 PTQ 与量化感知训练 QAT 将模型压缩到 INT8 精度,而把量化模型导出为 INT8 TensorRT 引擎这一步至关重要——量化本身只是降低了模型体积和计算位宽,真正的高速推理发生在 TensorRT 编译生成的引擎上。

原文档开头的 TLDR 直言:"在 4090 上跑 YOLO-NAS 只有 10 FPS 感到被骗了?请仔细阅读本文!" 这正是本文的出发点:绝大多数性能不佳的案例,根源不在模型本身,而在于导出与编译流程不正确——例如没有融合 RepVGG 分支、没有携带量化节点就强行用--int8编译,导致精度暴跌或速度不升反降。

从源码结构看,SuperGradients 为模型导出提供了两套 API:一是本文重点涉及的trtexec命令行编译路线(对应 export_quantized_module_to_onnx 产出的 ONNX);二是更高层的model.export()一站式导出 API(详见 models_export.md),二者殊途同归,最终都需要经过 TensorRT 编译才能拿到真实性能数字。

Step 1:正确导出 YOLO-NAS 到 ONNX

把模型交给 TensorRT 之前,必须先确保 ONNX 图处于"可编译"状态。在导出前必须完成两件事,缺一不可。

1.1 调用prep_model_for_conversion融合 RepVGG 分支

第一件必做之事是调用model.prep_model_for_conversion。这是必须的操作,因为 YOLO-NAS 内部大量使用 QARepVGG 块(量化友好的 RepVGG 变体)。若不调用,多分支的 RepVGG 结构不会被融合,推理速度将显著下降——无论对 PyTorch 模型还是最终编译出的 TRT 引擎都是如此

该方法的实现位于 src/super_gradients/modules/qarepvgg_block.py,其签名与行为如下:

def prep_model_for_conversion(self, input_size=None, full_fusion: bool = False, **kwargs): """Prepare the QARepVGGBlock for conversion. :WARNING: the default `full_fusion=True` will make the block non-trainable. :param full_fusion: If True, performs full fusion, converting the block into a non-trainable, fully fused block. If False, performs partial fusion, slower for inference but still trainable. """ if full_fusion: self.full_fusion() else: self.partial_fusion()

源码揭示了两个关键信息:

  • partial_fusion(部分融合):融合 3x3、1x1 与恒等分支的卷积核与偏置(对应_get_equivalent_kernel_bias_for_branches()),但保留后续 BN-激活结构交由推理框架处理,融合后模块仍可训练;
  • full_fusion(完全融合):进一步把整个块变成不可训练的完全融合块,推理更快但不可再训练

好消息是:如果你用 SuperGradients 走 PTQ/QAT 流程,这一步在导出 ONNX checkpoint 时已经在内部替你完成了,无需手动调用。而在更高层的model.export()API 中,框架也会自动调用prep_model_for_conversion——见 exportable_detector.py:

if hasattr(model, "prep_model_for_conversion"): model.prep_model_for_conversion(**prep_model_for_conversion_kwargs)

且该调用是幂等的(idempotent),即使后续在ConvertableCompletePipelineModel包装时再次触发也无副作用(见同文件 L433-L434 注释)。同时,default_conversion_params.yaml 中也提供了prep_model_for_conversion_kwargs配置项,允许通过配置文件向该方法传参(例如指定input_sizefull_fusion)。

1.2 替换为"伪量化"层(Fake-Quantized Layers)

第二件必做之事是让网络中的层携带量化信息——这一步在 SuperGradients 执行 PTQ 或 QAT 时自动发生。量化后的模型会在原网络结构之外引入新的Quantize/Dequantize 层(伪量化节点),这些节点记录了每个张量的量化尺度与零点,供 TensorRT 在编译时直接映射为 INT8 算子。

使用 Netron 打开 PTQ/QAT 后导出的 ONNX 文件,可以看到这些新增的 Quantize/Dequantize 节点:

这是一张极好的"体检图":看到 Quantize/Dequantize 层,就说明模型已经为 INT8 TensorRT 编译做好了准备

底层量化替换由SelectiveQuantizer完成(详见 ptq_qat.md),它支持跳过指定层、用量化友好模块替换自定义块,并通过QuantDescriptor配置TensorQuantizer的位宽、校准方法(max/histogram)、逐通道量化等细节。校准阶段则由QuantizationCalibrator用代表性数据(默认取无增强的训练集,也可在 recipe 中指定calib_dataloader)统计激活值分布,方法支持percentileentropymse等。

注意:携带伪量化块的模型在 PyTorch 中的推理反而更慢(因为多了量化/反量化算子),这是正常现象——一旦编译成 TRT 引擎,速度会大幅提升。因此千万不要用 PyTorch 前向速度去评估量化模型的真实性能,这正是本文强调"必须走到 TensorRT 编译"的根本原因。

1.3 获取量化 ONNX 的三种途径

  1. recipe 一键导出:走 SuperGradients 的 QAT recipe(如 roboflow_yolo_nas_s_qat.yaml),训练结束后量化 ONNX 会自动落在 checkpoints 目录,文件名形如<experiment_name>_16x3x640x640_qat.onnx
  2. 命令行 QAT 启动:使用 qat_from_recipe.py 启动(train_from_recipe.py会得到错误结果,见 ptq_qat.md 的明确警告);
  3. DIY 代码导出:调用export_quantized_module_to_onnx(位于 src/super_gradients/training/utils/quantization/export.py):
import torch from super_gradients.training.utils.quantization.export import export_quantized_module_to_onnx onnx_filename = "qat_model_1x3x224x224.onnx" dummy_input = torch.randn([1, 3, 224, 224], device="cpu") export_quantized_module_to_onnx( model=quantized_model.cpu(), onnx_filename=onnx_filename, input_shape=[1, 3, 224, 224], input_size=[1, 3, 224, 224], train=False, )

需要明确:这份 ONNX 本身仍是 FP32 精度,其中的量化信息是以伪量化(QuantizeLinear/DequantizeLinear)形式存在,真正的 INT8 化发生在 TensorRT 编译阶段。

如果你更希望走"单行导出 + 自动校准"的现代 API,也可以使用model.export(..., quantization_mode=ExportQuantizationMode.INT8, calibration_loader=...)直接产出带校准的 INT8 ONNX(参考 models_export.md 的"Export of quantized model"一节)。量化相关的更多前置知识(FP32/FP16/INT8 对比、混合量化、选择性量化、量化残差/跳跃连接等)可参阅 PTQ 与 QAT 详解,YOLO-NAS 端到端量化微调流程可参阅 PTQ and QAT with YOLO-NAS。

Step 2:使用 trtexec 构建 INT8 TensorRT 引擎

拿到带 Quantize/Dequantize 节点的 ONNX 后,就可以进入生产部署环节。

2.1 前置条件

  • 安装 NVIDIA TensorRT,版本要求 >= 8.4(这也是导出 API 在 models_export.md 中明确列出的限制:TensorRT 8.4.1 或更高);
  • 由于pytorch_quantization依赖 NVIDIA NGC 源,需按 ptq_qat.md 说明安装。

2.2 编译命令

trtexec --fp16 --int8 --avgRuns=100 --onnx=your_yolonas_qat_model.onnx

这条命令各部分的含义:

参数作用
--onnx=your_yolonas_qat_model.onnx指定输入的量化 ONNX 文件
--int8以 INT8 精度构建引擎,模型中的伪量化层会被 TensorRT 适配为真正的 INT8 算子
--fp16允许 FP16 精度,与--int8组合使用
--avgRuns=100编译完成后运行 100 次推理取平均,获得更稳健、受噪声影响更小的基准数据

为什么必须--int8因为只有走 PTQ/QAT 后的模型才带有量化节点,--int8标志才能让这些节点落地为 INT8 计算。如果模型没有经过量化,强行加--int8急剧恶化编译后模型的精度——这是新手最容易踩的坑。

为什么--fp16--int8一起传?二者组合允许混合量化:即部分层按 INT8 执行,其余层保留 FP16/FP32,兼顾精度与速度。

另外,trtexec也支持--saveEngine=xxx.engine将编译好的引擎持久化,避免每次部署重新编译(参考 ptq_qat.md 中--saveEngine=qat_model_1x3x224x224.pkl的用法)。

2.3 编译耗时预期

构建引擎本身是一个耗时的优化过程,具体取决于 GPU、模型规模与输入尺寸——在较小的设备上等待 40 分钟都是合理的,请耐心等待,不要误以为是死机。

Step 3:解读 trtexec 基准输出

运行完上面的命令后,终端会输出类似下面的基准报告:

3.1 关注哪些数字

实际吞吐与延迟(蓝色部分):这是模型真实的推理性能指标,直接回答"我的模型到底跑多快"。

端到端延迟(黄色部分):包含三个阶段——输入准备并拷贝到 GPU(H2D)、GPU 计算、输出从 GPU 拷回主机(D2H),覆盖完整 batch 的往返时间。适用场景判断:

  • 如果你计划同步地逐 batch 推理,端到端延迟就是真正影响你的数字;
  • 如果你使用异步推理引擎(如流水线式推理),则实际受蓝色部分的 GPU 计算延迟影响。

统计口径trtexec会同时给出最小、最大、均值和中位数。当这些值差异显著时,说明测量噪声较大——可能的原因包括:测速期间有其他进程占用 GPU、GPU 散热不足导致降频等。

3.2 H2D 与 D2H:两个关键的传输瓶颈信号

  • 高 H2D 值(Host→Device):说明输入尺寸对性能影响巨大。此时应考虑在 CPU 侧提前完成输入缩放(不要在 GPU 上做 resize),或者尝试不同的 batch size 寻找最优配置;
  • 高 D2H 值(Device→Host):说明输出数据量可能过大。可以针对任务类型压缩输出表示:
    • 检测模型:在输出端使用top-k限制输出的框数量(对应导出 API 中的num_pre_nms_predictions/max_predictions_per_image参数,见 models_export.md);
    • 分割模型:在输出端增加softmax 层,将输出表示转换为维度更小的形式(如类别概率图而非 logits 堆叠)。

3.3 与导出 API 的对照

如果你使用的是model.export()新 API,可以提前在导出阶段就为 TensorRT 编译做性能优化:通过ExportTargetBackend.TENSORRT选择 TensorRT 后端(其 NMS 实现比 ONNX Runtime 的 opset 实现更快),并通过num_pre_nms_predictionsmax_predictions_per_imagenms_thresholdconfidence_threshold等参数控制输出规模——这正好与上面"用 top-k 压低 D2H"的优化思路一脉相承。需要注意 TensorRT 后端导出的模型无法被 ONNX Runtime 运行(反向可以),且动态 batch/输入尺寸尚不支持,只能以固定 shape 导出。

完整工作流串联:从训练到基准数字

将上述步骤与仓库中的配套流程串起来,一条完整的 YOLO-NAS 生产链路是:

  1. 训练:在自有数据集上用 roboflow_yolo_nas_s.yaml 等 recipe 训练得到 FP32 checkpoint(ckpt_best.pth);
  2. 量化:用 roboflow_yolo_nas_s_qat.yaml 通过 qat_from_recipe.py 执行 PTQ(自动校准)→ QAT(按QATRecipeModificationCallback的经验规则降低 batch size、epoch、学习率进行微调),最终自动导出带 Quantize/Dequantize 节点的 ONNX 到 checkpoints 目录;
  3. 编译trtexec --fp16 --int8 --avgRuns=100 --onnx=your_yolonas_qat_model.onnx构建 INT8 引擎(可加--saveEngine持久化);
  4. 基准:解读蓝色吞吐延迟、黄色端到端延迟与 H2D/D2H 数值,针对性优化输入预处理与输出后处理。

量化参数(校准方法、逐通道、num_calib_batchespercentile等)的完整 YAML 形式定义在 default_quantization_params.yaml,结合 ptq_qat.md 可逐项对照理解。

常见误区与注意事项速查

  • 误区一:拿 PyTorch 前向速度评估量化模型。伪量化层会让 PyTorch 推理更慢,必须编译成 TRT 引擎后再测速;
  • 误区二:未量化模型加--int8编译。精度会断崖式下降;
  • 误区三:跳过 RepVGG 分支融合。QARepVGG 多分支不融合会拖慢 PyTorch 与 TRT 两端的推理;
  • 注意:量化目前仅在 GPU 与 TensorRT 环境下受支持;
  • 注意trtexec测速期间应保证 GPU 独占与散热良好,避免 min/max/mean/median 大幅波动污染数据。

延伸阅读

  • PTQ 与 QAT 详解(量化原理、SelectiveQuantizer、校准器)
  • PTQ and QAT with YOLO-NAS(数据集→训练→量化→导出的完整实操)
  • 模型导出新 API(model.export 的 INT8/FP16、校准、NMS 定制)
  • 模型导出核心实现(ConvertableCompletePipelineModel 与 prep_model_for_conversion 调用链)
  • QARepVGG 块实现(partial_fusion / full_fusion 逻辑)
  • YOLO-NAS 快速上手

【免费下载链接】super-gradientsEasily train or fine-tune SOTA computer vision models with one open source training library. The home of Yolo-NAS.项目地址: https://gitcode.com/GitHub_Trending/su/super-gradients

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/18 7:10:01

pyasc 算子开发指南:load_data_with_transpose 实现带转置的 2D 数据加载

pyasc 算子开发指南&#xff1a;load_data_with_transpose 实现带转置的 2D 数据加载 【免费下载链接】pyasc 本项目为Python用户提供算子编程接口&#xff0c;支持在昇腾AI处理器上加速计算&#xff0c;接口与Ascend C一一对应并遵守Python原生语法。 项目地址: https://git…

作者头像 李华
网站建设 2026/9/18 7:07:36

RS485工业现场频繁掉线?从物理层排查到接口设计的完整指南

1. 实验室正常不代表现场正常&#xff1a;RS485掉线问题的本质先说结论&#xff1a;RS485在实验室里跑得稳&#xff0c;是“应该的”&#xff1b;到工业现场频繁掉线&#xff0c;也是“活该的”。这话听着刺耳&#xff0c;但干过现场调试的人都知道&#xff0c;实验室环境跟工业…

作者头像 李华
网站建设 2026/9/18 7:07:34

ESP32烧录不再烦:RuView工具一键识别芯片与固件烧写实战指南

写 ESP32 这些年&#xff0c;我手里来来去去过了不下十块开发板&#xff0c;有合宙的、乐鑫官方的&#xff0c;也有各种模块厂商出的奇形怪状的板子。每次新拿到一块板子或者要从旧项目里把一个模块翻出来复用&#xff0c;最烦的就是"确认这板子到底是什么型号、Flash 多大…

作者头像 李华
网站建设 2026/9/18 7:07:04

抖音下载器完全指南:从单条无水印视频到批量收藏一次讲清

抖音下载器完全指南&#xff1a;从单条无水印视频到批量收藏一次讲清 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback su…

作者头像 李华
网站建设 2026/9/18 7:05:53

Claude Code 从安装配置到实战:高频报错排查与效率技巧

1. 为什么写“Claude-Red”这份实践记录Claude从去年开始就成了我工作台上离不开的搭档。所谓“Claude-Red”&#xff0c;算是我给自己这套实操笔记起的内部代号&#xff0c;“Red”一方面代表踩坑时标红的那些红线&#xff0c;另一方面也代表一个个真实跑通过的案例记录。今天…

作者头像 李华