LLM 量化综述:数据格式、PTQ 与 QAT 的算法演进

理解量化,首先要知道一个数还剩下哪些合法取值,然后才能讨论怎样把模型放进这些取值里。INT8 和 FP8 都是 8 bit,却有不同的动态范围和误差形态;INT4、NF4、MXFP4、NVFP4 都与 4 bit 有关,但它们的格点、scale 和计算路径并不相同。

数据格式规定可表示范围、格点密度和特殊值行为,决定数值稳定性的基础边界;实际误差还取决于分组、scale、校准分布和运算精度。 所以,格式相同的两个模型也可能有完全不同的精度,格式更小的模型也未必推理更快。

接下来先讲格式,再把量化工作流分成 PTQ 与 QAT;随后分别讨论 8 bit、4 bit 和低于 4 bit。每种方法都围绕四个问题展开:前一种做法哪里不够、它改变了什么、核心优化如何实现、数值和部署代价是什么。旋转、蒸馏、混合精度和码本会放回对应工作流中解释。

1. 数据格式:量化误差与数值稳定性的起点

1.1 先分清存储位宽、计算位宽与累加位宽

常见数值格式与低比特表示

图中的位域解释单个元素如何编码;用于张量时,还要加上 scale 和可能的 zero-point。W4A16 只表示权重采用 4 bit、相应 activation 采用 16 bit,没有规定它们是整数还是浮点,更没有规定 KV、累加器和输出的精度。

格式未缩放的表示特征对数值稳定性的直接影响
FP32E8M23,最大有限值约 常用于统计、scale、参考计算及部分训练状态
BF16E8M7,指数范围接近 FP32不易因范围不足溢出,但尾数舍入仍明显
FP16E5M10,最大有限值 65504主体分辨率较细,但大 activation、梯度或倒数更易溢出
INT8有符号编码通常为 通过 scale 提供张量范围;格点等间距,异常值会拉粗步长
FP8 E4M3FN4 位指数、3 位尾数,最大有限值 448,无 Infinity 编码相对分辨率较好,范围小于 E5M2
FP8 E5M25 位指数、2 位尾数,最大有限值 57344更大范围换来更粗的相对分辨率
INT4有符号编码通常为 仅 16 个编码,范围与主体精度的冲突更突出
FP4 E2M1最大幅度 6,非均匀格点必须结合 scale;不能当作均匀 INT4 量化
NF4为特定权重分布设计的 4 bit 非均匀码本改善相应分布下的存储误差,不能据此推出 FP4 原生计算能力

E4M3 必须继续区分 FN 与 FNUZ:前者上表为 448,FNUZ 变体的最大有限值为 240。不同特殊值与指数偏置规则不能混用。TF32 则主要是 Tensor Core 的计算精度模式,并非通用的 19 bit checkpoint 格式。FP8 格式论文、OCP MX 规范

INT8 乘积常以 INT32 累加,FP8/FP4 GEMM 也需要区分输入、部分和、累加与输出精度。高精度累加减少的是运算过程的误差,无法恢复输入已经量化丢失的信息。

1.2 INT8 与 INT4:绝对舍入误差由步长决定

均匀整数量化可以写成:

这里 是反量化乘数, 是整数零点。有的框架存的是 ,所以读取名为 scale 的字段时,必须顺着消费它的乘除运算确认含义。

例如使用有效范围 的对称 INT4,对 [-0.1, 0.2, 0.4, 6.0] 取 ,前三个数都会 round 到零。这里既没有 overflow,也没有 NaN,但信息已经明显损失。

这个例子体现了范围与精度的冲突:扩大范围可以减少 clipping,却会增大量化步长、损害主体分布;缩小范围可以改善主体分辨率,却会牺牲尾部。min/max 校准寻找的是覆盖范围,MSE 校准寻找的是误差折中,两者目标不同。

对称量化常用 ;非对称量化可以更好利用有偏分布的有限格点,但需要额外零点及修正。不要把“INT4 signed 范围是 ”“有效对称范围用 ”“框架取半个整数跨度作为 scale 分母”混成一种实现。它们都可能出现在真实系统中,训练与部署必须选同一约定。

也需要纠正一个常见表述:LayerNorm/RMSNorm 主要作用于 activation,并不会把 Linear 的权重矩阵归一化到零均值;RMSNorm 本身也不减均值。是否采用对称权重量化,应由权重分布和后端约束决定。

如果采用最近舍入、scale 精确且没有 clipping,则可推得:

这是绝对误差界,不是固定相对误差界: 接近零时,即使绝对误差很小,相对误差也可能很大。若 超出可表示区间,误差还包括它到区间端点的距离;没有对输入幅度的额外约束,就不存在仅由 bit 数决定的有限全局误差上界。

取同一目标范围 ,为了方便比较都使用有效对称范围,则:

位宽有效整数范围步长区间内最大舍入误差
INT8约 0.02362
INT4约 0.42857
INT31
对称三值63

最后一行只有三个有效值,不能与利用四个编码的非对称 INT2 混称。这个例子说明:8 bit 降到 4 bit,步长并不只是扩大两倍;继续降到 2–3 bit,单靠覆盖 min/max 很快就会失去主体分辨率。

1.3 FP8 与 FP4:指数扩大范围,尾数限制相对精度

对采用最近舍入的二进制浮点数,在正规数范围、没有上溢或下溢、scale 精确时,若尾数有 个显式位,一个常用相对误差上界是:

E4M3、E5M2、E2M1 对应的这一上界分别是 6.25%、12.5%、25%。这是满足条件时的舍入界,不是模型 accuracy 损失,也不是每个数都达到的误差。进入 subnormal/零附近之后,相对误差保证不再适用;实际 rounding 模式、scale 的离散化和 clipping 还会增加误差。

E2M1 的非负数值集合为:

再加上负值与带符号零构成其编码。它在小值附近分配较密、在大值附近分配较稀,与 INT4 等间距格点不同;但它的范围仍很小,因此实际张量必须缩放。用同样的 bit 数比较精度时,要比较完整的“元素格式 + scale + 分组”。

NF4 又是另一种选择。QLoRA 用适配近似正态权重的非均匀码本改善 4 bit 存储,并对量化常数再次量化以降低 metadata 开销。它不是 E2M1,不能把 NF4 checkpoint 换一个格式标签就交给 NVFP4 kernel。

1.4 MXFP4:元素之外,scale 也被限制到格点

OCP MXFP4 的基本分组是 32 个元素,每组共享一个 8 bit E8M0 scale:

E8M0 不是普通有符号 FP8 数据,它主要编码正的二次幂。读取 checkpoint 中保存为 uint8 的 scale 时,要解码指数,而不是把整数 127 直接当乘数 127;相应偏置下,127 可以表示 。

如果忽略 padding 和对齐,平均位数为:

它的额外误差来自 scale 自己的离散化。理想实数 scale 也许是 0.3,但 E8M0 只能选择相邻幂次附近的可表示值。把 scale 向上选,可以降低饱和风险,却可能增加主体 rounding 和 zero-collapse;适当向下选可能改善 MSE,但要付出 clipping。

MXFP4 格式规定了表示,不意味着所有量化器都用同一个 scale 搜索算法。 ceil(log2(amax/6)) 可以作为保守覆盖的教学方案,但不是本文源码快照的逐字实现。compressed-tensors 的 generate_mx_scales 使用与元素格式相关的指数偏移及位运算规则;做数值对拍时要调用实际实现。

1.5 NVFP4:更小分组与两级 scale

常见 NVFP4 推理表示可以概念化为:

这里使用的是反量化乘数约定。一个 FP32 tensor scale 将局部 scale 放到合适的范围;每 16 个元素再用 E4M3 编码局部 scale。与 E8M0 相比,E4M3 有尾数,局部 scale 更细,但仍会发生舍入、溢出和下溢。NVFP4 格式与训练说明

忽略少量全局 scale 和 padding,其平均位数为:

因此相对 BF16 的数据压缩比上限约是 ,而不是 4;MXFP4 对应约 3.76。真实模型还包含未量化层、对齐、索引、运行时临时区和 KV,显存比例不会简单等于这个理论比值。

在 llm-compressor 的 NVFP4 preset 中,weight 的局部和全局 scale 离线产生;activation 的 local scale 是动态的,global scale 则根据校准统计确定。所以**“activation dynamic”不等于“NVFP4 不需要数据”**。这也是只用几条短 prompt 校准后,长上下文输入可能出现严重饱和的原因之一。官方 NVFP4 示例

这个 compressed-tensors 快照中的 generate_global_scale 使用类似 的量化乘数方向,局部 scale 计算随后与它配合。它不等于上式中的反量化乘数 ;读字段必须同时看 helpers.py 和量化/反量化消费路径。

两者的设计差异可以归纳为:MXFP4 用幂次 scale 降低表示与缩放复杂度;NVFP4 用更小的组和带尾数的局部 scale,减轻共享范围与 scale 离散化的部分误差,但引入 global/local scale 协同问题。具体哪种更准,要在同一模型、量化器和目标 kernel 上测量。

1.6 scale 合法性与零值处理属于格式实现的一部分

设实际使用的 scale 为 ,编码值为 ,则重建误差含有:

提高元素量化质量并不能消除 。FP4 只有很少格点,scale 的小幅变化还可能让元素跨过 rounding 边界,使两种误差强烈耦合。

因此数值稳定性要覆盖四步:在足够高精度中统计;选择合法 scale;把 scale 编码成实际 dtype;再检查编码后的 scale 是否为零或非有限值。先对 FP32 scale 做 clamp_min(1e-8),然后 cast 到 FP16/FP8,仍可能得到零。

