共计 2028 个字符,预计需要花费 6 分钟才能阅读完成。
从数学原理理解自注意力机制
自注意力机制的核心是计算查询 (Query) 与键 (Key) 的相似度,然后对值 (Value) 进行加权求和。这个过程可以用以下公式表示:

$$
\text{Attention}(Q, K, V) = \text{softmax}(\frac{QK^T}{\sqrt{d_k}})V
$$
其中 $d_k$ 是 Key 的维度,用于缩放点积结果。当 Query 和 Key 的点积结果越大,经过 softmax 后的权重就越大,表示这两个位置的相关性越强。
注意力评分函数对比
常见的注意力评分函数主要有两种:
- 点积注意力(Dot-Product)
- 优点:计算简单高效,适合 GPU 并行
-
缺点:当维度 $d_k$ 较大时,点积结果可能过大导致 softmax 梯度消失
-
加性注意力(Additive)
- 优点:通过神经网络学习更复杂的相似度关系
- 缺点:计算复杂度更高,需要额外的参数
PyTorch 实现自注意力层
import torch
import torch.nn as nn
import torch.nn.functional as F
class SelfAttention(nn.Module):
def __init__(self, embed_size, heads):
super(SelfAttention, self).__init__()
self.embed_size = embed_size
self.heads = heads
self.head_dim = embed_size // heads
# 线性变换矩阵
self.values = nn.Linear(self.head_dim, self.head_dim, bias=False)
self.keys = nn.Linear(self.head_dim, self.head_dim, bias=False)
self.queries = nn.Linear(self.head_dim, self.head_dim, bias=False)
self.fc_out = nn.Linear(heads * self.head_dim, embed_size)
def forward(self, values, keys, query, mask):
# 输入形状: (N, seq_len, embed_size)
N = query.shape[0]
value_len, key_len, query_len = values.shape[1], keys.shape[1], query.shape[1]
# 分割为多头
values = values.reshape(N, value_len, self.heads, self.head_dim)
keys = keys.reshape(N, key_len, self.heads, self.head_dim)
queries = query.reshape(N, query_len, self.heads, self.head_dim)
# 计算注意力分数
energy = torch.einsum("nqhd,nkhd->nhqk", [queries, keys])
if mask is not None:
energy = energy.masked_fill(mask == 0, float("-1e20"))
# 缩放点积并计算注意力权重
attention = torch.softmax(energy / (self.embed_size ** (1/2)), dim=3)
# 应用注意力权重
out = torch.einsum("nhql,nlhd->nqhd", [attention, values])
out = out.reshape(N, query_len, self.heads * self.head_dim)
# 最终线性变换
out = self.fc_out(out)
return out
高注意力评分带来的问题及解决方案
- 梯度爆炸
- 问题:过高的注意力分数可能导致反向传播时梯度爆炸
-
解决方案:使用缩放点积 (除以 $\sqrt{d_k}$) 和梯度裁剪
-
过度关注局部
- 问题:模型可能过度关注少数高权重位置而忽略全局信息
-
解决方案:引入多头注意力机制,从不同子空间学习特征
-
计算效率
- 问题:全连接注意力计算复杂度为 $O(n^2)$
- 解决方案:使用稀疏注意力或局部注意力模式
生产环境最佳实践
- 批量处理优化
- 使用 padding 和 mask 处理变长序列
-
在数据加载器中设置合理的 batch_size
-
内存效率
- 使用混合精度训练减少显存占用
-
对长序列采用分块计算策略
-
稳定性技巧
- 初始化时适当缩小注意力权重范围
- 使用 LayerNorm 稳定训练过程
思考题
- 如何设计实验验证不同注意力评分函数对模型性能的影响?
- 在处理超长序列时,除了缩放点积,还有哪些方法可以缓解高注意力评分带来的问题?
- 为什么在 Transformer 中多头注意力比单头注意力效果更好?如何确定最佳头数?
通过本文的讲解和代码实现,我们深入理解了自注意力评分与模型效果的关系。在实践中,我们需要平衡注意力评分的强度和多样性,才能让模型学习到更丰富有效的特征表示。
正文完
