一、Self-Attention:Transformer的基石

说实话,我第一次接触Self-Attention时,脑子里就一个想法:这玩意儿凭什么能取代RNN?后来在项目中踩了不少坑,才慢慢理解它的精妙之处。今天咱们就来聊聊这个改变了NLP格局的核心机制。

1.1 Self-Attention的定义与计算流程

Self-Attention,说白了就是让序列中的每个位置都能“关注”到其他所有位置。我习惯把它理解成一种“全局信息聚合器”。

计算流程其实就三步:

  1. 生成Q、K、V:每个输入向量通过三个不同的线性变换,得到Query、Key、Value
  2. 计算注意力分数:Q与所有K做点积,再除以√d_k做缩放
  3. 加权求和:softmax归一化后,对V做加权平均

公式长这样:

Attention(Q, K, V) = softmax(QK^T / √d_k) V

嗯,这里有个细节要注意——为什么要除以√d_k?我在项目中曾经忽略了这个缩放因子,结果训练直接炸了。因为当d_k很大时,点积的值会变得非常大,softmax的梯度会趋近于0。说白了就是防止梯度消失。

核心要点:Self-Attention的计算复杂度是O(n²·d),n是序列长度。这意味着长序列场景下,计算量会爆炸式增长。这也是后来各种优化方法的出发点。

1.2 多头注意力机制(Multi-Head Attention)

你想想看,单头注意力只能捕捉一种关系模式。但实际文本中,词与词之间的关系是多元的——比如语法关系、语义关系、指代关系等等。

多头注意力就是解决这个问题的。它把Q、K、V拆成h份,每份独立做注意力计算,最后再拼起来。我习惯用8个头,这是Transformer论文里的经典配置。

MultiHead(Q, K, V) = Concat(head₁, ..., headₕ) W_O
其中 headᵢ = Attention(QW_Qᵢ, KW_Kᵢ, VW_Vᵢ)

我的经验:头数不是越多越好。我曾经试过32个头,结果模型反而变差了。一般来说,8-16个头是个安全区间。每个头的维度建议在64-128之间。

多头注意力的好处很明显:

  • 每个头可以学到不同的注意力模式
  • 计算可以并行,效率高
  • 模型容量更大,表达能力更强

1.3 位置编码(Positional Encoding)的必要性

这里有个关键问题:Self-Attention本身是置换不变的。什么意思?就是你把输入顺序打乱,输出结果完全一样。但语言是有顺序的——"我打你"和"你打我"意思完全不同。

所以我们需要给模型注入位置信息。Transformer用的是正弦余弦位置编码:

PE(pos, 2i) = sin(pos / 10000^(2i/d_model))
PE(pos, 2i+1) = cos(pos / 10000^(2i/d_model))

为什么选这个?我个人的理解是:

  • 正弦余弦函数的值域在[-1, 1],不会引入数值问题
  • 不同频率的组合可以编码不同粒度的位置关系
  • 可以外推到更长的序列(虽然效果会打折扣)

避坑指南:我曾经在项目中直接用可学习的位置编码,结果训练到一半发现序列长度变了,位置编码矩阵得重新初始化,导致模型需要重新训练。如果你不确定序列长度是否固定,建议用正弦余弦编码。

1.4 Transformer Encoder-Decoder架构概览

Transformer的整体架构,说白了就是Encoder吃输入,Decoder吐输出,中间通过Cross-Attention连接。

我画了一张图,帮你理清整体脉络:

Encoder Multi-Head Self-Attention Add & LayerNorm Feed Forward (两层线性 + ReLU) Add & LayerNorm Decoder Masked Multi-Head Self-Attention Add & LayerNorm Cross-Attention (Q来自Decoder, K/V来自Encoder) Add & LayerNorm Feed Forward K, V 输入序列 输出序列(自回归)

这张图里,Encoder和Decoder各自堆叠了N层(论文里N=6)。Decoder里有个关键设计——Masked Self-Attention,它确保当前位置只能看到之前的位置,不能偷看未来的信息。这在生成任务中至关重要。

架构要点总结

  • Encoder:双向上下文,适合理解任务(如分类、NER)
  • Decoder:单向上下文,适合生成任务(如翻译、摘要)
  • Cross-Attention:连接Encoder和Decoder的桥梁
  • 每个子层都有残差连接和LayerNorm,这是训练稳定的关键

我记得第一次自己实现Transformer时,在Cross-Attention的维度匹配上卡了整整两天。Q的维度来自Decoder,K和V的维度来自Encoder,这三者的维度必须对齐。如果你也遇到维度不匹配的错误,先检查这里。

实用建议:刚开始学Transformer时,我建议你先从单层Encoder开始实现,跑通一个简单的分类任务。等理解了Self-Attention的输入输出形状变化,再扩展到完整的Encoder-Decoder架构。一步到位容易把自己绕晕。

好了,这一章的内容就到这里。Self-Attention和Transformer的基石已经打好了,后面的章节我们会深入各种优化技巧——稀疏注意力、线性注意力、Flash Attention等等。这些都是在实际项目中真正能帮你省显存、提速度的硬核技术。

专注资料整理