全零 block 可以约定有限正 scale、全零编码,精确重建为零;E8M0 还需要明确零组的合法指数约定。非对称 min=max 的退化区间也要单独处理。输入已经出现 NaN/Inf 时,应追踪上游异常,不能仅靠 nan_to_num 把整个问题掩盖掉。

1.7 低于 4 bit:标量编码与平均 bits/weight 不再等价

INT3 可以直接把每个权重映射到 8 个编码;向量量化则把一组权重共同映射到码本索引。例如 8 个权重共享一个 16 bit 索引,索引载荷平均为 2 bits/weight,但每个权重并不是只能独立取四个值。

类似地,三值权重的状态数对应 bit。它是编码率的概念,不代表每个硬件地址能容纳“1.58 个二进制位”。真正比较模型大小时,还要算打包、scale、码本、索引和未量化参数;后文的 QuIP#、AQLM 与 BitNet 会分别利用这些不同的表示方式。

2. 方法分类:PTQ 与 QAT,两条工作流面对同一个误差问题

2.1 用优化对象与训练过程分类,不用算法名字分类

PTQ(Post-Training Quantization) 从已有预训练模型出发,主要通过统计校准、参数等价变换、重建补偿与有限的局部优化完成压缩。QAT(Quantization-Aware Training) 将目标量化器放入训练前向,让模型参数或可训练增量持续适应离散表示。

工作流典型优化对象常见目标与方法
PTQ:范围与分布处理scale、clipping、异常通道、等价缩放/旋转RTN 校准、LLM.int8、SmoothQuant、AWQ、QuaRot
PTQ:重建与有限优化权重落点、rounding、变换、码本等GPTQ、AdaRound、AutoRound、OmniQuant、SpinQuant、QuIP#、AQLM
QAT:目标量化下训练模型权重、clipping/scale、adapter 等STE、PACT、LSQ、LLM-QAT、匹配部署格式的 LoRA/QAT
QAT:从头训练的延伸从预训练阶段学习低比特权重BitNet / BitNet b1.58;应与改造已有 checkpoint 的 QAT 区分

后文按 PTQ/QAT 两条主线组织。“用了 backward”不能单独决定分类。 AdaRound、AutoRound 和 OmniQuant 通过局部反传优化压缩参数,通常仍归 PTQ;QuIP# 和 AQLM 还包含有限微调,属于带恢复阶段的 PTQ。若额外进行大规模端到端量化感知训练,应明确标出 QAT 阶段,而不是抹掉这段成本。

旋转、蒸馏、混合精度都可以成为某条工作流的组成部分,不需要另设第三大类。MXFP4/NVFP4 是格式,Marlin/CUTLASS 是实现后端,也不与 PTQ/QAT 并列。分类是为了说明优化发生在哪里;部分论文的边界用语确有交叠,具体步骤比单个标签更可靠。

按位宽的阅读地图如下,列的是代表性使用场景,不意味着方法被永久限制在该位宽:

目标PTQ 重点QAT 重点
8 bit范围校准、异常通道、动态 scale、W8A8学 clipping/步长,让权重适应量化
4 bit输出重建、通道重要性、旋转、FP4 scale权重与激活联合适应、蒸馏、部署一致性
低于 4 bit更强 rounding 优化、向量/加性码本、误差补偿更粗格点下的优化稳定性、三值/二值训练

2.2 优化的是层输出,最终验收的是模型任务

全文统一使用 PyTorch Linear 布局:

是 token 数, 是输入通道, 是输出通道;为突出量化主路径,暂时省略 bias。下面 若出现在矩阵乘法中,表示量化后再反量化到实数的重建值,而非未经解码的整数索引。

记权重误差为 ,激活误差为 ,则:

第一项是 activation 加权后的权重误差,第二项是权重放大后的 activation 误差,第三项是联合量化的交叉项。这个分解直接解释了后文的方法选择:

  • GPTQ 重点处理 ,所以需要输入二阶统计。
  • AWQ 利用 activation 重要性修改权重的量化条件。
  • SmoothQuant 在 和 之间重新分配困难。
  • W4A4 下只把权重做得很准,不能消除 。
  • QAT 让网络在这些误差共同存在时重新优化,但仍受目标格式的表达能力限制。

误差也不一定随层数或上下文长度单调增加;残差、归一化、attention 分布都可能放大或抑制它。要测实际输出和任务退化,不能仅凭“误差会累积”预测幅度。

2.3 scale 的粒度决定误差在哪些元素之间耦合

对象与粒度按本文布局的逻辑 scale 形状可以解决的问题
per-tensor元数据最少,无法隔离跨通道异常值
per-output-channel不同输出通道独立选范围
沿 分组,group size 为 将异常值影响限制在局部组
dynamic per-token每个 token 独立适应幅度变化
沿 分组进一步隔离同一 token 内的异常值
二维 block 权重让 scale 与二维 tile、转置路径协调

若 activation 按 token、weight 按输出通道量化,scale 可以从点积中提出:

若二者沿 分组,计算变成:

每个 reduction 分组都有不同 scale,不能只在最终 epilogue 乘一次。更细粒度通常改善量化表达,但也增加 metadata、局部缩放和布局约束。这就是“per-channel 更准确”不能独立于 kernel 讨论的原因。

3. 8 bit:先解决动态范围和异常通道

8 bit 有较多格点,常见困难首先是少数异常通道把整组范围拉得过大。若把范围和分组处理好,简单量化就值得作为基线;若仍不能满足质量目标,再增加补偿或训练。

3.1 PTQ:RTN、静态校准与动态 scale

RTN(Round-to-Nearest)是在确定 scale、zero-point 后直接舍入。它不做跨权重补偿,因此成本低,也是判断复杂算法是否有效的必要基线。

校准集的作用取决于方案:静态 activation 需要范围统计;GPTQ 需要输入协方差;AWQ 需要 activation 幅度和候选缩放的重建误差。只有静态权重与动态 activation 的简单 RTN 路径,才可能完全不需要校准数据。

常见 observer 包括 min/max、滑动统计、percentile 与 MSE 搜索。percentile 丢掉少量极值不一定安全:稀有 code token、数学符号或 MoE expert 可能恰好承载重要行为。范围选择至少要在独立验证集上检查,并统计每层、每组的饱和率和非零值被量化成零的比例。

工程上应分开理解两种改进。per-channel weight scale 防止某个输出通道决定其他通道的步长;per-token activation scale 让每个 token 适应自己的幅度。但一个 token 内依然可能有少数巨大通道,因此 per-token 并不能解决全部 activation outlier。

FP8 dynamic 的主要变化是换成浮点格点并动态选择范围,省去静态 activation 范围校准这一环节。它并不学习最优权重,也不补偿层输出误差;如果当前误差已很小,这是成本较低的 PTQ 起点。llm-compressor FP8 示例

稳定性上,需要用足够高精度收集 amax,处理空/零 block,检查 scale cast 后的值,并确认动态 quant 与 GEMM 是否融合。若每次 GEMM 前都额外读写一遍完整 activation,数值上合理的动态方案也可能在小 shape 上产生明显开销。

3.2 PTQ:LLM.int8 把异常通道留给高精度路径

单一 INT8 路径既要容纳异常值,又要保住主体分辨率,冲突无法只靠一个 scale 消除。LLM.int8 的核心改进是混合精度分解:将输入通道分为普通集合 和异常集合 ,概念上计算:

第一项使用带缩放的低精度计算,第二项保留高精度。相对普通逐向量 INT8,它的创新是不强迫所有通道共享同一低精度计算路径;异常通道不会再迫使普通部分的步长一起变粗。

代价是检测、收集通道、额外矩阵乘和结果合并。阈值太小,高精度分支变大;阈值太大,剩余 INT8 部分仍可能被 outlier 主导。因此要同时测高精度分支占比、层输出误差与实际延迟。这里的混合精度分解是 PTQ 内部策略。

3.3 PTQ:SmoothQuant 把 activation 的量化困难迁移给 weight

SmoothQuant 也使用 ,但重点是给 W8A8 的 activation 腾出数值空间。定义:

工程上需要处理 、 为零,以及极端 scale。较大的 会更积极地减小 activation 异常通道,同时加重相应权重列的量化负担。因此 或示例中的 0.8 都只是候选值,不是模型无关的最优常数。SmoothQuant

AWQ 与 SmoothQuant 的区别不在那条等价公式,而在目标函数和量化对象:

维度AWQSmoothQuant
经典目标保护 activation 敏感的权重量化平衡 weight 与 activation 的量化难度
常见场景W4A16W8A8
统计起点输入幅度重要性及重建误差activation、weight 的通道范围
失败信号保护一列却扩大组 scale,其他列受损activation 更平滑,但放大后的 weight 误差更大

由于 SmoothQuant 改变参数化、GPTQ 优化权重落点,两者可以组合。正确顺序是先变换,再在一致的坐标系中收集统计并量化。原坐标的 Hessian 不能随意用于已旋转或缩放的权重;例如 时,应有 。

相对 LLM.int8 的分支处理,SmoothQuant 的创新在于用离线等价变换争取更规则的低精度 GEMM:将 吸收到前驱 norm/线性层,将 吸收到消费该 activation 的权重。它减少了对动态异常分支的依赖,但前提是所有消费者都正确变换,且权重增加的误差小于 activation 减少的误差。

它与后文 AWQ 使用相似公式,但优化动机不同:SmoothQuant 为 W8A8 平衡两侧范围;AWQ 的典型目标是 W4A16 下保护重要权重列。这里的“相对前作”是在比较机制,不意味着这些论文按一条严格串行的时间线发展。

3.4 QAT:STE 让权重适应离散前向

