游乐游手机版
首页/AI热点日报/热点详情

模型量化:用NVIDIA TensorRT将FP8检查点转为高性能推理引擎

类型:热点整理2026-07-06
将FP8量化CLIP模型经ONNX编译为TensorRT引擎后,与FP16基线相比,引擎大小缩减34%至50%,推理延迟显著降低,图像编码器从166 2毫秒降至119 8毫秒,文本编码器延迟同样大幅下降。
markdown 你是一名专业的中文搜索引擎 SEO 内容优化专家。 请在不改变页面结构和代码的前提下,根据我提供的【原始文章内容】对文字内容进行 SEO 重写与优化,以提升页面在搜索引擎中的排名表现。 核心约束(必须严格遵守): 所有 HTML 标签、属性、层级结构必须保持完全不变 所有图片相关代码(如 标签、图片地址、alt 属性)必须原样保留,不得修改、删除或新增 只允许修改纯文本内容,不得调整标签位置或结构 文字优化要求: 不改变文章原有核心观点与事实信息 优化语言表达,使其更符合用户搜索习惯 合理使用同义词、近义表达,提升原创度 适当增强信息完整性与逻辑连贯性 自然融入相关搜索关键词,避免关键词堆砌 提升可读性与专业度,避免机械化改写 输出要求: 输出内容需为完整 HTML 正文 除文字内容外,其他任何内容不得发生变化 不要输出解释、注释或多余说明 原始文章内容(含 HTML 与图片):把量化的模型检查点转换成 NVIDIA TensorRT 引擎,这一步至关重要——它连接了模型优化与生产部署,直接决定了加速推理、提升吞吐量以及在规模下更高效利用 GPU 的能力能否真正落地。 在之前的一篇文章中,我们已经用 NVIDIA TensorRT Model Optimizer 产出过一个高质量的 FP8 量化 CLIP(Contrastive Language-Image Pretraining)检查点。那篇更像是准备工作。 这篇文章,我们直接从那个点出发,完整走一遍:如何将检查点导出为 ONNX,再把它编译成一个可以直接用于生产的 TensorRT 引擎。最后,还会拿这个 FP8 引擎跟 FP16 基线做个对照,看看量化之后的实际加速效果到底如何。 图 1 展示的是一个典型的端到端量化工作流的五个阶段,这也是部署一个量化 CLIP 模型的标准流程。至于量化后的 LLM 走的是另外一条路线,通过 TensorRT-LLM 来完成,具体可以看这篇教程。 Figure 1. 使用 ModelOpt 和 TensorRT 的端到端量化与部署工作流 ## 将模型导出为 ONNX 格式 第一步,把 ModelOpt 检查点导出成 ONNX。下面的伪代码展示了如何利用 ModelOpt 内置的辅助函数,完成这个 FP8 量化 CLIP 检查点的导出(注意导出目标指定为 ONNX opset 20 或以上,因为该版本才完整支持 FP8 的 QuantizeLinear/DequantizeLinear)。这个导出过程会把每个权重侧的 Q-DQ(量化-去量化)对折叠成仅含 DQ 的链,而且权重已经存储为 FP8,这样 ONNX 文件的体积会显著减小。 当然,原生 `torch.onnx.export` 也能用,但那样就得自己写转换脚本了,麻烦不少。 ```python import torch from transformers import CLIPModel, CLIPTokenizer from transformers.models.clip.modeling_clip import CLIPAttention import modelopt.torch.opt as mto import modelopt.torch.quantization as mtq from modelopt.torch._deploy.utils import OnnxBytes, get_onnx_bytes_and_metadata from modelopt.torch.quantization.plugins.diffusion.diffusers import _QuantAttention # 包装类,为 ONNX 导出提供单一 forward 接口 class TextEncoder(torch.nn.Module): def __init__(self, m): super().__init__(); self.m = m def forward(self, x): return self.m.get_text_features(x) class ImageEncoder(torch.nn.Module): def __init__(self, m): super().__init__(); self.m = m def forward(self, x): return self.m.get_image_features(x) def prepare_for_fp8_onnx_export(model): # 1) 开启 FP8 注意力融合(默认关闭,且重载后不保留) # 2) 清除 CLIP 的浮点 `scale` —— 导出器会卡住 for _, mod in model.named_modules(): if isinstance(mod, _QuantAttention): mod._disable_fp8_mha = False if isinstance(mod, CLIPAttention) and getattr(mod, "scale", None) is not None: mod.scale = None def export(wrapper, dummy, axis_name, out_name): """ModelOpt 导出器会把权重上的 Q+DQ 折叠成仅含 DQ 的链(FP8 存储), 同时将 TRT 自定义算子改写为原生的 ONNX QDQ 节点——输出文件可直接用 TensorRT 处理。""" onnx_bytes, _ = get_onnx_bytes_and_metadata( model=wrapper, dummy_input=(dummy,), model_name=out_name, dynamic_axes={axis_name: {0: "batch"}}, onnx_opset=20, weights_dtype="fp16", ) OnnxBytes.from_bytes(onnx_bytes).write_to_disk("./onnx_output", clean_dir=False) # 从 ModelOpt 检查点恢复 FP8 量化模型 mto.enable_huggingface_checkpointing() mtq.QuantModuleRegistry.register({CLIPAttention: "CLIPAttention"})(_QuantAttention) model = (CLIPModel.from_pretrained(modelopt_ckpt, attn_implementation="sdpa", torch_dtype=torch.float16).eval().cuda()) prepare_for_fp8_onnx_export(model) # 导出文本编码器 tok = CLIPTokenizer.from_pretrained(model_ckpt) dummy_text = tok(["a photo of a cat"], return_tensors="pt", padding="max_length", max_length=77)["input_ids"].cuda() export(TextEncoder(model), dummy_text, "text_input", "text_clip_fp8") # 导出图像编码器 dummy_image = torch.randn(16, 3, 224, 224, dtype=torch.float16).cuda() export(ImageEncoder(model), dummy_image, "image_input", "image_clip_fp8") ``` | 模型组件 | FP8 ModelOpt 检查点 | FP16 HuggingFace 检查点 | 尺寸缩减 | |-------------------|-------------------|--------------------------|---------| | CLIP 文本编码器 ONNX | 156 MB | 237 MB | ~34% | | CLIP 图像编码器 ONNX | 292 MB | 582 MB | ~50% | Table 1. CLIP ONNX 模型大小:FP8 vs FP16 从表 1 可以看到,FP8 ModelOpt 检查点导出的 ONNX 文件明显更小——文本编码器小了约 34%,图像编码器小了约 50%。这里有个细节:缩小 ONNX 文件本身只是顺带的好处,并非强制要求。TensorRT 在引擎构建阶段会把权重侧的 Q 节点融合进 FP8 权重。而 ModelOpt 的 ONNX 导出器选择提前在 ONNX 层面完成这种折叠,就是为了让磁盘上的文件更小。 导出后的 ONNX 文件,可以用 NVIDIA Nsight Deep Learning Designer 查看,这是个很好用的工具,能对 ONNX 模型进行编辑、性能分析,也能用来构建 TensorRT 引擎。 图 2 里展示了在 Nsight Deep Learning Designer 中看到的 ONNX 图的一部分。可以看到,图中已经包含了 QuantizeLinear/DequantizeLinear(Q/DQ)节点,这些节点标记了 FP8 计算的边界。 Figure 2. FP8 ONNX 图中注意力 MatMul 周围的 Q/DQ 节点 在引擎构建阶段,TensorRT 会把这些节点跟相邻层融合,从而优化推理性能。这种融合消除了不必要的量化-去量化转换,让计算可以直接使用经过优化的 FP8 内核。 ## 用 TensorRT 分析 ONNX 模型 好,现在 ONNX 模型已经就位了。接下来一步,就是把它交给 TensorRT,测测跑得有多快。动手之前,先确认 TensorRT 已经正确下载并安装好,可以参考这篇教程。一切就绪后,我们用 `trtexec`(TensorRT 的命令行工具)来给 ONNX 模型做个基准测试,命令如下: ```bash # 设置 TensorRT 环境 export PATH=:$PATH export LD_LIBRARY_PATH=:$LD_LIBRARY_PATH # 用 trtexec 对 ONNX 模型进行基准测试 trtexec --onnx=text_clip_fp8.onnx --shapes=text_input:128x77 --stronglyTyped --sa veEngine=text_clip_fp8.plan trtexec --onnx=image_clip_fp8.onnx --shapes=image_input:128x3x224x224 --stronglyTyped --sa veEngine=image_clip_fp8.plan ``` 几个参数简单说明一下: - `--onnx`:指定输入的 ONNX 模型,TensorRT 会用它来构建引擎。 - `--shapes`:固定输入的形状,这样 TensorRT 可以针对这个精确尺寸构建一个高度优化的引擎。 - `--stronglyTyped`:强制 TensorRT 尊重 ModelOpt 在 ONNX 图中嵌入的精度注释,确保我们的 FP8 权重和激活值确实在 FP8 上执行。 - `--sa veEngine`:将构建好的 TensorRT 引擎保存到磁盘,后续可以复用来做独立的 TensorRT 推理,或者通过 NVIDIA Triton 推理服务器提供服务(参考这个例子)。 不过有个小坑需要注意。ModelOpt 的导出器会把注意力缩放操作包在一个 FP32 的往返转换里,这会导致 `--stronglyTyped` 模式报错(通常是一个 Float vs Half 类型不匹配的错误)。所以在执行 `trtexec` 测试之前,我们需要把这些缩放常量和 Cast 操作改回 FP16,这样才能得到一个干净的、完全强类型的引擎。 ```python # 将 FP8 ONNX 中所有 FP32 类型的初始化和 Cast(to=FP32) 操作重新设为 FP16 import numpy as np import onnx from onnx import TensorProto, numpy_helper, shape_inference model = onnx.load("clip_fp8.onnx") for init in model.graph.initializer: if init.data_type == TensorProto.FLOAT: arr = numpy_helper.to_array(init).astype(np.float16) init.CopyFrom(numpy_helper.from_array(arr, name=init.name)) for node in model.graph.node: if node.op_type == "Cast": to_attr = next(a for a in node.attribute if a.name == "to") if to_attr.i == TensorProto.FLOAT: to_attr.i = TensorProto.FLOAT16 model = shape_inference.infer_shapes(model, data_prop=True, check_type=False) onnx.sa ve(model, "clip_fp8_strongtyped.onnx") ``` 当然,你也可以选择用 Nsight Deep Learning Designer 来对 ONNX 模型做性能分析,具体步骤可以看官方用户指南里的相关章节。 这次测试是在一块 NVIDIA RTX 6000 Ada GPU 上进行的,TensorRT 版本是 10.16,静态 batch size 设为 128。报告中每个延迟值都是默认测量窗口内所有推理迭代的中位数。需要提醒一点:FP8 目前只在 Ada 及之后的架构(计算能力 8.9 及以上)上,对矩阵乘法(GEMM)有支持。每种数据类型具体支持哪些 GPU,可以参考 TensorRT 的支持矩阵。 Figure 3. CLIP FP8 vs FP16:TensorRT 引擎大小与推理延迟对比 图 3 非常直观地展示了 FP8 量化相对于 FP16 的优势,无论是引擎大小还是推理延迟。左侧,图像编码器从 588 MB 降到了 306 MB(缩减 48%),文本编码器从 238 MB 降到了 156 MB(缩减 34%),加起来磁盘占用几乎减半。这些节省在推理时直接转化为 GPU 显存占用降低——引擎小了,加载和运行所需的内存自然也更少。 右侧的延迟数据同样令人印象深刻。图像编码器从 166.2 毫秒降到了 119.8 毫秒,文本编码器从 13.2 毫秒降到了 9.1 毫秒,图像侧加速比达到 1.39x,文本侧更是达到了 1.45x。 Figure 4. CLIP 图像编码器在 FP16(左)和 FP8(右)下的逐层性能分析(Nsight Deep Learning Designer) 那么,FP8 的加速到底从哪来?除了 `trtexec` 报告的数据,Nsight Deep Learning Designer 提供了一个更直观的逐层视图,能帮我们找到答案。 图 4 把 FP16 和 FP8 两个图像编码器的分析结果并排放置,三个差异立刻映入眼帘。 1. **GEMM 性能飞跃**:GEMM(通用矩阵乘法)的执行时间从大约 1.8 毫秒降到了 0.84 毫秒,加速超过 2 倍。这正是 NVIDIA RTX 6000 Ada GPU 上 FP8 Tensor Core 内核的功劳。 2. **注意力机制融合**:FP16 分析图中可见的“fusion”层类别,在 FP8 图中消失了。原因是 TensorRT 现在把整个注意力模块路由到了一个专门的 FP8 多头注意力(MHA)内核中,执行路径更加精简高效。 3. **精度图样变化**:表示精度的环形图从以橙色(FP16)为主,转变为以紫色(FP8)为主。这些信号都确认了:我们量化的权重和激活值,确实运行在了 FP8 Tensor Core 上。而 FP8 的一切增益,都来源于此——在每个涉及大量矩阵乘法的步骤中,实现了更高的计算吞吐量和更低的内存带宽占用。 ## TensorRT 中的量化机制 当 TensorRT 导入一个 ONNX 模型时,它会自动寻找 QuantizeLinear / DequantizeLinear(Q/DQ)节点。这些节点标记了图中张量在完整精度和低精度(比如 FP8)之间过渡的位置。 在内部,TensorRT 要求在每一个可量化层的每个输入上,都必须有一个 Q/DQ 层对。在引擎构建阶段,优化器会把这些 Q/DQ 节点融合到相邻层中,然后用一个专门的内核替换掉原始层,这个内核直接对低精度张量进行计算。这样一来,就省去了量化-去量化的来回转换,引擎得以在更高的计算吞吐量和更低的内存带宽下运行。 图 5 展示了 FP8 GEMM 的转换过程。在导出的 ONNX 中,激活值(x_f)和权重张量都被一对 QuantizeLinear/DequantizeLinear 包裹。经过 TensorRT 优化器的融合后,只剩一个单一的 FP8 GEMM 内核——它直接接收 FP8 量化的激活值和预先存储的 FP8 权重张量。 Figure 5. TensorRT 中的 FP8 GEMM Q/DQ 融合 如果想深入理解 TensorRT 量化的机制,可以查阅官方文档。 ## 开始使用 这篇文章,我们完整走了一遍 ModelOpt → ONNX → TensorRT 的量化模型部署流程。具体来说,就是把 CLIP 检查点导出为带 Q/DQ 节点的 ONNX 模型,再构建成 TensorRT 引擎,并用 `trtexec` 和 Nsight Deep Learning Designer 对它与 FP16 基线进行了详细对比。 测试结果很明确:在 RTX 6000 Ada GPU 上,FP8 量化相比原始 FP16 模型,带来了非常显著的推理速度和内存占用优势。文章最后还简要介绍了 TensorRT 如何在构建时通过将 Q/DQ 节点融合为专用的低精度内核,来实现这些性能提升。 不妨亲自试试 NVIDIA Model Optimizer 和 NVIDIA TensorRT,体验一下模型量化带来的效率提升。
来源:https://www.bestblogs.dev/article/d43a7d36?utm_source=rss&utm_medium=feed&utm_campaign=resources&entry=rss_article_item

相关热点

继续查看同栏目近期热点。

延伸阅读

补充最近整理过的热点入口。