【NLP】This Post Is All You Need阅读笔记
一、自注意力机制的动机
传统序列模型的瓶颈
-
RNN的缺陷
- 无法并行计算:必须按顺序处理序列,时间复杂度为O(n),训练速度慢。
- 长距离依赖丢失:随着序列长度增加,远距离词之间的关联难以捕捉(梯度消失)。
-
CNN的局限
- 依赖固定窗口大小,难以建模全局依赖关系。
自注意力的核心思想
- 并行计算:通过矩阵运算同时处理所有词的关系,时间复杂度仍为O(n²),但GPU并行效率极高。
- 全局感知:每个词直接与序列中所有其他词交互,公式如下:
- Attention ( Q , K , V ) = softmax ( Q K T d k ) V \text{Attention}(Q,K,V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V Attention(Q,K,V)=softmax(dkQKT)V
(Q
为查询向量,K
为键向量,V
为值向量,d_k
为维度缩放因子)
二、多头注意力的必要性
单头注意力的问题
- 模式单一:单组注意力可能仅捕捉到一种类型的依赖关系(如句法结构)。
- 过拟合风险:模型可能过度关注某些局部特征(如高频词或自身位置)。
多头注意力的设计
- 拆分与组合
- 将输入向量拆分为
h
个头(例如8头),每个头独立计算注意力。 - 拼接所有头的输出并线性变换为最终结果。
- 将输入向量拆分为
- 优势
- 多样性:不同头学习不同模式(如一个头关注动词-宾语关系,另一个头关注代词指代)。
- 鲁棒性:避免单一注意力机制的偏差。
伪代码示例
# 输入维度: [batch_size, seq_len, d_model]
Q = split_heads(Q, h) # 拆分为h个头 [batch_size, h, seq_len, d_k]
K = split_heads(K, h)
V = split_heads(V, h)
attention_output = scaled_dot_product_attention(Q, K, V) # 每个头独立计算
output = concat_heads(attention_output) # 拼接后线性变换
三、位置编码的作用与设计
为何需要位置编码?
- 自注意力机制本身是置换不变(permutation-invariant)的,无法区分序列顺序。
- 例如:“猫追老鼠”和“老鼠追猫”在无位置编码时会被视为相同。
位置编码方案
-
绝对位置编码(原始Transformer)
- 使用正弦和余弦函数生成位置向量:
PE(pos, 2i) = \sin(pos / 10000^{2i/d_{model}}) PE(pos, 2i+1) = \cos(pos / 10000^{2i/d_{model}})
- 特点:可外推到比训练序列更长的位置。
- 使用正弦和余弦函数生成位置向量:
-
相对位置编码(改进方案)
- 编码词与词之间的相对距离(如相邻词、间隔3个词)。
- 代表工作:Transformer-XL、T5。
四、Decoder的预测与训练差异
训练阶段(Teacher Forcing)
- 输入:完整目标序列(右移一位,如
<START> 我 爱 AI
)。 - 输出:预测序列(
我 爱 AI <END>
)。 - 并行计算:所有位置同时预测,使用掩码遮挡未来信息。
推理阶段(自回归生成)
- 逐步预测:每次生成一个词,将其作为下一时间步的输入。
- 缓存优化:为加速推理,可缓存已计算的Key/Value向量(如GPT的KV Cache)。
掩码实现关键代码
def generate_mask(seq_len):mask = torch.triu(torch.ones(seq_len, seq_len), diagonal=1)mask = mask.masked_fill(mask == 1, float('-inf'))return mask # 下三角为0,上三角为-inf
五、Q/K/V的来源与角色
场景 | Q来源 | K/V来源 | 功能描述 |
---|---|---|---|
Encoder自注意力 | 输入词嵌入 | 输入词嵌入 | 捕捉输入内部依赖关系 |
Decoder自注意力 | 解码器输入 | 解码器输入 | 建模输出序列内部结构 |
Encoder-Decoder交互 | 解码器中间输出 | Encoder最终输出 | 对齐源语言与目标语言 |
六、多层Transformer架构
Encoder堆叠结构
- 核心组件
- 多头自注意力 → 残差连接 + 层归一化 → 前馈网络(FFN) → 残差连接 + 层归一化。
- 层级功能
- 底层:捕捉局部特征(如词性、短语结构)。
- 高层:建模全局语义(如指代消解、逻辑关系)。
Decoder堆叠结构
- 核心组件
- 掩码多头自注意力 → Encoder-Decoder注意力 → 前馈网络(均含残差连接)。
- Memory传递
- 所有Decoder层共享同一组Encoder输出(Memory),确保信息一致性。
七、Transformer中的两类掩码
1. 注意力掩码(Decoder专用)
- 功能:阻止模型访问未来信息。
- 实现:生成上三角矩阵,softmax前将未来位置设为负无穷。
2. Padding掩码(通用)
- 功能:忽略填充符
<PAD>
的影响。 - 实现:将填充位置对应的注意力权重置零。
# 计算注意力权重时应用掩码
attention_scores = torch.matmul(Q, K.transpose(-1, -2)) / sqrt(d_k)
attention_scores += mask # 叠加两种掩码
attention_weights = F.softmax(attention_scores, dim=-1)
八、残差连接(Residual Connection)
问题背景
- 深层神经网络中,梯度反向传播时可能逐层衰减(梯度消失)。
残差连接设计
-
公式
x o u t = Layer ( x i n ) + x i n x_{out} = \text{Layer}(x_{in}) + x_{in} xout=Layer(xin)+xin -
作用
- 梯度直传:允许梯度跳过某些层直接回传,缓解梯度消失。
- 稳定训练:即使深层网络也能有效更新参数。
-
Transformer中的应用
- 每个子层(自注意力、FFN)后均添加残差连接。
- 配合层归一化(LayerNorm)使用,加速收敛。