从0训练LLM · 现代大模型体系 导读 导读 ≈ 15 分钟
C3 注意力:一个 Token 怎么从别的 Token 那里取信息 章导读

注意力:一个 Token 怎么从别的 Token 那里取信息

到上一章为止,每个 token 都是一个带着位置的向量,可它只知道自己。这一章从「直接拿向量比相似度」出发,一步步被逼出 Q/K/V、点积、softmax、因果掩码、多头,再到生成时的 KV cache 和把它压小的 GQA、MLA。

本章一问:一个 Token 怎么从其他 Token 那里取信息?

主线定位

🧭

上游(C2):每个 token 已经是「embedding + 位置」:Embedding 说明它是什么,RoPE 准备好在注意力内部标出它在哪。
本章(C3):让每个 token 按自己的需要,从前面的 token 那里把信息取回来——这是整条流水线里唯一让 token 之间交换信息的地方。
下游(C4):信息取回来之后,每个 token 自己还要做一次加工(FFN、残差、归一化、门控),一层才算完整。

下面是累计数据流,本章点亮「注意力」一环。点它看锚点模型 Qwen3.8-27B 里这一步的真实形状和参数量。

累计数据流 · 从文字到下一个 token 的概率 已学本课新增还没学
解码层

点任一已学环节,看这一步的输入 → 输出形状、参数量,以及它解决了什么问题(数字取自 Qwen/Qwen3.8-27B 真实 config)。

本章问题链

每一课只回答一个问题,上一课留下的缺口就是下一课的问题。

  1. 已经有 Embedding 了,为什么还要变成 Q、K、V 三份?——直接比相似度,「给了」最像的是它自己。
  2. Q 和 K 怎么算匹不匹配?为什么偏偏用点积?——几何含义清楚,而且全部配对一次矩阵乘算完。
  3. 分数怎么变成「关注多少」的权重?——按比例分会出负数;softmax;为什么除以 √d。
  4. 训练时怎么防止模型偷看答案?——因果掩码:softmax 之前把未来置为 −∞。
  5. 找到该关注谁之后,取回来的是什么?——取回 K 会丢掉「是谁」,所以要单独的 V。
  6. 回扣:RoPE 为什么偏偏旋转 Q 和 K,不旋转 V?——C2 埋下的伏笔在这里兑现。
  7. 一套 Q/K/V 只能看一种关系,够吗?——多头:同样的计算量,分成几份各自 softmax。
  8. 生成时,每一步都要把前面所有 token 的 K、V 重算一遍吗?——KV cache。
  9. 每个头都存一份 K/V 太贵,怎么办?——MHA → MQA → GQA。
  10. KV 还能再压吗?——MLA:只存一个低秩潜向量。
  11. 实验课:在我们自己的模型里看注意力

演进地图

