自注意力(Self Attention)的计算过程。
说明:数学上,向量 $\boldsymbol{v}$ 通常指列向量(即 $d \times 1$ 的矩阵),其线性投影记作 $\boldsymbol{M} \boldsymbol{v}$,其中 $\boldsymbol{M}$ 是投影矩阵,形状是 $r \times d$。若改用行向量表示,则需转置为 $\boldsymbol{v}^\top \boldsymbol{M}^\top$。而本文遵从 Transformer 的惯例:向量(如 embedding、query、key、value)均表示为 $1 \times d_{model}$ 的行向量,同时权重矩阵 $\boldsymbol{W}^Q$、$\boldsymbol{W}^K$ 和 $\boldsymbol{W}^V$ 的形状分别直接定义成 $d_{model} \times d_k$、$d_{model} \times d_k$ 和 $d_{model} \times d_v$(其中 $d_k$ 和 $d_v$ 不一定相等),使得投影运算可以直接写成 $\boldsymbol{e} \boldsymbol{W}^Q$、$\boldsymbol{e} \boldsymbol{W}^K$、$\boldsymbol{e} \boldsymbol{W}^V$,无需额外转置。这样记的好处是更接近于编程:$n$ 个 token 的 embedding 向量组成 $n \times d_{model}$ 的矩阵,每行对应一个 token,批量投影只需一次矩阵乘法。
计算过程 (1)
假设一句话包含 4 个 token,它们的 embedding 分别是 $\boldsymbol{e}_1$、$\boldsymbol{e}_2$、$\boldsymbol{e}_3$ 和 $\boldsymbol{e}_4$。并假设权重矩阵($\boldsymbol{W}^Q$、$\boldsymbol{W}^K$ 和 $\boldsymbol{W}^V$)已知。
计算 Attention Score (1.1)
计算各个 token 的 key 向量 $\boldsymbol{k}_i$($i=1,2,3,4$)。
$$
\begin{aligned}
\boldsymbol{k}_1 & = \boldsymbol{e}_1 \boldsymbol{W}^K \\
\boldsymbol{k}_2 & = \boldsymbol{e}_2 \boldsymbol{W}^K \\
\boldsymbol{k}_3 & = \boldsymbol{e}_3 \boldsymbol{W}^K \\
\boldsymbol{k}_4 & = \boldsymbol{e}_4 \boldsymbol{W}^K
\end{aligned}
$$
Token 的 key 向量定义我能被什么匹配到。
然后,以 token $\boldsymbol{e}_1$ 为例,计算它的 query 向量 $\boldsymbol{q}_1$:
$$
\boldsymbol{q}_1 = \boldsymbol{e}_1 \boldsymbol{W}^Q
$$
Query 向量定义我在找什么。Token $\boldsymbol{e}_1$ 和 $\boldsymbol{e}_2$ 的匹配度(关联性)就是注意力得分——即 $\boldsymbol{e}_1$ 对 $\boldsymbol{e}_2$ 的注意力,记作 $\alpha_{12}$。
$$
\alpha_{12} = \boldsymbol{q}_1 \cdot \boldsymbol{k}_2
$$
同理,计算 token $\boldsymbol{e}_1$ 和 $\boldsymbol{e}_3$、$\boldsymbol{e}_4$ 的注意力得分,以及自己和自己的注意力得分。汇总如下:
$$
\begin{aligned}
\alpha_{11} & = \boldsymbol{q}_1 \cdot \boldsymbol{k}_1 \\
\alpha_{12} & = \boldsymbol{q}_1 \cdot \boldsymbol{k}_2 \\
\alpha_{13} & = \boldsymbol{q}_1 \cdot \boldsymbol{k}_3 \\
\alpha_{14} & = \boldsymbol{q}_1 \cdot \boldsymbol{k}_4
\end{aligned}
$$
可见,注意力得分就是 query 向量和 key 向量的点积或内积(dot-product 或 inner-product)。
数学上,两个向量的点积是:
$$
\boldsymbol{q}_i \cdot \boldsymbol{k}_j = \lVert \boldsymbol{q}_i \rVert \lVert \boldsymbol{k}_j \rVert \cos(\theta)
$$
其中 $\theta$ 是两个向量的夹角。所以,点积就是两个向量的模长相乘,再乘以夹角的余弦值。也就是说,在模长相近的情况下,两个向量方向越一致(夹角越小),注意力得分越高。换言之,token 之间的相关性,体现在 query 向量和 key 向量的夹角上。
假设 query 向量代表“它”,句子中 token 的 key 向量分别代表:
- $\boldsymbol{k}_1$:行人
- $\boldsymbol{k}_2$:街道
- $\boldsymbol{k}_3$:黄狗
- $\boldsymbol{k}_4$:下雨
经过训练,模型会让“它”的 query 向量和“黄狗”的 key 向量夹角较小,于是:
$$
\begin{aligned}
\boldsymbol{q}_{\text{它}} \cdot \boldsymbol{k}_{\text{黄狗}} \gg \boldsymbol{q}_{\text{它}} \cdot \boldsymbol{k}_{\text{行人}} \\
\boldsymbol{q}_{\text{它}} \cdot \boldsymbol{k}_{\text{黄狗}} \gg \boldsymbol{q}_{\text{它}} \cdot \boldsymbol{k}_{\text{街道}} \\
\boldsymbol{q}_{\text{它}} \cdot \boldsymbol{k}_{\text{黄狗}} \gg \boldsymbol{q}_{\text{它}} \cdot \boldsymbol{k}_{\text{下雨}}
\end{aligned}
$$
为什么不是直接用原始向量?因为原始 embedding 向量并不适合直接做相似度比较。模型会用 $\boldsymbol{W}^Q$、$\boldsymbol{W}^K$ 和 $\boldsymbol{W}^V$ 把输入投影到三个不同的子空间:
- $Q$ 空间:定义“我在找什么”
- $K$ 空间:定义“我能被什么匹配到”
- $V$ 空间:定义“我能提供什么信息”(见后文)
所以,注意力不是简单比较两个词像不像,而是在学出来的语义子空间里比较投影的相似度。
补充:点积只是计算 Attention Score 的一种方法。实际上,还有别的计算方法,例如 Additive(加性注意力):$\tanh(\boldsymbol{q} + \boldsymbol{k}) \boldsymbol{W}$,过程是:
- 把 query 和 key 向量逐元素相加(而不是点乘),结果是一个行向量;
- 相加后的向量做逐元素 $\tanh$(双曲正切函数),结果仍是一个行向量;
- 最后经过一个线性层($\boldsymbol{W}$ 是一个列向量),得到标量 $\alpha$(注意力得分)。
模长代表什么 (1.2)
上一节说,在模长相近的情况下,两个向量方向越一致(夹角越小),注意力得分越高。换言之,token 之间的相关性,体现在 query 向量和 key 向量的夹角上。可是,影响点积结果的不止夹角,还有两个向量的模长。
在训练好的表示空间里,一个向量的模长大,通常意味着这个 token 在该注意力头所关注的维度上更活跃、更突出。比如句子“我去吃饭”中,“我”的向量可能模长最大,因为它作为主语与后面每个词都有关联;而“去”的模长较小,角色相对单一。
点积天然保留了这个信息:
- 若某个 token 的 key 向量模长较大,它会与更多 query 产生较大的点积,从而更容易被其他 token 关注到;
- 若某个 token 的 query 向量模长较大,它对所有 key 的点积都会整体变大,得分之间的绝对差距也随之放大;而 softmax 对数值差距敏感,经过 softmax 后,注意力分布会更尖锐,更集中在得分最高的几个 key 上。注:softmax 在下一节引入。
所以,注意力得分大致可以理解为:
$$
\text{AttentionScore} = \text{双方重要性} \times \text{匹配度}
$$
确实也有些模型会显式做 QK-Norm,例如部分现代 LLM (如 Qwen3)会在计算点积前对每个头的 $\boldsymbol{q}$、$\boldsymbol{k}$ 做 RMSNorm 或 L2 归一化。这就更接近只看向量的方向(匹配度)。不过实际实现通常还会乘一个可学习缩放,相当于一个可学温度(用于捕获 token 的重要性)。
归一化成权重 (1.3)
上一节得到的注意力得分 $\alpha_{1j}$ 只是原始匹配分数,它们可以是任意实数,不能直接当作权重使用。为了让它们变成一组注意力权重(大于0,且和为1),需要对它们做归一化。最常用的归一化方法是 softmax。
这里有一个细节:原始 Transformer 在 softmax 之前还会除以 $\sqrt{d_k}$(其中 $d_k$ 是 key 向量的维度)。注意,这里把缩放后的得分仍记作 $\alpha_{1j}$,即先计算缩放后的得分,再做 softmax。
$$
\alpha_{1j} = \frac{\boldsymbol{q}_1 \cdot \boldsymbol{k}_j}{\sqrt{d_k}} \quad \quad j=1,2,3,4
$$
这一步叫缩放点积。缩放不是归一化,缩放之后仍然不是权重——可能小于0,总和也不为1。缩放的作用是防止 $d_k$ 较大时点积值过大,导致 softmax 进入梯度极小的饱和区,影响训练稳定性。
缩放之后,送入 softmax 进行归一化。对于 token $\boldsymbol{e}_1$,归一化得到:
$$
w_{1j} = \operatorname{softmax}\left(\alpha_{1j}\right) = \frac{\exp(\alpha_{1j})}{\sum_{k=1}^4 \exp(\alpha_{1k})} \quad \quad j=1,2,3,4
$$
这样得到的 $w_{1j}$ 都为正且和为 1,可以解释为权重,即注意力权重(Attention Weight)。或者说,$w_{1j}$ 表示 token $\boldsymbol{e}_1$ 在聚合上下文信息时,分配给 token $\boldsymbol{e}_j$ 的注意力的多少。
总结起来,注意力权重(Attention Weight)计算过程如下:
$$
w_{1j} = \operatorname{softmax}\left(\frac{\boldsymbol{q}_1 \cdot \boldsymbol{k}_j}{\sqrt{d_k}}\right) \quad \quad j=1,2,3,4
$$
也可以通过下图表示:

说明:在分类生成式模型的第 6.4 节,我们也曾采用 softmax 进行归一化,那里用 softmax 有其背后的道理;相比之下,这里就没有那么多道理可言,单纯为了归一化成权重。也可以不用 softmax,有人尝试过使用 ReLU,效果也不错。