QAT 的前向计算可以是:

FQ 内部 quantize 后立即 dequantize,输出仍是浮点 Tensor,但取值受目标格点限制。浮点参数保留并交给优化器更新;真实低比特打包通常放到导出阶段。FP32 master weights 是否存在,取决于训练栈和优化器,并不是所有 QAT 都天然维护一份 FP32 参数。

round 的真实导数几乎处处为零,所以使用 Straight-Through Estimator(STE)近似反传。对固定 scale 的带截断 fake quant,一种常用近似是:

范围内近似传递梯度,饱和区外截断;具体边界与 kernel 的 mask 约定需保持一致。“STE 就是梯度永远等于 1”遗漏了 clipping 的处理。PyTorch QAT 工作流

下面只演示固定 scale、对称整数格式、范围内 STE 的逻辑,不是 NVFP4 模拟器,也不包含可学习 scale 的梯度:

import torch
 
def fake_quant_fixed_scale(x, scale, qmin=-8, qmax=7):
    u = x.float()
    if not torch.isfinite(u).all():
        raise FloatingPointError("non-finite fake-quant input")
    s = scale.detach().float()
    if not torch.isfinite(s).all() or not (s > 0).all():
        raise ValueError("scale must be finite and positive")
    clipped = torch.clamp(u / s, qmin, qmax)
    rounded = clipped + (torch.round(clipped) - clipped).detach()
    return (rounded * s).to(x.dtype)

.detach() 让 backward 忽略 round 带来的不连续变化,clamp 则保留饱和区的梯度门控。若使用 BF16 输入,也先在 FP32 中完成 scale 除法和范围运算,避免低精度中间值提前 overflow/underflow;最终返回的 dtype 不代表内部统计可以随意降精度。

相对前面的 PTQ,QAT 的改变是模型参数本身可以根据带量化的任务损失持续更新;代价是训练数据、backward、优化器状态和可能的能力漂移。STE 是代理梯度,不是 round 的真实导数,因此仍需验证最终离散模型的质量,不能只观察连续权重的收敛。

3.5 QAT:PACT 与 LSQ 分别学习截断范围和量化步长

固定 quantizer 的 QAT 能移动权重,但量化格点可能仍不合适。两类经典改进是直接让训练目标决定 clipping 或 scale;它们也可用于后文更低位宽,8 bit 章节先建立其基本机制。

PACT:学习哪些尾部值得牺牲。 原始 PACT 对非负 activation 使用可学习上界 :

相对固定 min/max 或固定 clipping,它让任务梯度与对 的约束共同选择范围:较小 改善主体分辨率,较大 保留尾部。参数必须保持合法正值,并监控落在截断区的比例。LLM 的有符号 activation 不能直接照搬非负形式,需要与目标量化器一致的双边范围或对称阈值。

LSQ:不仅学习范围,还控制 scale 梯度的量级。 令 ,对整数 fake quant 的代理导数有:

同一个 scale 被大量元素共享,梯度总量会随着共享元素数 变化。LSQ 使用与 相关的梯度缩放,使步长与权重的相对更新更平衡。相对只把 scale 设为可学习参数,这个优化控制才是稳定训练的关键之一。

实现时应按 per-tensor/per-channel/per-group 的实际共享范围定义 ,避免把整个模型参数量代入;scale 的参数化、梯度精度、学习率和冻结时机都要明确。极低位宽下 scale 的小幅变化会使很多值跨过格点,独立 scale 学习率和变化幅度监控尤其有用。

4. 4 bit:从覆盖范围转向输出重建与联合适应

进入 4 bit 后,“范围内没有溢出”远远不够。少量格点使 rounding 本身成为主要误差;W4A4 还同时受到权重和 activation 两侧误差影响。这里先讲 PTQ 如何改变落点与坐标,再讲 QAT 如何让网络在这些误差下重新优化。

4.1 PTQ:GPTQ 用二阶信息补偿已经量化的误差

对某一输出通道,将权重视作列向量 。固定校准输入后:

这是该层重建目标的 Hessian,不是整个语言模型交叉熵对所有参数的完整 Hessian。对于固定输入的这个二次目标,上式是精确的;把层重建损失作为最终任务损失的替代,才是更重要的近似。

假设先固定第 个权重为离散值 ,令调整量为 ,约束 。在当前尚可调整的坐标集合中求解:

拉格朗日条件给出:

这解释了 GPTQ 的核心:某个坐标被迫落到格点后,利用输入通道相关性调整还没固定的坐标,尽量抵消输出变化。并不是把每个权重单独量化后再统一修补,也不是去更新 activation。论文的高效实现让权重行共享处理次序,并用分块更新减少开销。GPTQ

在 llm-compressor 的 gptq_quantize.py 中,可以对应到四个实现细节:

  1. Hessian 与临时权重计算使用 FP32。输入展平后转置,累加二阶统计。
  2. 对角线为零的 dead channel 被单独处理。它只表示校准数据没有激活这个方向,不保证真实业务永远不会激活它。
  3. 先加 ,其中 ,再做 Cholesky 和逆矩阵相关计算。
  4. 逐列量化、更新当前块,随后将整个块的误差补偿传播到剩余列。

源码中的 Hinv 在分解之后实际保存的是逆 Hessian 的上三角 Cholesky 因子。不能把其中一行 err / d 直接当成上面完整逆矩阵公式的逐字翻译。

block_size 与 group_size 也不是同一个参数。 前者控制 GPTQ 更新的计算分块,后者决定哪些权重共享 scale。两个值都可能是 128,但改变的是不同东西。act-order 则按输入重要性改变处理顺序,其分组和 g_idx 的含义依具体实现而异;不能推断所有 GPTQ checkpoint 都必须运行时重排 activation。

如果 Cholesky 失败,这个源码快照会记录 warning 并对该模块退回 RTN。脚本能保存模型,并不代表每层成功执行了 GPTQ。应保留 fallback 层名单,检查校准覆盖、非有限数值、样本多样性,再适度增加 damping;过强 damping 又会削弱通道相关性带来的补偿能力。

GPTQ 最初重点是 weight-only。现在 llm-compressor 可以把相同的权重补偿思路用于支持的 FP4 scheme,但这不意味着 GPTQ 会直接解决 FP4 activation 的所有误差。

相对 RTN,GPTQ 从“当前元素最近的格点”推进到“考虑输入相关性的层输出重建”;相对逐个权重执行昂贵二阶更新的早期思路,它通过共享列顺序、Cholesky 形式和分块延迟更新,使大矩阵量化可执行。稳定性代价集中在 Hessian 估计与分解,而不是 scale 一个参数上。

4.2 PTQ:AWQ 用 activation 重要性改变权重的量化条件

AWQ 的起点是:权重元素大小不是输出敏感度的唯一依据,还要看该输入通道实际被多大 activation 使用。对角缩放矩阵 满足:

缩放前后浮点函数不变,但 落入量化格点的方式改变了。某个权重组的量化步长为 时,在缩放没有同比例扩大整组范围的情况下,重要通道在原坐标中的舍入误差尺度约为 。所以放大重要列可能保护它,但并不是“放大多少就一定改善多少”。

实际选择要比较:

典型做法由 构造候选 scale,再搜索幂指数及相关参数。llm-compressor 的 AWQ 实现 缓存必要输入,测试缩放后的 fake-quant 输出,并支持 duo_scaling 候选搜索。它不是仅打印 activation 统计量就结束。

这里需要区分三个概念:

  • 论文发现少量 salient weights 对精度很重要,不等于部署时必须保留这些权重为 BF16。
  • AWQ 没有全模型反向训练,但会改变浮点权重的参数化,并进行量化候选的输出误差评估。
  • AWQ 的等价缩放要在相邻层中正确吸收。一个 norm 的输出同时送入 Q/K/V 时,三个消费者必须使用一致的变换;只改一个 Linear 会破坏原函数。

它适合 W4A16 等权重误差主导的路径。若 activation 也被压到 4 bit,需要重新评价联合误差,而不是默认 weight-only 搜到的 scale 仍最优。AWQ 论文

相对 GPTQ 的二阶相关性补偿,AWQ 用更轻量的通道幅度与 scale 搜索改善权重量化条件,不构建同样的完整输入 Hessian。它牺牲了一部分相关性信息,换来另一种成本与效果的平衡;这不是某个方案对所有模型都严格占优的关系。

4.3 PTQ:AdaRound 与 AutoRound 把 rounding 当作优化变量

GPTQ 按顺序补偿离散落点,但给定 scale 后,最近舍入本身未必让一个 block 的输出最接近浮点模型。可以把每个权重“向上还是向下”改写为待优化选择。

以 AdaRound 的思想为例,忽略边界时写成:

优化局部重建损失,同时用正则和退火使软选择 最终趋向 0 或 1。相对 RTN,它把每个 rounding 决策与层输出关联;相对 GPTQ,它使用可优化的软离散选择,而非只按闭式二阶补偿逐列推进。最终必须将软选择硬化后再验收,否则软模型的好 loss 不能证明整数模型也好。

AutoRound / SignRound 则用 STE 处理舍入,并通过 signed gradient descent 等设计优化 rounding 与范围。其核心不是重新训练全部预训练权重,而是针对 block 输出重建,迭代调整量化参数;当前 llm-compressor 文档列出 rounding 参数 与 clipping 参数 。固定版本接口

相对只优化 rounding,联合范围优化增加了可搜索空间,也增加了过拟合校准数据的风险。实现上应保存最佳验证状态,使用代表性 token,监控 clipping、有限正 scale 和硬化后的输出误差;迭代数与学习率要成套调整。它同样可用于 2–3 bit,但不能据此保证任何位宽、格式和 serving 后端都已有可用 kernel。

