3219 字
约 10 分钟
16
S23-B04 · 量化入门:精度与显存的交换

显存不够时,第一个被想到的手段通常是量化:把 16 位浮点换成 8 位甚至 4 位整数,权重体积直接砍半再砍半。听起来像白捡,但它是一笔交易——用一点精度换显存和带宽。

入门要搞清的不是"哪种量化方法最强",而是三件事:它到底省掉了什么、误差从哪里来、怎么判断这一刀砍得值不值。方法名字(GPTQ、AWQ、SmoothQuant、bitsandbytes 等)是后面的事,先有这套判断框架,才不会被"4bit 无损"这类说法带偏。


1. 量化的本质

量化就是把连续的浮点数值映射到有限的整数格子上,再配一个缩放因子还原:

量化:   q = round(x / scale) + zero_point
反量化: x' ≈ (q - zero_point) × scale
bit 与字节:字节数 = 位宽 / 8      # 16bit→2,8bit→1,4bit→0.5

因为格子有限,落不进格子的信息就丢了,这就是量化误差的唯一来源。所有方法(分组、逐通道、混合精度、校准)都是在决定"格子怎么切、切多细、哪里切细一点"。

2. 量化省的是什么,不省什么

省掉 不省
权重占用的显存 总浮点运算量(INT4 不会让矩阵乘变成 4 倍速)
每步 decode 要读的字节数 KV Cache(除非单独做 KV 量化)
从显存到计算单元的搬运时间 激活峰值(通常还在,甚至因为算得快而更集中)
从磁盘/网络加载的传输量 调度、排队、框架开销

关键推论:收益主要在带宽受限的场景。decode 每步都要把权重完整读一遍,权重变小 → 读得快 → 每 token 更快、能塞更多请求。而在 prefill 这种算力受限的阶段,量化带来的提速往往有限,甚至因为反量化开销而略慢。

权重显存 = 参数量 × 位宽 / 8
显存下降比例 = 1 − 量化位宽 / 原始位宽
decode 单步读取量 ≈ 权重字节(该项随位宽线性下降)

3. 几种常见形态的入门对照

形态 权重精度 激活精度 显存收益 大致适用
FP16 / BF16 16bit 16bit 1×(基线) 显存充裕、精度敏感
INT8 仅权重(W8A8 之外的 W8) 8bit 16bit 约 2× 保守方案,质量风险小
INT8 权重+激活(W8A8) 8bit 8bit 约 2×,另有算力收益 需要硬件 INT8 算力支持
INT4 仅权重(W4A16) 4bit 16bit 约 3–4×(实际不到 4×) 显存紧张的 decode 场景
KV Cache 量化 — KV 单独降精度 按 KV 精度比例 长上下文、高并发的关键手段

"仅权重"与"权重+激活"的差别值得单独说清:

  • 仅权重量化(weight-only):只把权重压小,计算时反量化回高精度再做乘加。收益是显存与读取带宽,实现简单,精度风险相对可控。
  • 权重+激活量化(W8A8 等):权重和激活都压小,可用整数张量核直接算,收益还包括算力利用率。代价是需要校准激活的分布,对离群值更敏感,实现与硬件支持要求更高。

入门选型的朴素建议:先把显存问题解决(仅权重),再考虑算力问题(权重+激活)。不要一上来就同时动两头,出问题无法归因。

4. 量化误差从哪里来

来源 机制 典型表现
离群值 少数极大值把缩放因子撑大,其余值被挤到很少的格子上 整体精度崩,个别通道失真严重
通道尺度差异 不同通道数值范围差几个量级,共用一组 scale 时小通道被抹平 特定能力退化(如数字、代码)
分组粒度太粗 一组共享一个 scale,组内分布差异大 误差随组大小上升
校准数据不匹配 用通用语料统计,实际流量是长文档/代码 线上比离线差,离线测不出来
层敏感度不同 某些层(如首尾层、norm)对精度格外敏感 局部退化,整体困惑度看不出

对应的入门解法各一句:逐通道或小分组切细格子;混合精度把敏感层留在高精度;校准集贴真实分布;用真实流量抽样验证。

5. 校准的作用与最小做法

校准就是用一小批有代表性的数据跑一遍前向,统计每一层激活(或权重)的数值范围,据此定 scale。没有校准的对称量化只能靠猜范围,离群值一来就崩。

最小可用做法(伪代码,接口名按所用框架核对):

# 1) 准备校准集:几十到几百条,必须贴近真实流量(长度分布、领域、语言)
calib = load_jsonl("CALIB_SET.jsonl")[:NUM_CALIB]

# 2) 跑前向,只统计分布,不更新任何权重
with torch.no_grad():
    for batch in calib:
        model(**tokenize(batch))     # hook 里累计每层 min/max 或分位数

# 3) 由统计量生成 scale(逐通道 / 分组),再执行量化导出
# 4) 立刻做一次冒烟:同一条 prompt,量化前后各跑一遍,比对输出

三个必须遵守的点:校准集不能只用训练集(会高估效果);不能太少(几十条起,且要覆盖长度上界);不能只覆盖短文本(长上下文场景要单独放长样本)。

6. 量化后可能出现的现象