注意力的演进:每一代都被上一代的某个真数字逼出来
① 训练时:一个 token 怎么从别的 token 那里取信息
  1. 起点 RNN:一个接一个地读 注意力之前的主流
    解决了能读任意长的序列,参数与长度无关;手里只带一个固定大小的状态 h。
    卡在ht 要等 ht−1 算完:T = 4,096 时每层 4,096 步不能并行,第 1 个 token 的信息要经过 4,095 次更新才到最后;翻译时整句还得挤进一个定长向量——Bahdanau 2014 说的瓶颈。
    展开岔路 B1
  2. 第一代 Bahdanau 加性注意力 Bahdanau 2014
    解决了解码器每一步回头给源句的每个位置打分、加权取回,不再只靠那一个定长向量:score = vT·tanh(W1q + W2k)。
    卡在每一对都要单独过 tanh,交不给矩阵乘单元;朴素实现要先落一个 T×T×da 的中间张量:T = 4,096、da = 256 时单头单层 8.0 GiB(BF16),点积只留 T×T 个分数,32 MiB。它还长在 RNN 翻译模型里,串行没解决。
    展开第 2 课
  3. 第二代 ① 自注意力:Q/K/V 三种投影 + 点积 Vaswani 2017 §3.2
    解决了直接比 embedding 时「给了」最像的是它自己(余弦 1.000),小明、苹果、小王排在最后;投影成 Q、K 再点积,它自己排到最后、前三名是苹果、小王、小明,全部配对一次矩阵乘 QKT;取回用单独的 V——两个人名的 K 余弦 0.995,取回 K 分不清是谁。
    卡在不缩放:锚点每头 256 维,点积标准差 √256 = 16,同一行分差十几二十是常态(e20 ≈ 4.9 亿),softmax 几乎独占,梯度传不回 WQ、WK。
  4. 第二代 ② softmax 与 ÷√d:缩放点积 Vaswani 2017 式 (1)
    解决了softmax 把分数变成正的、和为 1 的权重,只看分差(按占比分,对话样本的 10、3、−4 会给「汽车」−44.4%);除以 √dk = 16,点积方差回到 1。
    卡在训练时整句一次喂进去:不加掩码,「给了」一行有 32.5% 的注意力直接落在它要预测的答案「小王」上,loss 低得虚假。
    展开第 3 课
  5. 第二代 ③ 因果掩码 Vaswani 2017 §3.2.3
    解决了softmax 之前把右上三角置为 −∞:未来的权重恰为 0,一次前向做完 4 道「只看前缀」的题(逐个前缀喂要 5 次前向、15 个位置)。
    卡在一次 softmax 只有一份 100%:「给了」要同时找「谁给的」和「给了什么」,只能在苹果 56.5% 与小明 39.4% 之间劈开,取回两个 V 的混合。
    展开第 4 课
  6. 回扣 C2 RoPE 只转 Q、K Su 2021;锚点部分旋转
    解决了旋转后 q·k 只依赖距离 j − i;V 不参与打分,不转(转了会把绝对位置混进取回的内容)。锚点每头 256 维里只转 64 维。
    卡在旋转矩阵随位置变,夹在展开矩阵和缓存之间就没法事先并进 Q:MLA 因此把 RoPE 单独拆出 64 维另存(DeepSeek-V2 config,第 10 课)。
  7. 第二代 ④ 多头注意力 Vaswani 2017 §3.2.2
    解决了同一组投影按列切成几个头,各做各的 softmax,参数与乘法次数不变:头 A 把 89.5% 给「小明」、头 B 把 77.0% 给「苹果」;锚点 24 个头 × 256 维。
    卡在生成时一次只出一个 token:每一步把整段重新喂进去,提示 2 个、再生成 3 个就要算 9 份 K/V,其中 5 份是上一步刚算过的;K/V 次数随长度平方增长。
    展开第 7 课
  8. 旁支 attention sink 与它的出口 Xiao 2023 → Gated Attention 2025、DeepSeek-V4
    解决了标准 softmax 逼每行分完 100%:「苹果」一行 3 个分数只差零点几(0.04、0.36、0.00),照样分成 30% / 41% / 29%;分母加可学习的 sink logit,或在输出上乘门,这个头就能「这次不取」——锚点开着输出门(attn_output_gate = true)。
    卡在出口的效果只有实验证据:Gated Attention 原文说门控「缓解」sink,不是消除;DeepSeek-V4 没给 sink logit 的单独消融。
    展开岔路 B4
