注意力机制
作为一个堂堂正正的中国人,用英文做的那一版笔记是在难以下咽,因此用中文重新做一遍
1. 背景
1.1 前浪:RNN / LSTM 时代
在 Transformer 出现之前,序列建模任务(机器翻译、文本摘要、语音识别等)几乎都依赖 RNN 及其变体 LSTM / GRU。它们按时间步依次处理序列:
即第 个位置的隐状态 依赖前一个位置的隐状态 和当前输入 。
这种设计带来两个根本问题:
| 问题 | 具体表现 |
|---|---|
| 无法并行 | 第 步必须等第 步算完,序列越长,训练越慢 |
| 长距离依赖困难 | 梯度会随着序列长度衰减或爆炸,远距离词之间的关系很难稳定保留 |
Example
在句子 “The animal didn’t cross the street because it was too tired.” 中,理解 “it” 指的是 “animal” 而不是 “street”,需要模型建立较长距离的依赖。RNN 在这类场景中常常吃力。
1.2 过渡:注意力机制的萌芽
2015 年,Bahdanau 等人在 Seq2Seq 翻译模型中引入了 Attention。
解码器在生成每个词时,不再只依赖编码器最后一个隐状态,而是会对编码器所有位置的隐状态进行加权汇总。
这让模型可以“动态聚焦”到源句中最相关的部分,显著改善了长句翻译效果。
但此时的注意力机制只是 挂在 RNN 上的外挂,并没有解决 RNN 的顺序计算瓶颈。
1.3 破局:Transformer 的诞生
2017 年,Vaswani 等人在论文 Attention Is All You Need 中提出 Transformer,核心思想极其激进:
完全抛弃循环结构,只用注意力机制来建模序列。
这意味着:
- 不再按时间步串行处理
- 让序列中任意两个位置都能直接交互
- 整个序列可以并行计算
Transformer 的几个关键创新:
- Self-Attention:每个位置都能直接关注整个序列中的所有位置
- Multi-Head Attention:并行使用多个注意力头,从不同子空间捕捉不同关系
- Positional Encoding:显式注入位置信息,弥补注意力本身对顺序不敏感的问题
- Residual + LayerNorm:让深层网络稳定训练
1.4 原始 Transformer 与 Modern Transformer
原始论文中的 Transformer 是一个 Encoder-Decoder 架构,主要面向机器翻译:
- Encoder:读入源序列,输出上下文表示
- Decoder:在读取编码器输出的基础上,自回归生成目标序列
而现代大语言模型(GPT、LLaMA、Qwen、DeepSeek 等)大多采用 Decoder-Only 架构,即只保留解码器。
Note
原始 Transformer 是“先读后写”;现代 LLM 更常见的是“边读边续写”。
2. 核心思路
2.1 Transformer 到底想解决什么
RNN 的根本问题是:信息必须沿着时间步一级一级传递。
如果句首的词要影响句尾的词,信息必须穿过很多中间状态,路径很长,容易衰减。
Transformer 的思路是:
让每个位置直接和所有位置交互。
这样一来:
- 任意两个位置的信息传递路径长度都是
- 所有位置可以同时计算
- 长距离依赖不再依赖“多步传话”
2.2 Q / K / V 的直觉
注意力机制可以理解成一个“信息检索”过程。
| 符号 | 直觉类比 | 含义 |
|---|---|---|
| Q(Query) | 我在找什么 | 当前这个位置发出的查询 |
| K(Key) | 我是什么标签 | 每个位置暴露出来的索引信息 |
| V(Value) | 我真正携带的信息 | 被取出来并聚合的内容 |
整个过程就是:
- 当前 token 发出一个 Query
- 用 Query 和所有 Key 算相似度
- 相似度越高,对应位置的 Value 权重越大
- 最后把所有 Value 按权重加权求和,得到新的表示
Tip
Q 决定“找谁”,K 决定“匹不匹配”,V 决定“真正取什么”。
2.3 Self-Attention 与 Cross-Attention
Self-Attention(自注意力)
Q、K、V 来自 同一个序列。
也就是说,序列中每个位置都会去看整个序列,从而获得上下文信息。
例如:
“我 / 爱 / 北京 / 天安门”其中“北京”这个位置可以关注“我”“爱”“天安门”,综合上下文更新自己的表示。
Cross-Attention(交叉注意力)
Q 来自一个序列,K 和 V 来自 另一个序列。
在原始 Transformer 中:
- Q 来自解码器当前状态
- K、V 来自编码器输出
也就是说,解码器在生成目标词时,会去“查询”源句里最相关的部分。
Note
区别就一句话:
Self-Attention 是自己查自己,Cross-Attention 是一个序列去查另一个序列。
2.4 编码器和解码器各自做什么
编码器(Encoder)
编码器负责:
读完整个输入序列,生成每个位置的上下文表示。
每一层包含两个子层:
- Multi-Head Self-Attention
- Position-wise Feed Forward Network
并且每个子层外面都包着:
- 残差连接(Residual Connection)
- 层归一化(LayerNorm)
结构可写成:
输入
↓
Multi-Head Self-Attention
↓
Add & Norm
↓
Feed Forward
↓
Add & Norm
↓
输出解码器(Decoder)
解码器负责:
根据已经生成的部分,自回归地生成下一个 token。
每一层包含三个子层:
- Masked Multi-Head Self-Attention
- Multi-Head Cross-Attention
- Position-wise Feed Forward Network
结构可写成:
输入
↓
Masked Multi-Head Self-Attention
↓
Add & Norm
↓
Cross-Attention
↓
Add & Norm
↓
Feed Forward
↓
Add & Norm
↓
输出2.5 为什么现代模型多是 Decoder-Only
现代大语言模型大多采用 Decoder-Only,主要原因有:
- 架构更简单:只保留一种主干模块
- 训练目标统一:直接做 next-token prediction
- 更适合规模化:更容易堆大模型、喂更多数据
- In-Context Learning 能力强:只靠续写目标就能完成很多任务
典型三类 Transformer 变体:
| 架构 | 代表模型 | 特点 |
|---|---|---|
| Encoder-Only | BERT | 擅长理解任务 |
| Encoder-Decoder | 原始 Transformer、T 5、BART | 擅长显式输入→输出映射 |
| Decoder-Only | GPT、LLaMA、Qwen | 擅长统一建模和生成 |
Tip
原始 Transformer 更像“翻译机”;现代 LLM 更像“超大规模续写机”。
3. 机制
3.1 输入表示:Embedding + Positional Encoding
注意力机制本身不感知顺序,因此必须把位置信息显式加到词向量中。
设输入序列长度为 ,模型维度为 。
词嵌入矩阵记为:
位置编码与词嵌入逐元素相加后,作为真正输入:
原论文采用的是固定的正弦/余弦位置编码:
Note
现代模型中常见的位置信息方案还有 RoPE、ALiBi 等,但原论文使用的是正余弦位置编码。
3.2 Scaled Dot-Product Attention
3.2.1 先定义维度
最一般地,设:
- Query 序列长度为
- Key / Value 序列长度为
则:
这些量来自线性投影:
其中:
若是 Self-Attention,则:
于是通常有 。
若是 Cross-Attention,则:
- 来自解码器
- 来自编码器
所以此时一般 。
3.2.2 第一步:计算相似度分数
矩阵中的每个元素:
表示第 个 Query 对第 个 Key 的匹配程度。
3.2.3 第二步:缩放
为什么要除以 ?
核心假设: 假设所有 和 是独立同分布(i.i.d)的随机向量,每个分量均值为 0,方差为 1。
计算乘积方差:
既然
那么
既然独立,就有
期望与求和可以交换,于是
由 ,,得
因此,不难看出
当 很大时(如 512),点积值可能非常大,导致 softmax 输出接近 one-hot 向量,梯度几乎为 0。
缩放后可以让数值更稳定。
3.2.4 第三步:归一化
Softmax 是按行做的,即每个 Query 对所有 Key 的权重和为 1。
其中 表示:第 个位置对第 个位置的注意力权重。
3.2.5 第四步:对 Value 加权求和
因此:
最终完整公式为:
3.2.6 维度总结
Self-Attention
若输入序列长度为 :
则:
最后输出:
Cross-Attention
若 Query 长度为 ,Key / Value 长度为 :
则:
输出:
Tip
注意力输出的“行数”永远跟 Query 一致,因为“有多少个 Query,就会产出多少个输出位置”。
3.3 Multi-Head Attention
3.3.1 为什么需要多头
如果只有一个注意力头,模型只能用一种方式去衡量“相关性”。
但真实语言中的关系很多:
- 句法依赖
- 指代关系
- 时态关系
- 语义搭配
- 长距离依赖
所以 Transformer 并不是只算一次注意力,而是同时算多次,让不同头学习不同模式。
3.3.2 具体计算
设头数为 ,通常有:
原论文中:
- 所以
对每个头 ,分别学习不同的投影矩阵:
然后独立计算注意力:
最后把所有头拼接起来,再做一次线性变换:
3.3.3 维度变化
假设输入是:
则每个头看到的是:
每个头输出:
拼接后:
再经过 ,输出仍然保持:
这样就能层层堆叠。
3.4 Mask(掩码)
Mask 的作用是:
在 softmax 之前,把不该看的位置强行屏蔽掉。
常见做法是把这些位置加上 (实现时常用很大的负数如 ),这样 softmax 后这些位置的权重就接近 0。
3.4.1 Padding Mask
在 batch 训练中,句子长度不同,通常需要补 <pad> 到同一长度。
这些 pad 位置没有语义,不应该参与注意力计算。
因此要构造一个 Padding Mask,把 pad 对应位置屏蔽掉。
若某个位置是 pad,则:
否则:
然后:
Note
Padding Mask 在编码器和解码器里都可能出现,因为两边的输入都可能被 pad。
3.4.2 Causal Mask(因果掩码)
解码器在生成第 个 token 时,不能看到未来位置,否则就相当于“作弊”。
因此在解码器的 Self-Attention 中,需要使用 Causal Mask(也叫 Look-Ahead Mask)。
它本质上是一个上三角屏蔽矩阵:
即第 个位置只能看见:
- 自己
- 自己左边的位置
不能看右边尚未生成的位置。
例如长度为 4 时,mask 形状为:
3.4.3 Causal Mask 与 Causal Self-Attention 的区别
这两个不是并列概念。
- Causal Mask:一个掩码矩阵,是实现手段
- Causal Self-Attention:加上了因果掩码的自注意力机制,是完整模块
也就是说:
Tip
Causal Mask 是“工具”,Causal Self-Attention 是“用了这个工具之后的机制”。
3.5 Position-wise Feed Forward Network
每个注意力层后面都会接一个前馈网络(FFN):
原论文中通常取:
也就是说,先升维,再降回去。
它的作用不是处理序列关系,而是对每个位置独立做更强的非线性变换。
Note
Attention 负责“在不同位置之间交换信息”;FFN 负责“对每个位置内部做深加工”。
3.6 Residual Connection 与 LayerNorm
Transformer 很深,如果直接层层堆叠,训练会不稳定。
因此每个子层都使用:
- Residual Connection
- Layer Normalization
原论文写法是:
这样做的好处是:
- 残差连接帮助信息和梯度直接穿过多层
- LayerNorm 稳定每层输入输出的分布
Note
原始 Transformer 使用的是 Post-LN 风格;很多现代 LLM 更常见的是 Pre-LN,即先归一化再进子层。
4. 编码器与解码器的完整结构
4.1 编码器层(Encoder Layer)
每一层结构:
输入
↓
Multi-Head Self-Attention
↓
Add & Norm
↓
Feed Forward
↓
Add & Norm
↓
输出如果写成公式(原论文风格):
编码器一般堆叠 层。
最终输出一串上下文表示,供解码器查询。
4.2 解码器层(Decoder Layer)
每一层结构:
输入
↓
Masked Multi-Head Self-Attention
↓
Add & Norm
↓
Multi-Head Cross-Attention
↓
Add & Norm
↓
Feed Forward
↓
Add & Norm
↓
输出可写成公式:
其中 表示编码器输出。
Tip
解码器比编码器多的那一层,就是 Cross-Attention。
4.3 原始 Transformer 总体流程
源序列
↓
词嵌入 + 位置编码
↓
Encoder × N
↓
编码器输出
↓
Decoder × N
↓
Linear
↓
Softmax
↓
目标词概率分布训练时使用 Teacher Forcing:
- 解码器输入是真实目标序列右移一位
- 目标是预测下一个 token
5. Modern Transformer:为什么大模型多是 Decoder-Only
5.1 Decoder-Only 的结构
现代大语言模型通常只保留下面这个重复模块:
输入 token
↓
词嵌入 + 位置编码
↓
[Causal Self-Attention + FFN] × L
↓
Linear / LM Head
↓
预测下一个 token这里没有:
- 编码器
- Cross-Attention
整个模型只做一件事:
给定前文,预测下一个 token。
5.2 为什么它反而成了主流
原因 1:训练目标统一
只做一个任务:
这比 Encoder-Decoder 的训练框架更直接、更统一。
原因 2:更容易规模化
Decoder-Only 模块更简单,更适合:
- 加深层数
- 增大参数量
- 喂入海量数据
原因 3:Prompt 就能承载任务描述
例如:
把下面句子翻译成英文:
我是中国人。模型直接续写即可,不一定非要显式分成 encoder 和 decoder。
原因 4:In-Context Learning 很强
随着模型规模增大,Decoder-Only 会涌现出很强的 few-shot / zero-shot 能力。
5.3 但 Encoder-Decoder 仍然没有消失
在一些任务中,Encoder-Decoder 依然非常有价值:
| 任务 | 为什么适合 Encoder-Decoder |
|---|---|
| 机器翻译 | 输入输出结构明确,Cross-Attention 对齐很自然 |
| 文本摘要 | 输入长、输出短,先编码再生成很合理 |
| 语音识别 | 音频输入和文本输出是不同模态 |
| 多模态任务 | 图像编码器 + 文本解码器很常见 |
所以并不是 Encoder-Decoder 过时了,而是:
在通用大语言模型这个方向上,Decoder-Only 更容易成为统一范式。
| Causal Self-Attention | 加了 Causal Mask 的 Self-Attention |
| Padding Mask | 用于屏蔽 <pad> 位置 |
| Encoder-Decoder | 原始 Transformer 架构 |
| Decoder-Only | 现代大语言模型主流架构 |
6.4 Transformer 的代价
Transformer 虽然强大,但也有明显代价:
- 注意力矩阵大小为
- 时间和空间复杂度对序列长度通常是二次增长
- 超长上下文时代价很高
这也是后来出现各种改进(FlashAttention、稀疏注意力、线性注意力、KV Cache、MoE 等)的原因之一。
Tip
Transformer 解决了 RNN 的并行性和长距离依赖问题,但也引入了新的瓶颈:注意力的二次复杂度。