Skip to content

权重量化与混合精度

本页速览 权重量化(weight-only)把 LLM 权重压到 INT4/INT8 同时激活保持 FP16/BF16——专门为 decode 阶段带宽墙设计。本文讲透 GPTQ 的 Hessian 二阶补偿、AWQ 的显著权重保护、Marlin kernel 的极致融合、以及 W8A16/W4A16/W4A8 等组合的选型。

权重量化与混合精度

概念定义:攻 decode 阶段带宽墙的最强武器

LLM 推理在 decode 阶段是 memory-bound——每生成一个 token 都要把整个模型权重从 HBM 读一遍。**权重量化(weight-only quantization)**就是专门为此设计:把权重压到 INT4/INT8(4 倍/2 倍字节减少),激活仍用 FP16/BF16(精度无损),就能让 decode 吞吐 3-4 倍。

理解 weight-only 的两个关键认知:

  1. 它只压权重,不压激活——因为激活只占小头(一次前向只算当前 token 的几 KB),权重才是大头(70B 模型 140GB);
  2. 它专攻 decode,prefill 受益有限——prefill 是 compute-bound,减字节不直接换速度;decode 是 memory-bound,减字节直接换速度。

权重量化是当前 LLM 推理的事实标准——vLLM、TensorRT-LLM、llama.cpp 都内置支持。

一、weight-only 的基本套路

text
原始:    W (FP16) × X (FP16)  →  Y (FP16)         # decode 阶段带宽瓶颈
量化:    W (INT4) → dequant → W' (FP16) × X (FP16) → Y

                            反量化在算 matmul 前即时完成

关键问题:反量化(dequant)放在哪里?两种主流做法:

方案流程优势劣势
离线反量化W INT4 → W FP16(推理前一次性反量化)实现简单显存没省,速度没快——反例
在线反量化 + 融合 kernel在 matmul 内部即时反量化每组权重显存省 4 倍,带宽省 4 倍kernel 要手写优化(Marlin)

不要"离线反量化"

"先把 INT4 权重反量化回 FP16 再推理"是新手最常踩的坑——那样显存没省(还是要存 FP16),速度还慢了(多一步反量化)。真正的 weight-only 必须用融合 kernel——反量化算在 matmul 内部,每读一组 INT4 立刻反量化立刻算,权重全程留在 INT4 状态。Marlin kernel 就是为此而生。

二、GPTQ:Hessian 二阶补偿

核心思想

GPTQ(Frantar et al., 2023)是 INT4 权重量化精度最高的算法之一。它的核心:按列顺序量化权重,每量化一列就用 Hessian 信息调整剩余列补偿误差

数学原理:

text
量化误差最小化:minimize || W × X - Q × X ||²
其中 X 是校准数据,X × X^T ≈ H(Hessian 矩阵)

GPTQ 用一种基于二阶信息(Hessian)的贪心算法——逐列量化,每量化完一列就把误差用 Hessian 加权投影到剩余列,让后续列补偿已发生的误差。这种"补偿式"量化让累积误差最小。

工程实现

python
# AutoGPTQ 简化使用流程
from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig

quant_config = BaseQuantizeConfig(
    bits=4,
    group_size=128,
    desc_act=False,           # 是否按 Hessian 排序
)
model = AutoGPTQForCausalLM.from_pretrained("llama-2-70b")
model.quantize(calibration_data, quant_config)
model.save_quantized("llama-2-70b-gptq-4bit")

优势与局限

  • 优势:INT4 精度极佳(<1% loss),兼容性广(几乎所有 LLM 都有 GPTQ 版本);
  • 局限:量化过程慢(要跑校准 + Hessian 计算,70B 模型要几小时),kernel 速度略逊 AWQ。

三、AWQ:保护显著权重

核心思想

AWQ(Lin et al., 2023)的核心观察:LLM 中有 1% 的"显著权重"(salient weights)对精度起决定性作用——通常是激活幅度大的通道对应的权重。如果能保住这部分权重,其他 99% 的权重量化精度损失可以忽略。

但"保护 1% 的权重"该怎么实现?AWQ 用了一个聪明技巧:等价缩放

text
原始:     Y = W × X
等价变换: Y = (W / s) × (s · X) = W' × X'
                  ↑              ↑
              缩放后的权重    缩放后的激活

通过对激活幅度大的通道乘以 s > 1(让显著权重的相对值变小,落到 INT4 量化范围更友好区段),等价地把 X 的对应通道除以 s——这样数学上等价,但显著权重在量化时损失更小

为什么 AWQ 比 GPTQ 快

AWQ 的量化过程是无需 Hessian 的轻量搜索——只在权重大小上观察激活幅度,几百次前向就能定出每组的 scale。kernel 实现也更高效——AWQ kernel(vLLM 实现)和 GPTQ Marlin 在同等精度下 AWQ 速度通常领先 10-30%。

工程实现

python
# AutoAWQ 简化使用流程
from awq import AutoAWQForCausalLM
from transformers import AutoTokenizer

model = AutoAWQForCausalLM.from_pretrained("llama-2-70b")
tokenizer = AutoTokenizer.from_pretrained("llama-2-70b")
quant_config = {"w_bit": 4, "q_group_size": 128, "zero_point": True}
model.quantize(tokenizer, quant_config)
model.save_quantized("llama-2-70b-awq-4bit")

四、GPTQ vs AWQ:实战对比

