新分类续接之前的注意力机制内容开始,展开一些更现代的理论。
在之前的深度学习内容中,我们已经介绍了注意力机制的核心流程,其本质可以概括为:在解码的每一个时间步增加注意力计算得到上下文向量,让模型可以根据当前状态,从输入序列中动态选择相关信息。

实际上,你会发现:在这个传播过程中,传统的注意力机制只是一个插件。
在这个机器翻译的例子里,模型的主干仍然是 RNN,如果在解码的每一步去除了注意力计算,那么整个模型就是一个常见的不等长循环神经网络。
而注意力计算的实质,其实是对解码器每一步的隐藏状态到该步输出间的一次"再加工"。
它是对解码器当前隐藏状态的一次信息增强 ,使得模型在生成输出时能够参考输入序列中的关键部分。
总结来说就是:
注意力机制并没有改变模型"如何建模序列",而只是让结果"更准确"。
于是一个想法产生了:
既然这种"信息增强"在本质上是有益的,为什么我们要把它限制在解码阶段?
这就是自注意力机制的出发点,它让注意力机制彻底摆脱了"优化插件"的地位,不再依附于 RNN 或其他结构存在,而是被抽象为一种独立的计算层,与全连接层、卷积层处于同一层级,最终成为 Transformer 乃至整个现代深度学习领域的核心内容。
1.自注意力机制的背景
不必过多赘述,自注意力机制出自大名鼎鼎的论文:Attention Is All You Need
这篇 17 年的论文目前的引用量已超过十万级别,并持续快速增长,其影响力不仅局限于 NLP 领域,更扩展到计算机视觉、多模态学习等多个方向,是近年来深度学习领域最具里程碑意义的工作之一。
在当前大模型的发展中,Transformer 已经成为事实上的核心架构,而自注意力就是它的核心计算单元。
如果把自注意力机制理解为一句话,它做的事情其实非常简单:
对于序列中的每一个位置,都去"看一遍"整个序列,然后根据相关性重新生成自己的表示。
我们知道:在传统序列建模中,每个位置的隐藏状态 \(\mathbf{h}^{(i)}\) 仅依赖于当前输入 \(\mathbf{x}^{(i)}\) 和前一时刻的状态 \(\mathbf{h}^{(i-1)}\)。
但在自注意力中:
每一个位置的表示,不再依赖于时间递推,而是由整个序列共同决定。
因此,在之后的相关内容中,就不会在出现由时间步递推而产生的"隐藏状态"这个词,而是回到了"层级间的输入和输出"这个范畴。
下面就来展开其详细过程:
2. 自注意力机制的运算过程
2.1 自注意力层的输入
首先,给定一个长度为 \(n\) 的序列信息,经过嵌入层得到输入:
\[\mathbf{X} = [\mathbf{x}^{(1)}, \mathbf{x}^{(2)}, \dots, \mathbf{x}^{(n)}] \]
现在, \(\mathbf{x}^{(i)}\) 就表示第 \(i\) 个位置的输入特征向量,假定每个向量的维度为 \(d\) 。
我们先用单个位置的向量,来说明自注意力机制的运算过程。
2.2 Query、Key 和 Value
每个输入向量 \(\mathbf{x}^{(i)}\)进入自注意层的第一件事,是做三次线性变换,得到三种不同语义的表示:
- Query(查询):
\[\mathbf{q}^{(i)} = \mathbf{W}_Q \mathbf{x}^{(i)} \]
- Key(键):
\[\mathbf{k}^{(i)} = \mathbf{W}_K \mathbf{x}^{(i)} \]
- Value(值):
\[\mathbf{v}^{(i)} = \mathbf{W}_V \mathbf{x}^{(i)} \]
这里的 \(\mathbf{W}_Q, \mathbf{W}_K, \mathbf{W}_V\) 都是可学习参数矩阵,它们的矩阵维度为:
\[W_Q \in \mathbb{R}^{d \times d_k}, \quad W_K \in \mathbb{R}^{d \times d_k}, \quad W_V \in \mathbb{R}^{d \times d_v} \]
其中,\(\mathbf{W}_Q\) 和 \(\mathbf{W}_K\) 的维度必须相同所以只使用一个参数, \(d_k\) 和 \(d_v\) 是超参数,但我们一般也要求二者相同,具体原因我们下面就会讲到。

