对应 Maps to:原课 CS349D(Spring 2026)的阅读清单没有单独讲量化。它是实践中最常用的推理优化之一(第 1 讲 §6.3、第 17 讲 §3.3 里单项收益最大的就是 FP8),所以作为可选的附录补上。 依据说明:T. Dettmers et al., LLM.int8(): 8-bit Matrix Multiplication for Transformers at Scale(NeurIPS 2022);E. Frantar et al., GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers(ICLR 2023);G. Xiao et al., SmoothQuant(ICML 2023);J. Lin et al., AWQ: Activation-aware Weight Quantization(MLSys 2024 最佳论文);P. Micikevicius et al., FP8 Formats for Deep Learning(2022);B. D. Rouhani et al., Microscaling Data Formats for Deep Learning(2023);Z. Liu et al., KIVI(ICML 2024);S. Ashkboos et al., QuaRot(2024);E. Frantar et al., MARLIN(2024);Y. Lin et al., QServe(MLSys 2025);A. Dutta et al., Accuracy is Not All You Need(2024)。NVFP4 和 B200 的规格来自 NVIDIA 公开资料的二手汇总(我没能直接核对数据手册,文中注明)。论文里的数字写成”论文报告”;讲义里的其他数字都来自配套代码的实际运行。 配套代码 Code:
code/appendixA/(numpy;1 个模块quant_lab.py:各种数制与粒度、RTN / AWQ / GPTQ / LLM.int8() / SmoothQuant / FP8 / KIVI 的实现、合成的”带离群通道”的数据、量化第 1 讲 tiny_llm 的端到端比较、量化后的 roofline;4 个脚本,每个几秒) 预计阅读时间:2.5–3 小时(含运行代码)
0. 本讲导航 · How to read this lecture
0.1 学习目标 Learning goals
学完这一讲,你应该能够:
- 说清楚量化给推理系统带来的三笔账:读的字节、显存的容量、Tensor Core 的算力——以及它们分别在 prefill 和 decode、小批和大批里起不起作用。
- 比较整数与浮点格式(INT8 / INT4 / FP8 / FP4),解释缩放因子的粒度(每张量、每通道、每组、MXFP4 / NVFP4 的块)为什么决定了 4 位能不能用。
- 解释 LLM 激活里的”离群通道”从哪来、为什么让激活比权重难量化,以及 LLM.int8()、SmoothQuant、FP8、旋转(QuaRot)各自怎样对付它。
- 说出 GPTQ(二阶补偿)和 AWQ(按激活缩放)的思路、代价和适用场景,包括对校准数据的敏感性。
- 解释 KV cache 量化为什么 key 要按通道、value 要按 token(KIVI),以及它对长上下文吞吐的意义。
- 用”和原模型的距离”(KL、翻转率)而不只是平均准确率来评估一个量化模型。
0.2 先修与本讲范围 Prerequisites & scope
| 默认你已经会 Assumed | 本讲不展开 Not covered |
|---|---|
| 第 1 讲:roofline、prefill 与 decode、KV cache 的账 | 量化感知训练(QAT)的细节、低精度训练 |
| 第 3、9 讲:KV 的容量为什么重要 | 剪枝、稀疏(2:4 稀疏只顺带一提) |
| 线性代数:矩阵乘法、对称正定矩阵、Cholesky 分解(GPTQ 用到) | 具体内核的实现(只讲它们解决什么问题) |
0.3 本讲地图 Map
§1 为什么量化:三笔账,和它们什么时候不成立
§2 数制与粒度:INT、FP8、FP4,每张量 / 每通道 / 每组 / 块缩放 ← 代码 01
§3 仅权重量化:RTN、AWQ、GPTQ ← 代码 02
§4 权重 + 激活:LLM.int8()、SmoothQuant、FP8、W4A4 与旋转 ← 代码 03 演示 1–2
§5 KV cache 量化:KIVI ← 代码 03 演示 3
§6 系统视角:快多少、什么时候不快、要几块卡 ← 代码 04
§7 怎样评估一个量化模型的质量
§8 现状(2026)
§9–12 小结、常见误区、练习、延伸阅读
0.4 记号 Notation
| 符号 | 含义 |
|---|---|
| WxAyKVz | 权重 x 位、激活 y 位、KV z 位,例如 W4A16(4 位权重、16 位激活)、W8A8、W4A8KV4 |
| RTN | round-to-nearest,最近取整:最简单的量化 |
| 缩放因子 scale、零点 zero point | 量化 q = round(x / scale)(+ 零点),反量化 x̂ = (q − 零点) × scale |
| 粒度 granularity | 多少个数共用一个缩放因子:每张量、每通道(每行 / 每列)、每组(例如每 128 个)、每块 |
| E4M3、E5M2、E2M1 | 浮点格式:E 后面是指数位数,M 后面是尾数位数(另有 1 个符号位) |
| SQNR | 信号量化噪声比,10·log10(信号能量 / 误差能量),单位 dB;每多 1 个比特约多 6 dB |
| 离群通道 outlier channel | 激活里少数几个维度在几乎每个 token 上都特别大 |
| PTQ / QAT | 训练后量化 / 量化感知训练 |
0.5 关于数字 · About the numbers
本讲有两类实验。数值实验(§2–§5)用合成数据:带离群通道的激活、近似正态的权重、带离群通道的 key——它们模仿了论文里描述的统计特征,但不是真实模型的激活;误差用”层输出的相对误差”或”注意力输出的相对误差”衡量。端到端的比较用第 1 讲随机初始化的 tiny_llm,只能比较方法之间的相对好坏。系统实验(§6)用第 1 讲的 roofline,其中反量化的代价是假设值。论文里的困惑度、准确率和测得的加速比都写成”论文报告”。
1. 为什么量化 · Why quantize
1.1 三笔账
回到第 1 讲的 roofline:一步 forward 的时间 ≈ max(运算 / 算力, 字节 / 带宽)。量化同时动了这个式子里的三样东西:
- 读的字节:decode 时一步要把全部权重读一遍,batch 小时几乎只做这件事。权重从 16 位变成 4 位,字节数降到约四分之一,速度就接近 4 倍。KV 量化同理,在长上下文、大批的 decode 里,读 KV 的字节往往比读权重还多。
- 显存的容量:Llama-3-70B 的 BF16 权重约 141 GB,一块 80 GB 的 H100 放不下;4 位权重(层内矩阵)只要约 36 GB,加上保持 16 位的嵌入表和 lm_head 也不到 40 GB。容量还决定了 KV 能放多少 token,进而决定批大小(第 1 讲的事实 3)和前缀缓存的命中率(第 17 讲 §4.3)。
- Tensor Core 的算力:H100 的 FP8 / INT8 Tensor Core 是 BF16 的 2 倍,Blackwell 的 FP4 是 4 倍(公开资料)。但只有矩阵乘法的两个输入都是低精度时才用得上——只量化权重(W4A16)时,权重在进 Tensor Core 之前要先反量化成 16 位,算力一点没变,还多了反量化的开销。
这三笔账在不同阶段的分量完全不同:prefill 受限于算力,只有第 3 笔账有用;小批 decode 受限于读权重,第 1 笔账最有用;长上下文、大批 decode 受限于读 KV,要量化 KV 才有用。§6 用代码把这张表填满。
1.2 代价:误差
量化就是用更少的值去近似一个连续的数,必然有误差。问题在于误差落在哪里:
- 权重的分布平坦、接近正态,8 位几乎无损,4 位配合分组和好的算法也能接近无损;
- 激活里有离群通道(§4),8 位都可能出问题;
- KV 的 key 有离群通道、value 没有(§5);
- 误差会沿着层传播、在生成里累积:一个 token 选错,后面就一路分叉(§7)。
1.3 一条时间线
| 时间 | 工作 | 解决的问题 |
|---|---|---|
| 2022 | LLM.int8() | 发现 6.7B 以上模型的”涌现离群特征”,用混合精度做 W8A8 |
| 2022 | FP8 格式(NVIDIA / Arm / Intel) | 定义 E4M3 / E5M2,H100 硬件支持 |
| 2022–23 | GPTQ | 用二阶信息把权重压到 3–4 位,175B 模型几小时量化完 |
| 2022–23 | SmoothQuant | 把激活的离群值”挪”给权重,让 W8A8 能用最快的内核 |
| 2023 | AWQ | 按激活大小保护重要的权重通道,不依赖反向传播,泛化好 |
| 2023 | Microscaling(MX)格式 | 把”每块一个缩放因子”标准化为硬件格式(MXFP8 / MXFP6 / MXFP4) |
| 2024 | KIVI、QuaRot、Marlin、QServe | 2 位 KV、旋转去掉离群值的 W4A4、大批量下的 4 位内核、W4A8KV4 的系统协同设计 |
| 2025– | Blackwell 的 NVFP4、带低精度权重发布的模型 | FP4 进入硬件;模型直接以 FP8 / MXFP4 形式训练或发布(§8) |
2. 数制与粒度 · Number formats and granularity
2.1 整数与浮点
整数量化:选一个缩放因子 s,把 x 映到最近的整数 q = round(x / s),存 q,用的时候算 q × s。对称量化让 0 对齐、正负范围相同(INT8 是 −127 … 127);非对称量化多存一个零点,用满 [min, max](权重量化常用)。
浮点量化:数 = 符号 × 2^指数 × 1.尾数。FP8 有两种编码(论文表 1):
| 格式 | 指数 / 尾数 | 最大值 | 最小正数 | 在 1 附近的相邻间隔 |
|---|---|---|---|---|
| E4M3 | 4 / 3 | 448 | 2^−9 ≈ 0.00195 | 12.5% |
| E5M2 | 5 / 2 | 57,344 | 2^−16 ≈ 1.5 × 10^−5 | 25% |
| E2M1(FP4) | 2 / 1 | 6 | 0.5 | 50% |
E4M3 不表示无穷大、只留一个 NaN 的位模式,把范围多扩了一个 2 的幂(到 448)。FP4 E2M1 只有 0、0.5、1、1.5、2、3、4、6 八个非负值——它必须配合很小的块和块缩放因子才能用(§2.3)。
两者的根本区别在格点的形状(代码 01 演示 1):整数格点等间隔,绝对误差处处相同,所以小的数相对误差大;浮点格点”对数均匀”,每个 2 的幂区间里有一样多的值,相对误差处处差不多,代价是在一个区间里比整数稀疏。
2.2 同样 8 位,谁更准?取决于分布
代码 01 演示 2(每张量一个缩放因子;SQNR 越大越好):
| 数据 | INT8 | FP8 E4M3 | FP8 E5M2 | INT4 |
|---|---|---|---|---|
| 正态分布 | 39.4 dB | 31.6 dB | 25.6 dB | 14.2 dB |
| 重尾(t 分布,自由度 3) | 20.0 dB | 31.6 dB | 25.6 dB | 1.6 dB |
| 正态 + 0.1% 的值放大 50 倍 | 15.2 dB | 31.9 dB | 25.8 dB | 5.4 dB |
数据近似正态时,INT8 把 255 个格点均匀铺满整个范围,比 FP8 准;一旦有重尾或离群值,INT8 的缩放因子被最大的几个值撑大,普通的数只分到很少几个格点;FP8 的相对精度几乎与分布无关,三种数据上都是约 32 dB。这就是 FP8 在推理里流行的原因:激活有离群值,FP8 用一个每张量的缩放因子就大致够用。另一个经验:均匀量化每少 1 个比特,SQNR 约少 6 dB——4 位天生只有 8 位的”四分之一精度”左右,必须靠更细的粒度和更好的算法补回来。
2.3 粒度:多少个数共用一个缩放因子
代码 01 演示 3,4,096 × 4,096 的权重(各行的尺度不同)量化成 4 位:
| 格式与粒度 | SQNR | 每个数实际的比特 |
|---|---|---|
| INT4,整张量一个缩放 | 0.7 dB | 4.00 |
| INT4,每个输出通道一个 | 9.1 dB | 4.00 |
| INT4,每 128 个一组(非对称) | 17.5 dB | 4.16 |
| INT4,每 32 个一组(对称) | 18.2 dB | 4.50 |
| INT4,每 32 个一组(非对称) | 20.6 dB | 4.62 |
| MXFP4(32 个一块,2 的幂缩放) | 18.0 dB | 4.25 |
| NVFP4(16 个一块,E4M3 缩放) | 20.7 dB | 4.50 |
| FP8 E4M3,每个输出通道一个 | 31.6 dB | 8.00 |
| INT8,每个输出通道一个 | 34.0 dB | 8.00 |
4 位只有 16 个格点,一个缩放因子管的数越多,越容易被其中最大的那个拖累:整张量一个缩放几乎没法用,每 128 个一组(GPTQ、AWQ 的默认)好一大截,多出来的缩放因子和零点只占约 0.16 位。
块缩放格式把”分组”做进了硬件:MXFP4(OCP Microscaling 标准)每 32 个数一块,共用一个 8 位的纯 2 的幂缩放因子(E8M0),元素是 E2M1;NVFP4(Blackwell)每 16 个数一块,块缩放因子是一个 E4M3 浮点数(不必是 2 的幂,更贴合每块的实际范围),外面再有一个整张量的 FP32 缩放因子把块缩放放进 E4M3 的范围(据 NVIDIA 公开资料的汇总)。NVFP4 每个数多 0.25 位,换来更小的误差。
2.4 激活的离群通道,以及”为什么不按通道缩放”
代码 01 演示 4:一个 2,048 × 1,024 的激活,6 个通道约为典型幅度的 40 倍。
| 缩放粒度 | 整体 SQNR | 普通通道的 SQNR |
|---|---|---|
| 每张量 | 27.1 dB | 21.1 dB |
| 每 token(每行) | 30.0 dB | 24.0 dB |
| 每通道(每列) | 45.5 dB | 41.6 dB |
| FP8 E4M3,每张量 | 31.2 dB | 31.5 dB |
每张量 INT8 时,整个张量的最大值约 17.5,一个最大值约 1.4 的普通通道只分到约 20 个格点(SmoothQuant 论文的估算:2^8 × m_i / m)。按 token 缩放救不了——每个 token 里都有那几个离群通道。按通道缩放最好,但它不能用在 INT8 矩阵乘法里。原因要看矩阵乘法的结构:
Y[t, o] = Σ_i X[t, i] · W[o, i] (t:token;o:输出通道;i:输入通道,累加的那一维)
整数矩阵乘法:Y ≈ s_X[t] · s_W[o] · Σ_i qX[t, i] · qW[o, i]
↑ 缩放因子只能挂在"外面"两维(t 和 o)上,在累加结束后乘一次
如果按输入通道 i 缩放:Σ_i s_X[i] · qX[t, i] · qW[o, i]
↑ 每一项都要乘一个不同的数——Tensor Core 的整数累加里插不进这一步
所以真正的问题是:离群值在输入通道这一维上,而硬件只允许在另外两维上缩放。 §4 的几种方法都是在绕这个限制。
3. 仅权重量化:RTN、AWQ、GPTQ · Weight-only quantization
3.1 场景
只量化权重(W4A16、W3A16)、激活保持 16 位,是最早普及的 LLM 量化:它对小批 decode(单用户、边缘设备)收益最大(§6),而且只需要处理”好量化”的权重。最简单的做法是 RTN:每行每 128 个一组,直接四舍五入。它在 8 位时几乎无损,到 4 位、3 位就明显变差(GPTQ 论文表 3:OPT-175B 的 WikiText2 困惑度,全精度 8.34,4 位 RTN 10.54,3 位 RTN 上千——“完全崩溃”)。
3.2 哪些权重重要?看它乘的激活
代码 02 演示 1,一个 1,024 → 1,024 的线性层,输入有 6 个离群通道,每 128 个一组(误差是在另一批同分布数据上的输出相对误差):
| 方法 | 4 位 | 3 位 |
|---|---|---|
| RTN | 25.2% | 54.0% |
| 保留 1% 通道:按激活幅度挑 | 12.5% | 26.8% |
| 保留 1% 通道:按权重范数挑 | 25.1% | 54.0% |
| 保留 1% 通道:随机挑 | 25.1% | 54.0% |
| AWQ(α = 0.40) | 14.8% | 31.6% |
| GPTQ | 12.4% | 26.9% |
| GPTQ + act-order | 13.6% | 29.2% |
离群通道上的激活大几十倍,这几列权重的量化误差也被放大几十倍,它们决定了 RTN 的大部分误差。按激活幅度挑出 1% 的通道保留全精度,误差几乎减半;按权重范数挑、随机挑都没用。这正是 AWQ 论文表 1 的发现(OPT-6.7B、INT3 每 128 一组:RTN 困惑度 23.54,按激活保留 1% 降到 11.39,按权重范数或随机保留几乎不变)。
3.3 AWQ:不保留,而是放大
混合精度(一部分列 16 位、其余 4 位)对硬件不友好。AWQ 的观察是:把一个输入通道的权重乘 s > 1、对应的激活除以 s,乘积不变;而一组权重的量化步长由组内最大值决定,放大一个(不是最大的)元素通常不改变步长,于是这个元素的相对误差缩小到 1/s。重要的通道(激活大的)就这样被”保护”了。
s 怎么取?AWQ 只搜一个参数:s = s_X^α,s_X 是每个通道激活的平均幅度,α 在 [0, 1) 上网格搜索 20 个点。代码 02 演示 2 的曲线:α = 0(就是 RTN)误差 25.2%,α = 0.4 最低(14.8%),α 再大又变差(0.9 时 30.7%)——放大的通道把整组的最大值撑大,其他通道的步长变粗(AWQ 论文表 2:s = 2 最好,再大反而变差)。
论文卡片 Paper card · AWQ
- 问题:4 位、3 位的仅权重量化损失大;GPTQ 依赖重建,可能过拟合校准数据;混合精度保留重要权重对硬件不友好。
- 关键想法:权重的重要性由它乘的激活决定;用等价的逐通道缩放保护激活大的通道,s = s_X^α,α 网格搜索;不需要反向传播或重建。
- 系统:TinyChat 把 4 位权重的理论节省变成实测加速(内核融合、按平台打包权重),在桌面和移动 GPU 上平均比 HuggingFace FP16 快 3.2–3.3 倍(论文报告);让 Llama-2-70B 能跑在 64 GB 的 Jetson Orin 上。
- 结果(论文报告):对校准集的大小和领域都不敏感(图 8:换领域时困惑度只变差 0.5–0.6,GPTQ 变差 2.3–4.9);适用于指令微调和多模态模型。
- 局限:本身只解决权重;4 位以下仍有明显损失;大批量服务时 W4A16 内核的反量化开销仍在(§6)。
3.4 GPTQ:量化一列,补偿后面的列
GPTQ 换了个思路:既然量化每一个权重都会引入误差,那就在量化下一列之前,调整还没量化的列来抵消它。目标是逐层的输出误差 ‖WX − ŴX‖²,它对每一行权重是一个二次函数,Hessian 是 H = 2XXᵀ。
- 来历:OBS / OBQ(“最优脑外科医生”一系)每次挑误差最小的一个权重量化,并用 H⁻¹ 更新其余权重,计算量随列数的三次方增长,只适合小模型。
- GPTQ 的三步:(1)所有行按同样的顺序量化——H 只依赖输入 X、与是哪一行无关,于是 H⁻¹ 的更新只做 d_col 次而不是 d_row × d_col 次,“顺序其实不太重要”;(2)懒惰的批更新:一次处理 128 列,块内逐列量化和补偿,块外的更新攒到最后一次做,把访存受限的操作变成矩阵乘法;(3)Cholesky 改写:只需要 H⁻¹ 每一行从对角线开始的部分,用 Cholesky 分解一次算好,数值上比反复更新 H⁻¹ 稳定(大模型上反复更新会变得不正定)。
- 配合分组量化时,每到一组的开头,用”当前已经被补偿过的”权重计算这一组的缩放。
代码 02 的实现就是论文的 Algorithm 1。在演示 1 的层上,GPTQ 和”保留 1% 全精度”一样准(12.4% 对 12.5%),而且不需要混合精度。act-order(先量化激活能量最大的列,让后面更多的列帮它补偿)在这里反而略差(13.6%)。
论文卡片 Paper card · GPTQ
- 问题:在 GPT-3 规模上,已有的训练后量化要么太慢(OBQ、AdaRound 一类)、要么在 4 位以下崩溃(RTN)。
- 关键想法:逐层最小化输出误差,按固定顺序逐列量化,用 H⁻¹(Cholesky 形式)把每一列的误差补偿到后面的列;懒惰批更新。
- 结果(论文报告):一块 A100 约 4 小时量化完 175B 模型;OPT-175B 在 4 位时 WikiText2 困惑度 8.37(全精度 8.34、RTN 10.54),3 位分组 128 时 8.45;3 位的 OPT-175B 能放进一块 80 GB 的 A100,生成时每 token 的延迟比 5 块 A100 上的 FP16 快 3.25 倍(A6000 上 4.5 倍)。
- 局限:需要校准数据,补偿方向为校准数据的相关结构量身定做(§3.5);只量化权重。
3.5 校准数据:GPTQ 的双刃剑
代码 02 演示 3:校准数据和实际数据来自不同的”领域”(通道之间的相关结构不同;3 位)。
| 校准数据 | 方法 | 在领域 A 上 | 在领域 B 上 |
|---|---|---|---|
| 领域 A,2,048 个 token | AWQ | 31.6% | 31.5% |
| 领域 A,2,048 个 token | GPTQ | 26.9% | 39.8% |
| 领域 B,512 个 token | AWQ | 31.6% | 31.5% |
| 领域 B,512 个 token | GPTQ | 45.6% | 30.3% |
GPTQ 在和校准数据同一领域的数据上最准,换一个领域就明显变差:它用校准数据的 XᵀX 决定补偿方向。AWQ 只用每个通道激活的平均幅度——离群通道是模型的性质、不是数据的性质,这个统计量在两个领域里一样——所以两个领域上的误差几乎相同。这与 AWQ 论文图 8 的结论一致。实践中的选择:校准数据尽量像真实流量;对多领域的通用模型、多模态模型,AWQ 更省心;两者也可以结合(先 AWQ 缩放、再 GPTQ 量化)。
3.6 端到端:tiny_llm
代码 02 演示 4 把第 1 讲的 tiny_llm(2 层、d = 64;每 16 个输入通道一组)量化,比较和全精度模型的距离。为了模仿真实模型的离群通道,我们给它”装上”2 个离群通道:RMSNorm 的缩放在这两个通道上乘 20,后面线性层的对应权重行除以 20——全精度下的函数完全不变,但量化看到的是”激活离群、对应的权重很小”。
| 模型 | 位数 | 方法 | KL(nat) | 翻转率 | 贪心生成平均第几个分叉(共 48) |
|---|---|---|---|---|---|
| 原模型 | 4 | RTN | 0.0045 | 10.8% | 8.8 |
| 原模型 | 4 | AWQ | 0.0043 | 10.8% | 6.8 |
| 原模型 | 4 | GPTQ | 0.0029 | 9.3% | 6.6 |
| 装上离群通道 | 4 | RTN | 0.0232 | 26.1% | 2.8 |
| 装上离群通道 | 4 | AWQ | 0.0045 | 11.5% | 9.1 |
| 装上离群通道 | 4 | GPTQ | 0.0135 | 20.5% | 5.5 |
| 原模型 | 8 | FP8 | 0.0006 | 3.1% | 16.4 |
装上离群通道后,RTN 的 KL 大了 5 倍:离群通道对应的权重行变小了,在每组 16 个数里被别的权重的缩放”吞掉”。AWQ 把这些行放大回来,几乎恢复到没有离群通道时的水平;GPTQ 也有改善,但不如 AWQ——在这个小模型上,按激活幅度保护通道正中要害。(“分叉位置”一列只有 8 个提示,噪声很大;GPTQ 的 KL 最小,分叉却不是最晚的。)§7 再讨论这些指标的意义。
4. 权重 + 激活都量化 · Weight-and-activation quantization
4.1 为什么要量化激活
只量化权重省的是读的字节;要让 prefill 和大批 decode 变快,矩阵乘法的两个输入都要是低精度,才能用上 2 倍(FP8 / INT8)或 4 倍(FP4)的 Tensor Core。难点就是 §2.4 的离群通道。
4.2 LLM.int8():把离群列拿出来
论文卡片 Paper card · LLM.int8()
- 发现:Transformer 的隐藏状态里有”涌现的离群特征”:幅度比其他维度大到约 20 倍,集中在极少数维度上;随模型变大,约 6.7B 时出现”相变”——所有层、75% 的序列位置都受影响;6.7B 模型每个序列约 15 万个离群值,却只集中在 6 个维度上。把这些维度置零,注意力的 top-1 概率质量下降 20% 以上、困惑度变差 600%–1000%;置零同样多的随机维度,困惑度只变差约 0.1%(论文报告)。
- 方法:向量级量化(每 token × 每输出通道一个缩放)+ 混合精度分解:只要某个输入通道里有值超过阈值 6.0,这一列就走 16 位矩阵乘法,其余 99.9% 以上的值走 INT8。
- 结果(论文报告):到 175B 都没有性能损失,显存减半。
- 代价:拆分矩阵的开销很大——论文附录 D 的测量里,只有 13B 和 175B 的模型比 FP16 快,更小的模型反而变慢。
4.3 SmoothQuant:把难度挪给权重
SmoothQuant 注意到:激活难量化、权重好量化,而且离群值”总在同样的通道上”。那就用一个数学上等价的逐通道缩放,把激活的离群值压小、同时把权重的对应列放大:
s_j = max|X_j|^α / max|W_j|^(1−α),用 X / s 和 W · s 代替 X 和 W。
α = 0.5 时,两边在这个通道上的最大值相等,“难度平分”。X / s 可以并进前一层(LayerNorm 的缩放或前一个线性层),推理时零开销;之后就可以用最快的每张量 INT8(论文的 O3 配置)。
代码 03 演示 1,同一个带离群通道的层(误差的分母是输出里随 token 变化的那部分,原因见下一节):
| 做法 | 输出误差 |
|---|---|
| 只量化权重(INT8,每输出通道;误差的下限) | 2.7% |
| W8A8,激活每张量 | 8.8% |
| W8A8,激活每 token | 6.6% |
| W8A8,激活每通道(参照,不能用在 INT8 GEMM 里) | 2.9% |
| LLM.int8()(6 列走 16 位) | 1.8% |
| SmoothQuant α = 0.25 / 0.5 / 0.75,每张量 | 6.4% / 3.5% / 3.0% |
| SmoothQuant α = 0.5,每 token | 2.6% |
| FP8 E4M3,激活每张量 / 每 token | 7.1% / 6.5% |
SmoothQuant 把每张量 INT8 的误差从 8.8% 降到 3% 左右,接近”按通道缩放”这个理想参照。α 取 0.5–0.75 都不错(论文默认 0.5,离群更严重的模型如 GLM-130B 用 0.75)。论文报告:OPT-175B 用朴素的每张量 W8A8 时零样本准确率掉到约 35%(全精度 66.9%)、困惑度上万,SmoothQuant 保持了精度;集成进 FasterTransformer 后最多快 1.56 倍、显存减半,530B 的模型能放进一个 8 卡节点。
4.4 一个评测上的陷阱:用什么做分母
写演示 2 时我发现一个问题:离群通道在每个 token 上几乎是同一个大数,它们对层输出的贡献像一个很大的”偏置”,占了输出范数的绝大部分。如果用 ‖Ŷ − Y‖ / ‖Y‖ 衡量误差,离群值越大,分母越大,哪怕普通通道的信息被量化完全抹掉,相对误差看起来也越来越小。所以本讲的层输出误差都用”输出里随 token 变化的那部分”做分母——携带信息的正是这部分。这和第 17 讲 §5 的教训一样:指标的定义可以悄悄改变结论。
4.5 离群值越来越大时
代码 03 演示 2(典型幅度约 0.25;表中是输出误差):
| 离群幅度 | INT8 每张量 | INT8 每 token | FP8 每张量 | SmoothQuant 每张量 | LLM.int8()(列数) |
|---|---|---|---|---|---|
| 2.5(约 10 倍) | 3.2% | 2.3% | 4.0% | 2.2% | 2.3%(0) |
| 10(约 40 倍) | 8.8% | 6.6% | 7.1% | 3.5% | 1.8%(6) |
| 40(约 160 倍) | 21.8% | 16.3% | 15.7% | 4.9% | 1.2%(6) |
| 160(约 640 倍) | 18.1% | 16.2% | 19.1% | 4.1% | 0.4%(6) |
几点:(1)INT8 每张量 / 每 token 的误差随离群值变大而变大,普通通道分到的格点越来越少。(2)FP8 每张量也会退化——这是我写代码前没想到的:缩放因子由最大的离群值决定,普通的数被缩得很小,落进 E4M3 的次正规数区间(2^−6 以下格点稀疏),相对精度就没有了。浮点能容忍的”大小差距”是有限的(E4M3 的正规数只覆盖约 2^15 倍)。(3)SmoothQuant 和 LLM.int8() 几乎不受影响。(4)离群幅度只有 2.5 时,没有一列超过 LLM.int8() 的阈值 6,它就退化成普通的每 token INT8。
实践中,FP8 的 W8A8(权重每通道、激活每张量或每 token 的动态缩放)在大多数模型上是”几乎无损、几乎不用调”的选择,这也是 H100 之后它成为默认的原因;遇到离群值特别严重的模型,再加 SmoothQuant 式的变换或更细的缩放粒度。
4.6 再往下:W4A4 与旋转
把激活也压到 4 位(W4A4),才能用上 INT4 / FP4 的 Tensor Core,但 4 位激活对离群值更敏感。QuaRot 的思路是:用一个正交矩阵(例如随机 Hadamard 矩阵)旋转隐藏状态,Q·x 的能量被”摊”到所有维度上,离群值就消失了;由于 QᵀQ = I,旋转可以并进相邻的权重,模型的输出不变。论文报告:权重、激活和 KV 全部 4 位的 Llama-2-70B,WikiText-2 困惑度最多只差 0.47,保留 99% 的零样本性能。但 QServe 论文指出,W4A4 要按组缩放才准,而 INT4 Tensor Core 输出的部分和要在 CUDA core 上反量化,实际速度反而不如 W4A16 和 W8A8——低比特不一定更快(§6)。
5. KV cache 量化 · KV cache quantization
KV cache 是推理系统里最大的”动态数据”(第 3、9 讲)。量化它有两个好处:显存能放更多 token(更大的批、更高的前缀命中率),长上下文 decode 读的字节更少。难点是:key 有固定的离群通道(与权重和激活里的发现一致),而且 KV 是流式追加的——新的 token 一个个来,量化的分组要能跟着增长。
代码 03 演示 3(一个头,2,048 个 token × 128 维;key 有 4 个离群通道;每组 32 个,非对称;误差是注意力输出的相对误差):
| key / value 的分组方式 | 4 位 | 2 位 |
|---|---|---|
| key 按 token,value 按 token | 9.8% | 64.5% |
| key 按 token,value 按通道 | 10.5% | 62.4% |
| key 按通道,value 按通道 | 10.0% | 42.9% |
| key 按通道,value 按 token(KIVI) | 9.3% | 44.7% |
| KIVI + 最近 128 个 token 全精度 | 7.5% | 37.6% |
| FP8 E4M3(每 token 一个缩放) | 2.7% | — |
论文卡片 Paper card · KIVI
- 发现:key cache 有少数固定的大通道,应该按通道量化(每个通道里每 G 个 token 一组),把离群值的影响限制在它自己的通道里;value cache 没有明显的通道结构,但注意力输出是 value 的加权混合,应该按 token 量化,让一个 token 的误差不影响别的 token。论文表 1(Llama-2-13B,2 位,组大小 32):key 按 token 时 CoQA 从 66.37 掉到 52.93(value 也按 token)或 2.80(value 按通道);key 按通道、value 按 token 时是 63.53。
- 方法:2 位非对称量化;按通道分组要先攒够一组 token,所以最近的 R(≤ 128)个 token 保留全精度(“残差”),注意力时量化部分和全精度部分用分块矩阵乘法合起来。
- 结果(论文报告):Llama、Falcon、Mistral 几乎不掉质量;峰值显存(含权重)少 2.6 倍,批可以大到 4 倍,真实负载的吞吐 2.35–3.47 倍。
- 局限:2 位的质量依赖模型;按通道量化让”追加一个 token”变复杂,需要残差窗口和专门的内核。
我们的合成数据复现了”key 按通道更好”(2 位时差别最明显:约 44% 对 64%)和”残差窗口有用”(一半的 query 正好关注最近的 token);没有复现”value 必须按 token”——我们的合成 value 没有模仿出那种结构。2 位时我们的误差仍然很大,而 KIVI 报告真实模型几乎无损:真实的 K / V 比我们的合成数据”好压缩”得多(能量集中在少数方向上)。实践中,生产系统最常用的是 FP8 KV(每 token 或每头一个缩放,几乎无损、实现简单);4 位、2 位 KV 主要用在长上下文和显存极紧的场景。
6. 系统视角:快多少、什么时候不快、要几块卡 · The systems view
6.1 decode:批越大,只量化权重越没用
代码 04 演示 1(Llama-3-8B / H100,每秒输出 token 数与相对 BF16 的加速;反量化代价是假设值):
上下文 2,048:
| 格式 | 批 1 | 批 16 | 批 64 | 批 256 | 批 1024 |
|---|---|---|---|---|---|
| BF16 | 161 | 2,077 | 5,114 | 8,062 | 9,419 |
| FP8 W8A8 + FP8 KV | 1.74× | 1.78× | 1.86× | 1.94× | 1.98× |
| W4A16(AWQ / GPTQ + Marlin 式内核) | 2.64× | 2.00× | 1.45× | 1.14× | 1.04× |
| W4A8KV4(QServe 式) | 2.73× | 2.86× | 3.09× | 3.36× | 3.49× |
上下文 256(KV 很少):W4A16 在批 256 时 1.20 倍、批 1024 时 0.77 倍(受限于算力 + 反量化);FP8 仍有 1.96 倍;W4A8KV4 降到 1.71 倍。
读这张表的方法就是 §1.1 的三笔账:
- 批 1:几乎只读权重。W4A16 把层内矩阵的字节从 13.96 GB 降到 3.63 GB,但 lm_head(1.05 GB)、KV 照读,还有每步 0.5 毫秒的固定开销,所以是 2.64 倍而不是 4 倍(练习 4)。
- 上下文长、批大:KV 的字节随批线性增长,成了要读的大头,W4A16 没有压缩它,优势消失;每一步都仍然受限于带宽。
- 上下文短、批大:这一步变成受限于算力。W4A16 的矩阵乘法仍是 BF16,还要在 CUDA core 上反量化,比 BF16 还慢。QServe 论文说现有的 4 位方法在大批量服务时有 20%–90% 的反量化开销,指的就是这种情形。
- FP8 在所有情形下都快 1.7–2.0 倍:权重和 KV 都减半,算力翻倍,没有反量化。W4A8KV4 三样都压,矩阵乘法走 INT8 Tensor Core,长上下文大批时 3 倍以上——QServe 的贡献就在于让这种组合在精度和内核上都可行(渐进式分组量化:先 8 位再 4 位,让矩阵乘法全在 INT8 Tensor Core 上;SmoothAttention 降低 4 位 KV 的误差)。论文报告:相对 TensorRT-LLM,Llama-3-8B 的最大吞吐在 A100 上提高 1.2 倍、L40S 上 1.4 倍,Qwen1.5-72B 分别 2.4 倍和 3.5 倍。
6.2 Marlin 的曲线
Marlin 论文说:4 位权重的矩阵乘法在批 ≤ 16–32 时能接近理想的约 3.9 倍,之后逐渐下降,批 128 时约 1.5 倍;集成进 vLLM 后端到端最多快 2.8 倍。代码 04 演示 2 用 roofline 在 A10 上算同一个形状(8,192 → 28,672):
| 批 | W4A16 的加速 | 不计反量化时 |
|---|---|---|
| 1 | 3.84× | 3.84× |
| 32 | 3.79× | 3.79× |
| 64 | 2.65× | 2.88× |
| 128 | 1.34× | 1.45× |
| 256 | 0.92× | 1.00× |
roofline 本身就给出了这条曲线的形状:批小时两个版本都受限于读权重,4 位就快 4 倍;批大到让 4 位的版本先撞上算力上限(A10 的屋脊点约 200 FLOP / 字节,4 位权重让每个字节对应的运算多 4 倍),加速就开始下降。反量化的代价(我们假设的参数)只让它再低一点。Marlin 的工程价值在于:用异步拷贝、精心的任务划分和流水线,让真实内核贴近这条 roofline、让反量化几乎不额外花时间——“能做到理论值”本身就很难。
6.3 prefill:只有低精度的计算才有用
代码 04 演示 3(2,048 token 的 prefill):BF16 41.8 毫秒,FP8 21.1 毫秒(1.98 倍),W4A16 55.1 毫秒(0.76 倍),W4A8KV4 24.5 毫秒(1.71 倍)。prefill 受限于算力,少读字节没有用。TTFT 由 prefill 决定,要靠低精度的计算;TPOT 由 decode 决定,主要靠少读字节——同一种量化,对两个指标的作用可能相反。
6.4 长上下文:量化 KV
代码 04 演示 4:32 个请求、每个上下文 32,768 token。BF16 的 KV 要读 137.4 GB,一步 57.4 毫秒;W4A16 只量化权重,53.5 毫秒,几乎没变;FP8 KV 读 68.7 GB,29.2 毫秒;4 位 KV 38.7 GB,16.7 毫秒。KV 能放的 token 数:BF16 约 42.7 万、FP8 约 95.9 万、W4A8KV4 约 180 万——第 3、9、14 讲里所有”显存放不下”的问题,都因此缓解;第 17 讲 §4.3 看到,FP8 在缓存受限的负载上 goodput 提高 2.16 倍,一部分就来自容量带来的命中率。
6.5 要几块卡
代码 04 演示 5,Llama-3-70B(张量并行,90% 显存可用),KV 能放多少 token:
| 格式 | 1 块 H100 | 2 块 | 4 块 | 8 块 |
|---|---|---|---|---|
| BF16 | 放不下 | 9k | 448k | 1,327k |
| FP8 W8A8 + FP8 KV | 放不下 | 432k | 1,311k | 3,069k |
| W4A16 | 98k | 318k | 757k | 1,636k |
| W4A8KV4 | 349k | 1,131k | 2,693k | 5,818k |
BF16 的 70B 两块 H100 刚放下权重,几乎不剩 KV 的空间;FP8 让两块卡就能正常服务;4 位权重让一块卡也能跑。量化的第一个作用常常不是”快”,而是”用更少的卡放得下”——卡少了,张量并行的通信也少了(第 6 讲)。
Blackwell 上(公开资料汇总:BF16 约 2.25 PFLOPS、FP8 2 倍、FP4 4 倍;8 TB/s),Llama-3-8B 的 prefill(2,048 token)在 BF16 / FP8 / NVFP4 下是 18.7 / 9.6 / 5.0 毫秒;批 256 的 decode 是每秒 18,840 / 35,882 / 38,501 个 token——decode 只快了一点,因为 KV 仍是 FP8、占了要读的字节的大头。
7. 怎样评估一个量化模型的质量 · Evaluating quality
7.1 平均准确率不够
常见的做法是报告困惑度和几个基准上的准确率,“和全精度差不多”就算无损。Dutta et al. 2024 指出这不够:即使平均准确率几乎不变(0–2%),很多题目的答案在量化后从对变错、又从错变对——他们称之为”翻转”(flips)。论文报告:六种量化方案在七个基准上的准确率都和 16 位差不多,但除了 GPTQ W8A16 之外,翻转率最高到 13.6%;在 MT-Bench 这样的自由生成任务上,多数量化方法让 Llama-2-70B 的分数掉约 5%、较难的第二轮掉到约 10%。他们建议同时报告和原模型的距离:KL 散度和翻转率,两者高度相关。
本讲代码 02 演示 4 正是这样做的:即使 KL 只有千分之几,top-1 也有约十分之一的位置”翻转”,贪心生成几个 token 之后就和全精度模型分道扬镳。(tiny_llm 是随机初始化的,前两名 logit 往往很接近,翻转率比训练好的模型高——要注意,把 logits 整体放大不会改变翻转率:量化造成的扰动也被同样放大了。)
7.2 一份评估清单
- 和原模型的距离:在真实流量的提示上算 KL 和翻转率;它们便宜、灵敏,适合比较配置。
- 任务指标:覆盖你关心的能力——知识、推理(长链推理对误差的累积更敏感)、代码、长上下文(KV 量化的影响主要在这里)、多轮和自由生成(可以用 LLM 评审)。
- 校准数据:和真实流量同分布;报告用了多少、来自哪里(§3.5)。
- 系统指标:在目标的批大小和上下文长度下测速度和显存(§6)——“4 位”不等于”4 倍快”。
- 端到端:在线上用灰度的方式比较用户可见的指标;量化模型的”翻转”会以用户能察觉的方式出现。
8. 现状(2026)· State of practice
- FP8 是 H100 / H200 上服务的默认选择:主流引擎(vLLM、SGLang、TensorRT-LLM)都支持 FP8 权重 + 激活和 FP8 KV;第 17 讲的纸上实验里,它是单项收益最大的特性。
- 模型直接以低精度形式发布或训练:Meta 发布了 Llama 3.1 405B 的 FP8 版本;DeepSeek-V3 用 FP8 混合精度训练(激活按 1 × 128、权重按 128 × 128 的块细粒度缩放);OpenAI 的 gpt-oss 以 MXFP4 发布 MoE 部分的权重。量化从”训练后的压缩”变成了”模型设计的一部分”,量化感知训练(QAT)也越来越常见。
- FP4 进入硬件:Blackwell 的 NVFP4 / MXFP4 Tensor Core 让 W4A4 第一次在大规模服务里变得有吸引力,配套的是更小的块、旋转类方法和 QAT。
- 4 位权重仍是边缘和单用户场景的主力:AWQ、GPTQ 的变体加上 Marlin 一类内核,在笔记本、手机和小批服务上最常见。
- KV 量化:FP8 KV 已经普及;更低位的 KV 和其他 KV 压缩方法(第 9 讲的 CacheGen、低秩、稀疏)主要用在长上下文。
9. 小结 · Summary
- 量化动了 roofline 里的三样东西:读的字节(decode、尤其小批)、显存的容量(能不能放下、批和缓存有多大)、Tensor Core 的算力(只有两个输入都是低精度时才有)。它们在 prefill 和 decode、小批和大批里的分量完全不同。
- 整数格点等间隔、浮点格点对数均匀:数据近似正态时 INT8 更准(39 dB 对 32 dB),有重尾或离群值时 FP8 更稳(三种数据都约 32 dB)。4 位必须配合细粒度的缩放(每组 128、MXFP4 的 32、NVFP4 的 16)。
- 激活的离群通道在输入通道那一维上,而整数矩阵乘法只能在 token 和输出通道两维上缩放——这是激活量化的核心困难。LLM.int8() 把离群列拿出来(准但慢),SmoothQuant 把难度挪给权重(α 取 0.5–0.75),FP8 用浮点的动态范围顶住中等的离群值,QuaRot 用旋转把离群值摊平。
- 仅权重量化:判断重要性要看激活(保留 1% 按激活挑能让误差减半,按权重挑没用);AWQ 用等价缩放保护重要通道、对校准数据不敏感;GPTQ 用二阶信息逐列补偿、最准,但会适应校准数据的分布。
- KV 量化:key 按通道、value 按 token、最近的 token 保留全精度(KIVI);FP8 KV 是最常用的选择。它对长上下文的吞吐和容量至关重要。
- 系统上:W4A16 在小批 decode 快 2–3 倍,大批、短上下文时反而比 BF16 慢(反量化 + BF16 算力);FP8 在各种情形下都快约 2 倍;prefill 只受益于低精度的计算。量化的第一个作用常常是”用更少的卡放得下”。
- 评估量化不能只看平均准确率,还要看和原模型的距离(KL、翻转率)和长上下文、推理、自由生成等更敏感的能力。
10. 常见误区 · Common pitfalls
- “4 位就是 4 倍快。” 只有小批 decode 接近;lm_head、KV、固定开销照旧,大批时 W4A16 甚至更慢,prefill 也更慢(代码 04)。
- “量化只是为了快。” 很多时候是为了放得下:70B 从两块卡变一块、KV 容量翻倍、缓存命中率提高。
- “FP8 不怕离群值。” 中等离群值下比 INT8 稳;离群值极端时,普通的数被挤进次正规数区间,FP8 每张量也会明显退化(代码 03 演示 2)。
- “激活也能像权重一样按通道量化。” 按输入通道缩放进不了整数矩阵乘法的累加;这正是 SmoothQuant、LLM.int8() 要绕开的限制。
- “挑最大的权重保护起来就行。” 重要性看激活,不看权重本身(代码 02 演示 1;AWQ 表 1)。
- “GPTQ 总比 AWQ 好。” 同领域时 GPTQ 往往更准;校准数据和真实流量不一样时,它的优势可能变成劣势(代码 02 演示 3)。
- “KV 的 key 和 value 用同一种分组。” key 有通道离群值,应该按通道;value 按 token(KIVI)。
- “困惑度只差 0.1,就是无损。” 平均指标会掩盖大量的翻转;要看 KL / 翻转率,并测长上下文、推理和自由生成。
11. 练习 · Exercises
参考答案里的数字来自代码 01–04 的输出或
quant_lab.py的函数。
练习 1(每个数占几个比特)。(a) INT4、每 64 个一组、FP16 缩放 + 4 位零点,每个数占几个比特?(b) Llama-3-70B 层内矩阵约 684.5 亿个参数,用 INT4 每 128 个一组(约 4.16 位)存,要多少 GB?嵌入表和 lm_head(约 21 亿参数)保持 BF16 呢?(c) 和 MXFP4、NVFP4 比,为什么硬件格式选了更小的块?
参考答案
(a) 4 + (16 + 4) / 64 ≈ 4.31 位。(b) 684.5 亿 × 4.16 / 8 ≈ 35.6 GB;加上 BF16 的嵌入表和 lm_head 约 4.2 GB,共约 39.8 GB——一块 80 GB 的 H100 放得下,还剩约 32 GB 给 KV(代码 04 演示 5:W4A16 一块卡约 9.8 万 token 的 KV)。(c) 4 位只有 16 个格点,块越小,每块的最大值越接近块里的典型值,误差越小;硬件格式用 8 位的块缩放(MXFP4 每 32 个 4.25 位,NVFP4 每 16 个 4.5 位),比 FP16 缩放 + 零点便宜,所以能用更小的块。代码 01 演示 3:NVFP4 的 SQNR(20.7 dB)和 INT4 每 32 个一组非对称(20.6 dB、4.62 位)相当,比 MXFP4(18.0 dB)好。
练习 2(有效格点数)。一个激活张量的最大值是 17.5(来自离群通道),某个普通通道的最大值是 1.4。(a) 每张量 INT8 量化时,这个通道大约能用多少个格点?(b) SmoothQuant 用 α = 0.5,如果这个离群通道的 max|X_j| = 17.5、对应权重列的 max|W_j| = 0.07,缩放后两者的最大值各是多少?
参考答案
(a) 2^8 × 1.4 / 17.5 ≈ 20 个(代码 01 演示 4 的估算)。(b) s = 17.5^0.5 / 0.07^0.5 = √(17.5 / 0.07) = √250 ≈ 15.8;激活的最大值变成 17.5 / 15.8 ≈ 1.11,权重列的最大值变成 0.07 × 15.8 ≈ 1.11——两者相等,“难度平分”。整个张量的最大值不再由这个通道决定,普通通道的格点数就多了很多。
练习 3(AWQ 的误差比)。AWQ 论文的公式(3):把一个权重乘 s、激活除以 s,量化误差变成原来的 (Δ’/Δ) · (1/s),其中 Δ 是组的量化步长。(a) 为什么 s 不能无限大?(b) 用代码 02 演示 2 的曲线说明。
参考答案
(a) 放大一个元素时,只要它还不是组里最大的,步长 Δ’ ≈ Δ,误差按 1/s 下降;s 太大,它变成组里的最大值,Δ’ 随之变大,同组的其他通道的误差都被放大 Δ’/Δ 倍(论文表 2:s 从 1 到 4,Δ 改变的组的比例从 0% 增加到 21.2%,最好的困惑度在 s = 2)。(b) α = 0(不缩放)误差 25.2%,α = 0.4 最低 14.8%,α = 0.9 升到 30.7%,比 RTN 还差——保护过头,代价超过了收益。
练习 4(批 1 为什么不是 4 倍)。Llama-3-8B / H100,上下文 2,048,批 1。(a) 算 BF16 和 W4A16 一步各要读多少字节(层内矩阵约 69.8 亿参数、lm_head 约 5.25 亿参数保持 BF16、KV 每 token 128 KiB)。(b) 加上每步 0.5 毫秒的固定开销、有效带宽 3.35 TB/s × 0.8,各要多久?加速比多少?
参考答案
(a) BF16:层内 13.96 GB + lm_head 1.05 GB + KV 2,049 × 131,072 字节 ≈ 0.27 GB,共约 15.28 GB。W4A16:层内 69.8 亿 × 4.16 / 8 ≈ 3.63 GB,其余不变,共约 4.95 GB。字节只少了 3.09 倍。(b) BF16:15.28 / 2.68 TB/s ≈ 5.7 毫秒 + 0.5 ≈ 6.2 毫秒;W4A16:4.95 / 2.68 ≈ 1.85 毫秒 + 0.5 ≈ 2.35 毫秒;加速约 2.64 倍(代码 04 演示 1)。要再快,就要连 lm_head、KV 一起压,并减少每步的固定开销(CUDA graph)。
练习 5(选格式)。为下面三个场景各选一种部署格式,说明理由:(a) 笔记本上单用户跑 8B 模型聊天;(b) 数据中心 H100 上服务一个 8B 模型,高峰时批 200 以上,平均上下文 2k;(c) 同上,但平均上下文 32k 的文档问答。
参考答案
(a) W4A16(AWQ / GPTQ),批 1 的 decode 受限于读权重,4 位权重快 2.6 倍以上,还能放进较小的显存。(b) FP8 W8A8 + FP8 KV:大批时 W4A16 只快 1.1 倍左右(代码 04:批 256 时 1.14 倍),FP8 快约 1.9 倍、几乎无损、实现简单;如果能接受更多的精度风险,W4A8KV4 更快(3.4 倍)。(c) 一定要量化 KV:上下文 32k 时一步 decode 的时间主要花在读 KV 上,只量化权重几乎没用(代码 04 演示 4:57.4 → 53.5 毫秒),FP8 KV 让它减半、容量翻倍;4 位 KV 再翻一倍,但要仔细评估长上下文任务的质量。
练习 6(思考:怎样上线一个量化模型)。你要把一个线上聊天服务的模型从 BF16 换成 FP8。写出上线前要做的评估,和上线时的保护措施。
参考答案(要点)
上线前:用真实流量的提示(脱敏后)算 KL 和翻转率;跑任务基准,特别是长上下文、多轮、推理、代码和格式化输出(结构化输出的约束对 logits 的微小变化很敏感);在目标批大小和上下文下测速度和显存,确认确实受益;检查校准数据(如果用了静态缩放)是否覆盖了各类流量。上线时:灰度发布,按用户可见的指标(重试率、点踩率、对话长度)比较;保留快速回滚到 BF16 的能力;对特别敏感的流量(例如医疗、法律)可以保留全精度的路由。
12. 延伸阅读 · Further reading
本讲依据的论文
- T. Dettmers, M. Lewis, Y. Belkada, L. Zettlemoyer. LLM.int8(): 8-bit Matrix Multiplication for Transformers at Scale. NeurIPS 2022(arXiv:2208.07339)。
- E. Frantar, S. Ashkboos, T. Hoefler, D. Alistarh. GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers. ICLR 2023(arXiv:2210.17323)。
- G. Xiao, J. Lin, M. Seznec, H. Wu, J. Demouth, S. Han. SmoothQuant: Accurate and Efficient Post-Training Quantization for Large Language Models. ICML 2023(arXiv:2211.10438)。
- J. Lin, J. Tang, H. Tang, S. Yang, W.-M. Chen, W.-C. Wang, G. Xiao, X. Dang, C. Gan, S. Han. AWQ: Activation-aware Weight Quantization for On-Device LLM Compression and Acceleration. MLSys 2024(arXiv:2306.00978)。
- P. Micikevicius et al. FP8 Formats for Deep Learning. arXiv:2209.05433, 2022。
- B. D. Rouhani et al. Microscaling Data Formats for Deep Learning. arXiv:2310.10537, 2023。
- Z. Liu, J. Yuan, H. Jin, S. Zhong, Z. Xu, V. Braverman, B. Chen, X. Hu. KIVI: A Tuning-Free Asymmetric 2bit Quantization for KV Cache. ICML 2024(arXiv:2402.02750)。
- S. Ashkboos et al. QuaRot: Outlier-Free 4-Bit Inference in Rotated LLMs. arXiv:2404.00456, 2024。
- E. Frantar, R. L. Castro, J. Chen, T. Hoefler, D. Alistarh. MARLIN: Mixed-Precision Auto-Regressive Parallel Inference on Large Language Models. arXiv:2408.11743, 2024。
- Y. Lin, H. Tang, S. Yang, Z. Zhang, G. Xiao, C. Gan, S. Han. QServe: W4A8KV4 Quantization and System Co-design for Efficient LLM Serving. MLSys 2025(arXiv:2405.04532)。
- A. Dutta, S. Krishnan, N. Kwatra, R. Ramjee. Accuracy is Not All You Need. arXiv:2407.09141, 2024。
相关
- NVIDIA 关于 NVFP4 的技术博客(Introducing NVFP4 for Efficient and Accurate Low-precision Inference)。
- DeepSeek-AI. DeepSeek-V3 Technical Report(FP8 混合精度训练)。
- 第 1 讲(roofline)、第 9 讲(CacheGen 对 KV 的量化与熵编码)、第 17 讲 §3–§4(FP8 在完整引擎里的价值和它与前缀缓存的相互作用)。