维度GPTQAWQ
核心算法Hessian 二阶补偿显著权重保护 + 等价缩放
量化时间慢(70B 几小时)快(30-60 分钟)
INT4 精度<1% loss<1% loss(相当)
kernel 速度Marlin kernel 优化后接近 AWQ原生更快
生态AutoGPTQ、vLLM、TensorRT-LLMAutoAWQ、vLLM、TensorRT-LLM
微调友好度LoRA 加在量化权重上稍麻烦LoRA 加在量化权重上更顺
校准数据需求128-1024 条128-512 条

选哪个

  • 追求极致精度 + 算力不紧:GPTQ + Marlin kernel;
  • 追求部署速度 + LoRA 微调:AWQ(当前社区主流推荐);
  • H100+ 卡:FP8(不需要量化算法,原生支持,精度无损);
  • 追求极致压缩:W4A16 + 2:4 稀疏(叠加剪枝)。

五、混合精度组合:选型矩阵

权重量化 + 激活量化的不同组合,应对不同瓶颈特性:

组合权重激活显存压缩decode 速度prefill 速度精度损失适用
W16A16(基线 FP16)FP16FP160基线
W8A16INT8FP16~1.5×~1×<0.5%中等压缩、精度优先
W4A16INT4FP16~3-4×~1×1-3%decode 主流
W8A8INT8INT8~2×~2×1-5%prefill 密集
W4A8INT4INT84×(权重)+2×(激活)~3×~2×3-8%平衡但精度风险
W4A4INT4INT44×+4×~4×~4×5-15%极致算力,精度差
FP8 W8A8FP8FP8~2×~2×<1%H100+ 旗舰
FP4 W4A4FP4FP4~4×~4×2-5%B200 Blackwell

decode 优先 W4A16,prefill 优先 W8A8

  • W4A16 是当前在线 LLM 服务的事实标准——decode 是带宽墙,权重量化直接 4 倍加速,激活 FP16 不影响计算(反正算力闲置 99%);
  • W8A8 适合 prefill 密集场景(如离线批处理)——prefill 是 compute-bound,激活也压成 INT8 才能让 Tensor Core INT8 算力(989 TF × 2 = 1978 TOPS)跑满;
  • W4A4 极致但风险大——激活 INT4 在 LLM 上精度很难保,慎用。

六、混合精度策略:哪些层要保 FP16

不是所有层都能量化到 INT4 而不损精度。敏感层要保留 FP16,这是混合精度(mixed precision)的核心:

量化建议原因
Final LayerNormFP16输出分布对量化极敏感
Attention softmaxFP16概率分布量化后失真严重
EmbeddingFP16 或 INT4 都可量化影响小,看显存
LM head(output projection)FP16输出 logits,量化影响 next-token 分布
Q/K/V projectionINT4 OK中间表示,量化误差被后层吸收
FFN matmulINT4 OK同上

混合精度不是"省事"——是必需

统一量化所有层到 INT4 在 70B 以上模型经常翻车(精度退化 5%+),保留 3-5 个敏感层 FP16 几乎无损(<1% loss)。AutoGPTQ 和 AutoAWQ 都支持 layer-wise mixed precision 配置——配好 YAML 文件就行。

七、Marlin kernel:W4A16 的极致融合

痛点

W4A16 的朴素实现:

text
1. 从 HBM 读 INT4 权重 → SRAM
2. unpack INT4 → INT8 → FP16(在 SRAM 内)
3. 用 FP16 算 matmul
4. 写回 HBM

这每一步都在 SRAM 里——但 1+2+3 是分三个独立 kernel 写的,每一步的中间张量都要写回 HBM 再读回来,反量化的好处被 HBM 往返吃光。

Marlin 的做法

Marlin(Frantar et al., 2024)把"读 INT4 → unpack → 反量化 → matmul"全融合进一个 kernel

  • 权重在 SRAM 内即时反量化——一次 HBM 读,全程不写回;
  • warp-level 分块 + shared memory tiling——把 SRAM 用满;
  • async memcpy——HBM 读和 SRAM 算并行流水线;
  • INT4 → FP16 转换用 SIMD——一行 CUDA 指令把 8 个 INT4 解成 8 个 FP16。

效果:W4A16 在 A100/H100 上的 matmul 算力从朴素实现的 ~30 TFLOPS 拉到 ~150-200 TFLOPS——5-7 倍提升

主流实现

  • GPTQ Marlin:vLLM 默认 kernel,GPTQ 量化模型用;
  • AWQ Marlin:vLLM AWQ 模型用,速度比 AWQ 原生 kernel 快 30%+;
  • exllama:早期 INT4 kernel,已被 Marlin 取代;
  • TensorRT-LLM 内核:NVIDIA 自家实现,性能与 Marlin 接近但闭源。

详见算子融合与自定义核

八、权衡与取舍

  • 算法选 GPTQ 还是 AWQ:精度相当,AWQ kernel 速度领先——主流选 AWQ;极致精度选 GPTQ + Marlin;
  • bit 数选 4 还是 8:decode 优先 W4A16;prefill 密集 W8A8;H100+ 直接 FP8;
  • group size 选 32/64/128:越小精度越好但元数据越多——INT4 主流 128,INT8 不需要分组;
  • 要不要混合精度:70B 以上模型强烈建议,保留 final norm / softmax / lm_head 几个敏感层 FP16;
  • 要不要 LoRA 叠加:量化模型 + LoRA 是微调 LLM 的甜点方案——AWQ + LoRA 兼容性更好,详见实践指南

延伸阅读

参考资料