② 生成时:K、V 怎么越存越少
  1. 第三代 KV cache 自回归生成的标准做法
    解决了因果掩码保证旧 token 的 K、V 永不再变,存下来反复用:同一个例子只算 4 份,输出逐位相同(项目测试核对)。
    卡在缓存随上下文线性增长:若 24 个 Q 头各存一份(MHA),锚点形状下每 token 16 层 × 2 × 24 × 256 × 2 B = 384 KiB,原生 262,144 上下文 96 GiB——一条请求,还没算权重。
    展开第 8 课
  2. 第四代 MQA:所有头共用一份 K、V Shazeer 2019
    解决了缓存直接除以头数:锚点形状下每 token 16 KiB,262,144 上下文 4 GiB。
    卡在质量会掉、训练可能不稳:GQA 论文表 1(T5-XXL,七个任务平均)MHA 47.2 → MQA 46.6。
    展开第 9 课
  3. 第五代 GQA:分组共用 K、V Ainslie 2023;锚点 4 组
    解决了24 个 Q 头分 4 组、每组 6 个共用 1 个 KV 头(组数 = KV 头数):每 token 64 KiB、262,144 上下文 16 GiB;T5-XXL 上 GQA-8 平均 47.1、推理 0.28 s,质量接近 MHA(47.2、1.51 s),速度接近 MQA(0.24 s)。
    卡在再减 KV 头就回到 MQA:DeepSeek LLM 67B 已是 GQA-8,每 token 仍要 389,120 B(每头一份的 MHA 是 3,112,960 B),1M token 单条请求 380 GiB。
    展开第 9 课
  4. 第六代 MLA:只存一个低秩潜向量 DeepSeek-V2 2024 → V3、GLM-5.3
    解决了不存 K、V,每层每 token 只存 512 维潜向量 + 64 维 RoPE = 576 个数,用时再展开:DeepSeek-V2(60 层)每 token 69,120 B、V3(61 层)70,272 B;相对 67B 按 BF16 降 82.2%,官方「−93.3%」还含约 6 bit 的 KV 量化。
    卡在仍随长度线性增长,打分仍是 T²:GLM-5.3 同是 576 个数、78 层,每 token 89,856 B,原生 1,048,576 上下文时单条请求只算潜向量就要 87.75 GiB。
  5. 交接 C11 线性注意力 / 稀疏注意力 锚点另外 48 层;DeepSeek-V4.1
    解决了换掉「按长度存」本身:锚点 64 层里 48 层不存 KV,只存固定大小的状态(FP32 共 144 MiB),与上下文长度无关(这些层是什么、怎么更新,C11 第 4 课揭晓);DeepSeek-V4.1 叠加压缩、稀疏与低精度,官方报告全局 KV 890 B/token。
    卡在固定状态装不下任意多对键值,锚点仍留 16 层全注意力;稀疏注意力每步只读挑出来的一部分,挑本身也有代价——各自省了什么、没省什么,C11 讲。
数字口径:锚点 Qwen3.8-27B 与 DeepSeek LLM 67B / V2 / V3、GLM-5.3 的字节数由 anchor-model.json / frontier-models.json 的官方 config 在构建时现算(BF16 每元素 2 字节);「给了」一行的余弦、权重、各头注意力与 sink 那一行,由本章 teaching-world.json 现算——那是手工构造的教学向量,不是模型学到的,与各课组件同一份数据;T = 4,096 是第 2 课与岔路 B1 取的示例长度;T5-XXL 分数出自 GQA 论文表 1,「−93.3%」出自 DeepSeek-V2 报告,890 B 出自 DeepSeek-V4.1 模型卡(均为官方自报)。

贯穿例句

全章都在加工同一句话:「小明把苹果给了小王」。锚点模型 Qwen3.8-27B 的真 tokenizer 把它切成 5 个 token:小明 / 把 / 苹果 / 给了 / 小王(见 C1 的切分数据)。

⚠

前 7 课用来手算的 4 维向量和投影矩阵是手工构造的教学数据,不是任何模型学到的,每一维也没有名字——真实 embedding 的某一维不能读成「人名程度」。它们只用来让每一步都能手算核对。真模型的注意力在实验课里看:那是我们自己从 0 训练的小模型在这几句话上的真实权重。

三层交互

