Transformer 的注意力机制,到底在算什么
从 Q/K/V 到多头,用最小例子把 self-attention 算一遍。
attention 几乎是所有大模型的承重墙,但很多解释停在"让模型关注重要的词"就走了。这篇把它算一遍:张量形状怎么变、每一步在做什么、多头到底多了什么。
从一句话开始
输入 "猫 坐在 垫子 上",经过 embedding 后是四个向量,形状 [4, d_model]。self-attention 要回答的问题是:每个词在输出新表示时,应该从哪些词那里取多少信息。
Q、K、V 是一次矩阵乘法
三个可学习的投影矩阵把同一份输入变成三组向量:Q = XW_q、K = XW_k、V = XW_v。直觉上 Q 是"我在找什么",K 是"我是什么",V 是"我能提供的内容"。注意 K 和 V 来自同一个 X 但用了不同的投影——这是关键,匹配用的特征和内容用的特征不必相同。
分数、缩放、加权
softmax(QK^T / sqrt(d_k)) V。逐项看:QK^T 得到 4×4 的相关性分数;除以 sqrt(d_k) 是因为维度高了以后点积方差变大,softmax 会饱和成 one-hot,梯度消失;softmax 之后每行是一个权重分布;最后用这个分布对 V 加权求和。整个式子没有循环,四个词是并行算完的。
多头多出来的是什么
把 d_model 切成若干头,各自在小维度上做上面这套,再拼接投影回来。单头的注意力分布往往糊在一起;分开小空间后,不同头会自发分化——有的学句法邻近,有的学指代关系,这在 BERT 时代的探针实验里反复被观察到。多头不是"更多注意力",是"更多种匹配的子空间"。
因果掩码与 KV cache
生成式模型在 softmax 前把上三角置为负无穷,保证当前 token 看不到未来。推理时逐 token 生成,历史 token 的 K、V 不变,缓存起来即可省掉重复计算——这就是 KV cache,也是长上下文吃显存的主因:显存占用大致随「层数 × 头数 × 序列长度」线性增长。
把 attention 背下来不难,难的是每次看到形状变化都能说出为什么。能手推一遍,读后续论文会快很多。