真机实测通过:本文实验已在 RK3588 板端实测完成(2026-09;方法学与原始记录见仓库 docs 与《实验脚本》目录)
一句话导读:q8 KV 精度对照实验:fp32 与 q8 两套 KV 走同一注意力公式,板端实测输出分量差约 0.01、端到端 PPL 损失小于 1%,讲清误差来自步长而非偏置、这个量级为何划算。
9-1 说 q8 KV“near-lossless”,9-2 说单遍内核优雅——可这两个词都得用数字说话:KV 从 f16 压到 int8 后,注意力输出到底差多少?今天做对照实验,并给出“这个量级意味着什么”的判读。
1. 知识点:怎么测“量化进注意力”的损失
KV 量化误差的传播路径比权重误差更短:K 只影响Q·K^T打分,V 只影响加权求和,两者都在当次注意力内结束。所以对照实验很干净:
- 基线:K/V 用原始 fp32,走标准注意力(Q·K^T → 稳定 softmax → 加权 V);
- 被测:K/V 先按引擎规则量化成 int8(每 token 每头 max-abs/127),再反量化回 fp32 做同一套注意力;
- 指标:逐输出维的
|Δout|(max 与 mean)。
两者唯一差别就是“KV 先被量化过”——误差即量化贡献,不含任何内核差异(这是 5-3“对拍只改一个变量”纪律的又一次使用)。
2. 对应代码:量化规则以引擎为准
实验用的量化规则照抄 9-1 的引擎写入路径(kv_quantize_per_head):对每个 (token, 头) 的 128 维求max_abs,scale = max_abs/127,q = round(v/scale)钳到 [-127,127],反量化v' = q × scale(即KVQ_SCALE = 1/127的逆,vllm_safetensors.c 第 7358 行)。注意力本体用引擎参考实现同一公式(score = Q·K^T / √128、减 max 稳定 softmax、加权 V)。
3. 改动后果:板端实测 fp32-KV vs q8-KV 注意力输出
在板端跑对照(RK3588 / gcc 11.4 / fp32 / 2026-09;序列 256 token、hd=128,K/V 取确定性伪随机 ~N(0, 1)):
L=256 hd=128 | fp32-KV vs q8-KV attention output: max|d_out| = 0.01251 mean|d_out| = 0.00856 out_f[0..3] = 0.1889 0.0202 -0.2286 -0.1125 out_q[0..3] = 0.1945 0.0275 -0.2178 -0.1038 (avg K per-token scale ~ 0.01719 -> q8 step ~ 0.01719)怎么读这组数(判读比数字本身更重要):
- 绝对量级:输出分量 ~0.1–0.23,q8 引入的分量差 ~0.01——相对输出幅值约几个百分点,且方向随机(过零附近的分量差看起来占比大,但绝对值小);
- 误差源是“步长”而非“偏置”:平均 scale ~0.017(=max/127),即量化步长约 0.017——每个反量化值的误差 ≤ 半步 ~0.009,与 mean|Δ| 0.0086 同量级,误差没有放大(softmax 的归一化把逐点小误差摊平成权重微扰);
- 引擎自己的更大规模背书:代码注释记录 8B 档 INT8 KV 在 M4e/M4f 路径PPL≈0.994–0.998(vllm_safetensors.c 第 8213 行)——即端到端困惑度损失 ~0.5%,文本质量几乎无损。合成实验中那 ~0.01 的输出差,落进 128 维累加与后续 layer 后就是这个量级。
结论:q8 KV 的代价是“输出分量级 ~0.01、端到端 PPL 损失 <1%”;换来缓存与 decode 扫描带宽 ×0.52(9-1)。对边缘推理,这是教科书式的划算交易。若你的场景连这 0.5% 都敏感(医疗/法务数值场景),引擎仍留了 f32 镜像缓存(9-1 写入代码里那句“Also store in float cache”)——量化与精确两条路共存,按场景选(这也呼应 Day 23 起“可验证推理”对数值可追溯的要求)。
更进一步的诚实:本实验是合成分布的“单元级”对照,真实文本的 K/V 分布更尖(long-tail),量化误差的 worst-case 会更大但概率更低;引擎级验证永远以 PPL/greedy 口径为准(报告链接见任务)。
4. 学员调试任务
- A 档(板端动手):复刻第 3 节实验(K/V ~N(0,1),L=256,hd=128),记录你自己的
max|d_out|与mean|d_out|;把 K/V 幅度放大 3 倍再跑,观察误差是否同步放大(预期:放大 → scale 变大 → 相对误差基本不变,验证“按行定标”的抗幅度特性)。 - B 档(纯读源码):读
kv_quantize_per_head实现,确认“一个头 128 维共用一个 scale”;再在vllm_safetensors.c第 8213 行注释里找到 PPL≈0.994–0.998 的原始语境,复述它验证的是哪条路径。
预期输出:你能用一组自己的数字说明“q8 KV 的输出差 ~0.01、端到端 PPL 损失 <1%”,并解释为什么这个量级“划算”。
收尾
- 本篇源码点名:vllm_safetensors.c(
kv_quantize_per_head写入路径、KVQ_SCALE第 7358 行、8B PPL 注释第 8213 行)。 - 开源仓库:Kestrel-LLM (Gitee)(源码可得双许可:学习 / 学术研究免费)
- 下篇预告:q8 KV 单遍扫全量,O(n) 也是 n——上下文到 8K 后每词仍要扫 8K 的 KV。第 10 天上稀疏注意力:能不能只扫“该看的块”,把 decode 从 O(n) 再往下压?
- 关键词:q8 KV、精度对照、量化误差、PPL、RK3588
上一篇:Day 9·2 flash_attn_single_q_q8_neon——单 q 单遍扫全 KV
下一篇:等待更新......