从Seq2seq到Attention再到Self Attention:模型演进与深度解析(二)

一、从Seq2seq到Attention:信息瓶颈的突破

1.1 Seq2seq的原始架构与局限性

Seq2seq(Sequence-to-Sequence)模型通过编码器-解码器结构实现序列转换任务(如机器翻译),其核心思想是将输入序列映射为固定维度的上下文向量(Context Vector),再由解码器生成输出序列。然而,固定长度的上下文向量在处理长序列时存在信息丢失问题,尤其在输入与输出序列长度差异较大时(如中英翻译),模型性能显著下降。

示例:长序列翻译的挑战
假设输入为一段包含50个中文词的句子,编码器RNN的最后一个隐藏状态作为上下文向量,需承载所有语义信息。但解码器在生成第20个英文词时,可能已无法有效利用输入序列前部的关键信息(如专有名词或时间状语),导致翻译错误。

1.2 Attention机制的引入:动态权重分配

Attention机制通过为解码器的每个时间步动态计算输入序列的权重分布,解决了固定上下文向量的瓶颈。其核心公式为:
[
ct = \sum{i=1}^{Tx} \alpha{t,i} hi
]
其中,( \alpha
{t,i} )为解码器第( t )步对编码器第( i )个隐藏状态的注意力权重,通过Softmax函数归一化:
[
\alpha{t,i} = \frac{\exp(e{t,i})}{\sum{k=1}^{T_x} \exp(e{t,k})}, \quad e{t,i} = a(s{t-1}, hi)
]
( a(\cdot) )为评分函数(如点积或加性模型),( s
{t-1} )为解码器上一时间步的隐藏状态。

实现步骤

  1. 计算相似度:通过评分函数计算解码器状态与编码器各隐藏状态的相似度。
  2. 归一化权重:使用Softmax生成权重分布。
  3. 加权求和:根据权重聚合编码器隐藏状态,生成动态上下文向量。

优势

  • 长序列处理:动态权重允许模型聚焦于输入序列的相关部分,避免信息压缩损失。
  • 可解释性:注意力权重可视化可直观展示模型关注点(如翻译中“苹果”对应输入的“Apple”)。

二、从Attention到Self Attention:解耦编码器与解码器的依赖

2.1 Self Attention的核心思想

传统Attention机制依赖编码器-解码器交互,而Self Attention(自注意力)在单个序列内部计算注意力权重,使模型能够捕捉序列内元素间的长距离依赖。其公式为:
[
\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V
]
其中,( Q )(Query)、( K )(Key)、( V )(Value)为输入序列的线性变换,( d_k )为维度缩放因子。

为什么需要缩放因子?
点积结果的方差随维度增大而增加,可能导致Softmax梯度消失。缩放因子( \sqrt{d_k} )使点积分布稳定,避免数值不稳定。

2.2 Self Attention的实现细节

步骤1:线性变换
将输入序列( X \in \mathbb{R}^{T \times d} )(( T )为序列长度,( d )为维度)通过三个矩阵( W^Q, W^K, W^V )投影为( Q, K, V ):
[
Q = XW^Q, \quad K = XW^K, \quad V = XW^V
]

步骤2:计算注意力分数
[
S = \frac{QK^T}{\sqrt{d_k}}
]
( S \in \mathbb{R}^{T \times T} ),表示序列中每对元素的相关性。

步骤3:生成权重与输出
[
A = \text{softmax}(S), \quad \text{Output} = AV
]
( A )为注意力权重矩阵,Output为加权后的值向量。

代码示例(PyTorch)

  1. import torch
  2. import torch.nn as nn
  3. class SelfAttention(nn.Module):
  4. def __init__(self, d_model):
  5. super().__init__()
  6. self.d_k = d_model // 8
  7. self.W_q = nn.Linear(d_model, d_model)
  8. self.W_k = nn.Linear(d_model, d_model)
  9. self.W_v = nn.Linear(d_model, d_model)
  10. self.scale = torch.sqrt(torch.tensor(self.d_k, dtype=torch.float32))
  11. def forward(self, x):
  12. Q = self.W_q(x) # (batch_size, seq_len, d_model)
  13. K = self.W_k(x)
  14. V = self.W_v(x)
  15. # 分割多头(简化版,实际需多头并行)
  16. Q = Q.view(Q.size(0), Q.size(1), -1, self.d_k).permute(0, 2, 1, 3)
  17. K = K.view(K.size(0), K.size(1), -1, self.d_k).permute(0, 2, 1, 3)
  18. V = V.view(V.size(0), V.size(1), -1, self.d_k).permute(0, 2, 1, 3)
  19. scores = torch.matmul(Q, K.permute(0, 1, 3, 2)) / self.scale
  20. attn_weights = torch.softmax(scores, dim=-1)
  21. output = torch.matmul(attn_weights, V)
  22. output = output.permute(0, 2, 1, 3).contiguous()
  23. output = output.view(output.size(0), output.size(1), -1)
  24. return output

2.3 Self Attention的优势

  • 并行化:所有位置的计算可并行,突破RNN的时序依赖。
  • 长距离依赖:直接建模序列内任意距离的元素关系,避免梯度消失。
  • 多模态适配:通过Query-Key-Value的解耦设计,可灵活适配不同任务(如文本、图像)。

三、工程实践与性能优化

3.1 多头注意力(Multi-Head Attention)

将输入分割为多个子空间(头),每个头独立计算注意力,最后拼接结果:
[
\text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, \dots, \text{head}_h)W^O
]
其中,( \text{head}_i = \text{Attention}(QW_i^Q, KW_i^K, VW_i^V) )。

优势

  • 模型容量提升:不同头可学习不同模式的依赖(如语法、语义)。
  • 稳定性增强:分散注意力计算,避免单头过拟合。

3.2 位置编码(Positional Encoding)

Self Attention本身是位置无关的,需通过位置编码注入时序信息。常用正弦/余弦函数:
[
PE{(pos, 2i)} = \sin(pos / 10000^{2i/d{\text{model}}}})
]
[
PE{(pos, 2i+1)} = \cos(pos / 10000^{2i/d{\text{model}}}})
]
其中,( pos )为位置,( i )为维度索引。

3.3 性能优化建议

  • 批处理(Batching):合并多个序列的注意力计算,提升GPU利用率。
  • 稀疏注意力:对长序列(如文档),仅计算局部或重要位置的注意力,减少计算量。
  • 混合精度训练:使用FP16加速训练,同时保持FP32的稳定性。

四、总结与展望

从Seq2seq到Attention再到Self Attention,模型设计逐步解耦了序列处理的时序依赖与信息压缩问题。Self Attention凭借其并行化、长距离依赖建模能力,成为Transformer架构的核心,推动了预训练语言模型(如BERT、GPT)的发展。未来,结合稀疏计算、动态路由等技术的改进,将进一步提升模型在长序列、多模态场景下的效率与性能。开发者在实际应用中,需根据任务特点选择合适的注意力变体,并关注工程优化以实现高效部署。