2、Transformer基础回顾:自注意力机制、多头注意力、位置编码、残差连接与层归一化

Transformer架构自2017年由Vaswani等人提出以来,已经成为自然语言处理、计算机视觉乃至多模态学习领域的基石。要深入理解“全额支付”(Full Payment)这一针对注意力机制的改进变体,首先必须牢固掌握原始Transformer的五大核心组件:自注意力机制(Self-Attention)、多头注意力(Multi-Head Attention)、位置编码(Positional Encoding)、残差连接(Residual Connection)与层归一化(Layer Normalization)。本章将从原理推导、数学表达、工程实现与常见误区四个维度,逐一拆解这些组件,为后续学习全额支付变体中的“支付矩阵”与“信用分配”机制奠定坚实的理论基础。

Transformer 核心组件关系与数据流图 输入嵌入 ( Embedding) 位置编码 (Positional Encoding) + 多头注意力 (Multi-Head Attention) Q, K, V 线性投影 → 缩放点积注意力 → 拼接 → 输出投影 核心:注意力权重 = softmax(QK^T / √d_k) 残差连接 (Residual) + 层归一化 前馈网络 (FFN) Linear → ReLU → Linear + 层归一化 输出 → 下一层 / 预测头 图例 残差连接 嵌入/位置 注意力模块 层归一化

上图清晰地展示了Transformer编码器层内部的数据流:输入嵌入与位置编码相加后,依次经过多头注意力子层、残差连接与层归一化,再经过前馈网络子层、残差连接与层归一化,最终输出到下一层。这一“注意力+残差+归一化”的模块化设计,是Transformer能够高效训练深层网络的关键。下面我们逐一深入剖析。

2.1 自注意力机制:从全局依赖到动态权重

2.1.1 核心原理:Query、Key、Value的交互

自注意力机制(Self-Attention)的核心思想是:对于序列中的每一个,通过计算它与序列中所有(包括自身)的相关性,来动态地聚合全局信息。具体而言,输入序列 \( X \in \mathbb{R}^{n \times d_{model}} \)(\( n \) 为序列长度,\( d_{model} \) 为模型维度)会被分别乘以三个可学习的权重矩阵 \( W^Q, W^K, W^V \),得到查询(Query)、键(Key)和值(Value)三个向量集合:

Q = X @ W^Q      # 形状: (n, d_k)
K = X @ W^K      # 形状: (n, d_k)
V = X @ W^V      # 形状: (n, d_v)

其中 \( d_k \) 是Query/Key的维度,\( d_v \) 是Value的维度。注意力权重的计算分为三步:

  1. 缩放点积:计算 \( Q \) 与 \( K \) 的点积,得到相似度矩阵 \( S = QK^T \),并除以 \( \sqrt{d_k} \) 进行缩放,防止点积过大导致Softmax梯度消失。
  2. Softmax归一化:对 \( S \) 的每一行应用Softmax,得到注意力权重矩阵 \( A = \text{softmax}(S) \)。\( A_{ij} \) 表示第 \( i \) 个对第 \( j \) 个的关注程度。
  3. 加权求和:将注意力权重 \( A \) 与 \( V \) 相乘,得到输出 \( \text{Output} = A \cdot V \)。

这一机制的本质是让模型能够根据输入内容自适应地建立之间的依赖关系,无论是短距离的局部依赖还是长距离的全局依赖。

2.1.2 判断方法与操作流程

在实际工程中,判断一个注意力实现是否正确,可以从以下三个维度检查:

  • 维度匹配:\( d_k \) 通常等于 \( d_{model} / h \)(\( h \) 为头数),确保多头拼接后维度一致。
  • 掩码处理:在解码器或因果任务中,需要将 \( S \) 的上三角部分(未来位置)置为 \( -\infty \),再经过Softmax,确保当前位置只能看到过去的信息。
  • 数值稳定性:Softmax前建议先减去每行的最大值(即 \( S - \max(S, \text{dim=-1}) \)),避免指数溢出。
关键公式速查:
Attention(Q, K, V) = softmax(QK^T / √d_k) · V
其中 QK^T 的维度为 (n, n),表示所有两两之间的相似度。

2.1.3 案例拆解:机器翻译中的长距离依赖

以英译中任务为例,输入句子“The animal didn't cross the street because it was too tired.” 在编码阶段,当模型处理代词“it”时,自注意力机制会计算“it”与句子中所有单词的注意力分数。经过训练,模型会学会将较高的注意力权重分配给“animal”(而不是“street”),从而正确理解“it”指代的是“animal”。这一过程完全由数据驱动,无需人工指定指代关系。

