13. decoder
深入解析 Transformer 解码器:核心模块和代码实现详解
在 Transformer 中,解码器(Decoder)是一个关键组件,它负责生成目标序列的每个词。解码器的设计允许模型在生成目标词时,结合编码器的输出信息,逐步生成上下文相关的输出序列。本文将带你逐步实现一个完整的 Transformer 解码器。
Transformer 解码器的主要组成部分
一个完整的 Transformer 解码器通常包含以下几个部分:
- 输入嵌入层(Embedding Layer):将目标序列中的每个词转换为向量表示。
- 位置编码(Positional Encoding):为每个词向量加上位置信息,使模型能够捕捉词序。
- 堆叠多个解码器块(Decoder Blocks):通常包含 6-12 个解码器块,每个块负责将当前词与前面词的上下文信息融合。
- 输出层:最终将解码器的输出用于生成目标词或用于其他下游任务。
解码器类实现:构建解码器主架构
以下代码实现了一个 TransformerDecoder
类,其中包括输入嵌入、位置编码、多个解码器块以及输出层:
import torch
import torch.nn as nn
import math
class PositionalEncoding(nn.Module):
def __init__(self, embed_size, max_length=100):
super(PositionalEncoding, self).__init__()
self.encoding = torch.zeros(max_length, embed_size)
position = torch.arange(0, max_length, dtype=torch.float).unsqueeze(1)
div_term = torch.exp(torch.arange(0, embed_size, 2).float() * (-math.log(10000.0) / embed_size))
self.encoding[:, 0::2] = torch.sin(position * div_term)
self.encoding[:, 1::2] = torch.cos(position * div_term)
self.encoding = self.encoding.unsqueeze(0)
def forward(self, x):
return x + self.encoding[:, :x.size(1), :].to(x.device)
class TransformerDecoder(nn.Module):
def __init__(self, tgt_vocab_size, embed_size, num_layers, heads, forward_expansion, dropout, max_length):
super(TransformerDecoder, self).__init__()
# 目标嵌入层
self.word_embedding = nn.Embedding(tgt_vocab_size, embed_size)
self.position_encoding = PositionalEncoding(embed_size, max_length)
# 解码器层堆叠
self.layers = nn.ModuleList(
[DecoderBlock(embed_size, heads, forward_expansion, dropout) for _ in range(num_layers)]
)
# 输出层
self.fc_out = nn.Linear(embed_size, tgt_vocab_size)
self.dropout = nn.Dropout(dropout)
def forward(self, x, enc_out, src_mask, tgt_mask):
# 1. 嵌入和位置编码
out = self.word_embedding(x)
out = self.position_encoding(out)
out = self.dropout(out)
# 2. 通过多个解码器块
for layer in self.layers:
out = layer(out, enc_out, src_mask, tgt_mask)
# 3. 输出层生成目标词
out = self.fc_out(out)
return out
代码解析:逐步解析 Transformer 解码器实现
1. 输入嵌入层和位置编码
self.word_embedding = nn.Embedding(tgt_vocab_size, embed_size)
self.position_encoding = PositionalEncoding(embed_size, max_length)
word_embedding
:将目标序列的词索引转换为嵌入向量,使得模型能够处理目标序列。position_encoding
:为每个词的嵌入向量加上位置信息,使模型能够识别目标序列中的词序。
2. 多个解码器块的堆叠
self.layers = nn.ModuleList(
[DecoderBlock(embed_size, heads, forward_expansion, dropout) for _ in range(num_layers)]
)
- 使用
ModuleList
创建多个DecoderBlock
,其中每个块都包含自注意力、编码器-解码器注意力、前馈神经网络和正则化层。 num_layers
是解码器块的数量,通常设置为 6,但可根据任务调整。
3. 输出层
self.fc_out = nn.Linear(embed_size, tgt_vocab_size)
- 输出层将嵌入向量转化为词汇表大小的向量,用于生成目标序列中的下一个词。
前向传播过程解析
-
词嵌入和位置编码
out = self.word_embedding(x) out = self.position_encoding(out) out = self.dropout(out)
- 将输入的目标序列转换为词向量表示。
- 为词向量添加位置编码,使模型能够识别词序。
- Dropout 防止过拟合。
-
逐层通过解码器块
for layer in self.layers: out = layer(out, enc_out, src_mask, tgt_mask)
- 将目标序列传递给每一个解码器块。
- 每个块中的编码器-解码器注意力层会根据编码器的输出信息和目标序列上下文,生成更精细的解码信息。
src_mask
和tgt_mask
分别用于在编码器-解码器注意力中屏蔽源序列和目标序列中的填充部分,确保模型关注有效信息。
-
输出层生成目标词
out = self.fc_out(out)
- 通过线性层生成目标词汇表大小的分布,用于选择下一个生成的目标词。
实现解码器块(Decoder Block)
为了更完整地理解解码器的工作机制,我们还需要实现 DecoderBlock
。一个解码器块由以下几个部分组成:
- 自注意力层(Masked Self-Attention Layer):防止模型看到未来的词。
- 编码器-解码器注意力层(Encoder-Decoder Attention Layer):将编码器的输出与解码器当前状态结合,获取上下文信息。
- 前馈神经网络层(Feed-Forward Network Layer):提升解码器的表达能力。
- LayerNorm 和 Dropout 层:保持数值稳定,防止过拟合。
class DecoderBlock(nn.Module):
def __init__(self, embed_size, heads, forward_expansion, dropout):
super(DecoderBlock, self).__init__()
self.attention = MultiHeadAttention(embed_size, heads)
self.norm1 = nn.LayerNorm(embed_size)
self.norm2 = nn.LayerNorm(embed_size)
self.norm3 = nn.LayerNorm(embed_size)
self.encoder_decoder_attention = MultiHeadAttention(embed_size, heads)
self.feed_forward = FeedForward(embed_size, forward_expansion)
self.dropout = nn.Dropout(dropout)
def forward(self, x, enc_out, src_mask, tgt_mask):
attention = self.attention(x, x, x, tgt_mask)
x = self.dropout(self.norm1(attention + x))
enc_dec_attention = self.encoder_decoder_attention(x, enc_out, enc_out, src_mask)
x = self.dropout(self.norm2(enc_dec_attention + x))
forward = self.feed_forward(x)
out = self.dropout(self.norm3(forward + x))
return out
解码器块的前向传播解析
-
自注意力层:Masked Self-Attention 屏蔽未来的词,确保解码器生成当前词时不会看到之后的词。
attention = self.attention(x, x, x, tgt_mask) x = self.dropout(self.norm1(attention + x))
-
编码器-解码器注意力层:结合编码器的输出,通过 Encoder-Decoder Attention 提取源句子的信息。
enc_dec_attention = self.encoder_decoder_attention(x, enc_out, enc_out, src_mask) x = self.dropout(self.norm2(enc_dec_attention + x))
-
前馈神经网络:进一步处理信息,提升特征的表达能力。
forward = self.feed_forward(x) out = self.dropout(self.norm3(forward + x))
测试 Transformer 解码器
以下代码用于测试 TransformerDecoder
类,确保其可以正常运行:
# 设置参数
tgt_vocab_size = 10000 # 假设目标词汇表大小
embed_size = 512
num_layers = 6
heads = 8
forward_expansion = 4
dropout = 0.1
max_length = 100
seq_length = 20
batch_size = 2
# 假设输入
x = torch.randint(0, tgt_vocab_size, (batch_size, seq_length))
enc_out
= torch.rand(batch_size, seq_length, embed_size)
src_mask, tgt_mask = None, None
# 实例化解码器并前向传播
decoder = TransformerDecoder(tgt_vocab_size, embed_size, num_layers, heads, forward_expansion, dropout, max_length)
out = decoder(x, enc_out, src_mask, tgt_mask)
print("解码器的输出形状:", out.shape)
期望输出形状:(batch_size, seq_length, tgt_vocab_size)
,例如 (2, 20, 10000)
。
总结
通过实现和逐步分析 Transformer 解码器模块,我们可以看到它是如何结合编码器输出,在生成目标序列时保持语义和上下文一致的。希望本文能帮助你理解解码器的实现过程。后续内容可以深入研究完整的 Transformer 模型搭建,包括编码器与解码器的组合。