想象一下你在嘈杂的咖啡厅里和朋友聊天,虽然周围有音乐声、其他人的谈话声,但你的大脑能自动"聚焦"在朋友的语音上——这就是人类注意力的神奇之处。在NLP领域,注意力机制正是模仿这种能力的技术方案。
从数学角度看,注意力机制可以分解为三个核心运算阶段:
用PyTorch实现基础注意力层只需要不到20行代码:
python复制class BasicAttention(nn.Module):
def __init__(self, dim):
super().__init__()
self.scale = dim ** -0.5
def forward(self, Q, K, V):
# Q/K/V shape: [batch, seq_len, dim]
scores = torch.matmul(Q, K.transpose(-2, -1)) * self.scale
weights = torch.softmax(scores, dim=-1)
return torch.matmul(weights, V)
实际应用中我发现几个关键点:
scale系数
传统RNN面临的核心困境是:当前时刻的计算必须等待前一时刻完成,这种串行特性严重限制了计算效率。自注意力机制的突破性在于:
Transformer中的自注意力具体实现包含以下创新点:
每个输入向量会生成三种衍生表示:
这种分离设计让模型可以灵活控制信息流动。在我的实验中,调整Q/K/V的维度比例会显著影响模型性能。
由于自注意力本身不具备位置感知能力,Transformer采用正弦位置编码:
python复制class PositionalEncoding(nn.Module):
def __init__(self, d_model, max_len=5000):
pe = torch.zeros(max_len, d_model)
position = torch.arange(0, max_len).unsqueeze(1)
div_term = torch.exp(torch.arange(0, d_model, 2) * -(math.log(10000.0) / d_model))
pe[:, 0::2] = torch.sin(position * div_term)
pe[:, 1::2] = torch.cos(position * div_term)
self.register_buffer('pe', pe)
def forward(self, x):
return x + self.pe[:x.size(1)]
有趣的是,在图像分类任务中,我发现可学习的位置编码有时比固定编码效果更好,这可能是因为图像patch的相对位置关系比文本更复杂。
单一注意力头就像只用一种颜色的荧光笔标记文本,而多头注意力相当于使用多色荧光笔同时标注不同层面的重点。具体实现时:
PyTorch实现核心代码:
python复制class MultiHeadAttention(nn.Module):
def __init__(self, d_model, num_heads):
self.head_dim = 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)
def forward(self, Q, K, V, mask=None):
# 投影到多头空间
Q = self.W_q(Q).view(batch_size, -1, num_heads, self.head_dim)
K = self.W_k(K).view(batch_size, -1, num_heads, self.head_dim)
V = self.W_v(V).view(batch_size, -1, num_heads, self.head_dim)
# 各头独立计算注意力
scores = torch.einsum('bqhd,bkhd->bhqk', [Q, K]) / math.sqrt(self.head_dim)
if mask is not None:
scores = scores.masked_fill(mask == 0, -1e9)
weights = torch.softmax(scores, dim=-1)
output = torch.einsum('bhqk,bkhd->bqhd', [weights, V])
# 合并多头输出
return self.W_o(output.contiguous().view(batch_size, -1, d_model))
在文本分类任务中,通过可视化不同注意力头,我发现:
Transformer的编解码器交互通过注意力实现特殊的信息流动:
在机器翻译任务中,这种机制表现出三个典型模式:
经过多个项目的实践验证,这些技巧特别有效:
python复制# 典型的Transformer训练循环片段
optimizer = Adam(model.parameters(), lr=1e-4, betas=(0.9, 0.98))
scheduler = get_linear_schedule_with_warmup(optimizer, 4000, 100000)
scaler = GradScaler()
for batch in dataloader:
with autocast():
outputs = model(batch.src, batch.trg)
loss = label_smoothed_cross_entropy(outputs, batch.labels)
scaler.scale(loss).backward()
scaler.unscale_(optimizer)
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
scaler.step(optimizer)
scaler.update()
scheduler.step()
在部署阶段,模型量化能将模型尺寸压缩75%而精度损失不到1%。特别是在边缘设备上,使用TensorRT等工具进行图优化可以进一步提升推理速度。