2.1.4 常见误区与总结

误区1:认为注意力权重是静态的。实际上,权重完全由当前输入动态计算,不同输入序列会产生不同的注意力分布。
误区2:忽略缩放因子 \( \sqrt{d_k} \)。如果不缩放,当 \( d_k \) 较大时,点积结果方差变大,Softmax会进入饱和区,梯度极小,训练难以收敛。

自注意力机制是Transformer的核心,它用“动态权重”取代了RNN/CNN的“固定连接”,实现了并行计算与全局建模的统一。

2.2 多头注意力:从单一视角到子空间联合建模

2.2.1 核心原理:并行注意力头与特征融合

多头注意力(Multi-Head Attention)将自注意力机制复制 \( h \) 份(通常 \( h=8 \)),每份使用不同的线性投影,从而将输入映射到 \( h \) 个不同的子空间(Subspace)。每个头独立执行注意力计算,最后将 \( h \) 个头的输出拼接(Concat)并经过一个输出投影矩阵 \( W^O \) 融合。其数学表达为:

MultiHead(Q, K, V) = Concat(head_1, ..., head_h) @ W^O
其中 head_i = Attention(Q @ W_i^Q, K @ W_i^K, V @ W_i^V)

多头机制的优势在于:不同的头可以关注不同的关系模式。例如,一个头可能关注语法结构(主谓宾),另一个头可能关注指代关系,第三个头可能关注修辞修饰。这种多视角的建模能力显著增强了模型的表达能力。

2.2.2 操作流程与参数配置

参数 典型值 说明
头数 h 8 / 12 / 16 头数越多,模型关注不同子空间的能力越强,但计算量线性增加
每头维度 d_k 64 通常 d_k = d_model / h,保证拼接后维度不变
d_model 512 / 768 / 1024 模型整体隐藏层维度
输出投影 W^O d_model × d_model 用于融合所有头的输出

在PyTorch中,实现多头注意力通常使用 nn.MultiheadAttention 模块,或者手动将输入拆分为多头后并行计算。工程上需要注意:头的数量必须能够整除 d_model,否则无法完成维度拆分与拼接。

2.2.3 实战场景:BERT中的多头注意力

以BERT-Base为例,其配置为 \( d_{model}=768, h=12, d_k=64 \)。在预训练阶段,12个头分别学习到了不同的语言规律:有的头关注相邻词的关系,有的头关注句法依赖,还有的头关注共指关系。这种“分工合作”的模式使得BERT在下游任务(如情感分类、命名实体识别)中表现优异。

2.2.4 常见误区与总结

误区:盲目增加头数。头数过多会导致每个头的维度太小(如 d_k=16),模型表达能力受限,且训练不稳定。经验法则:d_k 不宜小于 32。

多头注意力通过“分而治之”的策略,让模型在多个子空间中捕捉不同类型的依赖关系,是Transformer性能强大的重要保障。

2.3 位置编码:为并行计算注入序列顺序

2.3.1 核心原理:正弦函数与可学习嵌入

由于自注意力机制本身是“排列不变”的(即打乱输入顺序,输出结果不变),模型无法感知的先后顺序。因此,必须在输入中注入位置信息。原始Transformer使用固定频率的正弦/余弦函数生成位置编码:

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

其中 \( pos \) 是位置索引,\( i \) 是维度索引。这种编码方式具有两个优点:一是值域在 [-1, 1] 之间,利于训练;二是对于任意偏移 \( k \),\( PE(pos+k) \) 可以表示为 \( PE(pos) \) 的线性函数,使得模型更容易学习相对位置关系。

2.3.2 判断方法与替代方案

  • 固定正弦编码:无需训练参数,外推性好(可处理比训练时更长的序列)。
  • 可学习位置嵌入:如BERT直接使用随机初始化的位置矩阵,通过训练学习。优点是灵活,但外推性差。
  • 相对位置编码:如Transformer-XL、T5,在注意力计算时直接加入相对位置偏置,效果更优但实现复杂。
工程建议:对于固定长度任务(如分类),可学习位置嵌入足够;对于长文本生成,推荐使用正弦编码或相对位置编码。

2.3.3 案例拆解:序列长度变化的影响

假设训练时最大序列长度为512,使用可学习位置嵌入。在推理时输入长度为600的文本,由于位置矩阵只有512行,超出部分将报错或需要截断。而使用正弦编码,模型可以外推到任意长度(虽然效果可能略有下降)。这也是系列模型采用可学习位置嵌入但通过训练数据长度控制来规避此问题的原因。

2.3.4 常见误区与总结