4.4 PTQ:OmniQuant 联合学习 clipping 与等价变换

固定规则的 SmoothQuant/AWQ 不一定给每个 block 找到最合适的范围分配。OmniQuant 用 Learnable Weight Clipping(LWC)和 Learnable Equivalent Transformation(LET),在局部重建中联合校准这些参数,基础权重可保持冻结。

其优化可以概括为:

等价平移与缩放的一个线性示意是:

真正吸收到计算图时,要处理 bias、norm 和多个消费者的耦合。相对固定幂指数的缩放方案,创新是让局部重建目标选择变换和 clipping 的组合;相对完整 QAT,它将训练范围约束在少量校准参数,降低成本。

LWC 还有一个具体设计:学习相对于当前 min/max 的 clipping 强度,而非直接学习一个不随权重变化的绝对阈值。以包含零的范围为例,若 ,用受约束的 定义 ,再计算量化步长。这使范围能跟随 LET 改变后的权重统计调整; 时退回原始 min/max。它解释了为什么 LWC 与 LET 要联合优化,而不只是依次叠加两个独立开关。

稳定性上,过小/过大的 会分别放大输入或权重,clipping 上下界还要保证次序正确。应在 FP32 中维护关键统计,限制非法 scale,逐层检查浮点变换的等价性,再比较量化输出;不要让重建损失掩盖一个本来就不等价的图变换。

4.5 PTQ:QuaRot 通过等价旋转分散异常坐标

令 为正交矩阵,,则:

旋转保持向量二范数和内积,但不保持最大坐标、稀疏性和量化分组内的幅度分布。对于沿少数坐标集中的向量,归一化 Hadamard 变换可以把能量分散到多个维度,改善部分量化器的有效分辨率。

例如长度 16 的向量 ,乘归一化 Hadamard 后,各坐标幅度成为 4:最大值降了 4 倍,二范数仍是 16。但原向量用一个对称 scale 可以恰好表示非零值和所有零;最大值降低本身不能证明量化误差下降。

同样,正交相似变换保持 的特征值,所以完整正交旋转不会神奇地降低 Hessian 的二范数条件数。它改变的是坐标分布及其与离散格点、分组的关系,不是凭空消除信息。

还可以用一个不依赖 GPU 的小实验,把“最大值下降”和“量化误差下降”明确分开。取 ,使用 E2M1 格点、一个 16 元素分组、实数 scale ,比较直接量化与“归一化 Hadamard → 量化 → 逆变换”。运行 配套 Python 脚本 得到:

路径量化前的最大幅度回到原坐标后的平方误差NMSE
直接量化600
旋转、量化、逆变换1.8750.3750.010067

原向量恰好落在格点上;旋转虽然压低了最大值,却破坏了这种对齐。脚本也检查了不量化时的可逆性与范数保持。这是使用理想实数 scale 的教学反例,不是 NVFP4/MXFP4 模拟器或模型精度评测;真实格式还需要加入 scale 编码及运行时舍入规则。

QuaRot 相对对角缩放的主要变化,是用正交混合把集中在少数坐标的能量分散开,并结合模型计算图安排权重、activation 和 KV 路径。对角缩放改变不同方向的长度,正交旋转保持二范数但改变与量化坐标轴的对齐,两者不是同一种变换。

“离线旋转”表示可以预先融合进权重;“在线旋转”表示推理 activation 仍需变换。RMSNorm 的归一化部分具有相应性质,但逐通道增益要正确吸收;LayerNorm 的均值、RoPE、残差、共享 embedding、tensor parallel 分片也有额外约束。特别是 通常成立,旋转不能任意穿过非线性。

4.6 PTQ:SpinQuant 进一步优化旋转矩阵的选择

随机正交矩阵都能保持浮点等价,但经过量化后精度可能差很多。SpinQuant 的创新是把旋转本身变成待优化对象,在正交约束下针对量化模型优化,而不是只接受一次随机或固定变换。

其思路可以写为 ,约束 。若只用普通优化器任意更新矩阵元素,矩阵可能不再正交,浮点等价性也随之丢失;需要论文对应的正交流形优化或约束保持更新。应同时检查 、无量化输出偏差与实际量化损失。

论文采用 Cayley SGD:从投影梯度构造反对称矩阵 ,通过形如

的更新保持正交性,其中梯度方向符号由 的构造约定决定。实现用固定点迭代近似这一更新,避免每一步显式求逆。主要优化可吸收的 R1/R2;在线 R3/R4 保留为可快速执行的 Hadamard。这说明它同时考虑了量化质量与推理变换成本。Cayley 优化细节

论文级的旋转学习与工具提供的固定旋转必须分清。在本文核对的 llm-compressor 源码中,SpinQuantModifier 会拒绝 learnable=True;它不是把论文训练过程完整封装成了一个 oneshot 开关。具体配置在工程章节说明。

4.7 PTQ:MR-GPTQ 将旋转与具体 FP4 格式共同设计

NVFP4 按 16 个元素分组,局部动态范围主要由组内数值决定,不再由整个 tensor 共用一个元素步长;不过 tensor 的 global scale 仍会影响各组局部 scale 的编码。MXFP4 则还要将组 scale 限制到 E8M0 的幂次格点。旋转可能改善组内极值,也可能把原本准确表示的零、小值和稀疏结构变成大量难以表示的新值。

MR-GPTQ 的分析和实验给出了很有价值的反例:在其研究的配置下,旋转配合普通 RTN 可以改善 MXFP4,却损害 NVFP4。后续改善依赖针对格式的量化优化,而不是只换一个更“平滑”的分布。这个结果不能外推成“NVFP4 禁止旋转”,但足以否定“所有 4 bit 都应该先做全维 Hadamard”。误差分析与方法

相对把全维 Hadamard 直接接到 RTN 前面,MR-GPTQ 把小块旋转、格式相关的 MSE scale 优化、排序和 GPTQ 补偿结合起来。关键是旋转尺寸、量化 group 和 scale 编码共同影响格点选择;论文的专门执行路径也属于整体方法,不能只比较离线误差而忽略在线变换成本。

因此需要先回答“当前是元素舍入误差,还是 scale/分组误差”,再选择是否旋转。详细指标放在第 7 节;结论应来自目标量化器和留出集,而不是只看激活直方图是否更平滑。

4.8 QAT:LLM-QAT 用蒸馏恢复联合低比特表示下的能力

4 bit 下,逐层重建足够好也可能留下跨层累积与任务分布差异。LLM-QAT 将量化模型放回训练过程,通过教师生成的数据和输出分布约束低比特学生,并考虑权重、activation 与 KV 的量化。它的 data-free 指不依赖原始预训练数据,不表示不需要样本或训练算力。

相对局部 PTQ,它优化的是更完整的模型行为;相对只用少量硬标签的 QAT,教师软分布提供了更多词表和上下文关系。通用蒸馏式 QAT 可以写为下式,其中 hidden loss 是可选扩展,并非所有论文都采用全部项:

实现时冻结教师并关闭其梯度;学生在真实目标格式的 fake quant 下训练,KL/softmax/logits reduction 使用足够高的精度。padding、next-token shift、有效 token 数和梯度累积的归一化必须一致,否则损失权重会随 batch 或序列长度变化。

W4A16 只模拟权重还可能足够;W4A4 必须把 activation 格点、scale 和 clipping 同时放入训练。对于 MXFP4/NVFP4,还要量化 scale 本身。使用 INT4 fake quant 学到的补偿,不能直接认作 E2M1 与 E4M3/E8M0 scale 下的补偿。

QLoRA 把冻结的基础权重低比特存储,梯度经反量化计算流向 LoRA。它主要解决微调内存问题,并不自动模拟最终的 W4A4 activation、KV 或 NVFP4 kernel。

尤其要检查:

训练时在反量化基础模型外加高精度 adapter,部署时却先合并再整体量化,会改变前向函数。需要匹配的 QAT/LoRA 合并策略或合并后的再次评测,不能只验证未合并模型。

原生低精度训练则进一步让 forward、dgrad、wgrad 的 GEMM 使用 FP4 操作数,必须处理梯度舍入、转置量化、累加误差和优化器状态。它与“用 BF16 GEMM 执行 fake quant 的 QAT”有不同的性能目标和稳定性要求。

4.9 QAT 与原生 FP4 训练:稳定前向还不够

普通 QAT 可以用浮点 GEMM 计算反量化后的 FP4 操作数,因此它的收益首先体现在最终模型质量。若进一步要求训练 GEMM 本身用 FP4,就进入原生低精度训练的问题:这是训练执行方式的延伸,需额外处理 backward,不能仅由 W4A4 推断。

对于 ,三类主要 GEMM 是:

它们的 reduction 方向不同,同一权重在 forward 与 backward 中还会以不同方向被消费。沿一维分组重新量化转置后的矩阵,一般有 ,意味着两个方向看到的离散权重不同。

Transformer Engine 的 NVFP4 训练 recipe 采用 16×16 的二维权重 scale,让转置路径更一致;它是训练策略,不能据此声称所有 NVFP4 推理权重都按 16×16 共享 scale。常见推理表示仍是上面的 1×16 分组。训练 primer

另外两项训练技术也要区分作用范围:

  • TE 2.16 在 wgrad 使用的 columnwise input/gradient 量化路径上应用 RHT,降低这些 reduction 方向的异常值影响。它不是把每层 forward 激活统一旋转后就结束。
  • 随机舍入用于梯度量化。对相邻格点 ,取上格点的概率为 ,下格点的概率为 ,在未饱和等条件下有 。这能降低系统性舍入偏差,但不能保证每一步梯度准确,也不能修复 clipping 的偏差。

