共计 2736 个字符,预计需要花费 7 分钟才能阅读完成。
自注意力机制 (Attention) 入门指南:从数学原理到 PyTorch 实现
自注意力机制是 Transformer 架构的核心组件,它让模型能够动态地关注输入序列中不同位置的信息。下面我们从原理到实现逐步拆解这个看似复杂的机制。

一、自注意力机制的数学原理
1. Query/Key/Value 三矩阵图解
想象你在图书馆找资料:
- Query:你的问题(” 我想找关于深度学习的书 ”)
- Key:书籍的索引标签(书名 / 分类)
- Value:书籍的实际内容
数学上这三个矩阵的关系是:
\text{Attention}(Q,K,V) = \text{softmax}(\frac{QK^T}{\sqrt{d_k}})V
其中:
– Q ∈ R^{n×d_k}:查询矩阵
– K ∈ R^{m×d_k}:键矩阵
– V ∈ R^{m×d_v}:值矩阵
– d_k:键向量的维度
2. 计算过程逐步分解
- 相似度计算:QK^T 得到注意力分数矩阵
- 缩放处理:除以√d_k 防止梯度消失
- 归一化:softmax 得到注意力权重
- 加权求和:权重与 V 相乘得到输出
具体推导示例:
\begin{aligned}
&\text{设} Q = \begin{bmatrix}1\\2\end{bmatrix}, K = \begin{bmatrix}0.5\\1.5\end{bmatrix}, V = \begin{bmatrix}10\\20\end{bmatrix}, d_k=1 \\
&\text{步骤 1:} QK^T = \begin{bmatrix}0.5&1.5\\1&3\end{bmatrix} \\
&\text{步骤 2:} \frac{QK^T}{\sqrt{1}} = \begin{bmatrix}0.5&1.5\\1&3\end{bmatrix} \\
&\text{步骤 3:} \text{softmax}(\begin{bmatrix}0.5&1.5\\1&3\end{bmatrix}) ≈ \begin{bmatrix}0.27&0.73\\0.12&0.88\end{bmatrix} \\
&\text{步骤 4:} \begin{bmatrix}0.27&0.73\\0.12&0.88\end{bmatrix} \begin{bmatrix}10\\20\end{bmatrix} = \begin{bmatrix}17.3\\18.8\end{bmatrix}
\end{aligned}
3. 多头注意力的优势
就像有多组专家同时从不同角度分析问题:
- 每组注意力头学习不同的关注模式
- 并行计算提高效率
- 最终拼接所有头的输出获得更丰富的表示
二、PyTorch 实现详解
1. 单头注意力实现
import torch
import torch.nn as nn
import torch.nn.functional as F
class SingleHeadAttention(nn.Module):
def __init__(self, d_model, d_k):
super().__init__()
self.W_q = nn.Linear(d_model, d_k) # [d_model, d_k]
self.W_k = nn.Linear(d_model, d_k) # [d_model, d_k]
self.W_v = nn.Linear(d_model, d_k) # [d_model, d_k]
def forward(self, x, mask=None):
# x: [batch, seq_len, d_model]
Q = self.W_q(x) # [batch, seq_len, d_k]
K = self.W_k(x) # [batch, seq_len, d_k]
V = self.W_v(x) # [batch, seq_len, d_k]
scores = torch.matmul(Q, K.transpose(-2, -1)) / torch.sqrt(torch.tensor(K.size(-1)))
# scores: [batch, seq_len, seq_len]
if mask is not None:
scores = scores.masked_fill(mask == 0, -1e9)
attn_weights = F.softmax(scores, dim=-1)
output = torch.matmul(attn_weights, V) # [batch, seq_len, d_k]
return output
2. Masked Attention 实现技巧
在解码器中需要防止看到未来信息:
# 创建下三角掩码矩阵
seq_len = 10
mask = torch.tril(torch.ones(seq_len, seq_len)) # [seq_len, seq_len]
# 应用示例
attn = SingleHeadAttention(d_model=512, d_k=64)
output = attn(x, mask=mask) # x: [batch, 10, 512]
三、工程实践中的避坑指南
1. 梯度消失问题
- 当 d_k 较大时,QK^T 的值可能非常大
- 导致 softmax 进入梯度饱和区
- 缩放因子√d_k 保持梯度稳定
2. 内存优化方案
对于长序列(如 >512 tokens):
- 分块计算:将序列拆分为多个块处理
- 稀疏注意力:只计算局部位置的注意力
- 内存高效实现:使用 FlashAttention 等优化
四、动手实验:温度系数的影响
调节 softmax 温度系数观察注意力分布变化:
def visualize_attention(temperature):
# 随机生成注意力分数
scores = torch.randn(5, 5) # [seq_len, seq_len]
# 应用不同温度系数的 softmax
attn = F.softmax(scores/temperature, dim=-1)
# 可视化
plt.matshow(attn.detach().numpy())
plt.title(f"Temperature={temperature}")
plt.colorbar()
plt.show()
# 实验对比
temperatures = [0.1, 1.0, 10.0]
for temp in temperatures:
visualize_attention(temp)
预期现象:
– 低温(0.1):注意力更集中(接近 one-hot)
– 常温(1.0):合理分布
– 高温(10.0):接近均匀分布
通过这个实验可以直观理解温度系数如何影响模型的关注模式。
五、总结与下一步
掌握自注意力机制需要注意:
- 理解 QKV 的物理意义比死记公式更重要
- 实际实现时多检查矩阵维度
- 长序列场景需要考虑计算效率优化
建议下一步:
1. 尝试实现完整的 Transformer 层
2. 在不同任务上观察注意力权重的实际分布
3. 研究相对位置编码等改进方案
希望这篇文章能帮你揭开自注意力机制的神秘面纱!
正文完
发表至: 深度学习
近一天内
