一、Transformer概览:抛弃循环,拥抱注意力
传统RNN及其变体(如LSTM、GRU)处理序列数据时存在顺序依赖的瓶颈:必须逐个处理序列元素,难以并行计算,且对长程依赖建模能力较弱。Transformer的革命性在于:
-
完全基于自注意力机制:直接计算序列中任意两个元素之间的关系强度,无视距离。
-
并行化计算:序列所有元素同时参与计算,极大提升训练效率。
-
堆叠层结构:通过多层堆叠(通常6层或更多),逐步提取更复杂的特征和表示。
Transformer的整体架构图是其精髓的直观体现:
输入序列 -> [编码器] -> 中间表示 -> [解码器] -> 输出序列
(N个相同层) (N个相同层)
-
编码器:负责理解和压缩输入序列(如源语言句子),将其转化为富含上下文信息的中间表示(Context Representation)。
-
解码器:负责生成输出序列(如目标语言句子)。它利用编码器提供的中间表示,并结合自身已生成的部分,一步步预测下一个元素(自回归生成)。
二、编码器(Encoder):信息的深度理解与融合
编码器由 N
个(通常N=6)结构完全相同的层堆叠而成。每一层都包含两个核心子层:
-
多头自注意力机制层(Multi-Head Self-Attention Layer)
-
前馈神经网络层(Position-wise Feed-Forward Network, FFN)
每个子层周围都应用了关键的残差连接(Residual Connection) 和 层归一化(Layer Normalization)。即每个子层的输出是 LayerNorm(Sublayer(x) + x)
。
1. 输入嵌入与位置编码(Input Embedding & Positional Encoding)
-
输入嵌入:将输入序列中的每个词(或子词)token映射为一个
d_model
维(如512、768、1024)的稠密向量(词向量)。例如:# 假设词汇表大小 vocab_size=10000, d_model=512 embedding_layer = nn.Embedding(10000, 512) input_embeddings = embedding_layer(input_ids) # shape: [batch_size, seq_len, 512]
位置编码(Positional Encoding, PE):由于Transformer本身没有循环或卷积结构,它无法感知序列元素的顺序。位置编码将序列中每个位置的索引信息注入到输入嵌入中。其公式为:
PE(pos, 2i) = sin(pos / 10000^(2i/d_model)) PE(pos, 2i+1) = cos(pos / 10000^(2i/d_model))
-
-
pos
:词在序列中的位置(0, 1, 2, ..., seq_len-1)。 -
i
:维度索引(0 <= i < d_model/2)。 -
使用正弦和余弦函数能保证模型轻松学习到相对位置关系(如
PE(pos+k)
可以表示为PE(pos)
的线性变换)。 -
最终输入:
Input = Input_Embedding + Positional_Encoding
。相加后输入张量维度为[batch_size, seq_len, d_model]
。
-
2. 核心组件:自注意力机制(Self-Attention)
自注意力让序列中的每个词都能直接关注到序列中的所有其他词(包括自身),动态计算它们之间的相关性权重,并据此加权聚合信息。
-
核心概念:Query, Key, Value (Q, K, V)
-
每个输入词向量(
Input
)通过三个独立的线性变换生成:-
Query(Q):代表当前词在“询问”什么信息。
-
Key(K):代表其他词能“提供”什么信息的关键标识。
-
Value(V):代表其他词实际“携带”的信息内容。
-
-
线性变换:
Q = Input * W^Q
,K = Input * W^K
,V = Input * W^V
。W^Q, W^K, W^V
是可学习参数矩阵,维度通常为[d_model, d_k]
(Q, K)和[d_model, d_v]
(V),常设d_k = d_v = d_model / h
,h
是头数。
-
-
注意力分数计算与权重分配
-
计算
Q
与K
的点积:Scores = Q * K^T
(维度:[batch_size, h, seq_len, seq_len]
)。点积越大表示Query
和Key
越相关。 -
缩放(Scale):
Scores = Scores / sqrt(d_k)
。防止点积结果过大导致softmax梯度消失。 -
掩码(可选,在编码器自注意力中通常不需要):在解码器中会用到,防止看到未来信息。
-
Softmax归一化:
Attention_Weights = softmax(Scores, dim=-1)
。将分数转换为和为1的概率分布,表示每个Key
(对应每个词)对当前Query
(当前词)的重要性权重。 -
加权求和:
Output = Attention_Weights * V
(维度:[batch_size, h, seq_len, d_v]
)。这一步就是用权重对Value
向量进行加权求和,得到当前Query
词的新表示,它融合了所有其他词的信息。
公式总结:
Attention(Q, K, V) = softmax(Q * K^T / sqrt(d_k)) * V
-
-
多头注意力(Multi-Head Attention):这是Transformer性能强大的关键。
-
将
d_model
维的Q, K, V
分割成h
个头(如h=8),每个头在降维后的空间(d_k, d_k, d_v
)中进行独立的注意力计算。 -
好处:
-
并行计算:多个头可并行计算。
-
捕捉不同子空间信息:不同的头可以学习关注序列中不同类型的关系(如语法关系、指代关系、语义关系)。一个头可能关注局部依赖,另一个头可能关注长距离依赖。
-
-
合并输出:将
h
个头的输出拼接(concat
)起来,再通过一个线性层W^O
映射回d_model
维:MultiHead(Q, K, V) = Concat(head1, ..., headh) * W^O
。W^O
维度为[h * d_v, d_model]
。
-
3. 前馈神经网络(Position-wise FFN)
自注意力层输出后,会经过一个前馈神经网络。它对序列中的每个位置独立、相同地进行变换。
-
结构:通常是两层线性变换,中间加一个ReLU激活函数:
FFN(x) = max(0, x * W1 + b1) * W2 + b2
-
-
W1
维度[d_model, d_ff]
(如d_ff=2048)。 -
W2
维度[d_ff, d_model]
。 -
b1, b2
是偏置项。
-
-
作用:为每个位置的特征提供非线性变换能力,增强模型的表示能力。可以看作是在每个词的位置上独立应用一个小型MLP。
4. 残差连接与层归一化(Add & Norm)
-
残差连接(Add):将子层(自注意力层或FFN层)的输入直接加到其输出上:
y = Sublayer(x) + x
。-
核心作用:
-
缓解梯度消失:深层网络中,梯度可以直接通过残差路径回传。
-
保留原始信息:即使子层没学到新东西,输入信息也能无损传递。
-
-
-
层归一化(LayerNorm):对单个样本在特征维度(
d_model
)上进行归一化。LayerNorm(x) = γ * (x - μ) / sqrt(σ² + ε) + β
-
μ, σ²
是特征维度上的均值和方差。 -
γ, β
是可学习的缩放和偏移参数。 -
ε
是防止除零的小常数。 -
作用:稳定训练过程,加速收敛。它作用于每个样本的每个位置的特征向量上。
5. 编码器层堆叠
经过 N
个这样的编码器层(每层包含自注意力 + FFN,以及Add&Norm)处理后,输入序列被逐步转化为高度抽象、富含全局上下文信息的表示。最后一层编码器的输出即为整个输入序列的中间表示(Context Representation),它将被传递给解码器使用。
三、解码器(Decoder):自回归生成的艺术
解码器同样由 N
个(通常与编码器层数相同)结构相同的层堆叠而成。解码器层结构与编码器层相似,但包含三个核心子层:
-
(带掩码的)多头自注意力层(Masked Multi-Head Self-Attention Layer)
-
多头编码器-解码器注意力层(Multi-Head Encoder-Decoder Attention Layer)
-
前馈神经网络层(Position-wise FFN)
同样,每个子层周围都有残差连接和层归一化。
1. 输入:目标序列嵌入与位置编码
-
解码器的输入是目标序列(如待生成的翻译句子)的嵌入表示(加上位置编码)。
-
关键点:在训练时,我们使用完整的目标序列右移一位(Shifted Right)作为输入(例如,输入是
<sos> I love NLP
,期望输出是I love NLP <eos>
)。在推理时,则是自回归的:输入起始符(如<sos>
),预测第一个词;然后将预测出的词作为输入,预测下一个词,依此类推。
2. 核心组件1:掩码多头自注意力(Masked Multi-Head Self-Attention)
-
目的:让解码器在预测位置
i
时,只能看到位置 1 到 i-1 的信息(即只能看到已生成的部分),而不能看到位置 i 及之后的信息(未来信息)。 -
实现机制 - 注意力掩码:在计算
Q * K^T
得到注意力分数矩阵后,在softmax之前,将未来位置对应的分数设置为一个极大的负数(如 -1e9)。# 伪代码示例:创建下三角掩码矩阵(主对角线及以下为0,以上为 -inf) mask = torch.tril(torch.ones(seq_len, seq_len)) # 下三角矩阵,元素为1 mask = mask.masked_fill(mask == 0, float('-inf')) # 将0的位置替换为 -inf Scores = Q * K^T / sqrt(d_k) + mask # 加上掩码 Attention_Weights = softmax(Scores, dim=-1)
-
作用:确保解码器的自回归生成特性,使其在训练和推理时的行为一致。
3. 核心组件2:编码器-解码器注意力(Encoder-Decoder Attention)
-
目的:让解码器在生成目标序列的每个词时,能够聚焦于输入序列(源序列)中最相关的部分。
-
Q, K, V的来源:
-
Query (Q):来自解码器上一子层(掩码自注意力层)的输出。代表解码器当前要生成词的位置在“询问”什么。
-
Key (K) 和 Value (V):来自编码器最后一层的输出(即整个输入序列的中间表示)。代表源序列提供的所有信息。
-
-
计算过程:与多头注意力机制完全一致:
EncoderDecoderAttention(Q, K, V) = softmax(Q * K^T / sqrt(d_k)) * V
。这里没有掩码。 -
意义:这是连接源语言和目标语言的桥梁。解码器通过此机制动态地、有选择地从源序列中提取信息,指导当前目标词的生成。例如,在翻译时,生成某个目标词时,注意力权重可能高度集中在源句中对应的词或相关词上。
4. 前馈神经网络(FFN)与 Add & Norm
-
与编码器中的FFN子层完全相同,独立作用于每个位置。
-
同样应用残差连接和层归一化。
5. 解码器层堆叠与输出
经过 N
个解码器层处理后,得到解码器顶层的输出(维度 [batch_size, target_seq_len, d_model]
)。该输出通过一个线性层(将 d_model
维映射到目标词汇表大小维)和一个 Softmax层,计算出在目标词汇表上每个位置的概率分布:
# 伪代码
output_logits = linear(decoder_output) # shape: [batch_size, target_seq_len, target_vocab_size]
output_probs = softmax(output_logits, dim=-1)
模型的目标是最大化正确目标词序列的似然概率,通常使用交叉熵损失函数进行训练。
四、编码器与解码器的协同工作流程(以机器翻译为例)
-
输入处理(编码器):
-
源语言句子 "I love NLP" 被分词、嵌入并添加位置编码。
-
输入序列
[<sos>, I, love, NLP, <eos>]
送入编码器。 -
经过多层编码器处理,得到富含整个源句信息的中间表示(Context Tensor)。
-
-
初始化解码器:
-
解码器初始输入通常只包含起始符
<sos>
(及其位置编码)。
-
-
自回归生成(解码器):
- Step 1 (输入:
<sos>
): - 解码器掩码自注意力层:仅关注
<sos>
。 - 编码器-解码器注意力层:基于
<sos>
的 Query,从编码器的中间表示(Context Tensor)中计算注意力权重,聚焦于源句的相关部分(可能整个句子的信息都会被加权考虑)。 - FFN层处理。
- 输出层预测第一个目标词的概率分布。假设概率最高的是中文词 "我"。
- Step 2 (输入:
<sos>
, "我"): - 掩码自注意力:关注
<sos>
和 "我"。 - 编码器-解码器注意力:基于 "我" 的 Query,再次从 Context Tensor 中计算注意力权重(此时权重分布可能与 Step 1 不同)。
- FFN层处理。
- 输出层预测第二个词。假设预测为 "喜欢"。
- Step 3 (输入:
<sos>
, "我", "喜欢"): - 掩码自注意力:关注
<sos>
, "我", "喜欢"。 - 编码器-解码器注意力:基于 "喜欢" 的 Query,从 Context Tensor 中提取信息(可能高度聚焦于源句的 "love")。
- FFN层处理。
- 输出层预测第三个词。预测为 "NLP"。
- Step 4 (输入:
<sos>
, "我", "喜欢", "NLP"): - ... 过程同上。
- 输出层预测下一个词。预测为结束符
<eos>
。 - 结束:生成序列
<sos> 我 喜欢 NLP <eos>
,去除起始符得到最终翻译 "我喜欢 NLP"。
五、Transformer架构的核心优势
-
强大的长程依赖建模:自注意力机制允许序列中任意两个元素直接交互,彻底克服了RNN处理长序列时信息衰减的难题。
-
卓越的并行计算能力:序列所有元素在自注意力层和FFN层中同时计算,训练速度远超RNN/CNN。
-
灵活的注意力机制:多头注意力可捕获不同语义子空间的关系;编码器-解码器注意力实现动态源-目标对齐。
-
可扩展性强:堆叠更多层(如12、24、48层)、增大
d_model
、增加头数h
等,能显著提升模型容量和性能,为大模型时代奠定基础。 -
通用性:虽然最初为机器翻译设计,但其架构通用性使其在文本分类、问答、摘要、语音识别、图像生成(ViT)等众多领域大放异彩。
六、总结:理解与生成的完美协奏
Transformer的编码器和解码器是理解其强大能力的关键:
-
编码器如同一位精通源语言的读者,通过层层递进的自注意力阅读整个输入序列,抽丝剥茧,最终形成一个蕴含全局语义和细节的“思维导图”(中间表示)。
-
解码器如同一位精通目标语言的作者,在创作(生成目标序列)时:
-
时刻回顾自己已经写了什么(掩码自注意力)。
-
不断参考编码器提供的“思维导图”,精准找到与当前要写内容最相关的源信息(编码器-解码器注意力)。
-
融合这两部分信息,构思并写下最合适的下一个词(FFN + 输出层)。
-