误区:将位置编码直接加到输入上,而不是拼接。加法操作会改变原始嵌入的语义空间,但实验证明加法在保持模型容量和计算效率之间取得了最佳平衡。

位置编码是Transformer能够处理序列数据的前提,它弥补了自注意力机制“无序”的缺陷。

2.4 残差连接与层归一化:深层网络的稳定器

2.4.1 核心原理:梯度高速公路与特征重中心化

残差连接(Residual Connection)将子层的输入与输出相加,即 \( \text{Output} = \text{Sublayer}(x) + x \)。这一设计使得梯度可以无损地流过深层网络,有效缓解了梯度消失问题。层归一化(Layer Normalization)则对每个样本的所有特征维度计算均值和方差,并进行归一化:

LayerNorm(x) = γ * (x - μ) / √(σ² + ε) + β

其中 \( \mu \) 和 \( \sigma \) 是每个样本的均值和标准差,\( \gamma \) 和 \( \beta \) 是可学习的缩放和平移参数。与BatchNorm不同,LayerNorm不依赖batch大小,且对序列长度变化不敏感,因此非常适合NLP任务。

2.4.2 操作流程与位置选择

Transformer中残差连接与层归一化的标准顺序为:输入 → 多头注意力 → 残差连接 → 层归一化 → 前馈网络 → 残差连接 → 层归一化。这种“Post-Norm”结构是原始的默认配置。另一种变体“Pre-Norm”(即先归一化再进入子层)在训练时更稳定,但模型表达能力略弱。

结构 顺序 优点 缺点
Post-Norm 子层 → 残差 → 归一化 表达能力更强 深层训练不稳定,需要warmup
Pre-Norm 归一化 → 子层 → 残差 训练稳定,收敛快 表达能力略弱

2.4.3 实战场景:训练深层Transformer的稳定性

在训练一个12层Transformer时,如果不使用残差连接,当层数超过6层时,梯度会迅速消失,损失函数无法下降。加入残差连接后,即使层数增加到24层,梯度仍能有效回传。而层归一化则保证了每一层的输入分布相对稳定,使得模型可以使用更大的学习率(如从 1e-4 提升到 3e-4)而不会发散。

2.4.4 常见误区与总结

误区1:将LayerNorm放在残差连接之前(即Pre-Norm),虽然训练更稳定,但会降低模型最终精度。
误区2:在归一化时忘记添加 \( \epsilon \)(通常取 1e-5),导致除零错误。

残差连接与层归一化是Transformer深层化的“左膀右臂”,它们共同保证了模型在深度增加时依然能够高效、稳定地训练。

2.5 综合案例:从零构建一个Transformer编码器层

为了将上述组件融会贯通,我们通过一个简化的PyTorch代码示例,展示如何组合这些模块。假设输入为 \( X \in \mathbb{R}^{batch=2, seq=10, d_model=128} \),头数为8。

import torch
import torch.nn as nn

class TransformerEncoderLayer(nn.Module):
    def __init__(self, d_model=128, n_heads=8, d_ff=512, dropout=0.1):
        super().__init__()
        self.attn = nn.MultiheadAttention(d_model, n_heads, dropout=dropout)
        self.ffn = nn.Sequential(
            nn.Linear(d_model, d_ff),
            nn.ReLU(),
            nn.Linear(d_ff, d_model)
        )
        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)
        self.dropout1 = nn.Dropout(dropout)
        self.dropout2 = nn.Dropout(dropout)

    def forward(self, x):
        # x: (seq, batch, d_model) 注意PyTorch的MultiheadAttention输入格式
        # 1. 多头注意力 + 残差
        attn_out, _ = self.attn(x, x, x)
        x = x + self.dropout1(attn_out)
        x = self.norm1(x)
        # 2. 前馈网络 + 残差
        ffn_out = self.ffn(x)
        x = x + self.dropout2(ffn_out)
        x = self.norm2(x)
        return x

# 测试
x = torch.randn(10, 2, 128)  # (seq, batch, d_model)
layer = TransformerEncoderLayer()
out = layer(x)
print(out.shape)  # torch.Size([10, 2, 128])

该代码完整实现了“注意力→残差→归一化→FFN→残差→归一化”的标准流程。在实际训练中,还需要添加学习率预热(Warmup)和梯度裁剪,以进一步保证稳定性。

复盘要点:Transformer的五大组件各司其职——自注意力负责全局建模,多头注意力提供多视角,位置编码注入顺序信息,残差连接保障梯度流动,层归一化稳定训练分布。理解这些基础,是后续学习“全额支付”变体中“支付矩阵”如何动态调整注意力权重的前提。