Inference Quantization Formats

导言

W8A8W8A4W16A8 看似只差两个数字,实际可能对应完全不同的对象、尺度粒度、在线流程和硬件 kernel;FP8MXFP8 都是八位元素,却又因块尺度而具有不同的数据布局。更容易误解的是,量化位宽、检查点大小和最低运行显存是三个不同问题

本文先建立一套可复用的阅读方法,再用物理结构、实现逻辑、流程、时序和张量数据流解释常见路径,最后核对截至 2026-07-28 的 Qwen3.5、Kimi K3 和 GLM-5.2 开放权重。所有“多大”均来自当前 Hugging Face 仓库中 .safetensors 文件的实际字节和,而不是用参数量乘标称位宽反推。

先读懂量化记法

一句话先给结论:**WnAm 只是一段算子精度标签,不是一份完整的量化规格。**

  • W 是目标算子的 weightA 是输入 activation
  • nm 是计划使用的位宽,不说明数值是 INT、FP 还是 MX。
  • A 不是 accumulator。累加器可能是 INT32、FP16、FP32 或硬件定义的更宽内部格式。
  • 标签不说明尺度、零点、分组粒度、静态或动态量化、输出 dtype、排除模块、KV cache 和实际 kernel。

因此,看到一个短标签时,至少补全下面六列:

维度 必须追问 例子
数值家族 INT、FP、MX,还是厂商格式 INT8、E4M3、MXFP4、NVFP4
量化对象 权重、激活、KV、通信张量 W4A16 只压目标权重
粒度 tensor、channel、group、token、block GPTQ group 128、MX block 32
参数 scale、zero point、是否对称 INT8 对称量化可令 z=0
时机 离线、静态校准、每次动态生成 per-token dynamic activation
执行 原生低比特、融合解量化、fallback MXFP4 → W4A8 或 W4A16

常见记法可以先按“主要压缩对象”归类:

记法 权重 激活 首要收益 首要风险
W4A16 4 bit 16 bit 权重常驻量和读取带宽 解量化成本、权重误差
W8A16 8 bit 16 bit 较稳健的权重压缩 加速幅度依赖 kernel
W8A8 8 bit 8 bit 两侧带宽与低精度 GEMM 激活异常值、在线量化
W16A8 16 bit 8 bit 激活/通信带宽 不降低权重常驻量
W8A4 8 bit 4 bit 更激进的激活与计算压缩 A4 精度与硬件约束
MXFP8 W8A8 E4M3 E4M3 小块动态范围与原生 MX kernel 块尺度布局、硬件限制
MXFP4 W4A4/A8 E2M1 FP4/FP8 极低位宽 MoE/GEMM fallback 后可能变成 A16
![小黑压缩权重行李,但运行显存还包含尺度、KV 和工作区](https://pic.shaojiemike.top/shaojiemike/2026/07/25d494e03860a873f7e8e14392d1d5b7.png){ width=92% }
认知锚点:短标签只描述部分行李。压缩权重以后,尺度、KV 或循环状态、workspace 等运行对象仍需装上“运行显存”这辆车。该图用于解释概念,不作为容量证据。

量化算子的共同骨架

无论是 INT 还是 FP/MX,量化线性层都要处理三类对象:低精度元素、恢复数值范围的尺度,以及比输入更宽的累加/输出。区别主要发生在映射公式、尺度粒度和生成时机。

整数量化

b bit 整数,最常见的仿射量化写成:

$$
q = \operatorname{clip}\left(
\operatorname{round}\left(\frac{x}{s}\right) + z,,
q_{\min},q_{\max}
\right), \qquad
\hat{x}=s(q-z).
$$

其中 s 是 scale,z 是 zero point。对称量化通常令 z=0;若使用有符号 b bit 且按最大绝对值定标,可近似取:

$$
s=\frac{\max |x|}{2^{b-1}-1}.
$$

这两个式子只定义了数值映射。实现还要决定 max 在整张量、每通道、每组还是每 token 上求;粒度越细,局部范围通常越容易拟合,但尺度数量、布局和 kernel 复杂度也越高。TensorRT 的量化文档给出了 INT8 的舍入、裁剪和反量化定义,可作为理解框架。TensorRT Quantized Types

静态、动态与 QAT

  • PTQ(Post-Training Quantization):训练完成后,用权重统计或校准样本生成量化参数。GPTQ、AWQ 和许多 FP8 转换属于这一大类。
  • 静态激活量化:提前校准并保存激活尺度;运行时少做一次范围统计,但尺度对输入分布漂移更敏感。
  • 动态激活量化:每次执行按 token、row 或 group 求范围并生成尺度;适应性更好,但增加归约与转换。
  • QAT(Quantization-Aware Training):训练或 SFT 阶段模拟量化误差,使模型主动适应低精度。Kimi K3 的模型卡明确把 MXFP4/MXFP8 与 QAT 绑定。Kimi K3 Model Card

一个完整的动态量化线性层可以规范化为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def dynamic_quantized_linear(x16, packed_weight, weight_scale, spec):
# 1. 当前激活的量化参数
activation_range = reduce_amax(x16, axis=spec.activation_group_axis)
activation_scale = choose_scale(
activation_range,
bits=spec.activation_bits,
value_format=spec.activation_format,
)

# 2. 当前算子生命周期内的低精度激活
xq = quantize_and_pack(
x16,
scale=activation_scale,
bits=spec.activation_bits,
symmetric=spec.symmetric,
)

# 3. kernel 直接消费 packed W、xq 和两侧尺度
accumulator = low_precision_gemm(
xq,
packed_weight,
x_scale=activation_scale,
w_scale=weight_scale,
accumulator_dtype=spec.accumulator_dtype,
)

# 4. 输出通常回到残差路径要求的较宽 dtype
return rescale_and_cast(accumulator, spec.output_dtype)

TorchAO 也把 weight-only、dynamic activation plus weight、static quantization 分为不同工作流;“都是 8 bit”并不意味着运行阶段相同。 torchao Quantization Overview

W4/W8A16:只压权重

Weight-only 是最直接的推理量化:先缩小模型生命周期内的权重对象,不改变进入算子的高精度激活。

原理

W4A16 或 W8A16 的目标是让持久化权重从 BF16/FP16 变成低比特元素,加上较少的 scale/zero-point side data。激活仍保持 BF16/FP16。推理时有两种主要执行方式:

  1. 融合解量化 GEMM:kernel 读 packed weight,在寄存器或片上块内恢复数值,然后直接参与乘加。
  2. 原生混合低比特 GEMM:硬件和 kernel 直接支持低比特权重与 A16 的组合。

如果框架先把整层权重完整反量化到显存,再调用普通 GEMM,就会额外产生大张量和带宽,削弱 weight-only 的优势。

![W4/W8A16 权重量化的物理、逻辑、流程、时序和数据流](https://pic.shaojiemike.top/shaojiemike/2026/07/3d2f95d9946f665c963b7e27ec4b5478.png){ width=100% }
W4/W8A16 五视图。源码锚点为 vLLM commit 7aea73d8compressed_tensors_wNa16.py:2–8 bit 权重、pack factor、packed INT32 权重与 scale 注册,以及 A16 kernel 配置。图示不表示所有模块都被量化。

适用性与效果

  • 适合:模型主要受权重常驻量或 HBM 读取限制;目标硬件没有稳定的低比特激活路径;希望降低部署风险。
  • 直接效果:目标线性层的 packed weight 变小,权重带宽下降。
  • 不能推出:模型整体严格缩小为 4/16;embedding、norm、LM head、视觉编码器和尺度仍可能是高精度。
  • 性能边界:大 batch/prefill 可能更 compute-bound;解码时 weight-only 往往更容易体现权重带宽收益,但仍要实测。

vLLM 当前的通用 WnA16 scheme 明确注册了 packed 权重、尺度与目标激活 dtype,apply 最终委托给选中的 kernel,而不是由 W4A16 标签自行保证速度。vLLM WnA16 source

W8A8:权重与激活同时压缩

W8A8 进一步把当前算子生命周期内的 activation 也变窄,因而把动态范围统计和尺度流带进在线关键路径。

原理

INT8 W8A8 常把权重离线量化,把激活在线动态量化。一个 token/row 到达线性层后,前处理先求 amax、生成 input scale、舍入到 INT8;GEMM 再读取 INT8 weight 与 weight scale,使用较宽累加器,最后反缩放并输出 BF16/FP16。

![动态 INT8 W8A8 的物理、逻辑、流程、时序和数据流](https://pic.shaojiemike.top/shaojiemike/2026/07/4dfb6ac6fc34e79b05ce4b73086f92c1.png){ width=100% }
动态 INT8 W8A8 五视图。源码锚点为 vLLM commit 7aea73d8compressed_tensors_w8a8_int8.py:INT8 weight/scale、可选静态 input scale/zero point 与 kernel apply。

适用性与效果

  • 适合:目标硬件具有成熟 INT8/FP8 Tensor Core,权重和激活搬运都显著,校准或动态范围策略已验证。
  • 潜在收益:两侧操作数更窄,低精度矩阵吞吐更高。
  • 新增成本:动态 amax 归约、激活转换、scale 传递和可能的离群值处理。
  • 精度风险:激活分布比权重更依赖输入;少数大异常值会把 scale 拉大,使普通值的有效分辨率下降。

W8A8 不是 INT8 的同义词

W8A8 也可以是普通 FP8 或 MXFP8。只有把元素编码和尺度方案写出来,才能比较精度、存储和 kernel。

W16A8 与 W8A4:非对称混合位宽

这两个标签都让 W/A 位宽不同,但前者保留高精度权重,后者对激活施加更激进的四位约束,不能作为同一强度的优化理解。

W16A8:只压激活

W16A8 保留 16 bit 权重,只把激活变成 8 bit。它的价值通常在:

  • 减少激活读写或跨设备通信;
  • 使用硬件提供的 W16×A8 混合 kernel;
  • 让精度敏感权重保持高精度。

不会降低权重常驻量。若部署的主要瓶颈是数百 GiB 模型权重,W16A8 不能解决“模型放不下”的问题;若后端没有原生混合 kernel,在线量化甚至可能只增加开销。

W8A4:激进压缩激活

W8A4 把权重压到 8 bit、激活压到 4 bit。四位激活的可表达值很少,通常需要更细的 per-token/per-group 动态尺度,并依赖专用 kernel。

vLLM 当前一个 WnA4 compressed-tensors 路径明确限制为对称、动态、per-token/per-group INT4 activation,并拒绝静态、per-tensor 或非对称组合。这说明 W8A4 更像一个接口族,而不是跨框架完全一致的格式。vLLM WnA4 source

![W16A8 与 W8A4 的物理、逻辑、流程、时序和数据流](https://pic.shaojiemike.top/shaojiemike/2026/07/ad5fcfad0538bce2e1f63060b8faf993.png){ width=100% }
W16A8 与 W8A4 五视图。二者共享“激活在线量化”骨架,但压缩对象、误差预算和 kernel 完全不同。图中的 W8A4 约束来自 pinned vLLM WnA4 实现,不外推为所有框架。

规范化控制流是:

1
2
3
4
5
6
7
8
9
10
11
def mixed_width_linear(x16, weight, mode):
if mode == "W16A8":
xq, sx = dynamic_quantize(x16, bits=8, granularity="token_or_row")
return kernel_w16_a8(weight.w16, xq, sx)

if mode == "W8A4":
assert mode.symmetric and mode.dynamic
xq, sx = dynamic_quantize(x16, bits=4, granularity="token_group")
return kernel_w8_a4(weight.w8, weight.scale, xq, sx)

raise UnsupportedKernel(mode)

工程上必须先调用后端能力矩阵确认 kernel_w16_a8kernel_w8_a4 确实存在;否则标签可能被拒绝、重新量化,或者 fallback 到 A16。

FP8、MXFP8 与 MXFP4:浮点格式不是整数位宽

浮点低精度不仅要看总 bit,还要看指数/尾数怎样分配,以及尺度是全局、张量级还是每个小块共享。

FP8

OCP OFP8 规范定义两种八位浮点交换编码:

  • E4M3:1 sign、4 exponent、3 mantissa,最大有限幅值为 448,精度相对更高。
  • E5M2:1 sign、5 exponent、2 mantissa,最大有限幅值为 57,344,动态范围更大。

OCP 规范定义的是编码和从更宽格式转换时的舍入、饱和行为,并不规定模型必须怎样选 scale,也不保证速度或精度OCP OFP8 Specification

普通 FP8 推理仍常使用 per-tensor 或较大 block 的 scale。一个“FP8 checkpoint”也可能只量化部分 Linear,并排除 attention、embedding、LM head 或视觉模块。

MXFP8

MXFP8 在元素编码之外增加 microscaling:

$$
x_i \approx s_b q_i,\qquad q_i \in \text{E4M3},\qquad
s_b \in \text{E8M0},\qquad i\in \text{block}_b.
$$

NVIDIA Transformer Engine 的 MXFP8 路径让 32 个连续 E4M3 元素共享一个 E8M0 scale。E8M0 只有指数,表示 2 的幂。每块大致执行:

  1. 求 32 个值的 amax
  2. 以 E4M3 最大幅值 448 为基准生成 E8M0 指数;
  3. 用块尺度缩放;
  4. 舍入到 E4M3。

理想原始存储为:

$$
\frac{32\times 8 + 8}{32}=8.25\ \text{bit/value}.
$$

这还未计算 scale 布局、对齐、元数据和可能同时保存的 rowwise/columnwise 表示。MXFP8 的行向与列向分块方向不同,不能简单把一个量化张量转置后当成另一个方向的同值表示。NVIDIA MXFP8

MXFP4 与 fallback

MXFP4 使用 E2M1 四位元素,并为每 32 个元素提供一个 E8M0 scale。真正决定运行位宽的是后端:

  • vLLM 当前 compressed_tensors_w4a4_mxfp4.py 在支持的 SM100+ FlashInfer 路径使用低比特 activation;
  • 不满足该路径时,可以改走 Marlin W4A16。

因此,同一个 MXFP4 权重仓库可以在一台机器上表现为 W4A8/W4A4,在另一台机器上表现为 W4A16。 vLLM MXFP4 source

![FP8、MXFP8 与 MXFP4 的物理、逻辑、流程、时序和数据流](https://pic.shaojiemike.top/shaojiemike/2026/07/d85177a1b1ed5b815bea67afcf83e72e.png){ width=100% }
FP8/MX 五视图。格式证据来自 OCP OFP8 Revision 1.0、NVIDIA MXFP8 文档和 pinned vLLM MX schemes。图中的 8.25 bit/value 是元素与 E8M0 scale 的理想原始值,不是完整 checkpoint 或运行显存。

开放权重盘点

下面只统计模型组织的官方量化权重,以及与 GLM-5.2 明确绑定的 NVIDIA/AMD 厂商版本;不把持续变化的社区 GGUF、AWQ 或二次量化仓库混入同一口径。

统计口径

下表采用以下固定口径:

  1. 调用 Hugging Face model API 记录当前 repository SHA。
  2. 递归列出仓库文件。
  3. 对所有以 .safetensors 结尾的文件求字节和。
  4. 同时报告十进制 GB 和二进制 GiB:1 GB=10^9 bytes1 GiB=2^30 bytes

这比 参数量 × 标称 bit 更可靠,因为真实仓库还包含未量化模块、scale、zero point、padding、多模态组件和 MTP 权重。它仍只是检查点权重下界,不是进程峰值。

Qwen3.5

Qwen 的官方 Qwen3.5 集合当前为 397B-A17B、122B-A10B、35B-A3B 和 27B 列出 FP8 与 GPTQ-Int4;9B、4B、2B、0.8B 没有列出官方量化仓库。社区 GGUF/AWQ 版本更新频繁,不混入这张官方口径表。

官方仓库 当前 SHA safetensors 维护者给出的实际部署下界
397B-A17B-FP8 ea5b4f81 406.15 GB / 378.26 GiB SGLang:8×H100、4×H200、4×B200 或 2×B300;vLLM 另验证 8×H200
397B-A17B-GPTQ-Int4 df333de3 235.71 GB / 219.52 GiB vLLM recipe 标注约 239 GB aggregate;实际并行拓扑需按后端核验
122B-A10B-FP8 a099dee7 127.16 GB / 118.43 GiB 2×H200 或 4×H100
122B-A10B-GPTQ-Int4 30cd92cb 78.86 GB / 73.45 GiB 1×80 GB GPU
35B-A3B-FP8 9d1823d2 37.46 GB / 34.89 GiB 单张 H100/H200;recipe 运行预算约 42 GB
35B-A3B-GPTQ-Int4 3af5ca29 24.42 GB / 22.74 GiB 1×24 GB GPU
27B-FP8 97f5941b 30.87 GB / 28.75 GiB 1×40 GB GPU
27B-GPTQ-Int4 8f0c09f2 30.24 GB / 28.16 GiB recipe 写 1×24 GB,但当前完整仓库字节已超过 24 GB,见下方警告

这些设备结论来自 vLLM Qwen3.5 recipesSGLang Qwen3.5 cookbook,并受 engine 版本、上下文、并发和 text-only/multimodal 模式约束。

27B GPTQ 的 24 GB 冲突

当前 Qwen3.5-27B-GPTQ-Int4 的完整 safetensors 已是 28.16 GiB。因此,“单张 24 GB GPU 完整加载当前多模态仓库且无 offload”在算术上不成立。

vLLM recipe 的 24 GB 标签可能依赖 text-only 加载、跳过视觉组件、CPU offload、优化后的运行布局或不同修订。这里保留双方证据,不把 24 GB 写成无条件最低显存;真实部署必须记录启动参数和峰值。

Kimi K3

Kimi K32.8T total / 104B active 的 MoE,模型卡声明 MXFP4 weight、MXFP8 activation,并从 SFT 开始做 QAT。当前 SHA 9f62e4e9 的 96 个 safetensors 合计:

$$
\mathbf{1{,}560.94\ GB = 1{,}453.74\ GiB}.
$$

104B active 主要降低每 token 参与计算的专家数,不意味着只需常驻 104B 参数。当前 config 的 MXFP4 group size 为 32,但 attention、shared experts、普通 MLP pattern、LM head、vision tower 和 projector 等存在高精度排除项。

部署方面:

  • vLLM 表示最容易的路径是 8×B300 或 8×MI355X
  • 在 B200/GB200 这一代上至少需要 16 张
  • SGLang 给出的其他拓扑包括 16×H200 和 32×H100。

更重要的是,SGLang 说明 Blackwell 可走 FlashInfer MXFP4/W4A8,而 H100/H200 固定走 Marlin W4A16。模型卡的“MXFP8 activation”是训练与目标数值方案,checkpoint config 只序列化 weight compression;最终 activation 路径仍由运行 kernel 决定。vLLM Kimi K3 SGLang Kimi K3

GLM-5.2

Z.ai 的官方 GLM-5.2 集合当前只有 BF16 与 FP8。NVIDIA NVFP4 和 AMD MXFP4 是厂商量化仓库,应与 Z.ai 官方权重分开标注。

仓库 身份与量化范围 safetensors 维护者实际部署下界
zai-org/GLM-5.2-FP8 官方 FP8,部分模块排除 755.63 GB / 703.74 GiB vLLM:8×H200/H20;完整 1M context 使用 8×B200 + FP8 KV
nvidia/GLM-5.2-NVFP4 厂商版;主要量化 MoE expert linear,其他模块保留 FP8/BF16 464.82 GB / 432.90 GiB Blackwell-only,vLLM recipe 使用 TP8
amd/GLM-5.2-MXFP4 厂商版;主要量化 MoE weight,非 MoE 模块高精度 438.00 GB / 407.92 GiB 8×MI355X TP8 推荐;TP4 可做有余量的验证

GLM-5.2 FP8 的纯权重算术看似约五张 141 GB 设备就够,但维护者使用八张,是因为模型还要满足分片、非均匀模块、KV、workspace、图和服务余量。这正是“文件放得下”与“系统跑得起来”的差别。 vLLM GLM-5.2 Recipe SGLang GLM-5.2

显存下界与可运行拓扑

检查点回答“持久化权重至少占多少”,运行拓扑还要回答这些权重怎样分片,以及每个请求把哪些短期和长期状态带入设备。

完整峰值

推理峰值应拆为:

$$
\begin{aligned}
M_{\text{peak}}={}&M_{\text{weights}}
+M_{\text{KV/recurrent}}
+M_{\text{live activations}}\
&+M_{\text{operator workspace}}
+M_{\text{graph/communication}}
+M_{\text{allocator reserve}}
+M_{\text{margin}}.
\end{aligned}
$$

  • Weights:packed elements、scale、zero point、未量化模块和运行时重排。
  • KV/recurrent:KV cache、MLA latent、GDN/KDA state,随上下文、batch 和并发变化。
  • Activations:prefill 通常比单 token decode 保留更多中间量。
  • Workspace:动态量化、GEMM、Attention、MoE routing、repack/swizzle 的临时对象。
  • Graph/communication:CUDA Graph、TP/EP collective、对称内存和通信 staging。
  • Reserve/margin:分配器保留、碎片和服务波动余量。
![量化检查点到运行峰值的物理、逻辑、流程、时序和数据流](https://pic.shaojiemike.top/shaojiemike/2026/07/27f843e58f21956f2cb4b840bd9017c4.png){ width=100% }
检查点到运行显存五视图。仓库 shard 字节和只锚定 Mweights 的下界;其余项必须用具体 engine、硬件、上下文、并发和多模态模式测量。

三个必须分开的数字

  1. 仓库字节:固定 SHA 后求 safetensors 之和,是可复核事实。
  2. 权重算术下界ceil(checkpoint_GiB / device_GiB),只能回答聚合容量,不能证明能分片或启动。
  3. 维护者拓扑:给出硬件、TP/EP/PP、KV dtype、上下文和验证状态,才接近工程最低配置。

MoE 的 active parameters

Active parameters 影响每 token 的 FLOPs 和通信,不自动降低所有专家的常驻权重。除非系统明确做 expert offload、按需加载或分层存储,否则估算权重显存应使用 total checkpoint bytes。

本地测量方法

真正要确认“我的机器至少多少显存”,应固定下列条件再启动:

1
2
3
4
5
6
7
8
9
model repo + revision
+ engine image/version
+ quantization backend/kernel
+ TP/EP/PP topology
+ text-only or multimodal
+ max model length
+ KV/state dtype
+ max concurrent requests / batch tokens
+ CUDA graph and speculative decoding settings

然后分别记录:

  • load 完成后的 resident memory;
  • 首次 warmup/JIT/repack 峰值;
  • prefill 峰值;
  • steady decode 峰值;
  • 最大上下文和目标并发下的峰值;
  • 每卡最大值,而不是只看集群总和。

选型与验证清单

如果目标是“先跑起来,再逐步提速”,可以按以下顺序选择:

  1. 先核对 kernel:目标 GPU/加速卡是否原生支持该 W/A 组合;没有原生路径时,先把它当成兼容性或存储格式,而不是性能承诺。
  2. 再看压缩对象
    • 权重放不下:优先 W4/W8A16、GPTQ/AWQ、FP8/MXFP4 weight。
    • 激活或通信瓶颈:再考虑 W16A8、W8A8。
    • 追求极限低比特:W8A4、W4A4/A8,但先做精度回归。
  3. 读取 config:确认 target、group size、dynamic/static、symmetric、ignore 和 KV scheme。
  4. 核对完整仓库字节:不要从模型名推断大小。
  5. 按维护者拓扑预留:权重算术下界只能用来发现“不可能”,不能用来证明“可运行”。
  6. 分阶段验收精度:至少覆盖 perplexity/任务集、长上下文、工具调用、多模态和极端 activation。
  7. 分阶段验收性能:区分 load、prefill、decode、单请求延迟、并发吞吐和每卡峰值。

最终判断可以压缩为:

位宽决定候选表示,尺度与粒度决定数值误差,kernel 决定实际执行,完整对象生命周期决定显存。

参考资料

Author

Shaojie Tan

Posted on

2026-07-28

Updated on

2026-07-28

Licensed under