现象 说明 怎么发现
困惑度上升 最常见,幅度取决于位宽与模型 固定评测集算困惑度,与基线比
特定任务退化 数学、代码、结构化输出(JSON)最容易先坏 分任务跑小评测集
长上下文更差 KV 量化或长序列累积误差 按不同上下文长度分段测
输出格式不稳 该出 JSON 时漏括号、该停时不停 结构化输出成功率统计
重复与截断 分布尾部被压平 人工抽读 + 重复率指标
多语言退化 小语种在量化后最先掉 分语言抽样

注意一个反直觉的点:困惑度只涨一点点,任务表现可能掉很多。因为困惑度是全 token 平均,而任务失败往往由少数关键 token 决定。所以困惑度只能当筛查,不能当验收。

7. 评估量化的三个层次

层次 做什么 回答的问题 成本
1 困惑度 固定语料算 PPL,与基线对比 有没有整体性损伤 低
2 任务集 跑自己的任务评测集,分任务看 哪类能力退化、退化多少 中
3 真实流量抽样 从线上日志抽真实请求,人工/规则比对 用户实际会不会遇到问题 高,但最可信

三层缺一不可,且顺序不能颠倒:先用便宜的筛查,再用贵的验收。只做第 1 层就上线,是量化翻车最常见的路径。

# 验收口径建议写成可比较的形式
基线:FP16 在 TASK_SET 上的通过率 = A
候选:INT4 在 TASK_SET 上的通过率 = B
门槛:B ≥ A − 允许退化幅度,且任一子任务不得低于 A 的某个下限
另加:真实流量抽 N 条人工比对,格式错误率不得上升

具体的允许退化幅度由业务定,不要抄别人的数字——它对不同任务差别极大。

8. 混合精度与逐通道量化

  • 逐通道量化(per-channel):给每个输出通道单独一个 scale,而不是整个张量共用一个。一句话:把格子切细,代价是元数据变多。
  • 混合精度(mixed precision):把敏感层(首尾层、norm、部分 attention)留在高精度,其余层量化。一句话:把精度预算花在敏感的地方。

这两个手段可以叠加,也是"4bit 几乎无损"这类说法背后的真实原因——它们通常不是纯 4bit,而是 4bit 加上若干层保精度。

9. 什么时候不该量化

# 量化决策清单:五项全过才值得动手
[ ] 显存确实不够,且已排除并发配置与长度设置的问题
[ ] 有可复跑的评测集,且存着高精度基线结果
[ ] 推理引擎支持目标量化格式(不支持的格式等于白量化)
[ ] 能取到贴近真实流量的校准样本
[ ] 有回滚路径:高精度权重还留着
情况 理由
显存本来就充裕 换来的收益是余量,代价是质量风险,不划算
任务精度敏感(法律、医疗、金融计算) 退化难以用平均指标兜住
没有评估集 无法判断退化,等于盲改
延迟瓶颈在 prefill 或调度 量化帮不上,白付质量代价
硬件/引擎不支持该量化格式 会退回低效路径,甚至更慢
长上下文是核心场景,且未做 KV 侧验证 KV 量化对长序列的影响需要单独测

10. 四个常见误解

误解 实际
量化一定掉点很多 仅权重量化在多数模型上退化有限,但必须自己测,不能引用别人的结论
量化能提速所有场景 主要帮带宽受限的 decode;prefill 与调度瓶颈不受益
只在训练集/通用集上验证就够 分布不匹配时线上会更差,必须用真实流量抽样
量化后不做端到端回归 单测通过不代表流式输出、结构化解析、多轮对话都正常

11. 排错:五种量化相关的故障

现象 原因 处理
加载报错,缺 scale 或格式不匹配 量化格式与引擎不兼容 按引擎支持的格式重新导出,不要手工改文件
能跑但输出乱码/重复 反量化路径错误或分组配置不符 用官方脚本重导,逐层比对
长 prompt 时明显变差 KV 精度或长序列累积误差 只量化权重,KV 保持高精度
吞吐没提升甚至下降 瓶颈不在带宽,或走了低效 kernel 先定位瓶颈在 prefill 还是 decode
离线好、线上差 校准集与真实流量不匹配 用线上抽样重做校准集

12. 边界:量化解决不了的问题

问题 为什么量化无效
模型本身装不进最小的卡 位宽有下限,装不下就是装不下
并发能力不足 KV Cache 是主因,需单独做 KV 量化或降并发
首 token 太慢 prefill 算力问题,量化收益有限
调度与排队造成的长尾 与精度无关
需要更强能力 量化只会更弱,不会更强

13. 自测

  1. 量化省掉的是显存还是算力?为什么 decode 受益明显而 prefill 受益有限?
  2. "仅权重量化"和"权重+激活量化"各解决什么问题?为什么建议先动前者?
  3. 列出量化误差的三个来源,并各给一个入门级缓解手段。
  4. 校准集为什么不能用训练集?长度分布上要注意什么?
  5. 为什么困惑度只涨一点,任务表现可能掉很多?三层评估分别回答什么问题?
  6. 有哪几种情况本来就不该量化?各说出理由。
S23-B04 · 量化入门:精度与显存的交换
https://www.clxhxhhr.top/posts/5998/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。