RHT、二维 scale、随机舍入以及更高精度状态构成特定训练 recipe 的组合。不能把其中任意一个开关当作“FP4 稳定训练”的充分条件,也不能把预训练论文中的结果直接外推到 QAT。NVFP4 训练论文

5. 低于 4 bit:格点不足迫使优化目标与表示一起改变

2–3 bit 并不是把 4 bit recipe 的一个数字改小。相同范围下步长迅速增大;缩小 group 虽能降低部分误差,scale 开销却占更大比例;少数敏感层和校准偏差也更容易主导最终质量。因此,这一阶段既需要更强的 PTQ 重建,也需要考虑训练式量化。

5.1 PTQ:GPTQ / AutoRound 仍可使用,但要按真实预算比较

GPTQ 的二阶目标和 AutoRound 的 rounding 优化并没有限定必须 4 bit,可继续用于 3 bit、2 bit。变化在于单次离散化造成的扰动更大:二阶补偿的局部最优不代表下游非线性和最终任务损失也最优;局部重建的校准过拟合更容易被暴露。

可以比较更小 group、更多代表性校准 token、clipping 搜索、更多局部优化,以及少数敏感层保留高位宽。但“2 bit + 更密 scale + 更多高精度层”未必比规则 3 bit 更小。若每 个权重保存一个 16 bit scale,仅这一项就使平均位数变成:

例如 已是 3 bits/weight,还未计 zero-point 与其他 metadata。应比较相同 checkpoint/显存预算下的任务质量,而不是只比较 preset 名字。

数值上还应检查 GPTQ 的 damping 与 fallback、AutoRound 的硬化误差、局部误差的 P99,以及验证集随迭代是否反弹。混合精度选择同样属于 PTQ 内部的预算优化;如果随后用任务损失训练这些配置,再明确记录 QAT 阶段。

5.2 PTQ:QuIP / QuIP# 从独立标量转向结构化向量量化

QuIP 将 incoherence 处理与基于二阶统计的自适应舍入结合,缓解权重和 Hessian 的不利坐标结构。QuIP# 的主要推进是更高效的随机 Hadamard 处理、BlockLDLQ 与基于 的结构化向量码本,再加有限的量化恢复微调。

标量量化分别给每个 选一个值;向量量化则给一组 共同选择码字 。在输入相关性的度量下,可以把局部选择理解成:

这里是解释优化目标的示意,不是 BlockLDLQ 的完整实现。真实算法还要利用块间关系补偿先前量化误差。相对 GPTQ 的标量落点,创新是同时优化一组权重的联合表示,并利用规则码本结构控制解码成本。

需要注意两种“块”不是一回事:前文的 scale group 是共享缩放因子;这里的 vector group 是共享一个联合编码。后者可以在平均 2 bit 的预算下使用更丰富的向量形状,不能拿“每个标量只有四个值”的直觉直接判断其误差。

稳定性与部署代价包括:正交变换正确性、Hessian 分解、码本输入的归一化范围,以及专门的码本解码/矩阵乘。有限微调也要纳入压缩成本。llm-compressor 的 QuIPModifier 只提供相关变换能力,不能据此宣称已经实现 QuIP# 的完整 E8 码本和 BlockLDLQ 路径。

5.3 PTQ:AQLM 用多个可学习码本相加表示权重

固定码本结构便于优化 kernel,但未必适合每层权重。AQLM 把加性量化用于 LLM 的输入感知重建:一组权重由多个码本各选一个向量再相加。

是码本数, 是每本条目数, 是一组权重的维度;上式第二项只计算索引载荷。例如 时为 2 bits/weight,码本和 scale 还要另外计入。

核心优化分为离散与连续两个方向:通过 beam search 等方式选择 codes;固定或交替更新 codes 时,优化码本数值;再以 Transformer block 重建协调多层。相对普通向量聚类,它以输入分布加权后的层输出为目标;相对 QuIP# 的结构化码本,它进一步学习适合当前权重的加性码本,代价是搜索和解码复杂度。

这仍是从既有模型出发的 PTQ,可带有限恢复训练。工程验收要把 codebook、indices 与 scale 当作一个整体,检查反量化后输出;只保存索引或错配码本版本都会改变模型。码本更新采用足够高精度、避免少量校准样本过拟合,是实现时需额外验证的稳定性条件。

5.4 QAT:2–3 bit 下,代理梯度与部署格点的一致性更重要

继续降低位宽时,STE、LSQ、蒸馏等机制仍然适用,但每次跨格点会引起更大的离散跳变。连续参数看似平稳,不代表量化输出也平稳;应同时记录权重跨格点比例、scale 相对变化、饱和率与真正离散前向的验证损失。

可执行的训练顺序是:从浮点或 PTQ 初始化出发,按目标格式启用 fake quant;逐步引入最敏感的 activation/KV 量化点;在合法范围内优化权重与 scale;固定静态统计后继续适应;最后用目标 kernel 的舍入、打包和反量化做验收。逐步降位宽只是可选训练日程,最后必须在实际目标位宽下完成适应,不能用较高位宽的收敛替代验收。

对于码本模型,训练对象可能是码本或其他高精度参数,而不是逐权重 INT2 的 STE。应模拟实际表示:用标量 INT2 fake quant 训练后导出 AQLM,不具有数值等价性。这里的要点仍是前文 QAT 的契约,只是在更少 bit 下,失配代价更加明显。

5.5 QAT 的从头训练延伸:BitNet 从二值权重走向三值权重

BitNet 从模型训练阶段引入低比特 Linear,二值权重可以概念化为缩放后的 。相对现有模型的 PTQ,它让模型从学习过程开始就适应极低位宽;这需要训练预算,不能作为任意预训练模型的无损转换。

BitNet b1.58 的关键变化是加入零值,使用 absmean 缩放后的三值量化:

适当的位置再应用缩放因子。相比二值权重,零值让小权重能被显式忽略,减少把它们强制推到正负幅度的误差;论文中的 activation 仍使用更高位宽,不能称为全部操作数都是 1.58 bit。

这属于量化感知训练思想的从头训练延伸,不是通用现有 checkpoint 的 PTQ,也不同于少量步骤的 QAT 微调。高精度 latent weights 保存细小更新,STE 让梯度穿过离散前向,activation 归一化与合法正 scale 控制范围;优化器和梯度并未因此自动变成三值。

数值稳定性上,若连 latent weights 也每步强制覆盖成三个值,小于格点间隔的更新会直接丢失。要区分可训练状态与部署权重,并验证近零 、梯度裁剪和实际乘加/查表 kernel。理论编码率 也不能替代文件大小和端到端吞吐测试。

5.6 三种低于 4 bit 的方案,改变的是不同对象

路线解决格点不足的方式核心优化主要成本
GPTQ / AutoRound 的 2–3 bit PTQ在既定标量格点中选更合适的落点二阶补偿或局部 rounding/范围优化校准、重建与敏感层配置
QuIP# / AQLM 的 PTQ用一组权重的联合编码增加表达能力结构化向量量化或学习加性码本码本、索引、专用解码及恢复微调
BitNet 系列训练式量化让模型学习适应二值/三值权重带离散前向的训练训练资源、高精度状态与专用计算路径

因此,“都小于 4 bit”只是在比较预算;它们并没有相同的可表示集合、误差模型或实现难度。

6. llm-compressor:将不同位宽的 PTQ/QAT 选择落实为工程流程

以下沿用已核对的 llm-compressor 052d807f5eb2 与 compressed-tensors a2a210e9001d 源码快照说明接口。两者用于源码阅读,不代表本文执行过 GPU 验证的依赖组合;实验时还需锁定相互兼容的安装版本。

6.1 三层职责与版本边界

离线算法在 llm-compressor 中执行;compressed-tensors 描述量化 scheme、qparams、transform 元数据及压缩表示;vLLM/SGLang loader 再选择其支持的执行路径。

浮点模型 + 校准数据 + recipe
  → oneshot / CompressionLifecycle
  → transform → observer/Hessian 收集 → 权重量化
  → save_pretrained(save_compressed=True)
  → safetensors + quantization_config + transform 元数据
  → 推理框架 loader / repack
  → 目标硬件的量化 GEMM / attention kernel

能表达 scheme、能保存 checkpoint、能高效执行,是三次不同的验收。 例如官方 QuIP 示例仍包含额外 vLLM 改动的提示,不能由 QuIPModifier 可导入推断所有 serving 版本都支持它。

另一个具体版本陷阱是 SpinQuantModifier:在本文快照中,源码包含 R1/R2/R3/R4 的变换构造,但 learnable=True 和 randomize=True 会被 validator 拒绝。示例注释关于 R3 的描述还可能滞后于源码。因此本文把它作为旋转变换工具,而不声称运行 oneshot 就完成了 SpinQuant 论文的旋转学习。源码约束

6.2 事件、hook 和量化参数分别何时发生

在当前源码中,关键事件是 CALIBRATION_START、SEQUENTIAL_EPOCH_END、CALIBRATION_END;旧笔记中的 CALIBRATION_EPOCH_START/END 不应直接当作当前 API 名称。

阶段数据或状态变化为什么需要这个阶段
初始化 session 与 recipe匹配模块,绑定 scheme、observer、变换配置明确哪些层被改变,以及之后如何收集统计
CALIBRATION_START应用校准前变换、准备输入 hook 和统计统计必须对应后续实际量化的坐标系
当前 subgraph 的 forward收集 activation 范围、Hessian、AWQ 所需输入每种算法看到的并不是同一类“校准数据”
SEQUENTIAL_EPOCH_END搜索 scale、执行补偿、更新权重与 qparams在激活和临时矩阵可以释放前完成当前块
propagation forward在启用误差传播时,用当前压缩结果产生下一块输入后续层适应上游压缩带来的分布变化
CALIBRATION_END / finalize收尾状态与 hook避免继续更新本应固定的统计
compressed save序列化并进行压缩表示转换真正生成低比特存储,不等于训练/校准中的浮点 fake quant

