在自然语言处理领域,Transformer架构的出现无疑是一次里程碑式的革命。作为一名NLP技术研究者,我在学习Transformer的过程中深刻体会到,理解其核心机制——注意力机制,是掌握现代大语言模型的关键。本文将带你深入理解Transformer的注意力机制,并结合代码实现,分享我的学习心得。
一、从传统神经网络到注意力机制
在深入注意力机制之前,我们先回顾深度学习的三大基础架构:
1. 全连接神经网络(FNN)
- 每层神经元完全连接上下层
- 参数量大,适合小规模数据

个人体会:就像认识新朋友时,试图记住每个人的所有细节
2. 卷积神经网络(CNN)
- 局部连接,参数共享
- 擅长捕捉局部特征

学习心得:如同先认识局部特征,再组合成整体认知
3. 循环神经网络(RNN)
- 专为序列数据设计
- 能捕捉时序信息

核心问题:无法并行计算,难以捕捉长距离依赖
二、注意力机制:Transformer
2.1 注意力机制的核心思想
我的理解:当我们阅读文章时,不会平等关注每个词,而是聚焦于关键信息
技术定义:通过计算Query与Key的相关性,为Value加权求和
三个核心变量:
-
Query(查询):我们要寻找什么
-
Key(键):我们能提供什么
-
Value(值):实际返回的内容
2.2 从字典查询到注意力计算
通过一个例子理解注意力机制:
# 传统字典查询(精确匹配)
dictionary = {"apple": 10, "banana": 5, "chair": 2}
query = "apple"
result = dictionary[query] # 返回10
# 但如果我们查询"fruit"呢?
# 注意力机制给出了解决方案:
attention_weights = {"apple": 0.6, "banana": 0.4, "chair": 0}
result = 0.6*10 + 0.4*5 + 0*2 # 返回8
从直观上讲,我们可以认为 Key 与 Query 相关性越高,则其所应该赋予的注意力权重就越大。
2.3 注意力计算公式推导
基础公式:
Attention(Q, K, V) = softmax(QKᵀ/√dₖ)V
-
相似度计算:
QKᵀ计算Query和Key的相似度 -
缩放处理:除以
√dₖ防止梯度消失 -
归一化:
softmax转换为概率分布 -
加权求和:与Value相乘得到最终结果
代码实现:
def attention(query, key, value, dropout=None):
d_k = query.size(-1)
# 计算相似度得分
scores = torch.matmul(query, key.transpose(-2, -1)) / math.sqrt(d_k)
# Softmax归一化
p_attn = scores.softmax(dim=-1)
if dropout is not None:
p_attn = dropout(p_attn)
# 加权求和
return torch.matmul(p_attn, value), p_attn
心得:在实现时要注意矩阵维度的匹配,特别是转置操作的位置。
三、自注意力
3.1 自注意力 vs 普通注意力
普通注意力:
-
Q来自一个序列,K、V来自另一个序列
-
用于机器翻译等跨序列任务
自注意力:
-
Q、K、V都来自同一个序列
-
用于理解序列内部关系
# 自注意力计算
self_attention_output = attention(x, x, x)
3.2 自注意力的价值
实际案例:分析句子"I like programming because it is challenging"
通过自注意力,模型可以学习到:
-
"programming"与"challenging"的强关联
-
"it"指代"programming"
-
"because"表达的因果关系
个人体会:自注意力让模型能够建立词与词之间的关系图谱,而不仅仅是序列关系。
四、掩码自注意力
4.1 为什么需要掩码?
语言模型任务:根据历史词预测下一个词
问题:如果模型能看到未来信息,就失去了学习意义
解决方案:使用掩码遮蔽未来信息
4.2 掩码实现原理
掩码矩阵生成:
# 创建上三角掩码矩阵
mask = torch.full((1, seq_len, seq_len), float("-inf"))
mask = torch.triu(mask, diagonal=1) # 上三角部分为-inf
掩码应用:
scores = scores + mask # 未来位置分数变为-inf
scores = softmax(scores) # -inf经过softmax变为0
可视化理解:
输入序列: [A, B, C, D]
掩码矩阵:
[0, -inf, -inf, -inf]
[0, 0, -inf, -inf]
[0, 0, 0, -inf]
[0, 0, 0, 0]
心得:掩码机制是Transformer能够并行训练的关键,也是理解GPT等自回归模型的基础。
五、多头注意力
5.1 多头注意力的动机
核心思想:单一注意力头可能只捕捉一种关系,多个头可以捕捉多种关系
类比理解:就像多人阅读同一篇文章,每个人关注的重点不同,综合起来得到更全面的理解
5. 多头注意力实现
公式表达:
MultiHead(Q,K,V) = Concat(head₁,...,headₕ)Wᵒ
where headᵢ = Attention(QWᵢᵩ, KWᵢᴷ, VWᵢⱽ)
代码实现:
class MultiHeadAttention(nn.Module):
def __init__(self, args):
super().__init__()
self.n_heads = args.n_heads
self.head_dim = args.dim // args.n_heads
# 参数矩阵
self.wq = nn.Linear(args.n_embd, self.n_heads * self.head_dim)
self.wk = nn.Linear(args.n_embd, self.n_heads * self.head_dim)
self.wv = nn.Linear(args.n_embd, self.n_heads * self.head_dim)
self.wo = nn.Linear(self.n_heads * self.head_dim, args.dim)
def forward(self, q, k, v):
# 拆分多头
xq = xq.view(bsz, seqlen, self.n_heads, self.head_dim)
xq = xq.transpose(1, 2) # (B, n_heads, T, head_dim)
# 各头分别计算注意力
scores = torch.matmul(xq, xk.transpose(2, 3)) / math.sqrt(self.head_dim)
# ... 后续计算
5.3 多头注意力的优势
-
不同注意力头确实学习到不同模式
-
有的头关注语法结构,有的头关注语义关系
-
有的头捕捉局部依赖,有的头捕捉长距离依赖
心得:在文本分类任务中,通过可视化注意力权重,发现不同头确实关注文本的不同方面,这验证了多头设计的有效性。
六、学习心得
通过系统学习Transformer的注意力机制,我深刻认识到:注意力机制的本质是对信息的选择性聚焦,这模仿了人类的认知过程。自注意力让模型能够建立词与词之间的直接连接,突破了RNN的序列限制。掩码机制解决了训练并行性与因果关系的矛盾。多头设计提供了多角度理解文本的能力,增强了模型的表达能力。
个人感悟:学习注意力机制就像学习一种新的思维方式——不再局限于线性的、顺序的思考,而是能够建立全局的、网络化的认知。这种思维方式的转变。
资料来源:Happy-LLM
希望这份结合理论知识与个人心得的指南,能帮助你在NLP的学习道路上少走弯路。欢迎在评论区交流你的学习体会和遇到的问题!

被折叠的 条评论
为什么被折叠?