总之,这一步,是我们定义了三种变换并为其赋予了语义,具体语义是由我们后续的操作实现的,我们可以先简单了解如下:
- \(\mathbf{q}^{(i)}\):当前位置"想找什么"。
- \(\mathbf{k}^{(i)}\):当前位置"能提供什么特征"。
- \(\mathbf{v}^{(i)}\):当前位置"真正携带的信息"。
2.3 相关性计算
完成变换后,现在,对于某个固定位置 \(i\),它会和所有位置 \(j\) 计算相关性:
\[\text{score}_{ij} = \frac{\mathbf{q}^{(i)} \cdot \mathbf{k}^{(j)}}{\sqrt{d_k}} \]
注意:相关性的计算包括 \(i\) 位置自己!
这里,就可以开始理解我们为三种向量赋予的语义:
我们简单代入一个例子,假设:
\[\mathbf{q}^{(i)}=[食物,空气,水] \]
\[\mathbf{k}^{(j)}=[厨房,自然,湖泊] \]
二者的点积结果就会较大,因为 \(i\) 位置需要的信息和 \(j\) 位置提供的信息比较匹配,再换一种情况:
\[\mathbf{k}^{(j)}=[厕所,太空,沙漠] \]
显然,这种情况下 \(i\) 位置的需求和 \(j\) 位置的供给就不匹配,点积结果就会较小。
再次强调神经网络内部的不可知性,我们只是举例说明,一轮轮反向传播后,三种变换参数矩阵不断学习,会让变换结果的运算形成类型例子这样的效果。
从这个公式也可以看出来,\(d_q\) 和 \(d_k\) 必须相等来满足点积运算要求。
而使用 \(\sqrt{d_k}\) 进行缩放 ,则是让梯度更稳定,防止之后的 softmax 饱和。

这一步的逻辑就和常规注意力机制中相关度度量比较相似了,我们以此来了解所有位置的信息和当前位置信息的相关性。
2.4 softmax 归一化
继续,这步的逻辑也不陌生,对每个 \(i\),我们在所有 \(j\) 上做 softmax:
\[\alpha_{ij} = \frac{\exp(\text{score}{ij})}{\sum{j=1}^{n} \exp(\text{score}_{ij})} \]
现在,我们得到就是 \(i\) 位置对于每个位置的注意力权重 ,结果 \(\alpha_{ij}\) 就表示位置 \(i\) 从位置 \(j\) 获取信息的比例。

2.5 加权求和得到输出
最终,我们使用之前一直没用到的 \(\mathbf{v}\) 和上一步计算得到注意力权重进行加强求和。
\[\mathbf{z}^{(i)} = \sum_{j=1}^{n} \alpha_{ij} \mathbf{v}^{(j)} \]
在这里,我们才赋予 \(\mathbf{v}\) 语义,它代表真正携带的信息,用于计算最终的输出,这种效果也是不断地监督学习得到的。
每个位置 \(i\) 用自己的权重分布从所有 \(\mathbf{v}^{(j)}\) 中"提取信息",最终得到新的表示。
同样地,所有 \(\mathbf{v}^{(j)}\) 中也包括当前位置本身的 \(\mathbf{v}^{(i)}\) 。