SequentialPipeline 会在 propagation pass 关闭采集 hook,避免再次污染统计。这一遍是否执行由 propagate_error 控制;该快照对 AutoRound 会将它关闭,不能概括为“所有算法固定两次 forward”。

GPTQ 为宽度 的一层保存 FP32 Hessian,单这一项约需 字节: 时约 256 MiB,还没计权重副本、Cholesky 和 activation。Sequential/offload 减少同时驻留的对象,但不消除单层平方级状态;显存不足时要看具体哪个状态占用,而不是仅减小量化后的 group size。

通用 QuantizationModifier 内部的 fake quant 不意味着 oneshot 在执行 QAT。判断是否训练,要看是否有 optimizer step、哪些参数有梯度、优化的 loss 是什么;本文主线的 oneshot 示例是 PTQ。

6.3 先建立一条可复现的校准和保存链

下面采用本地 JSONL 校准文件,每行有一个 text 字段。对 instruction 模型,建议先用该模型 tokenizer 的 chat template 生成 text,后续 tokenization 避免重复加 BOS/EOS。不要用不匹配的模板让量化统计学到另一种输入分布。

from pathlib import Path
from datasets import load_dataset
from transformers import AutoModelForCausalLM, AutoTokenizer
from llmcompressor import oneshot
from llmcompressor.modifiers.gptq import GPTQModifier
 
MODEL_ID = "/models/base-model"  # 换成实际模型目录或 HF ID
OUT_DIR = "/models/base-model-w4a16-gptq"
N_CALIB = 256
MAX_LEN = 2048
 
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
model = AutoModelForCausalLM.from_pretrained(MODEL_ID)
ds = load_dataset("json", data_files="calibration.jsonl", split="train")
ds = ds.shuffle(seed=42).select(range(min(N_CALIB, len(ds))))
assert len(ds) > 0
ds = ds.map(
    lambda row: tokenizer(
        row["text"], truncation=True, max_length=MAX_LEN,
        padding=False, add_special_tokens=False,
    ),
    remove_columns=ds.column_names,
)
 
recipe = GPTQModifier(
    targets="Linear", scheme="W4A16", ignore=["lm_head"],
    block_size=128, dampening_frac=0.01,
)
oneshot(
    model=model, tokenizer=tokenizer, dataset=ds, recipe=recipe,
    max_seq_length=MAX_LEN, num_calibration_samples=len(ds),
)
Path(OUT_DIR).mkdir(parents=True, exist_ok=True)
model.save_pretrained(OUT_DIR, save_compressed=True)
tokenizer.save_pretrained(OUT_DIR)

这里的 256 条、2048 token 和 damping 都是起点。更有价值的是校准 token 的分布:覆盖语言、代码、推理长度、真实系统提示和工具调用;对 MoE,还要关注 expert 覆盖。校准集、用于挑选 recipe 的验证集、最终质量测试集要区分开。

仅量化 Linear 不一定覆盖模型中的所有矩阵:fused QKV、定制 MoE 层和非标准模块需要框架适配。应检查匹配到的模块数、忽略列表、处理日志,而不是看到脚本无异常就认为全模型按预期量化了。

6.4 只替换 recipe,但每次重载原模型

AWQ W4A16: 使用前置缩放与后续量化两段式配置。

from llmcompressor.modifiers.transform.awq import AWQModifier
from llmcompressor.modifiers.quantization import QuantizationModifier
 
recipe = [
    AWQModifier(duo_scaling="both"),
    QuantizationModifier(
        targets="Linear", scheme="W4A16_ASYM", ignore=["lm_head"],
    ),
]

AWQ 的 mappings 定义哪些生产者/消费者参与等价缩放,targets/ignore 定义哪些模块量化,两者不能互相代替。被 ignore 的层仍可能参与保持函数等价所必需的缩放。AWQ 示例与 mappings

SmoothQuant + GPTQ W8A8: 前者改善输入分布,后者补偿权重误差。

from llmcompressor.modifiers.transform.smoothquant import SmoothQuantModifier
 
recipe = [
    SmoothQuantModifier(smoothing_strength=0.8),
    GPTQModifier(targets="Linear", scheme="W8A8", ignore=["lm_head"]),
]

本文 compressed-tensors 快照中的 W8A8 是权重 per-channel static、activation per-token dynamic 的对称 INT8 配置。这里 0.8 沿用官方示例,需与其他候选比较。对应示例

FP8 dynamic: 可用于低成本验证压缩—导出—推理链路。

recipe = QuantizationModifier(
    targets="Linear", scheme="FP8_DYNAMIC", ignore=["lm_head"],
)

纯 RTN 的这个 preset 权重按 channel、activation 按 token 动态量化,不需要为了激活范围特意收集静态校准数据;用 pipeline="datafree" 的路径时不要误称其进行了 Hessian 校准。若前面加了依赖统计的 transform,则仍按 transform 的需求准备数据。

NVFP4 RTN 与 GPTQ: 先比较无旋转的同格式基线。

recipe = QuantizationModifier(
    targets="Linear", scheme="NVFP4", ignore=["lm_head"],
)
# 或在独立的一次运行中比较:
recipe = GPTQModifier(
    targets="Linear", scheme="NVFP4", ignore=["lm_head"],
    block_size=128, dampening_frac=0.01,
)

NVFP4 与 NVFP4A16 分别表示权重/激活联合量化和 weight-only;MXFP4 与 MXFP4A16 同理。preset 不能只看名字,要读取 quant_scheme.py。更细的 observer、act-order、scale 配置,应参考固定版本的 llama3_gptq_example.py,不要混用另一个版本的字段。

6.5 旋转在 recipe 中放在哪里

比较分组旋转时可以用下面的实验组合,但它并不等于完整 MR-GPTQ:

from llmcompressor.modifiers.transform import QuIPModifier
 
recipe = [
    QuIPModifier(
        rotations=["v"], transform_type="hadamard", transform_block_size=16,
    ),
    GPTQModifier(targets="Linear", scheme="NVFP4", ignore=["lm_head"]),
]

它表达的是“输入侧小块旋转 + GPTQ + NVFP4”。完整 MR-GPTQ 还涉及格式相关 scale 搜索、重排和专门 kernel 支持;把三个名字组合起来,不能声称复现了论文结果。即使块大小恰好是 16,也要检查 transform block 与 quantization group 的轴和排列是否一致。

模型级旋转可参考:

from llmcompressor.modifiers.transform import SpinQuantModifier
 
recipe = [
    SpinQuantModifier(rotations=["R1", "R2", "R4"],
                      transform_type="hadamard", transform_block_size=128),
    QuantizationModifier(targets="Linear", scheme="W4A16", ignore=["lm_head"]),
]

这对应当前示例中的固定变换,不执行 learned rotations。隐藏维度、head dimension 和 transform block 的整除要求需逐模型检查;R3 attention 变换还涉及专门适配,不能随意多加一个字符串就认为正确。SpinQuant 示例

旋转后至少保存变换类型、块大小、应用模块、在线/离线状态及相关参数。若服务器丢掉在线变换,权重文件即使成功加载,也可能计算另一个函数。带旋转的 checkpoint 必须先在实际 serving 后端验证输出,再做速度比较。

6.6 怎样判断导出的模型真的按目标方案执行

建议保留一个运行清单:原模型 revision、llm-compressor/ compressed-tensors/推理框架版本、CUDA 与 GPU、校准数据标识和 hash、seed、token 数、recipe、忽略层,以及量化 fallback 日志。

导出后检查三件事:

  1. config.json 的 quantization_config 与预期格式、group size、activation 动态策略一致,transform 元数据未丢失。
  2. safetensors 不只是保存了一个插有 fake quant 的 BF16 模型;实际存在对应压缩表示和 scale,权重载荷大小合理。不同格式的字段名不能机械套用 qweight/scales/qzeros。
  3. 推理日志和 profiler 显示实际 kernel。checkpoint 标着 NVFP4,不保证硬件执行 W4A4;官方示例指出较早架构可走 weight-only 路径,具体还依后端与 shape 支持。

对于常规受支持的 compressed-tensors checkpoint,vLLM 通常从配置识别量化方式;不要把 AWQ 优化出的 compressed-tensors 文件强行当成另一种 AWQ checkpoint 布局。GPU 支持、tensor-parallel 分片和真实 shape 都要包含在验收里。vLLM 集成说明

6.7 2–3 bit 的 PTQ recipe 与方法实现边界

在当前快照中,W2A16、W3A16 可以表达相应的整数量化 scheme,AutoRound 也提供相关工作流。下面展示替换 recipe 的方式,其他模型加载、校准与保存步骤沿用上面的完整示例:

from llmcompressor.modifiers.autoround import AutoRoundModifier
 
recipe = AutoRoundModifier(
    targets="Linear", scheme="W3A16", ignore=["lm_head"], iters=200,
)

需要安装该版本所要求的 AutoRound 依赖。iters=200 是官方示例的起点,不是质量保证;校准长度、batch、样本数量和学习率仍需配合调整。AutoRound 示例

