权重量化方案的选择与算子命中定位
在 **** 的 ****(8 卡,单卡 64GB HBM,卡间互联 392 GB/s)上用 vLLM 起一个 OpenAI 兼容服务,把模型换成 W4A16 量化版。权重文件明显变小,启动日志里权重占用那一行随之下降,服务正常启动、请求正常返回。改动只落在量化方案这一项,精度抽测却出现偏差超阈值:同一批题目的答案与 BF16 版本对不上。另一组配置精度几乎没掉,吞吐却与量化前持平、尾延迟更长,量化没有产生收益。这两类现象要在同一处解释:先确认量化方案的实际位宽与格式,再确认量化 kernel 是否命中目标算子路径,最后把收益与代价分开记录。
方案标记的含义:权重位宽与激活位宽
一个量化标记由两段组成,W 后的数字是权重位宽,A 后的数字是激活位宽。W8A8 指权重与激活都量化到 8 bit;W4A16 指权重压到 4 bit、激活保留 16 bit,即 weight-only 量化。INT8 与 FP8 描述低位的具体格式:前者是整数格式,后者是浮点格式,FP8 内部还分 e4m3 与 e5m2 两种位分配,e4m3 阶码短、尾数长,利于精度,e5m2 动态范围更大。
| 标记 | 权重 | 激活 | 量化对象 | 常见来源 |
|---|---|---|---|---|
W8A8 |
8 bit(整数或浮点) | 8 bit(整数或浮点) | 权重与激活 | 训练后量化,激活需校准 |
W8A16 |
8 bit | 16 bit | 仅权重 | GPTQ / AWQ |
W4A16 |
4 bit | 16 bit | 仅权重 | GPTQ / AWQ |
W4A8 |
4 bit | 8 bit | 权重与激活 | 训练后量化 |
INT8 |
8 bit 整数 | 视方案 | 视方案 | 训练后量化 |
FP8 |
8 bit 浮点(e4m3 / e5m2) |
视方案 | 视方案 | 原生低精度 / 训练后量化 |
量化产物的命名习惯里,位宽标记是文件名的一部分,例如 w8a16_gptq、w4a16-awq、w8a8c8、w4a16c8。名称可能带 W、A 之外的第三段,读方案时以完整名称为准,不能只看前两段。GPTQ、AWQ 属于 weight-only,作用面在权重一侧;SmoothQuant 一类方法在量化前对激活做等价缩放,把离群值从激活转移到权重,用来降低 W8A8 的激活量化误差。
校准:静态量化与动态量化的取舍
权重的数值范围在转换后固定,可以离线量化;激活的范围随输入变化,需要一组数据来估计,这一步即校准。两种做法的取舍如下:
| 做法 | 校准集 | 精度 | 额外步骤 |
|---|---|---|---|
| 动态量化 | 不需要 | 损失较大 | 无 |
| 静态量化 | 需要少量代表性数据 | 损失更小 | 需准备并维护校准集 |
静态量化用校准集预先算出激活的量化参数,精度损失更小,代价是校准集必须与线上分布接近;校准集偏了,激活误差就偏大,权重一侧的误差反而可控。校准方法本身也是一项选项(如 min_max 与 kl_divergence),换方法等价于换一组量化参数,需重新走一遍精度对照。只量化权重的 W4A16、W8A16 不需要激活校准,省去这一步,代价是激活仍按 16 bit 参与计算,收益只落在权重一侧。
收益与代价的来源
收益来自两处。权重占用按下式估算:
权重占用 ≈ 参数量 × 每参数字节数 ÷ tensor_parallel_size
每参数字节数:FP16 / BF16 = 2,INT8 / FP8 = 1,INT4 = 0.5
以 7B 级模型按上式估算(非实测):FP16 约 14 GB,INT8 约 7 GB,INT4 约 3.5 GB。decode 阶段每生成一个 token 要把参与该步的权重读一遍,当这一阶段受显存带宽约束时,每步读取的字节数随方案下降,带宽压力随之下降。这是量化在低并发、访存受限场景下的主要收益来源。
代价来自两处。一是量化误差:低位格式能表示的数值集合更小,权重与激活被截断,误差随位宽下降而上升。二是反量化开销:低位权重在参与计算前要还原到高位,若量化 kernel 未把这一步融合进矩阵乘,反量化会引入额外的指令与访存,抵消量化节省的一部分带宽。
量化 kernel 与算子路径的兼容性
量化配置能被解析、服务能启动,不等于量化算子真的被命中。量化后精度尚可而收益不成立甚至变差,多半是目标量化 kernel 没有命中,退回了一条未融合的通用实现。回退不报错,只在启动日志里留一行后端选择结果,判断方式与通用的静默回退一致:比对 target_backend 与 resolved_backend,两者不一致即发生回退;这两个是本笔记自设的记录字段,真实凭证是启动日志里那一行后端选择(vLLM 形如 Using <backend> backend ...)。
两类兼容约束最容易撞上。
- 与 attention 后端:KV cache 的数据类型参与后端 guard。若量化方案同时改了 KV dtype,目标后端对 KV dtype 的支持区间不覆盖该取值,整条 attention 路径即失格回退。
- 与 MoE 路径:MoE 的专家分组 GEMM 与量化 kernel 的组合窗口比 dense 路径窄,部分量化方案只覆盖 dense 线性层,专家层退回未量化实现。结果是权重占用降下来了,命中的计算路径却没变。
触发条件
| 负载 / 配置形态 | 现象 |
|---|---|
| 低并发、decode 受带宽约束 | 量化收益最容易兑现 |
| 高并发、算力已打满 | 带宽不再是瓶颈,量化收益收窄 |
| 校准集与线上分布不一致 | 权重误差可控,激活误差偏大,精度抽测偏差超阈值 |
| 量化方案只覆盖 dense、未覆盖 MoE | 权重占用下降,吞吐无变化 |
| KV dtype 与量化方案叠加、后端不兼容 | attention 路径回退,收益不成立 |
现象
- 精度抽测偏差超阈值:模型能加载、能出结果,长文或多步推理下输出与参考版本不一致。
- 收益不成立:权重占用确实下降,吞吐与量化前持平,或尾延迟更长。
- 分段不一致:权重读取下降的收益落在 decode 段,prefill 段无变化,端到端均值看不出差别。
三类结论可分开记录:量化后精度跌落过大、量化后收益不成立、量化配置不可落地。三者的处置方向不同,混写成「量化效果一般」会丢掉定位线索。
定位步骤
- 固定校准集。记录
calibration_source,同一组校准数据用于量化前后对照;校准集与线上分布不一致时,先换一组再判断精度偏差。 - 逐层比对。取若干层,比对量化前后同一输入的中间结果与权重张量,定位误差是均匀分布还是集中在少数层。
- 确认算子命中。比对
target_backend与resolved_backend,确认量化 kernel 真的落在目标算子路径上;未命中时先修 guard(KV dtype、block size、shape),再谈收益。 - 收益与精度分开记录。按
throughput_before/throughput_after与accuracy_before/accuracy_after两组数分别统计,量化流程走通不等于量化收益成立。
# 示意:一条带量化方案的启动命令(参数名取自框架,取值按本机规格填)
vllm serve <quantized-model-path> \
--tensor-parallel-size 8 \
--quantization <scheme> \
--kv-cache-dtype auto \
--attention-backend FLASH_ATTN \
--enforce-eager
处置
| 方向 | 动作 | 代价 / 前提 |
|---|---|---|
| 精度偏差超阈值 | 提高位宽(W4A16 → W8A16 → W8A8),或改用 FP8 |
占用上升,收益收窄 |
| 激活误差偏大 | 换校准集,或改用 SmoothQuant 一类先做等价缩放的方法 | 需重做校准 |
| 收益不成立 | 确认量化 kernel 命中;修 guard(KV dtype、block size) | 未命中时调参无用 |
| MoE 无收益 | 确认方案是否覆盖专家层 | 覆盖不到时该路径维持未量化 |
记录字段
# 一条量化记录(字段名示意)
hardware_sku: # 卡型(8 卡,单卡 64GB HBM,互联 392 GB/s)
base_stack_version: # 基础软件栈 / 运行时版本,写 <pinned-version>
model_name:
model_format:
quant_scheme: # W8A8 / W4A16 / W8A16 / INT8 / FP8 ...
calibration_source: # 校准集来源与规模
weight_dtype: # 量化后权重 dtype
activation_dtype: # 量化后激活 dtype
accuracy_before: # 量化前精度(同一评测任务)
accuracy_after: # 量化后精度
accuracy_loss_threshold: # 精度损失阈值,超过即判量化失败
throughput_before: # 量化前吞吐
throughput_after: # 量化后吞吐
operator_path:
target_backend: # 目标算子路径
resolved_backend: # 实际命中路径
fallback_observed: # 是否回退到未量化实现
status: # 流程走通 / 收益成立 / 收益不成立 / 精度不达标
小结
量化方案的选择由三段信息决定:W 与 A 两段给出权重与激活的位宽,收益来自权重字节数与带宽压力的下降,代价来自量化误差与反量化开销。量化配置能被解析不等于量化 kernel 命中目标算子路径,收益不成立时先比对 target_backend 与 resolved_backend。精度偏差超阈值时先固定校准集、逐层比对,再决定是否提高位宽。