上一课的朴素注意力有个死板之处:每个词只用一个向量同时干三件事。这一课把这三件事拆成三个专门的向量——这就是 Q / K / V。
| Topic | Query / Key / Value 三个投影 |
| Objectives | 理解朴素版的两个毛病;看 Q/K/V 如何各修一个;知道它们是学出来的 |
| Prerequisites | 朴素注意力 ✅(点积打分 → softmax → 加权和) |
| Outcome | 能说清为什么要三个投影,而不是直接用 embedding |
| Warning | Q/K/V 是同一个词的三个"角色向量",不是三个词 |
朴素注意力里,每个词的同一个向量 xᵢ 被拿去做了三件不同的事:
| 发起比较 | "我在找什么样的词"(当它是主动方时) |
| 被人比较 | "我是什么样的词,好让别人来匹配我"(当它是被查方时) |
| 提供内容 | "匹配上之后,我把什么信息交出去" |
三个角色被硬绑在一个向量上,带来两个具体毛病:
it 想找一个"名词、可作主语的东西",但 it 自己这个词本身平平无奇。用同一个向量既表达"我要找什么"又表达"我是什么",表达不清。xᵢ·xⱼ = xⱼ·xᵢ(对称);而 xᵢ·xᵢ=|xᵢ|² 恒大 → 每个词天然最关注自己,不够灵活。给每个词的向量 xᵢ 配三个学出来的矩阵 W_Q, W_K, W_V,投影出三个专门的向量:
| Query qᵢ = xᵢ·W_Q | "我在找什么" —— 当主动方时用(像搜索词) |
| Key kᵢ = xᵢ·W_K | "我是关于什么的" —— 当被查方时用(像索引标签) |
| Value vᵢ = xᵢ·W_V | "我能提供的信息" —— 匹配上后交出去的内容(像正文) |
三个矩阵全模型共用、由训练学出。于是打分和混合都用专门的向量:
对比朴素版:xᵢ·xⱼ → qᵢ·kⱼ;混合 xⱼ → 混合 vⱼ
q 表达,"我是什么"由 k 表达,两者解耦。it 的 q 可以专门指向"名词性、可作主语",与它自身平淡的词义无关。qᵢ·kⱼ,因为 W_Q≠W_K,不再对称(i 关注 j ≠ j 关注 i),也不再天然最爱自己。谁关注谁,由训练自由决定。v 而非原始 x——模型可以让"用来匹配的样子(k)"和"实际交出的信息(v)"不一样。一句话:Q/K/V = 把"找 / 被找 / 给"三个角色各配一个专用、可学习的向量。
三者平级——都是 x 经一个学出来的矩阵投影出的"视角":
每个都可以从"几乎等于 x"到"很不一样",由训练决定。k 和 v 的差别不在它们与 x 的关系类型(都是投影),而在用途不同 → 被训练成不同的样子:
| k | 去和别人的 q 做点积(打分)→ 被训练成"便于被正确匹配的标签"(广告词) |
| v | 匹配后被加权求和进输出 → 被训练成"值得传给别人的内容"(货) |
例(it → animal): k(animal) 装"我是可作主语的生物名词"(便于被搜到);v(animal) 装"那只具体的动物:单数、非人称、话题主体"(搜到后真正吸收的内容)。像搜索:你用关键词匹配标题(k),但真正要的是正文(v)。
更极端的例(功能词): 逗号 / the 的原始 x 几乎没语义,但模型可让它的 v 交出"句子结构/边界"信号 —— 体现 x(我是谁)和 v(我能给你什么)可以差很远。
存 W_Q/W_K/W_V(和 embedding 表),不存 q/k/v。 q/k/v 是运行时用 x·W 现算的中间结果。
为什么不能预存 q/k/v:因为它依赖的 x 不是固定的。 第 1 层的 x 是 embedding(固定),但第 2 层及以后的 x 是上一层 attention 现算出的"带上下文的新向量",取决于整句话、每句不同。所以"某个词的 k"没有一个固定值可存——同一个词在不同句子/不同层,x 都不同。
| embedding 表 | ✅ 可存:输入是固定整数 id,查表,组合有限(词表大小) |
| W_Q/W_K/W_V | ✅ 可存:学出来的固定参数 |
| q/k/v | ❌ 不存:依赖运行时的 x,x 随上下文/层变化,无固定值 |
就算只对第 1 层预存也不划算:词表 ~10 万 × 3 个向量 × 几百维 = 空间爆炸,省下的只是一次矩阵乘法(GPU 最便宜的操作);推理瓶颈是内存带宽,多搬数据反而更慢。
qᵢ·kⱼ 后面还会除以 √d 再 softmax(缩放,稳定数值);(2)实际会并行开多组 Q/K/V 捕捉不同关系,叫 Multi-head。这两个都在待讲清单里,下面几课讲。
xᵢ·xⱼ 是对称的(i 对 j = j 对 i)。为什么换成 qᵢ·kⱼ 后就不对称了?(提示:W_Q 和 W_K 是不是同一个矩阵)答完这 3 题,下一课 D. 缩放点积(÷√d)——一个很小的数值稳定技巧,然后是 Multi-head。