文中的方法当前工程入口不能由此推断的能力
INT8 / FP8 / NVFP4 RTNQuantizationModifier + 对应 scheme不自动执行二阶补偿或 QAT
GPTQGPTQModifier不保证每层成功分解、不替代 activation 校准
AWQ / SmoothQuanttransform + quantization/GPTQ 的组合不保证任意模型的跨层映射都正确
AutoRoundAutoRoundModifier + 独立依赖支持配置不等于 serving kernel 已覆盖所有位宽
QuaRot/SpinQuant 风格变换对应 transform 与模型适配固定变换不等于论文 learned rotation
QuIP# / AQLM专门算法、码本格式和加载/执行实现QuIPModifier 不提供完整 QuIP#,W2A16 不等于 AQLM
PACT / LSQ / LLM-QAT / BitNet对应训练实现或显式训练循环oneshot 不自动完成这些训练方法

只有数值表示、算法、导出格式和实际 kernel 连成完整路径,一个低位宽 recipe 才有部署意义。

6.8 QAT 的 prepare、训练、convert 与打包

一个可验证的日程是:先加载浮点或已有 PTQ 初始化;准备目标 FQ;用少量训练步 warm-up;开启目标位宽训练;待静态统计稳定后冻结 observer;以最终部署配置继续适应;最后 convert、pack、重新加载评测。warm-up 长度和冻结时间由实验决定。

冻结 observer 不等于冻结所有运行时 scale。dynamic per-token/per-block 的计算方式就是模型前向的一部分,部署需要它,QAT 也必须继续模拟它。

torchao 的核心接口可以表示为:

from torchao.quantization import (
    quantize_, Int8DynamicActivationInt4WeightConfig,
)
from torchao.quantization.qat import QATConfig
 
base_config = Int8DynamicActivationInt4WeightConfig(group_size=32)
quantize_(model, QATConfig(base_config, step="prepare"))
# 在这里构建 optimizer,并执行你自己的训练循环。
# train_loop(model)
quantize_(model, QATConfig(base_config, step="convert"))

这是接口骨架,model、训练数据和 optimizer 由调用者提供。它展示 prepare/convert 的职责,不意味着 torchao 的 Tensor subclass checkpoint 可直接作为 llm-compressor 的 compressed-tensors checkpoint 加载。两条导出链必须按各自后端验证。QAT API

最后要逐项对齐:位宽、signed 范围、group axis、padding、rounding tie rule、clipping、static/dynamic 策略、scale 编码、global scale 方向,以及敏感层的排除列表。对 FP4,fake quant 必须使用真实 E2M1 非均匀格点及量化后的 scale;拿 INT4 fake quant 训练再导出 NVFP4,没有数值等价性保证。

8 bit、4 bit 和 2–3 bit 的 QAT 都应保留训练日志与离散模型验收;若改了 quantizer、合并了 adapter 或替换了 backend,需要重新对拍,不能复用旧结果。

7. 数值稳定性与方法选择:用哪些指标判断有效

7.1 先验证浮点等价性,再测目标格式的量化误差

先固定最终 quantizer:元素格式、group size、scale dtype、clipping、rounding、scale 算法都不能在消融实验中悄悄改变。然后按下面顺序测量。

第一层:确认变换本身正确。 不打开量化,比较原模型与旋转模型的输出,记录逐层相对误差和 logit 偏差。允许浮点重排带来的舍入差异,但明显漂移通常表示转置、逆变换、norm 融合、RoPE 或分片处理出了问题。

第二层:看分布,但只作为诊断。 对每层、每 token、每个实际量化 block 统计:

再记录峰度、组间 amax 比例、zero-collapse、饱和比例和 scale 编码的极值占比。全零组单独处理,不用除法产生的巨大比值把它误判为 outlier。这里没有通用的“ 必须旋转”阈值。

第三层:用真实目标量化器检查输出。 至少记录:

同时看 cosine similarity 和误差的 P95/P99;接近零的参考输出单独统计绝对误差。weight-only 可以比较 ;W4A4 必须重新执行 ,不能只比较 。

第四层:以任务和部署决定是否保留。 独立留出集上的 、PPL、teacher/student logit KL,用于发现整体偏移;代码、数学、检索、长上下文和真实业务评测用于发现平均值掩盖的退化。最后测真实 kernel 下的 TTFT、TPOT、吞吐、显存和旋转耗时。

PPL 比值满足 ,因此 NLL 更适合比较小幅差异。评测 tokenization、chat template、序列裁剪和 loss mask 必须一致,否则 KL/PPL 的差异可能来自评测管线。

分布统计需要按真正的 quantization group 计算。例如长度为 的非零组,忽略 epsilon 有 ;对 NVFP4 的 16 元素组,上界只有 4。因此不能把从整层张量算出的阈值直接套到 block 指标上。这是诊断粒度影响结论的一个具体例子。

7.2 旋转是否保留:做同格式消融,而不是只比较异常值

候选目的与谁比较
BF16 原模型建立质量与性能基线所有候选
BF16 + 旋转检查图变换是否等价BF16 原模型
RTN,无旋转测格式本身的损失BF16
GPTQ,无旋转分离二阶补偿收益同格式 RTN
RTN + 分组旋转只考察旋转影响同格式 RTN
GPTQ + 分组旋转检查组合是否优于单项无旋转 GPTQ
更改旋转块大小或学习旋转检查额外复杂度是否必要前面最好的可部署候选

每个候选都从原始 checkpoint 重新开始,并在变换之后重新校准;不要在已经量化的权重上不断叠加旋转。若使用随机旋转,固定并保存 seed,至少比较多个 seed 的方差,避免挑中一次偶然好结果。

我的选择原则是:先把任务允许的掉点、P99 延迟和显存预算写成约束,再比较满足约束的候选。只有分布改善、却没有真实重建误差或留出集收益的旋转不应默认保留;只有精度收益、却没有可接受 kernel 路径的旋转,也还不是完成的工程方案。

7.3 按症状定位 PTQ 与 QAT 的稳定性问题

症状优先检查可验证的处理方向
小值大量变零,但没有 NaN组内 range、scale 编码、最小非零格点减小 group、搜索 clipping/scale、比较变换前后 NMSE
少数长输入明显掉点校准长度分布、静态 global scale、饱和率扩充代表性校准输入,检查 local dynamic 是否真的启用
GPTQ 某层异常或退回 RTNHessian 对角线、非有限数值、Cholesky、校准覆盖FP32 统计、适度 damping、记录并评估 fallback 层
QAT 开始后 loss 激增一次开启过多量化点、observer 快速变化、scale 梯度warm-up、分阶段启用、静态 observer 冻结、独立 scale 学习率
QAT loss 正常、部署明显退化fake quant 与 kernel 不一致、LoRA 合并、变换丢失对同一输入做量化前后、pack 前后和 loader 后的逐层对拍
FP16 NaN/Infreduction、softmax、scale 倒数、loss scaling用 FP32 统计与 reduction;必要时 BF16;先 unscale 再裁剪梯度
模型更小却更慢独立 dequant、旋转 GEMM、layout/repack、小 batch 开销profiler 分离 quant/rotate/GEMM,核对 fused kernel 与真实瓶颈

对于 QAT 的训练状态,至少监控 loss、gradient norm、非有限梯度次数、scale/阈值直方图、饱和率、zero-collapse、observer 更新幅度。使用梯度累积时,observer 是否每个 microbatch 更新、分布式统计是否合并,也会影响结果。

GradScaler 主要解决特定混合精度路径的梯度数值问题,不会自动让 E2M1 多出有效格点。BF16 的动态范围更大,常常不需要 FP16 风格的 loss scaling,但 BF16/FP4 的舍入噪声仍然存在。

敏感算子需要分别考虑:norm 的均值/方差或平方和统计、softmax 的减最大值与指数/reduction、长 reduction 的累加,通常需要比 FP4 元素更高的精度。INT8 GEMM 的典型乘积累加是 INT32;浮点 GEMM 要区分输入格式、累加类型、部分和归并方式和输出 dtype。高精度累加只能减少累加误差,不能恢复输入量化时已经丢掉的信息。

“保留高精度层”也应由消融驱动。常见候选是 lm_head、embedding、norm、router 和敏感 attention 路径,但全都排除会降低压缩收益;MoE router 的微小偏差可能改变 expert 选择,需要看路由分布与任务结果,而不只看 Linear 的平均 MSE。

8. 将相同思路用于 KV Cache 与实际 kernel

KV 的 scale 校准、异常值处理、离线选择量化轴可放在 PTQ 路线下理解;若训练前向模拟 KV 量化并优化模型,则属于 QAT 的一部分。KV 数据在运行时产生,所以“动态量化”描述的是数据与 scale 的产生方式,不意味着在线更新模型权重。

8.1 权重压缩为何不能代替 KV 压缩

Weight-only 的存储与计算路径

W4A16 常用低比特权重存储,再在 kernel 内解包和反量化到计算片段;不会必然执行 INT4×BF16 的原生乘法。优化的重点是把读取、dequant、scale 和 GEMM 连成一个 tile 数据流,而不是在 HBM 生成完整的 BF16 权重副本。

小 batch decode 常更受权重读取限制,prefill 或大 batch 更容易提高复用和算力利用率,所以同一低比特方案在不同阶段可能有不同收益。Marlin 的专用 pack/repack 价值也在于贴合消费顺序,不能只由“4 bit 少了一半”推导端到端速度。MARLIN

每条序列的 KV 数据量近似为:

为层数, 为缓存长度, 为 KV head 数, 为 head dimension, 为每元素数据位数。并发、多份缓存和 metadata 要另计,prefix sharing 则可能减少重复存储。

8.2 K 与 V 的量化轴为什么可能不同

KV Cache 数据与 scale 布局

