NLP学习笔记09:注意力机制——从 Self-Attention 到 Transformer
NLP学习笔记09:注意力机制——从 Self-Attention 到 Transformer
作者:Ye Shun
日期:2026-04-18
一、前言
注意力机制(Attention Mechanism)是现代深度学习,尤其是自然语言处理中的核心技术之一。它的灵感来自人类的认知过程:当我们阅读一句话时,并不会平均地处理每一个词,而是会把更多注意力放在当前最相关的部分。
例如在阅读句子:
猫坐在垫子上,因为它很舒服。
理解“它”指代什么时,人不会机械地平均看待所有词,而会自动把注意力集中到与“它”最相关的候选对象上。注意力机制希望让模型也具备这种“动态聚焦”的能力。
它的核心思想可以概括为一句话:
根据输入中不同部分对当前任务的重要性,动态分配不同权重。
这套思想已经成为 Transformer、BERT、GPT、T5 等模型的基础。理解注意力机制,几乎就是理解现代 NLP 的关键起点。
这篇笔记将围绕以下几个问题展开:
- 注意力机制到底在解决什么问题
- Query、Key、Value 分别是什么意思
- 自注意力和多头注意力是怎么工作的
- 注意力机制为什么能推动 Transformer 崛起
- 实践中如何实现和可视化注意力
二、为什么需要注意力机制
在注意力机制出现之前,处理序列数据的主力模型主要是 RNN、LSTM 和 GRU。它们虽然能处理上下文,但存在一些明显局限。
1. 长距离依赖难题
在长序列中,前后信息相距很远时,RNN 系列模型往往难以稳定捕捉这种依赖。即便 LSTM 和 GRU 已经缓解了问题,也并没有彻底解决。
2. 顺序计算限制
RNN 在时间步之间存在强依赖,因此很难像普通矩阵运算那样充分并行。训练长序列时,效率容易受到影响。
3. 信息压缩瓶颈
在早期 Seq2Seq 模型中,编码器通常需要把整个源句压缩成一个固定长度向量,再交给解码器。这个单一向量很容易丢失细节,尤其是在长句子上。
4. 注意力给出的改进思路
注意力机制的关键改进是:
- 不要求把所有信息压缩成一个固定向量
- 在每一步都能动态查看输入中的不同位置
- 根据当前任务重点重新分配权重
也就是说,模型在做决策时,不再只依赖“一个总摘要”,而是可以“回头查看原文中最相关的部分”。
三、注意力机制的基本概念
注意力机制最经典的数学形式是:
Attention(Q, K, V) = softmax(QK^T / √d_k) V这是缩放点积注意力(Scaled Dot-Product Attention)的表达式。
1. Q、K、V 分别是什么
这三个量可以理解为:
Q(Query):当前要查询什么K(Key):每个位置提供的“索引”或“匹配依据”V(Value):每个位置真正携带的信息
可以把它类比成数据库检索:
- Query 是检索请求
- Key 是检索键
- Value 是对应的数据内容
模型会先用Q和所有K做匹配,算出“当前应该关注谁”;再用这些权重对所有V加权求和,得到最终输出。
2. 为什么要除以√d_k
如果向量维度很大,QK^T的点积值容易变得很大,导致softmax之后分布过于尖锐,训练不稳定。
所以引入缩放项√d_k,让数值范围更平衡,梯度更稳定。
3. softmax 的作用
softmax会把匹配分数转换成一组和为 1 的权重,表示模型对不同位置的关注比例。
这就意味着:
- 权重越大,说明模型越关注那个位置
- 权重越小,说明那个位置对当前计算贡献较少
四、自注意力机制(Self-Attention)
自注意力(Self-Attention)是注意力机制中最关键的一种形式。它的特点是:
序列中的每个位置,都可以和序列中的所有其他位置建立联系。
也就是说,在自注意力中:
- Query 来自输入序列本身
- Key 来自输入序列本身
- Value 也来自输入序列本身
1. 工作流程
对于一个输入序列中的某个位置,自注意力通常按以下步骤工作:
- 计算当前词和所有词之间的相关性分数
- 对分数做 softmax,得到注意力权重
- 用这些权重对所有 Value 做加权求和
- 得到当前词新的上下文表示
2. 一个简化示例
importtorchimporttorch.nn.functionalasFdefself_attention(query,key,value):scores=torch.matmul(query,key.transpose(-2,-1))/(query.size(-1)**0.5)weights=F.softmax(scores,dim=-1)returntorch.matmul(weights,value)3. 自注意力的优势
全局上下文感知
每个位置都能直接访问整个序列中的所有位置,而不像 RNN 那样必须逐步传递信息。
更适合并行计算
自注意力可以把一个序列中所有位置的相关性计算写成矩阵乘法,因此更适合现代 GPU 并行计算。
需要特别说明的是:
- 它“更容易并行”
- 但不代表它在序列长度上的复杂度更低
标准自注意力在序列长度为n时,时间和内存开销通常是O(n^2)。这是它和 RNN 很不一样、也很重要的一个点。
更强的长距离建模能力
两个相距很远的词之间,也可以通过一次注意力计算直接建立联系,而不需要跨越很多时间步传递。
4. 自注意力的一个限制
自注意力本身并不天然编码位置信息。换句话说,如果不额外加入位置编码,它并不知道“哪个词在前,哪个词在后”。
所以在 Transformer 中,自注意力通常要配合位置编码(Positional Encoding)一起使用。
五、多头注意力(Multi-Head Attention)
单头注意力虽然已经很强,但模型在一次注意力计算中,可能只学到某一种关系模式。多头注意力(Multi-Head Attention)就是为了解决这个问题。
它的核心思想是:
把注意力机制并行做很多次,让不同的头去关注不同类型的关系。
1. 多头注意力的结构
多头注意力通常包括:
- 多组独立的
Q、K、V线性变换 - 多个并行注意力头
- 拼接多个头的输出
- 再通过一个线性层映射回原维度
2. 为什么多头更强
不同注意力头可能学习到不同模式,例如:
- 一个头关注主谓关系
- 一个头关注长距离依赖
- 一个头关注局部词组搭配
- 一个头关注指代消解
这会显著增强模型的表达能力。
3. 多头注意力示例
importtorchimporttorch.nnasnnimporttorch.nn.functionalasFclassMultiHeadAttention(nn.Module):def__init__(self,d_model,num_heads):super().__init__()self.d_model=d_model self.num_heads=num_heads self.d_k=d_model//num_heads self.W_q=nn.Linear(d_model,d_model)self.W_k=nn.Linear(d_model,d_model)self.W_v=nn.Linear(d_model,d_model)self.W_o=nn.Linear(d_model,d_model)defforward(self,query,key,value):batch_size=query.size(0)Q=self.W_q(query).view(batch_size,-1,self.num_heads,self.d_k).transpose(1,2)K=self.W_k(key).view(batch_size,-1,self.num_heads,self.d_k).transpose(1,2)V=self.W_v(value).view(batch_size,-1,self.num_heads,self.d_k).transpose(1,2)scores=torch.matmul(Q,K.transpose(-2,-1))/(self.d_k**0.5)weights=F.softmax(scores,dim=-1)output=torch.matmul(weights,V)output=output.transpose(1,2).contiguous().view(batch_size,-1,self.d_model)returnself.W_o(output)六、注意力机制在 NLP 中的应用
注意力机制已经成为现代 NLP 系统的核心组件,尤其在 Transformer 架构中几乎无处不在。
1. 机器翻译
在经典的 Seq2Seq with Attention 中,解码器在生成每个目标词时,不再只依赖固定长度的编码向量,而是动态关注源句中最相关的部分。
这显著改善了长句翻译质量。
2. 文本摘要
摘要模型需要识别原文中的关键信息。注意力机制可以帮助模型聚焦核心句子或核心片段,提高摘要生成质量。
3. 问答系统
问答任务中,经常需要计算“问题”和“文档”之间的对应关系。交叉注意力(Cross-Attention)可以帮助模型找到最相关的证据片段。
4. 语言模型
GPT 系列模型使用掩码自注意力(Masked Self-Attention),保证每个位置只能看到它前面的内容,从而实现自回归生成。
5. 表示学习模型
BERT 使用双向自注意力,可以同时利用左右上下文,因此在文本理解任务中表现非常强。
七、BERT 中的注意力
BERT 是注意力机制应用得最典型的模型之一。它本质上是由多层 Transformer Encoder 堆叠而成。
1. BERT 的关键特点
- 使用双向自注意力
- 每层都有多头注意力
- 通过多层堆叠不断增强上下文表示
2. 如何获取注意力权重
在 Hugging Face 中,如果想拿到 BERT 的注意力权重,一般要显式设置output_attentions=True:
fromtransformersimportBertModel,BertTokenizer tokenizer=BertTokenizer.from_pretrained("bert-base-uncased")model=BertModel.from_pretrained("bert-base-uncased")inputs=tokenizer("Hello, my dog is cute",return_tensors="pt")outputs=model(**inputs,output_attentions=True)attention=outputs.attentions这样outputs.attentions中才会包含各层、各头的注意力权重。
八、注意力机制的常见变体
随着序列越来越长、任务越来越复杂,研究者提出了很多注意力机制的变体。
1. 缩放点积注意力
这是 Transformer 中最经典的版本:
- 使用点积计算相似度
- 用
√d_k缩放 - 计算效率高
2. 加法注意力(Additive Attention)
这是更早期的一种注意力形式,常见于 Bahdanau Attention。它通过一个小型前馈网络来计算 Query 和 Key 的兼容性。
相比点积注意力:
- 计算更灵活
- 在低维场景下有时更稳定
- 但效率通常不如点积注意力
3. 局部注意力(Local Attention)
局部注意力只关注输入的一部分,而不是整段序列。这样可以显著减少计算成本。
4. 稀疏注意力(Sparse Attention)
稀疏注意力不会让每个位置都和所有位置建立连接,而是只计算部分位置之间的注意力。例如 Longformer 中的滑动窗口注意力。
这类方法的目标都是一样的:
在尽量保留建模能力的同时,降低标准自注意力的二次复杂度开销。
九、实践练习建议
练习1:实现基础注意力机制
可以先写一个最简单的 attention 模块,输入一组隐藏状态,输出上下文向量和注意力权重:
importtorchimporttorch.nnasnnimporttorch.nn.functionalasFclassSimpleAttention(nn.Module):def__init__(self,hidden_size):super().__init__()self.attention=nn.Linear(hidden_size,1)defforward(self,encoder_outputs):attention_scores=self.attention(encoder_outputs).squeeze(2)attention_weights=F.softmax(attention_scores,dim=1)context_vector=torch.bmm(attention_weights.unsqueeze(1),encoder_outputs)returncontext_vector.squeeze(1),attention_weights这个练习很适合帮助理解:
- 注意力分数是怎么来的
- 权重是如何归一化的
- 上下文向量是如何加权求和得到的
练习2:可视化注意力权重
如果把注意力权重画成热力图,会更直观地看到模型到底在关注什么。
importmatplotlib.pyplotaspltimportseabornassnsdefplot_attention(attention_weights,source_tokens,target_tokens):plt.figure(figsize=(10,8))sns.heatmap(attention_weights,xticklabels=source_tokens,yticklabels=target_tokens,cmap="YlGnBu")plt.xlabel("Source Tokens")plt.ylabel("Target Tokens")plt.title("Attention Weights Visualization")plt.show()这个练习对理解机器翻译和 Transformer 非常有帮助。
十、学习建议
如果你想真正把注意力机制学透,我建议按下面的顺序来:
- 先理解最基本的加权求和思想
- 再理解 Query、Key、Value 的角色分工
- 然后理解自注意力和多头注意力
- 接着理解注意力如何进入 Transformer
- 最后再去看 BERT、GPT、T5 等大模型
这样更容易把“公式、结构和应用”串起来。
十一、总结
注意力机制的本质,是让模型在处理输入时,不必平均看待所有信息,而是能够根据当前任务动态聚焦最相关的部分。
从方法角度看:
- 注意力机制解决了固定向量瓶颈问题
- 自注意力让序列中任意位置都能直接交互
- 多头注意力让模型可以并行学习多种关系模式
从应用角度看:
- 它推动了机器翻译、问答、摘要、语言模型等任务的发展
- 它也是 Transformer、BERT、GPT 等现代模型的核心基础
理解注意力机制之后,再去看 Transformer,就会更容易明白为什么现代 NLP 会从 RNN 时代走向自注意力时代。