层这一章里是什么在哪一课
概念动画RNN 逐步传递 vs 注意力一步看完(可步进);逐 token 生成时哪些 K/V 在重算、哪些从缓存读(可步进)岔路 B1、第 8 课
算法模拟器(真算法、小数据)余弦 vs 投影打分;点积逐项展开;softmax 与 √d 的方差实验(固定种子随机向量);5×5 注意力矩阵与掩码;V 的加权求和;RoPE 平移不变;单头 vs 多头;sink logit;KV 账本第 1–10 课
真模型 / 真数据我们自己训练的模型逐层逐头的真实注意力与 attention sink 统计(项目导出数据);锚点与前沿模型的官方 config 现算 KV 字节;外链 Transformer Explainer(浏览器里跑真 GPT-2)实验课、第 7 课、岔路 B4、第 8–10 课

项目推进:实现注意力层

对应 04-实践项目/ 的里程碑「实现注意力层」。代码在 minillm/model.py 的 Attention 类里(手写路径与 PyTorch SDPA 路径并存,互相校验)。

你要拍板的决策

决策选项这一章里的依据
头数 n_head 与每头维数头数 × 每头维数要不要等于模型宽度?项目代码里 head_dim = n_embd // n_head,所以必须整除;Qwen3.8 不遵守这个约定(24 × 256 = 6144 > 5120)第 7 课
KV 头数 n_kv_head= n_head(MHA)/ 1(MQA)/ 之间(GQA,必须整除 n_head)第 9 课;项目实验 kv_heads_ablation
要不要 QK-Norm(qk_norm)对每个头的 q、k 做 RMSNorm,把点积的尺度钉住;Qwen3.8 开着(q_norm/k_norm 各 256 维)第 3 课(√d 的前提);C8 讲它为什么能防训练发散

当前基线配置写在 configs/baseline.json(2026-09-26:8 个头、8 个 KV 头即 MHA、qk_norm 关),改动请只改一项、其余不动,方便对照。

验收标准(全部可测)

  1. python3.12 -m unittest discover -s tests -v 全部通过,其中与本章直接相关的:
    • TestGQA.test_kv_heads_equal_heads_is_mha:n_kv_head = n_head 时与独立手写的 MHA 输出一致;test_gqa_equals_mha_with_shared_kv_weights:GQA 等价于「组内复制 K/V 权重的 MHA」。
    • TestKVCache.test_incremental_matches_full_forward:用 KV cache 逐步推理与整段前向的 logits 最大差小于 1e-4;test_generate_with_and_without_cache:贪心生成逐 token 相同;test_gqa_cache_is_smaller:KV 头 4 → 2 → 1 时缓存字节恰好减半、再减半。
    • TestModelShapes.test_attention_weights_are_causal:因果掩码下未来位置权重恰为 0,每行和为 1。
  2. 导出本章实验数据 知识平台/src/data/project/c3-attention.json(格式见 C3 设计卡「项目实验数据约定」),实验课页面上的数据自检全部打 ✓。
  3. 能对着自己的配置口算:每 token 每层 KV 字节 = 2 × n_kv_head × head_dim × 每元素字节数(第 8 课)。

坑与带走

本章拦截的误解

