跳到内容

2 章 · 约 28 分钟

模型架构

计算、参数和上下文状态,如何变成 M、F、R?

阅读中·实验未完成·考核未交

从哪里来

8B 只说明参数量的约数

第 1 章把一次执行写成容量、运算量和读取量。数字从哪里来?“一个 8B 模型”只给出参数规模的数量级,没有说明每个 token 用哪些参数、上下文保存在哪、哪些工作必须先后发生。

计算图用节点表示运算、用边表示数据依赖。节点决定 F,边上的张量决定传递的字节,边的方向决定谁必须等谁。权重在请求之间保持不变,KV 随生成追加,中间激活往往用完即弃——三种数据的生命周期不同,优化手段也不同。

本课锚点:Qwen3-8B
它改什么
层数 L36重复的计算、逐层状态、深度依赖
隐藏维 d4096投影与激活的宽度
FFN 中间维 f12288三个 FFN 矩阵
Q / KV 头32 / 8GQA:每 4 个查询头共享一组 KV
头维 dh128点积与状态宽度
词表 V151936嵌入与输出头

Prefill 能并行,decode 被自己的输出卡住

RNN 在同一层等待前一个 token。因果 Transformer 不同:只要上一层的前缀已经算完,同一层里已知的输入 token 可以一起算。深度方向仍有依赖——第 l+1 层要用第 l 层的结果。

生成新 token 又多了一条依赖:下一步的输入就是这一步的输出。所以 prefill 处理已知输入,decode 逐步吐出新词。缓存把“重新计算旧 token 的投影和 FFN”变成“保存并读取它们的 K、V”。旧的查询已经完成任务,下一步用新的 Q 去打已经存下来的上下文。

每 token 的 KV 容量

c_KV = 2 · L · n_KV · d_h · b

Qwen3-8B、BF16:2 × 36 × 8 × 128 × 2 B = 144 KiB。8K 上下文就是 1.125 GiB。Batch 条独立请求就有 B 份。

MHA 32 KV

GQA 8 KV

MQA 1 KV

MLA 低秩

32 个查询头、8 组 KV。共享上下文表示,不合并查询。

MHA、GQA、MQA、MLA

多头注意力若为每个查询头都存一份 KV,容量按头数线性涨。分组查询注意力(GQA)让若干查询头共享一组 KV:Qwen3-8B 是 32 个 Q 头配 8 个 KV 头,相对于 MHA 省 4 倍状态。MQA 让全部查询共享一组,再省 8 倍,但表达力更差。MLA 把 KV 压进低秩潜空间,用计算换容量——DeepSeek 系列走这条路,8K 上下文大约只有 GQA 的一半。

权重、上下文、临时数据要分开记账。Qwen3-8B 的 BF16 权重约 16.38 GB,驻留后供所有请求反复使用;一步 decode 的主要权重读取约 15.14 GB(词嵌入按行查找,不必整表扫过)。8K 上下文约 1.125 GiB。当 batch 增大,各请求的 KV 读取会在某一点超过权重读取:H=8192 时大约 B=13,H=2048 时大约 B=51。上下文越长,权重复用的红利越早被独立状态吃掉。

实验

KV 缓存

每 token

147 KB

全部 KV

1.21 GB

权重+工作区后剩余

60.41 GB

还能再塞几条

50

Qwen3-8B 默认是 144 KiB/token。把 n_KV 从 8 拖到 32,就是从 GQA 回到 MHA。

考核

第 2 章考核

4 题

  1. 1.Qwen3-8B、BF16、GQA。每 token 的 KV 是多少?

  2. 2.把 Qwen3-8B 的 KV 头从 8 改成 4,查询头仍是 32。KV 容量如何变?

  3. 3.Qwen3-8B 一步 decode 权重读取约 15.14 GB,每请求 8K KV 为 1.125 GiB。上下文读取超过权重读取的最小整数 batch 约为?

  4. 4.为什么不能用总参数量直接代替一次 decode 的运算量?

全部作答后交卷。