2371 字
约 7 分钟
9
S23-J23 · 压缩、卸载与推测解码

适用读者:要在"装不下"和"跑不满"之间做取舍、要评估量化/卸载/投机解码是否值得的人。
前置:S23-J22(KV 容量与批处理)、J15(带宽与下界)。
覆盖旧文:A-4341 §8.4–§8.6(压缩与卸载 + 推测解码 + 负载下配置选择,478 点)→ 478 点。
扩展点:E-S23-079(Q2_K 平均 2.625 bit/value,元数据占 24%)、E-S23-080(KV 量化:1152 → 612 / 324 MiB)、E-S23-081(PCIe 卸载 42.5 ms/轮 → 吞吐 ≤ 94 tok/s,爆 7 s 时限)、E-S23-082(NVLink-C2C 450 GB/s → 6.0 ms/轮)、E-S23-083(推测解码块长最优 m=4,13.34 ms/token)、E-S23-084(Little 定律 n̄ = λT̄)。
上一篇:S23-J22 · 请求执行、批处理与 KV 分配
下一篇:S23-J24 · 分布式推理:布局与 PD 分离。


1. 一句话结论

"省内存"和"省时间"在三条路上是冲突的: 量化省容量、几乎不改速度;卸载省容量、按链路带宽付时间;推测解码省轮次、按接受率打折。选错方向就会像 PCIe 卸载那样——每轮 42.5 ms,直接超过 26.26 ms 的 decode 迭代。

出处:AI Infra 教材 §8.4–§8.6(id 4341)。

量化   :容量 ↓,速度 ≈ 不变
卸载   :容量 ↓,时间 ↑(≥ 搬移量/链路带宽)
投机   :时间 ↓(按接受率),算力 ↑

2. 量化:位宽降下去,元数据占比升上来(E-S23-079)

Q2_K(GGML 分组量化):每组 256 个值

项 大小
2-bit 码值 256×2/8 = 64 B
scale + min 等元数据 20 B
每组 84 B
平均每值 84×8/256 = 2.625 bit
元数据占比 约 24%

Qwen3-235B-A22B 的 Q2_K 变体实测:

项 大小
量化编码 + 未量化浮点 64.43 GiB
量化元数据 15.37 GiB
文件头/填充 ≈ 79.81 GiB
UD-Q2_K_XL 变体 81.97 GiB

M2 Max(96 GB 十进制):留给模型约 81.41 GiB。

79.81 GiB 文件 → 剩 1.60 GiB(够 1 条 8K:KV 1.47 GiB,余 0.13 GiB)
81.97 GiB 文件 → 超 0.56 GiB(装不下)
两文件只差 2.16 GiB,却决定能不能接一条请求
32K 上下文 → KV 要 5.88 GiB,必须加内存或换存放方式

判据:"能不能装下"是 2 GiB 级的判断题,不是"大概差不多"。 而且元数据也会随 KV 长度增长——量化不是免费的比例缩放。


3. KV 量化:只有最后一级能省(E-S23-080)

一条 8K 上下文的 BF16 KV = 1152 MiB;每 32 个 BF16 值占 64 B。

格式 每 32 值的字节 比例 8K KV
BF16 64 B 1 1152 MiB
q8_0(8 bit + 2 B scale) 34 B 34/64 612 MiB
q4_0(4 bit + 2 B scale) 18 B 18/64 324 MiB
q8_0 省 540 MiB;q4_0 省 828 MiB
平均每值:8.5 bit / 4.5 bit(不是 8 和 4——scale 也要摊)

判据:量化的收益要减去元数据。 位宽越低,元数据占比越高(Q2_K 已达 24%),所以"4 bit 就一定是 1/4"是错的。


4. 卸载:链路带宽直接决定可行性(E-S23-081、E-S23-082)

Qwen3-8B 一层 FFN 三个 BF16 矩阵 = 288 MiB;36 层里每 4 层卸 1 层,共 9 份 → 释放 2592 MiB。

预取缓冲 净省 多容纳 8K 请求
1 组(288 MiB) 2304 MiB 2 条
2 组(576 MiB) 2016 MiB 1 条
按生成完毕 1188 MiB 预留 — 两种都只 +1 条

4.1 时间账

每轮搬入 2592 MiB = 2.72 GB
PCIe Gen5 x16(64 GB/s/方向):2.72/64 = 42.5 ms/轮
对比 batch 1 一轮 decode:26.26 ms  →  已经超了
吞吐上限:4 条请求 / 0.0425 s ≈ 94 tok/s
256 输出 token:255 × 42.5 ms ≈ 10.8 s  >  7 s 时限
链路 每轮搬移 255 轮 可行性
PCIe Gen5(65 GB/s) 42.5 ms 10.8 s ❌ 爆 7 s
NVLink-C2C(GH200,450 GB/s) 6.0 ms 1.54 s ✅ 藏在计算里

判据:卸载的可行性由"链路带宽 vs decode 迭代时间"直接决定。PCIe 上卸载大块 FFN 是负优化;C2C 上才可能被预取掩藏。

预取的约束:复制完成后计算才能读;计算不再用这组权重后缓冲才能写下一组。两组缓冲才能重叠。


5. 推测解码:接受率决定一切(E-S23-083)

5.1 正确性(不是"猜对了就算")

贪心:草稿 4 个,目标模型第 3 个不同 → 保留前 2 + 修正 1 = 3 个输出,第 4 个作废
采样:α(x) = min(1, p(x)/q(x)),拒绝后从 [p−q]₊ 归一化重采样 → 输出仍服从 p

判据:推测解码不改分布,只是用草稿网络换目标模型的轮次。