在这一步,你会发现,\(d_k = d_v\) 并不是必须的,前者决定判断相似度的维度,而后者决定信息表示的维度。
其实,要求二者相等的原因除去结构对称这种原因外,更重要的原因是在多头注意力中方便拼接,我们在下一篇就会展开相关内容。
2.5 矩阵形式
我们已经从单个位置 \(i\) 的角度 理解了自注意力的计算过程。现在就来看看在实际计算中矩阵并行运算过程吧:
我们先将所有位置的向量堆叠起来:
\[\mathbf{X} = \begin{bmatrix} (\mathbf{x}^{(1)})^T \\ (\mathbf{x}^{(2)})^T \\ \vdots \\ (\mathbf{x}^{(n)})^T \end{bmatrix} \in \mathbb{R}^{n \times d} \]
同理,可以得到:
\[\mathbf{Q} = \mathbf{X}\mathbf{W}_Q \in \mathbb{R}^{n \times d_k} \]
\[\mathbf{K} = \mathbf{X}\mathbf{W}_K \in \mathbb{R}^{n \times d_k} \]
\[\mathbf{V} = \mathbf{X}\mathbf{W}_V \in \mathbb{R}^{n \times d_v} \]
显然,在这里 \(\mathbf{Q}\) 的第 \(i\) 行就是\(\mathbf{q}^{(i)}\)、\(\mathbf{K}\) 的第 \(j\) 行就是\(\mathbf{k}^{(j)}\)、\(\mathbf{V}\) 的第 \(j\) 行就是 \(\mathbf{v}^{(j)}\)。
继续下一步:计算相关性矩阵:
\[\mathbf{S} = \mathbf{Q} \mathbf{K}^T \in \mathbb{R}^{n \times n} ,S_{ij} = \mathbf{q}^{(i)} \cdot \mathbf{k}^{(j)} \]
加入缩放后就是:
\[\mathbf{S} = \frac{\mathbf{Q} \mathbf{K}^T}{\sqrt{d_k}} \]
对每一行做 softmax:
\[\mathbf{A} = \text{softmax}(\mathbf{S}) ,A_{ij} = \alpha_{ij} \]
最终进行加权求和:
\[\mathbf{Z} = \mathbf{A} \mathbf{V} \in \mathbb{R}^{n \times d_v} \]
其中第 \(i\) 行就是 \(\mathbf{z}^{(i)}\)。
现在,大的要来了:将所有步骤合并,自注意力可以写成一个紧凑的形式:
\[\mathrm{Attention}(\mathbf{Q},\mathbf{K},\mathbf{V})=\mathrm{softmax}\left(\frac{ \mathbf{Q}\mathbf{K}^T}{\sqrt{d_k}}\right) \mathbf{V} \]
这就是 Transformer 中最核心的一行公式。
最终,通过自注意力, 我们将原始输入增强成了一个融合了全局上下文的表示。
这就是自注意力的完整运算过程。
3. 自注意力机制的核心优势
与传统方法相比,自注意力有一个核心优势:模型可以直接建模任意长距离依赖关系 。
在传统序列模型(比如 RNN)中,信息是这样传播的:
\[\mathbf{x}^{(1)} \rightarrow \mathbf{h}^{(1)} \rightarrow \mathbf{h}^{(2)} \rightarrow \dots \rightarrow \mathbf{h}^{(n)} \]
路径长度是 \(n\) ,不仅路径长,而且信息需要经过多次非线性变换,容易发生梯度消失或信息衰减。
而在单层自注意力中:
\[\mathbf{z}^{(i)} = \sum_{j=1}^{n} \alpha_{ij} \mathbf{v}^{(j)} \]
位置 \(i\) 和任意位置 \(j\) 之间,是"一步直达"的。 \(i\) 可以直接从 \(j\) 获取信息,不需要经过任何中间节点,信息路径长度是 1 ,这就可以实现更长距离的依赖。
此外,自注意力机制可以在所有位置上并行计算,而 RNN 必须按时间步顺序递归计算,这使得训练效率大幅提升。
总结来说,自注意力机制用一次全局加权重建表示,把"序列依赖"从递归建模转变为全局直接建模,从而在提升表达能力的同时获得更短的信息传播路径与更高的计算效率。
这就是单层自注意力的逻辑,在下一篇,我们就以此为基础,展开多头自注意力的内容。