【A. 入口层】Tokenizer → Embedding查表 → +位置编码(正弦/RoPE/NoPE)
↓
【B. 每一层 ×80】
Pre-Norm (RMSNorm)
├─ QK-Norm ─ RoPE旋转 ─ Causal/SWA mask ─ MHA / GQA / MQA/MLA ─ Attention(实现用 FlashAttention ← 虚线引到 D)
│
└─ 残差相加
Pre-Norm (RMSNorm)
├─ SwiGLU 稠密FFN ← MoE 替换这里
└─ 残差相加
【C. 出口层】Final Norm → LM Head(线性+Softmax) [+ MTP头]
↓
【D. 推理时】
Prefill/Decode
↓ 产生
KV Cache ←── 用 PagedAttention 方式分页存储(不是"之后",是"本身")
↓ 读取
Attention 计算 ←── 用 FlashAttention kernel 实现(按 block_table 直接读分页 KV)补充1
先说清楚 MLA 在族谱里的位置。所有变体都在解决同一件事:多头注意力每个头都要存一份 K 和 V,头一多,KV Cache 就爆炸。
| 变体 | 怎么存 KV | KV Cache 大小 | 效果 |
|---|---|---|---|
| MHA(原始多头) | 每个头各存一份 K、V | 最大(= 头数 × 2) | 最好 |
| MQA(多查询) | 所有头共享一份 K、V | 最小(= 1×2) | 明显变差 |
| GQA(分组查询) | 几个头一组共享一份 | 折中(= 组数 × 2) | 接近 MHA |
| MLA(多头潜在) | 不存 K、V,存一个压缩的 latent | 极小,且效果不降 | 接近甚至超过 MHA |
补充2
把 K 拆成两部分: ├─ 位置部分(RoPE) → 不动它,单独存/单独处理 └─ 内容部分 → 这部分才做 QuaRot 旋转和压缩
关键认知:B 和 C 是"模型结构"(写死在权重里);D 全是"工程调度"(不改模型一个参数)。之前混乱的根源,就是把 D 层的技术当成模型的一部分去理解了。