误解纠正在哪一课
Q、K、V 是三个新 token同一个 token 的三种投影:查别人用 Q,被别人查用 K,被选中后交出去的是 V第 1 课
点积是唯一正确的选择点积、余弦、负距离、加性网络都能打分;点积胜在一次矩阵乘和不落大张量,效果靠实验第 2 课
除以 √d 只是经验技巧√d 是让点积方差回到 1 的那个数(在分量独立、方差为 1 的前提下可推导);「方差为 1 训练最好」本身是理论动机第 3 课
对话样本里 8/7/9 的权重是 40%/30%/30%softmax 真算是 24.5% / 9.0% / 66.5%第 3 课
因果掩码是把未来的词删掉分数置 −∞、矩阵仍是方阵,才能一次并行算完;softmax 之后再清零会让行和小于 1第 4 课
RoPE 给 embedding 加了一个位置它在注意力内部旋转 Q、K;V 不转第 6 课
每个头有干净的分工,可以命名多数头是几种模式的混合(实验课用我们模型的真实数据看)第 7 课、实验课
头数 × 每头维数必须等于模型宽度这是 GPT-2 那一代的约定;Qwen3.8 是 24 × 256 = 6144 ≠ 5120第 7 课
KV cache 是免费的它随上下文线性增长;锚点 256K 上下文要 16 GiB第 8 课
GQA 的「组数」和 KV 头数是两回事组数就是 KV 头数(Qwen3.8:4 组 = 4 个 KV 头,每组 6 个 Q 头)第 9 课
MLA 只是换了个名字的 GQAGQA 少存几份 K/V;MLA 不存 K/V,只存一个低秩潜向量,用时再展开第 10 课
DeepSeek-V2 的「KV −93.3%」是 MLA 相对同配置 MHA 的降幅它是相对 DeepSeek 67B,并且含了约 6 bit 的 KV 量化;只看 BF16 是 −82.2%,相对同配置 MHA 是 −98.2%第 10 课

常见的坑(写代码时)

坑症状 / 后果怎么办
忘了加因果掩码训练 loss 低得离谱,生成时胡言乱语检查注意力矩阵是不是下三角(第 4 课)
忘了除以 √d大 head_dim 下 softmax 几乎 one-hot,梯度极小,loss 降不动缩放是标配;或加 QK-Norm(第 3 课)
n_embd 不能被 n_head 整除项目代码直接断言失败按项目约定整除(如 256 ÷ 8 = 32);想像 Qwen3.8 那样独立设 head_dim,要改投影形状(第 7 课)
生成时不用 KV cache每生成一个 token 重算全部 K/V,越往后越慢必开;用项目测试核对有无缓存输出一致(第 8 课)
以为 KV cache 免费长上下文直接爆显存先算账:层数 × 2 × KV 头 × head_dim × 字节 × 长度(第 8–9 课)
MHA 用到底KV cache 太大,一张卡同时服务的请求少、每步读得慢用 GQA(质量接近 MHA)甚至 MLA(第 9、10 课);项目里对照 n_kv_head
拿 bbycroft 的 3D 可视化学 KV cache它每步重走整个流程,没有缓存的概念用第 8 课的步进器

带走这些句子

  1. Q 决定「我要找什么」,K 决定「我能被怎样找到」,V 决定「找到我之后给你什么」——同一个 token 的三种投影。
  2. 点积 = 方向对齐 × 长度,T 个 token 的全部配对一次矩阵乘就算完。
  3. softmax 把任意分数变成正的、和为 1 的权重,只看分差;除以 √d 是为了让分差不至于大到 softmax 饱和。
  4. 因果掩码在 softmax 之前把未来置为 −∞:训练时一次算完整句,又看不到答案。
  5. QK 决定听谁的,V 决定听到什么。
  6. RoPE 转 Q、K 是为了让打分只看相对距离;V 不参与打分,转它只会把绝对位置混进内容。
  7. 多头 = 同样的计算量切成几份,每份各做一次 softmax,各看各的关系。
  8. KV cache 用显存换计算:生成时每步只算新 token 的 K、V。
  9. GQA 让几个 Q 头共用一份 K、V;组数 = KV 头数。
  10. MLA 不存 K、V,只存一个低秩潜向量;RoPE 那部分单独存。

深入这一章

按你愿意花的时间选。每条都实际打开核对过(2026-09-26)。

🎮 想更直观 10–30 分钟