5.2 块长优化(原文练习 8-7)

a = 3/4、一轮验证 26.3 ms、草稿每 token 3.6 ms:

每轮期望输出 token 数 = 1 + a + a² + … + a^m = (1 − a^(m+1))/(1 − a)
T_m = 26.3 + 3.6m
块长 m 期望输出 T_m ms/token
1 1.75 29.9 ms 17.09
2 2.31 33.5 ms 14.49
4 3.05 40.7 ms 13.34 ✅
8 3.70 55.1 ms 14.89
按"每 4 个位置一组"执行(不足也按整组计时):m=5 需 T = 26.3+28.8 = 55.1 ms,输出 3.29 → 16.76 ms/token(更差)

实测(Qwen3-8B / DFlash,并发 1,中位数):

配置 完整耗时
普通 decode 90.0 ms
K7(7 个草稿) 30.6 ms
K15(15 个草稿) 29.4 ms

判据:K7 → K15 只再省 1.2 ms。块长有最优点:再长就只是多算被丢弃的 token(K15 一轮丢 14 个)。


6. 在线服务:Little 定律与准入(E-S23-084)

n̄ = λ·T̄      系统内平均请求数 = 到达率 × 平均停留时间
例:4 req/s × 0.5 s = 2 条;停留 2 s → 8 条

准入检查:先看 KV 空间与剩余时限。

短请求:TTFT 0.196 s + 生成 6.76 s = 6.95 s,离 7 s 只剩 0.05 s
再多排队 0.1 s 就超时 → 拒绝 / 转交 / 换更快的配置

判据:排队时间也是预算的一部分。 系统内请求数由 λT̄ 决定,而不是"能装多少 KV"——两者都要满足。

6.1 16 条长请求同时到达:配置选择清单

判断 优先手段
KV 放不下 分页 + 前缀共享 → 再量化 → 再换出
算力用不满 加 batch、投机解码(低负载时)
权重装不下 量化 → 卸载(仅当链路够快)
TTFT 超标 分块 prefill、准入控制、PD 分离(J24)
吞吐上不去 连续批处理 + 消除长 prefill 干扰

7. 可复算(实测)

$ cd /root/博客运营官/blog-v2 && python3 tools/s23_book_calc.py | tail -11
Q2_K: 64 B 码值 + 20 B 元数据 = 84 B / 256 值 → 2.625 bit/值,元数据 24%
KV q8_0: 1152 × 34/64 = 612 MiB(省 540 MiB)
KV q4_0: 1152 × 18/64 = 324 MiB(省 828 MiB)
卸载: 9×288 = 2592 MiB;净省 2304 / 2016 MiB
  PCIe 64 GB/s: 2.72 GB → 42.5 ms/轮;255 轮 10.83 s(超 7 s)
  C2C 450 GB/s: 2.72 GB → 6.0 ms/轮;255 轮 1.54 s
  PCIe 吞吐上限: 4/0.0425 s ≈ 94 tok/s
投机 m=1: 期望输出 1.75,T 29.9 ms → 17.09 ms/token
投机 m=2: 期望输出 2.31,T 33.5 ms → 14.49 ms/token
投机 m=4: 期望输出 3.05,T 40.7 ms → 13.34 ms/token
投机 m=8: 期望输出 3.70,T 55.1 ms → 14.89 ms/token
  按 4 个一组: m=5 → T 55.1 ms,输出 3.29 → 16.76 ms/token
Little: 4 req/s × 0.5 s = 2 条;× 2 s = 8 条

8. 前提与边界

结论 成立条件 不成立时
量化省容量 接受精度损失 质量敏感任务 → 用更高位宽
q4_0 = 18/64 每 32 值一组 分组更小 → 元数据占比更高
卸载可行 搬移时间 < decode 迭代 PCIe 搬大块 → 严重变慢
投机加速 接受率够高、算力有余 高负载 → 争用资源,收益转负
n̄ = λT̄ 稳定系统 突发流量 → 用排队模型

9. 常见误区

误区 纠正
"2 bit 就是 1/8 大小" Q2_K 实际 2.625 bit/值(元数据 24%)
"4 bit 量化就是 1/4" q4_0 是 18/64 ≈ 28%,不是 16/64
"卸载总能扩容量" PCIe 每轮 42.5 ms,直接爆预算
"草稿越长越好" m=8 反而 14.89 ms/token;K15 一轮丢 14 个
"能装 4 条就服务 4 条" 还要看 λT̄ 与时限

10. 自测

  1. Q2_K 每组 256 值、84 B,平均多少 bit/值?元数据占多少?
  2. 8K 上下文 BF16 KV 1152 MiB,改 q4_0 后多少?省多少?
  3. 卸载 2592 MiB/轮,PCIe 64 GB/s,每轮多久?能跑满 7 s 时限吗?
  4. a=3/4、T_m = 26.3+3.6m,块长 4 的每 token 耗时多少?
答案
  1. 84×8/256 = 2.625 bit;20/84 ≈ 24%。
  2. 1152×18/64 = 324 MiB;省 828 MiB。
  3. 2.72 GB/64 GB/s ≈ 42.5 ms;255 轮 ≈ 10.8 s,超 7 s,不可行。
  4. 输出 3.05 个、耗时 40.7 ms → 13.34 ms/token。

11. 下一篇

S23-J24 · 分布式推理:布局与 PD 分离 —— 进入第 9 章:模型怎么摆、prefill 与 decode 为什么要拆开、AFD 与专家放置怎么影响 KV 分布。

S23-J23 · 压缩、卸载与推测解码
https://www.clxhxhhr.top/posts/5550/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。