共计 1607 个字符,预计需要花费 5 分钟才能阅读完成。
背景:传统序列模型的局限性
在自然语言处理领域,传统的 RNN 和 LSTM 模型长期占据主导地位。但它们存在两个致命缺陷:
- 顺序计算限制:必须逐个处理序列中的元素,难以并行化。处理长文本时,计算效率低下。
- 长程依赖丢失:随着时间步增加,早期输入信息会逐渐衰减(梯度消失问题)。即使 LSTM 有所改善,超过 100 个时间步后仍会丢失关键上下文。
Transformer 架构革命
2017 年提出的 Transformer 架构彻底改变了这一局面。其核心设计思想是:
- 完全基于注意力机制:摒弃循环结构,通过自注意力全局建模关系
- 并行化处理:所有位置同时计算,极大提升训练速度
- 层次化表示:通过多层堆叠逐步抽象不同粒度的特征
(图示:Encoder-Decoder 结构,含多头注意力和前馈网络)
自注意力机制详解
数学本质
自注意力通过三个核心向量计算关联度:
Attention(Q,K,V)=softmax(\frac{QK^T}{\sqrt{d_k}})V
- Query(Q):当前关注的词向量
- Key(K):被比较的候选词向量
- Value(V):实际传递信息的词向量
计算步骤拆解
- 线性投影:将输入嵌入转换为 Q /K/ V 三个空间
q = torch.matmul(x, W_q) # [batch, seq_len, d_model] - 相似度打分:计算 Q 与所有 K 的点积并缩放
scores = torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(d_k) - 权重归一化:softmax 转换为概率分布
attn_weights = F.softmax(scores, dim=-1) - 上下文聚合:加权求和 V 向量
context = torch.matmul(attn_weights, v)
完整 PyTorch 实现
import torch
import torch.nn.functional as F
class SelfAttention(torch.nn.Module):
def __init__(self, d_model, d_k):
super().__init__()
self.W_q = torch.nn.Linear(d_model, d_k)
self.W_k = torch.nn.Linear(d_model, d_k)
self.W_v = torch.nn.Linear(d_model, d_k)
def forward(self, x):
# 投影到 Q /K/ V 空间 [batch, seq_len, d_k]
q = self.W_q(x)
k = self.W_k(x)
v = self.W_v(x)
# 计算注意力分数
scores = torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(d_k)
attn_weights = F.softmax(scores, dim=-1)
# 上下文聚合
context = torch.matmul(attn_weights, v)
return context
进阶优化技巧
多头注意力机制
将注意力分散到多个子空间,捕获不同类型的依赖关系:
# 拆分头部分解
q = q.view(batch, seq_len, num_heads, d_k//num_heads).transpose(1,2)
位置编码方案
通过正弦函数注入位置信息:
PE_{(pos,2i)} = sin(pos/10000^{2i/d_{model}})
生产环境陷阱与对策
- 内存爆炸 :长序列的注意力矩阵是 O(n²) 复杂度
- 解决方案:采用稀疏注意力或分块计算
- 训练不稳定:softmax 梯度消失
- 对策:使用 attention dropout 和梯度裁剪
延伸思考
- 自注意力机制如何建模词序之外的更复杂关系(如语法树结构)?
- 在超长文本场景下,有哪些替代方案可以突破 O(n²)计算限制?
- 如何可视化注意力权重以解释模型的决策过程?
通过本文的拆解,相信你已经掌握自注意力机制的核心要义。建议动手修改示例代码中的参数,观察不同维度设置对模型表现的影响。
正文完
发表至: 未分类
近两天内