K 的误差影响 和随后 softmax 的概率分布;V 的误差影响概率加权求和。两者的统计分布和使用方式不同,因此没有“所有 KV 都应该 per-token”或“所有 K 都应该更低位宽”的普遍结论。

KIVI 使用 key per-channel、value per-token 的不对称方案;KVQuant 进一步讨论 pre-RoPE key、非均匀量化和异常值处理。pre-RoPE 量化需要 attention/缓存路径配套,不是改 checkpoint 的一个字段就能实现。

若 K 的 scale 是每 token/head 一个标量,可以融合进相应 score 的缩放;若 scale 沿 head dimension 分组,则必须在 reduction 内处理。V 同样如此。只有满足对应广播条件,才能把公式简写为 dot(Q, K_q) * k_scale。

FlashAttention 通常不长期物化完整 score 矩阵。因此 attention 量化应明确是在 Q/K/V、KV 存储、QK/PV 乘法输入还是 softmax 中间结果上施加量化;这些对象不能用“attention score 量化”一词互相替代。

8.3 vLLM / SGLang 的参数与布局要按版本核对

vLLM 的 Quantized KV Cache 文档 区分 KV dtype、scale 来源与后端能力。模型 weight scheme 和 KV dtype 分别设置,导出权重量化文件不会自动启用所有 KV 路径。per-tensor、per-head 与 per-token-head 不是同一个 scale shape。

旧笔记记录过 Triton attention 将 FP32 scale 内联在每个 token/head 的 KV 数据尾部的布局:

[num_blocks, 2, block_size, num_kv_heads, data_head_size + scale_pad]
scale_pad = sizeof(float32) / sizeof(cache_storage_dtype)

这是一种具体实现方式,不是所有 vLLM cache 的公共契约。其好处是 scale 跟随 paged block 生命周期,代价是所有读写路径都必须理解尾部布局;具体版本以 Triton backend API 及对应源码为准。

SGLang 文档在本次核对时已分别列出 nvfp4 与 fp4_mx_block16 等 KV 选项。旧稿中的 fp4_e2m1 字符串不应视为当前通用启动参数;其 block-16 MX 风格 KV 也不能直接称作 OCP 标准 block-32 MXFP4。FP8 scale 缺失而使用 1.0 时,还应检查动态范围是否合适。SGLang KV 配置

8.4 TurboQuant、UltraQuant 与可部署性的距离

TurboQuant 将在线向量压缩、旋转、标量量化与残差估计联系起来,关注向量和内积误差;它并不等价于标准 MXFP4/NVFP4 checkpoint。

UltraQuant 则把低比特 KV 放进 context-heavy agent 的执行场景,考察格式近似、缓存压力与 attention kernel。旧稿记录其后期 agent round 的 P50 TTFT 最高约 3.47×、全轮次约 2.3×、输出吞吐约 1.63×;这些是原报告特定 workload 的结果,不是本文本机实测,也不能外推到短上下文服务。

这里可以看到一个跨层关系:如果 KV 压缩减少了缓存驱逐和重算,即使单次 attention 计算只略有改善,后期多轮请求的 TTFT 也可能明显下降。反过来,缓存本来就够用时,相同压缩格式的额外 dequant 反而可能成为开销。

9. 方法演进的主线与实验顺序

原有方法的不足后续改进方向代表方法核心优化对象
一个范围覆盖不了主体与异常通道混合精度分解、等价缩放LLM.int8、SmoothQuant计算路径、通道范围
权重最近舍入不等于输出最优输入加权重建与二阶补偿GPTQ权重落点及剩余误差
等价参数化影响重要权重的精度activation 感知的 scale 搜索AWQ通道相对缩放
固定 rounding 与范围不够灵活局部学习 rounding、clipping 与变换AdaRound、AutoRound、OmniQuant压缩参数
异常值集中在少数坐标正交混合、学习旋转、格式相关微旋转QuaRot、SpinQuant、MR-GPTQ坐标系与格式匹配
极低位宽的独立标量格点不足联合编码一组权重QuIP#、AQLM码字选择、码本与块重建
局部 PTQ 无法弥补模型级行为差异在目标离散前向下训练STE/PACT/LSQ、LLM-QAT权重、阈值/scale 与任务目标
后压缩模型不易适应二值/三值从学习阶段引入离散权重BitNet 系列量化感知的预训练

这些是问题与解法之间的关系,不是一张“越晚发表越好”的排名。GPTQ 与 AWQ 优化不同对象,旋转与码本可能增加运行开销,QAT 也需要明确目标格式和训练预算。

先锁定模型、tokenizer、chat template 和原始 checkpoint;按训练/校准、recipe 选择、最终验收分别留出数据。建立 BF16 的质量、显存和延迟基线之后,再分离权重、activation、KV 三条轴。

如果参数显存是主要限制,先比较 RTN/GPTQ/AWQ 的 W4A16;如果 GEMM 吞吐是主要限制,比较有实际内核支持的 W8A8/FP8;如果是 KV 容量限制,单独测试低比特 KV。Blackwell 上再把 NVFP4/MXFP4 作为完整候选,不把架构支持直接当成性能结论。

当 PTQ 无法达到质量约束时,先定位少数敏感层、scale 或校准覆盖问题,再考虑更昂贵的重建、旋转搜索或 QAT。QAT 的目标应是弥补已明确的量化缺口,而不是在部署格式尚未确定时训练一个无法导出的学生模型。

最终至少报告以下指标,并写明统计口径:

  • 质量:独立集 NLL/PPL、任务 accuracy 或 pass@k、logit KL、长上下文检索与多轮成功率。
  • 局部数值:分层 NMSE/SQNR、尾部误差、饱和率、zero-collapse、scale 分布、GPTQ fallback。
  • 存储:checkpoint 大小、权重载荷、scale/zero-point、KV 数据与 metadata、峰值 workspace。
  • 性能:固定 batch 和输入/输出长度下的 TTFT/TPOT、P50/P95/P99、吞吐及 profiler 中 quant/rotate/GEMM 占比。

把“浮点等价变换通过”“目标量化器误差可接受”“packed checkpoint 对拍通过”“部署任务达标”“真实性能有收益”作为连续的验收关口,才能知道一个方案究竟在哪一层有效。

回到格式这个起点:8 bit 的范围问题推动了异常值分解与缩放;4 bit 的粗格点推动了重建、补偿、旋转和联合训练;低于 4 bit 又推动了向量/加性码本与二值、三值模型训练。PTQ 主要改进如何压缩已有模型,QAT 进一步改变模型如何适应目标量化器。选择方法时,需要把元素格式、scale、核心优化、数值稳定性和实际 kernel 放在同一个实验里检验。

附录:保留旧稿的性能观察与外部评测

A. H20 GEMM 的历史记录

旧稿保存了下面这组 H20/Hopper、、AI 辅助实现的 GEMM 数据。这里保留作者当时的观察,但原记录缺少完整代码版本、编译配置、预热和计时口径,因此不能当作本文新测的可复现基准,也不能据此给不同框架作普遍排名。

方案实现时间吞吐
W8A8 INT8xINT8CUTLASS0.100 ms171.7 TFLOPS
W4A16 BF16xINT4CUTLASS0.162 ms105.7 TFLOPS
W4A16 BF16xINT4Triton0.170 ms101.2 TFLOPS
W4A8 INT8xINT4CUTLASS full path0.111 ms154.4 TFLOPS
W4A8 INT8 fusedTriton0.101 ms169.8 TFLOPS
W4A8 BF16 fusedTriton0.179 ms96.1 TFLOPS

表中的吞吐沿用旧稿命名,按有效工作量 理解;INT8 路径的计数不应误认为硬件执行了同等数量的浮点指令。几条融合路径是否包含 activation quant、weight unpack、scale 处理,也会直接影响比较。

我保留这组记录,是因为它提醒了一个具体问题:W4 比 W8 更小,并不保证这个 shape 下更快。若解包、类型转换和缩放成本超过节省的访存成本,端到端时间就可能增加。需要将这个判断带回真实 kernel 和 workload 验证。MARLIN 的内核设计 与 量化精度—性能评测 可作为进一步阅读。

B. SGLang 官方 KV accuracy 表

以下数值来自 SGLang Quantized KV Cache 文档,保留旧稿摘录并在本次核对。KV16/KV8/KV4 是该表的配置标签,具体模型、框架版本、格式与评测设置以原报告为准;这些不是本文本机实测。

模型数据集KV16KV8KV4
Qwen3-235B-A22Bgsm8k0.91680.91810.9186
Qwen3-235B-A22Baime250.77330.73330.6000
Qwen3-235B-A22Bgpqa_diamond0.70100.68990.6778
DeepSeek-R1-0528gsm8k0.91570.91540.9124
DeepSeek-R1-0528aime250.50670.49340.4000
DeepSeek-R1-0528gpqa_diamond0.77070.76970.7273
GPT-OSS-120Bgsm8k0.91610.91630.9152
GPT-OSS-120Baime250.75330.76670.3533
GPT-OSS-120Bgpqa_diamond0.50810.54340.3202

这个结果支持的判断是:单看 GSM8K 近似持平,无法保证 AIME 或 GPQA 也保持质量。它并不能单独证明退化一定来自某一量化轴或某个 outlier;定位原因仍需前文的分层误差与消融。

对于每 16 个 FP4 元素一个 8 bit scale 的数据区, 倍 BF16 容量、 倍 FP8 容量是忽略其他开销的理论关系;服务实际可容纳 token 数还取决于 page 对齐、其他 metadata 和固定显存开销。

参考资料

正文在对应机制旁链接了论文、固定源码和官方 recipe。下面保留原综述的生态资料入口,便于继续追踪实现;未固定版本的文档应按实际部署版本重新核对。