量化全景:GPTQ / AWQ / SmoothQuant / FP8¶
更新日期:2026-04-15
一、量化的动机¶
| 精度 | 比特数 | 内存比 | 典型应用 | 精度损失 |
|---|---|---|---|---|
| FP32 | 32 | 4× | 训练 baseline | 0 |
| BF16 / FP16 | 16 | 2× | 训练 + 推理标准 | 极小 |
| FP8 (E4M3 / E5M2) | 8 | 1× | H100 训练 + 推理 | 可控(DeepSeek-V3 已规模化) |
| INT8 | 8 | 1× | 推理(SmoothQuant) | <1% |
| INT4 (AWQ/GPTQ) | 4 | 0.5× | 推理(消费卡) | 1-3% |
| INT3 / INT2 | 3 / 2 | <0.4× | 端侧 | 显著,需重训 |
核心动机:模型参数量 N 决定推理延迟(带宽 bound),量化让同一卡跑更大模型。70B FP16 需 140GB(双 H100),INT4 仅 35GB(单 A100/4090)。
生产建议:
- 首选:FP8(需 H100+)或 INT4 AWQ/GPTQ(A100 及以下)
- 对精度零容忍:BF16
- 极端显存受限(端侧):INT3 或更低,必须做任务级评测确认精度可接受
二、权重量化方法¶
2.1 GPTQ:基于 Hessian 的精确量化¶
GPTQ 的核心思想:量化第 i 列时,用后续列补偿误差,保持输出层的激活尽可能接近原始。参考 GPTQ (Frantar et al., 2022)。
def gptq_quantize(W, calibration_X, n_bits=4, block_size=128):
"""
W: [out_features, in_features] 权重矩阵
calibration_X: [n_samples, in_features] 校准数据
"""
n_rows, n_cols = W.shape
# 1. 计算 Hessian: H = 2 * X^T X
# Hessian 编码了输入的二阶统计信息
H = 2 * calibration_X.T @ calibration_X
H += 0.01 * torch.eye(n_cols) # 正则化防奇异
H_inv = torch.linalg.inv(H)
Q = torch.zeros_like(W)
E = torch.zeros_like(W) # 累积误差
for col in range(n_cols):
# 2. 量化当前列 (考虑已累积的误差)
w = W[:, col] + E[:, col]
Q[:, col] = quantize_to_n_bits(w, n_bits)
# 3. 计算量化误差
err = w - Q[:, col]
# 4. 用 Hessian 信息将误差分配到后续列
# 直觉: 如果 col 和 j 相关性高, 把误差转到 j
for j in range(col + 1, n_cols):
E[:, j] += err * H_inv[col, j] / H_inv[col, col]
return Q
2.2 AWQ:保护激活值大的通道¶
AWQ 的观察:不同通道的激活值差异巨大,激活值大的通道对应的权重更重要。参考 AWQ (Lin et al., 2023)。
def awq_quantize(W, activation_stats, n_bits=4, alpha=0.5):
"""
W: 权重 [out, in]
activation_stats: 校准数据中各通道的激活值平均幅度 [in]
"""
# 1. 找出重要通道
# 激活值越大 → 通道越重要 → 权重对量化越敏感
importance = activation_stats.abs().mean(dim=0) # [in]
# 2. 计算保护性缩放因子
# 重要通道 scale up → 量化时相对误差小
scales = (importance / importance.mean()) alpha # [in]
# 3. 缩放权重
W_scaled = W * scales.unsqueeze(0)
# 4. 标准量化缩放后的权重
Q = standard_quantize(W_scaled, n_bits)
# 5. 推理时反缩放
# 输出 = W_scaled @ (X / scales)
# 等价于 W @ X (如果精确量化)
# 实际因为量化有损, 这种设计让重要通道损失最小
return Q, scales
# AWQ vs GPTQ:
# AWQ: 基于激活值设计, 无需梯度信息, 更快
# GPTQ: 基于 Hessian, 质量略高但慢
# 实际: 两者质量接近, AWQ 部署更普及
2.3 GGUF:llama.cpp 生态¶
GGUF 是 llama.cpp 的量化格式,支持多种精度混合(Q2_K / Q3_K / Q4_K / Q5_K / Q6_K / Q8_0)。社区最流行的边缘部署格式。 实用建议:端侧部署首选 Q4_K_M(质量/大小最佳平衡)。若显存允许可升到 Q5_K_M 获得更好质量。Q2_K/Q3_K_M 仅在设备极端受限时使用,建议先在目标任务上评测精度再部署。
三、激活量化¶
3.1 为什么难:Outlier 问题¶
LLM 的激活值有严重的 outlier。某些通道的值可能是其他通道的 100 倍,标准量化会把小值全压成 0。
3.2 SmoothQuant:难度转移¶
核心思想:将激活的量化难度转移到权重上。参考 SmoothQuant (Xiao et al., 2023)。
def smooth_quant(W, activation_stats, alpha=0.5):
# 激活的 per-channel 最大值
s_act = activation_stats.abs().max(dim=0) # [in]
# 权重的 per-channel 最大值
s_w = W.abs().max(dim=0) # [in]
# 平滑因子: 平衡激活和权重的难度
smooth_scales = s_act.pow(alpha) / s_w.pow(1 - alpha)
# 应用平滑
W_smooth = W * smooth_scales.unsqueeze(0) # 权重变大
# X_smooth = X / smooth_scales (推理时应用) # 激活变小
# 效果:
# 激活: outlier 被缩小 → 容易量化
# 权重: 略微放大 → 仍然容易量化
return W_smooth, smooth_scales
# W8A8 (权重+激活都 INT8):
# 标准量化: 质量严重下降
# SmoothQuant 后: 几乎无损
四、浮点数据类型全谱(FP4 → FP64)¶
4.1 现代 GPU 支持的所有 FP 类型¶
NVIDIA Blackwell(5th-gen Tensor Core)原生支持:FP4 / FP6 / FP8 / FP16 / BF16 / TF32 / FP32 / FP64。每种格式的位分配:
| 类型 | 总位 | sign | exp | mantissa | 表示形式 | 动态范围 | 最小正非零 | 用例 |
|---|---|---|---|---|---|---|---|---|
| FP4 (E2M1) | 4 | 1 | 2 | 1 | NVFP4 / MXFP4 | ±6 | 0.5 | 推理(权重 + 激活) |
| FP6 (E2M3) | 6 | 1 | 2 | 3 | MXFP6 高精度 | ±7.5 | 0.0625 | 高精度 4-bit 替代 |
| FP6 (E3M2) | 6 | 1 | 3 | 2 | MXFP6 大范围 | ±28 | ~0.0156 | 训练激活 |
| FP8 (E4M3) | 8 | 1 | 4 | 3 | NV E4M3 / MXFP8 | ±448 | ~0.00195 | 训练 forward / 推理 |
| FP8 (E5M2) | 8 | 1 | 5 | 2 | NV E5M2 / MXFP8 | ±57344 | ~1.5e-5 | 训练 backward(梯度) |
| FP16 | 16 | 1 | 5 | 10 | IEEE 754 half | ±65504 | ~6e-5 | 历史训练,已被 BF16 替代 |
| BF16 | 16 | 1 | 8 | 7 | Brain Float | ±3.4e38 | ~1.2e-38 | 训练默认(FP32 同范围) |
| TF32 | 19 | 1 | 8 | 10 | NVIDIA TF32 | ±3.4e38 | ~1.2e-38 | A100+ 自动 promote 模式 |
| FP32 | 32 | 1 | 8 | 23 | IEEE 754 single | ±3.4e38 | ~1.2e-38 | 累加器 / 主权重副本 |
| FP64 | 64 | 1 | 11 | 52 | IEEE 754 double | ±1.8e308 | ~2.2e-308 | 科学计算(HPC) |
位布局可视化(按总位长展开):
FP4 (E2M1): [s][ee][m] 4 bit
FP6 (E2M3): [s][ee][mmm] 6 bit
FP6 (E3M2): [s][eee][mm] 6 bit
FP8 (E4M3): [s][eeee][mmm] 8 bit
FP8 (E5M2): [s][eeeee][mm] 8 bit
BF16: [s][eeeeeeee][mmmmmmm] 16 bit
FP16: [s][eeeee][mmmmmmmmmm] 16 bit
TF32: [s][eeeeeeee][mmmmmmmmmm] 19 bit
FP32: [s][eeeeeeee][mmmmmmmmmmmmmmmmmmmmmmm] 32 bit
FP64: [s][eeeeeeeeeee][mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm] 64 bit
s=sign, e=exponent, m=mantissa
"E4M3" 即 Exponent=4 bits, Mantissa=3 bits
两个 trade-off:
↑ 范围(exponent 多)
FP8-E5M2 (5/2) ←─── 损失精度
│
BF16 (8/7)
│
FP16 (5/10)
│
FP8-E4M3 (4/3) ←─── 范围/精度均衡,FP8 主流选择
│
FP6-E3M2 (3/2)
│
FP4-E2M1 (2/1) ←─── 极致压缩,需要 microscaling 救场
精度 →(mantissa 多)
算力差距(H100 → B200,相对 BF16 = 1×):
| 精度 | H100 TFLOPS | B200 TFLOPS | 倍数 vs BF16 |
|---|---|---|---|
| FP64 | 67 | 90 | 0.05× |
| FP32 (TF32) | 989 | 1100 | 0.55× |
| BF16 / FP16 | 1979 | 2200 | 1× (基线) |
| FP8 | 3958 | 4500 | 2× |
| FP6 | — | 4500 | 2× (B200 起) |
| FP4 | — | 9000 | 4.5× (B200 起) |
→ 每降一精度约 2×,FP4 在 Blackwell 上是 BF16 的 4.5× 算力。这是为什么 frontier 一定要用 FP8/FP4。
4.2 FP8 详解(已成主流)¶
NVIDIA H100 / B200 原生支持 FP8 计算。FP8 质量接近 BF16,速度 2×,内存 ½。参考 FP8 Formats for Deep Learning (Micikevicius et al., 2022)。
E4M3 vs E5M2 选用:
- E4M3(精度高、范围小):训练 forward + 推理(权重 + 激活)
- E5M2(范围大、精度低):训练 backward(梯度量级跨度大需要大 exponent)
- FP32:累加器,防止 1000+ 次乘加累积误差
# 训练时混合精度示意
def fp8_matmul(x_fp8, w_fp8):
# FP8 × FP8 → FP32 累加(H100 Tensor Core 原生)
out_fp32 = tensorcore.matmul(x_fp8, w_fp8, accumulator='fp32')
# 量化回 FP8 进入下一层
return to_fp8(out_fp32, format='e4m3')
# H100 FP8: 4000 TFLOPS (vs BF16 2000,提速 2×)
# B200 FP8: 4500 TFLOPS (vs BF16 2200, 提速 2×)
训练时的"双精度"权重(关键技巧): - FP8 forward / backward - FP32 主权重副本(master copy),优化器在 FP32 上更新 - 每 step 把 FP32 主权重 cast 回 FP8 给下一 step
否则 FP8 累积误差会让训练发散。这是 Micikevicius 2022 推荐的标准配置。
4.3 FP4 — Blackwell 起的新一代量化¶
FP4 单 nibble 只能表示 16 个值(含正负),动态范围极小(±6)。直接当 weight 量化精度损失严重,必须 microscaling 才能用。
4.3.1 NVFP4 vs MXFP4 对比¶
NVIDIA Blackwell 上有两种 FP4 标准:
| 维度 | MXFP4 (OCP 标准) | NVFP4 (NVIDIA 优化) |
|---|---|---|
| 数据元素 | E2M1(FP4) | E2M1(FP4) |
| Block size | 32 个值共享一 scale | 16 个值 共享一 scale |
| Block scale 类型 | E8M0(power-of-2,整数 exp) | E4M3(非整数 exp,更细) |
| Tensor-level scale | 无 | FP32 标量(Level 2 scaling) |
| Block scale 量化误差 | 高(power-of-2 step) | 低(fractional E4M3) |
| 内存(每 16/32 个 4-bit 值) | 4×32+8 = 136 bit | 4×16+8 = 72 bit + per-tensor FP32 |
| 实际开销 | 4.25 bit / value | ~4.5 bit / value |
| 准确度(vs FP8) | 1-3pt 损失 | <1pt 损失 |
4.3.2 NVFP4 的两级 scaling 直观图¶
Tensor (e.g. weight matrix W shape [4096, 4096]):
┌───────────────────────────────────────────────────┐
│ │
│ ┌─16─┐ ┌─16─┐ ┌─16─┐ ┌─16─┐ ... │
│ │░░░░│ │░░░░│ │░░░░│ │░░░░│ ← 每 16 个 FP4│
│ └─┬──┘ └─┬──┘ └─┬──┘ └─┬──┘ 值一组 │
│ │ │ │ │ │
│ s_E4M3 s_E4M3 s_E4M3 s_E4M3 ← Level 1: │
│ (per-block, 8 bit each) 每组 1 个 │
│ E4M3 scale│
│ │
│ 全 tensor 1 个 FP32 scalar: │
│ S_FP32 ──── 用于校准整个 tensor 分布 │
│ │
└───────────────────────────────────────────────────┘
恢复一个值: x = x_q × s_block × S_tensor
↑ ↑ ↑ ↑
FP4 E4M3 FP32 原始浮点
(4) (8) (32)
为什么 NVFP4 比 MXFP4 准:
- Block 更小(16 vs 32)→ 局部分布动态范围更窄 → scale 更准
- Block scale 用 E4M3 而非 E8M0 → power-of-2 量化变 fractional 量化,误差降一个数量级
- 多一层 FP32 tensor scale → 整个 tensor 的"全局分布"被先归一化,块内只算偏差
实测(NVIDIA 自报,DeepSeek-R1-0528):FP8 → NVFP4 PTQ 后,< 1% 准确度下降,AIME 2024 反而 +2%。
4.3.3 MXFP6 / MXFP8 等中间档¶
OCP MX 标准其实是个家族,FP4 只是最激进的:
实操:
- MXFP4:最大压缩,Blackwell 起的推理新主流(取代 INT4)
- MXFP6:精度更好但压缩比一般,transitional,少有团队专门用
- MXFP8:和 NVIDIA 的 FP8 几乎等价,块 scale 比单 scale 略好
4.4 DeepSeek-V3 的 FP8 训练¶
DeepSeek-V3 是第一个在 671B MoE 规模验证 FP8 训练可行性的工作(详见 DeepSeek 工程深读 §四)。
要点: - per-tile fine-grained scaling:1×128 (act) / 128×128 (weight) - 全 forward + backward 用 E4M3(而非 E5M2 backward),靠 tile-scaling 吸收 dynamic range - FP32 累加 + FP32 主权重副本
V3 FP8 训练成果证明 ≤ BF16 的精度损失,671B 训练成本节省 ~50%。
五、Outlier 解决方案的演进¶
权重 + 激活 同时 4-bit 量化的核心难题是 outlier(§3.1 已说激活 outlier 的存在)。2022-2025 演进:
flowchart LR
raw["原始 LLM<br/>有 outlier"]
raw --> sq["SmoothQuant<br/>(2022)<br/>难度转移到权重"]
raw --> llm8["LLM.int8()<br/>(2022)<br/>混合 INT8 + FP16<br/>outlier 走 FP16"]
sq --> qrot["QuaRot<br/>(2024.04)<br/>Hadamard 旋转<br/>消除 outlier"]
llm8 --> qrot
qrot --> spin["SpinQuant<br/>(2024.05)<br/>学习旋转矩阵"]
spin --> mxnv["MXFP4 / NVFP4<br/>(2025)<br/>microscaling 自带<br/>tile-level outlier 控制"]
classDef era fill:#fff,stroke:#cc785c,color:#1a1a1a;
class raw,sq,llm8,qrot,spin,mxnv era
5.1 LLM.int8()(2022)¶
Dettmers 2022 思路:outlier 通道走 FP16,剩余通道走 INT8,混合精度矩阵乘。
- 优点:保住 outlier 信息
- 缺点:实现复杂,混合 dtype 拖慢推理 30%
5.2 SmoothQuant(2022)¶
详见 §3.2。把激活 outlier 通过缩放转移到权重。第一个能让 LLaMA 类全 INT8 的方法。
5.3 QuaRot(2024.04,arXiv:2404.00456)¶
关键 insight:outlier 是 hidden state 中特定通道的特性。如果给 hidden state 做一个正交旋转,outlier 就被打散到所有通道,平均化。
旋转矩阵 R 是正交的: R^T R = I
attention 输出经过旋转: y' = y · R
后续层先 unrotate: y = y' · R^T (因为 R^T = R^{-1})
等价于原网络,但 hidden state 分布变均匀
QuaRot 用 Hadamard 矩阵(特殊的 ±1 正交阵)做随机旋转。结果:LLaMA-2 全 4-bit 量化(W4A4KV4),accuracy 损失 < 1pt。
5.4 SpinQuant(2024.05,arXiv:2405.16406)¶
思路:QuaRot 用随机 Hadamard,能不能学一个最优旋转?
SpinQuant 把 R 设为可学习的正交矩阵,用 Cayley 参数化保证正交性,在 calibration data 上 fine-tune 50 step。
实测:LLaMA-3-8B 4-bit W4A4KV4,SpinQuant 比 QuaRot 缩小 accuracy gap 45.1%;比 SmoothQuant 强 25 pt。
5.5 NVFP4 / MXFP4(2025+)¶
Microscaling 自带 outlier 控制:每 16/32 个值就重新归一,再大 outlier 也只影响一个 block。不需要旋转 / smoothing 等"预处理"。
→ 2026 工业界主流是 直接 NVFP4 PTQ(NVIDIA TensorRT-Model-Optimizer / vLLM 默认 path),不再走 QuaRot/SpinQuant 那一套。
六、量化选型¶
6.1 实际选择建议(2026)¶
- Blackwell B200 / B100 / RTX 50:NVFP4 推理(W4A4),训练 FP8(E4M3 + per-tile)
- Hopper H100 / H200:FP8 推理 + 训练(NVFP4 不原生支持但可用 MXFP4 软件 emulate)
- Ampere A100 及以下:AWQ INT4(速度优先)或 GPTQ INT4(质量优先)
- CPU / 端侧:GGUF
Q4_K_M,显存允许升Q5_K_M - 精度敏感:从 FP8 起步逐步降到精度临界点
不确定时从高精度(FP8)开始,逐步降低直到精度不可接受。
七、MoE 量化的特殊考虑¶
MoE 量化不能用统一的 calibration 数据,因为不同专家看到的数据分布完全不同。
def per_expert_quantization(moe_model, calibration_data):
for layer in moe_model.moe_layers:
for expert_id, expert in enumerate(layer.experts):
# 只用路由到此专家的 token 做 calibration
expert_tokens = collect_routed_tokens(
calibration_data, layer, expert_id)
# 冷门专家数据少, 可能需要保守量化
if len(expert_tokens) < 100:
quantize(expert, expert_tokens, bits=8) # 保守
else:
quantize(expert, expert_tokens, bits=4) # 激进
八、量化的实用工具¶
| 场景 | 量化工具 | 推理后端 |
|---|---|---|
| 快速上手 | AutoAWQ | vLLM |
| 极致性能 | TensorRT-Model-Optimizer | TensorRT-LLM |
| 端侧部署 | llama.cpp(GGUF) | llama.cpp |
| 微调(QLoRA) | bitsandbytes | bitsandbytes / vLLM |
参考文献¶
-
[1] Frantar et al. GPTQ. 2022. 论文
-
[2] Lin et al. AWQ. 2023. 论文
-
[3] Xiao et al. SmoothQuant. ICML 2023. 论文
-
[4] Micikevicius et al. FP8 Formats for Deep Learning. 2022. 论文
-
[5] DeepSeek-V3 Technical Report (FP8 训练). 2024. 论文
-
[6] Dettmers et al. LLM.int8(). NeurIPS 2022. 论文
-
[8] AutoGPTQ
-
[9] AutoAWQ
↑ 上级 · G. 推理与部署