Baseten 解析高质量 NVFP4 量化:启发式规则、逐层敏感度评分与 SaturationQuant
Baseten 工程博客解析如何实现高质量 NVFP4 4-bit 量化,介绍了启发式规则、孤立层敏感度评分和 SaturationQuant 三种方案。NVFP4 每 16 个值共享一个 block scale,权重可直接计算 scale,激活值则需通过校准数据集统计分布。
Baseten 工程博客·2026-10-09 22:16· 1 小时前AI 评分47
什么造就了高质量的 NVFP4 量化?
AI 导读
Baseten 工程博客解析如何实现高质量 NVFP4 4-bit 量化,介绍了启发式规则、孤立层敏感度评分和 SaturationQuant 三种方案。NVFP4 每 16 个值共享一个 block scale,权重可直接计算 scale,激活值则需通过校准数据集统计分布。
正文
量化通过以更低精度格式存储模型的权重和激活值,使模型更小、更快。NVFP4 用 4 位表示每个值。在如此粗糙的舍入下,某些层会丢失模型所依赖的信息。另一些层则能以几乎不降低输出质量的方式处理 4 位。关键在于确定哪些层可以运行在 4 位,哪些需要更高精度。在这篇文章中,我们将通过三种方案来解释如何优化以实现高质量的 4 位量化:启发式规则、孤立层敏感度评分和 SaturationQuant。
量化在哪里有帮助?
内存受限型工作负载
模型权重存储在 VRAM(GPU 附带的高带宽内存)中。推理期间,GPU 必须将这些权重从 VRAM 移动到其计算单元(例如寄存器或共享内存)以执行计算。
如果削减权重体积,你就把必须获取的字节数削减了约 2 倍或约 4 倍。例如,FP16 每个权重使用 2 字节,而 FP8 使用 1 字节,FP4 使用 0.5 字节。
计算受限型工作负载
在计算受限型工作负载中,GPU 大部分时间都在做算术运算,而不是将权重和激活值从 VRAM 移动到其计算单元。对于 LLM,大部分算术运算是矩阵乘法,运行在 GPU 的张量核心上。量化对计算受限型工作负载的好处是更高的算术吞吐量:在像 NVIDIA Blackwell GPU 这样原生支持 FP4 的硬件上,FP4 张量核心操作可提供高达 FP16 峰值 FLOPS 的 4 倍。
什么被量化,以何种形式?
权重是训练期间学习到的参数。它们在推理时保持固定。两个神经元之间的每个连接都有一个权重,每一层都有自己的权重张量。
激活值:在推理期间,激活值由输入和权重产生。每个神经元将到达它的值组合起来,然后将结果通过非线性函数。该输出就是它的激活值。
✕
展示两个输入如何通过一个小型网络,放大其中一个神经元,该神经元将其传入的激活值乘以固定权重,求和,然后将结果通过 ReLU 以产生其激活值。权重在训练时设定一次,但激活值会为每个输入重新计算,因此它们是两者中更难量化的。
根据量化配置,一层的权重、激活值或两者都可以被量化为更低精度的格式。每个值都必须舍入到 4 位所能表示的少数几个数字之一。
为什么我们需要 scale?
FP4 只能表示一组固定的 16 个值:0、±0.5、±1、±1.5、±2、±3、±4、±6,但权重和激活值通常比这要小得多。 每组权重或激活值都有自己的动态范围,即从其最小值到最大值的跨度。scale 将网格映射到值所处的范围(适配到最大绝对值)。权重和激活值使用各自的 scale,因为它们的范围互不相关。
为清晰起见,以下图表省略了 NVFP4 的张量级 FP32 缩放,仅展示块级缩放步骤。
✕
带缩放与不带缩放的 FP4 量化。
块缩放:每 16 个值一个缩放因子
在 NVFP4 中,一个张量(例如一组权重或激活值)被拆分为每 16 个连续值组成的块,每个块设置自己的缩放因子。
✕
使用块缩放对一个 16 值块进行量化。
为什么要有块?
例如,如果我们对整个权重数组只用一个缩放因子,那么最大的离群值会在量化过程中影响所有其他值。缩放因子由那个离群值决定。假设数组中最大的值是 84,而其余值都在 1 或 2 左右。缩放因子变为 84 ÷ 6 = 14,于是 NVFP4 能表示的幅度现在为 0、7、14、21、28、42、56、84,而所有低于 3.5 的值都更接近 0 而不是 7。
✕
块缩放与整数组缩放对比。
权重缩放因子可以从权重计算得出,因为它们是固定的。但激活值只有在输入经过模型后才会存在,因此必须先通过校准来测量它们的范围。
校准
校准将一小组具有代表性的输入送入模型运行,并记录激活值的分布。这些统计数据用于计算缩放因子。
✕
量化流程中的校准。激活值需要样本数据来设置其缩放因子,因为它们的值取决于输入,而固定的权重则无需样本数据即可缩放。
校准包括三个步骤:
选择校准数据集:选择能够准确反映你预期输入和输出的结构、内容和工作负载类型(例如编码或智能体任务)的示例。将这些示例送入模型运行,以记录激活值的分布。
选择裁剪范围:量化必须将激活值映射到一组有限的可表示值中。使用最小值和最大值可以避免裁剪,但罕见的离群值会扩大范围,从而降低大多数激活值的精度。基于百分位数、直方图和误差的校准方法可能会裁剪少量离群值,以更精确地表示模型的典型激活值。
计算激活缩放因子:将每个激活张量划分为每 16 个值组成的块。对于每个块,找到其最大绝对值,并用它计算一个缩放因子,将该块的值映射到 NVFP4 可表示的 −6 到 6 范围内。
如何为每一层选择精度格式
基于启发式的算法
基于启发式的算法根据架构而非测量每一层对量化的敏感程度来确定每一层的精度。(测量敏感度需要校准数据集,逐层量化,并将输出与全精度模型进行比较。)一种常见的启发式方法是将 MoE 专家矩阵量化为较低精度,同时将注意力层保持为较高精度,因为注意力通常对量化更敏感。这可以节省内存,因为专家权重矩阵占 MoE 模型参数的大部分。简而言之,在许多 MoE LLM 中,专家层比注意力层对量化更鲁棒。
NVIDIA ModelOpt 提供了预定义配置,用于实现基于架构的量化启发式方法:
NVFP4_EXPERTS_ONLY_CFG仅量化 MoE 专家层。NVFP4_MLP_ONLY_CFG量化 MLP 和 MoE 层,同时将注意力层保持为较高精度。
与 ModelOpt AutoQuantize(见下文)不同,这些配置不会测量每一层对精度的敏感度来决定其精度。每一层的精度基于架构。
注意:MoE 是一种架构,其中模型被划分为许多专门的子网络(专家),但对于任何给定的 token,只有一小部分会被激活。
ModelOpt AutoQuantize
AutoQuantize 为每一层选择一种精度格式(例如 NVFP4、FP8,或保持不量化)。利用敏感度分数,AutoQuantize 选择一种格式组合,在不超过目标内存大小的前提下,使估计损失最小化。
AutoQuantize 支持三种敏感度评分方法:基于梯度、KL 散度和 Aumann–Shapley。
什么是敏感度?
敏感度是指将某一层的权重和激活值舍入为较低精度格式时,对模型输出造成的影响程度。有些层可以使用 NVFP4 等较低精度格式,而模型输出质量几乎不变。其他层会丢失模型所依赖的信息,因此 AutoQuantize 会为它们分配较高精度的格式。
孤立层敏感度评分:梯度法
梯度法估计的是:在保持其他所有层为基线配置的情况下,将某一层量化为给定格式会使模型损失增加多少。
AutoQuantize 有四个阶段:
✕
AutoQuantize 的四个阶段:校准、评分、求解和应用。
候选格式是 AutoQuantize 为每一层尝试的量化格式之一,例如 FP8 或 NVFP4。你可以通过 quantization_formats 选择候选格式,并且“不量化”始终作为一个选项包含在内。成本限制是目标内存大小(或比特数)。
model, search_state = mtq.auto_quantize(
model,
constraints={"effective_bits": 4.8},
quantization_formats=["NVFP4_DEFAULT_CFG", "FP8_DEFAULT_CFG"],
data_loader=calib_loader,
forward_step=forward_step,
loss_func=loss_func,
method="gradient"
)SaturationQuant
孤立层敏感度评分的局限性
AutoQuantize 使用敏感度分数来比较混合精度配方,并决定为每一层分配哪种量化格式。为了估计同时量化多个层所导致的损失增加,AutoQuantize 不能简单地将它们各自的敏感度分数相加。
✕
AutoQuantize 如何孤立地对层进行评分。每次量化一层为 NVFP4,同时保持其余层为基础精度,然后将每个分数测量为相对于未量化基线的损失增加。由于每个分数都假设没有其他层被量化,将它们相加会高估同时量化多个层的配方的损失。
量化某一层的影响取决于模型已经有多少部分被量化。当其他层已经被量化时,量化某一层通常会增加较少的损失。将孤立分数相加可能会高估完整配方的损失。
损失是有界的。每个新量化的层都会消耗剩余损失余量*的一部分。随着更多层被量化,总损失增加开始饱和。
*余量:当前损失与其可达到的最大值之间的差距。
✕
随着更多层被量化,损失如何趋于饱和。每一层的影响取决于已经量化的层,这就是为什么把孤立的分数相加会高估总损失。
AutoQuantize 中的 SaturationQuant 评分
SaturationQuant 使用 Aumann–Shapley 评分,在给每一层打分时考虑其他已量化的层。饱和性内置于分数之中,因此这些分数可以直接相加。这些分数之和能更准确地预测该配方产生的损失。
model, search_state = mtq.auto_quantize(
model,
quantization_formats=["NVFP4_DEFAULT_CFG", "FP8_DEFAULT_CFG"],
data_loader=calib_loader,
forward_step=forward_step,
method="aumann_shapley"
)你应该如何选择要量化哪些层?
有些层可以在 NVFP4 下运行而质量几乎不变,而另一些层则需要 FP8 或更高精度。校准数据用于测量激活范围,而缩放因子将权重和激活映射到 NVFP4 网格上。要选择哪些层以 NVFP4 运行:
当你需要快速得到配方而不想逐层搜索时,使用基于架构的启发式方法。
当你可以在具有代表性的校准数据集上计算损失,并希望衡量每一层的敏感度时,使用梯度评分。
当你有更严格的内存目标,并需要估计完整的混合精度配方将如何影响质量时,使用 Aumann–Shapley 评分。
来源:Baseten 工程博客 · baseten.co
来源:RadarAI · aihot.news