先玩这两个,再回来看公式会轻松很多
10–20 min英文需联网 论文 arXiv 2408.04619
浏览器里跑一个真的 GPT-2 small,输入任意句子,看 embedding 分出 Q/K/V、真实的注意力矩阵、12 个头各自的图案。
对应第 1、7 课和实验课。它的注意力矩阵是真模型算出来的,可以和我们小模型的图对照:都是下三角,每个头的图案都不一样。
20–30 min英文(文字量小)需联网
把一个完整的 GPT 拆成 3D 立体,每个 token 逐层穿过 LayerNorm → 自注意力 → MLP,能看到每次乘加落在哪个格子上。
对应第 1、7 课。Q/K/V 三块权重、多个头并排的体积一目了然。注意:它每步重走整个流程,没有 KV cache,学第 8 课别用它。
10 min英文需联网
一页图解 MLA 的压缩与展开,并和 GQA 的「共享 KV 头」并排对比。
对应第 9、10 课。同一个站点的 GQA 页挂在第 9 课侧栏;两页都是结构图,不是营销稿。

🔬 想吃透原理 1–3 小时

唯一必看:3Blue1Brown 第 6 章。其余按课挑
26 minB 站官方双语需联网 92 万播放(2026-09-26)
用一个贯穿全片的例子讲 Q、K、V 的来历、点积打分、softmax、掩码设成负无穷,以及多头。
对应第 1–7 课。它是动画,本章是可手算的数字,两者互补;掩码那一段正好解释为什么不是「删掉」。3B1B 官方账号,不是搬运。
1 h 56 min中英字幕(第三方精译)需联网
从空文件开始写出并训练一个 GPT:先写出能偷看未来的注意力,训练结果不对,再加上下三角掩码;再写多头。
对应第 4、7 课和项目推进。和本章同一个节奏:先让朴素做法失败,再改。字幕是第三方精译版,第 7 集就是这一讲。
长文含推导中文需联网 2024-05-13
逐步推导每一步省了什么、牺牲了什么,包括 MLA 为什么要解耦 RoPE、W^UK 为什么能被吸收进 Q。
对应第 8–10 课,是这三课的主心骨。第 10 课的「RoPE 让吸收失效」就是这篇讲得最透。
19 min中文需联网
真实模型里的头常见哪几种图案:把注意力倒在第一个 token 上的 sink、看前一个 token 的头、归纳头;最后几分钟在真实 Qwen 上看。
对应岔路 B4 和实验课。看完再去实验课对照我们自己小模型的数据,哪些图案出现了、哪些没有。

📄 想读原文 按需

本地 PDF 直接打开;没有本地版的链 arXiv
Transformer 起点
第 1–7 课的出处。最该读:§3.2.1 与脚注 4(为什么除以 √d_k)、§3.2.2 多头、表 1(与 RNN 比较)、表 3(A) 行(头数的消融)。
加性注意力需联网
注意力的起点:固定长度向量是瓶颈,让解码器每一步(软)搜索源句里相关的位置。第 2 课「加性注意力」就是它。
MQA需联网
所有头共用一份 K、V,大幅降低逐 token 解码的访存,质量只有小幅下降。第 9 课。
GQA
介于 MHA 与 MQA 之间的分组共享;表 1 给出 T5-XXL 上 MHA / MQA / GQA-8 的质量与推理时间。第 9 课。
MLA
§2.1 MLA:低秩联合压缩、W^UK 吸收、解耦 RoPE;表 1 各种注意力每 token 的 KV 元素数;§3.2.3 的 KV 量化。第 10 课。
🚫

我替你排除了什么:「10 分钟搞懂注意力」类速通(讲不清 √d 和掩码)· 把注意力讲成「人的注意力 / 聚光灯」却不给精确映射的比喻文 · 只贴公式、没有动机的二手转载 · 在线 KV cache 计算器(公式不透明;本章第 8–10 课已按官方 config 现算)· 用 bbycroft 学 KV cache(它没有这个概念)· AnimatedLLM(调研档案说有中文界面,2026-09-26 实测没找到,暂不收)· 李宏毅 2021 自注意力的 B 站版本(第三方搬运,不是官方账号)· StatQuest(无中文)。