深入解析 Transformer 模型:编码器和解码器的完整实现
14. encoder-decoder
深入解析 Transformer 模型:编码器和解码器的完整实现
Transformer 模型自提出以来,就以其并行计算的高效性和卓越的自然语言处理性能受到广泛关注。本文将深入介绍 Transformer 的整体架构,包括编码器(Encoder)和解码器(Decoder)模块的具体实现和作用,带你逐步理解如何构建一个完整的 Transformer 模型。
Transformer 的整体结构
Transformer 模型主要包含两个关键部分:编码器(Encoder)和解码器(Decoder)。
- 编码器:编码器将输入序列中的每个词转换为特征向量,并生成一个编码输出,这些编码包含了输入序列的语义信息。
- 解码器:解码器根据编码器的输出及已生成的词语,逐步生成目标输出序列。
整体流程:
- 输入嵌入层和位置编码:将输入词和目标词嵌入到向量空间并添加位置信息。
- 多层编码器块和解码器块的堆叠:编码器块和解码器块分别进行多层堆叠,以捕获深层次的上下文关系。
- 输出层:解码器生成的结果经过线性层输出为词汇表大小的向量,以生成目标词。
Transformer 编码器和解码器的代码实现
以下代码实现了一个完整的 Transformer 类,包括编码器、解码器和输出层的组合。
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 Transformer(nn.Module):
def __init__(self, src_vocab_size, tgt_vocab_size, embed_size, num_layers, heads, forward_expansion, dropout, max_length):
super(Transformer, self).__init__()
self.encoder = TransformerEncoder(src_vocab_size, embed_size, num_layers, heads, forward_expansion, dropout, max_length)
self.decoder = TransformerDecoder(tgt_vocab_size, embed_size, num_layers, heads, forward_expansion, dropout, max_length)
self.fc_out = nn.Linear(embed_size, tgt_vocab_size)
def forward(self, src, tgt, src_mask, tgt_mask):
enc_out = self.encoder(src, src_mask)
dec_out = self.decoder(tgt, enc_out, src_mask, tgt_mask)
out = self.fc_out(dec_out)
return out
代码解析:逐步分析 Transformer 主要模块的实现
1. 编码器类 TransformerEncoder
编码器的主要任务是将输入序列转换为一个编码表示,它包含以下几个步骤:
class TransformerEncoder(nn.Module):
def __init__(self, src_vocab_size, embed_size, num_layers, heads, forward_expansion, dropout, max_length):
super(TransformerEncoder, self).__init__()
self.word_embedding = nn.Embedding(src_vocab_size, embed_size)
self.position_encoding = PositionalEncoding(embed_size, max_length)
self.layers = nn.ModuleList(
[EncoderBlock(embed_size, heads, forward_expansion, dropout) for _ in range(num_layers)]
)
self.dropout = nn.Dropout(dropout)
def forward(self, x, mask):
out = self.word_embedding(x)
out = self.position_encoding(out)
out = self.dropout(out)
for layer in self.layers:
out = layer(out, mask)
return out
- 输入嵌入:将输入的词索引转化为嵌入向量。
- 位置编码:为每个词嵌入添加位置信息,使得模型能够识别输入词的顺序。
- 多层编码器块的堆叠:通过堆叠多个
EncoderBlock
层,使得模型可以学习深层次的上下文关系。
2. 解码器类 TransformerDecoder
解码器模块负责生成目标序列中的每一个词。它结合了编码器的输出和当前生成的词语,以保证生成结果与上下文一致。
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):
out = self.word_embedding(x)
out = self.position_encoding(out)
out = self.dropout(out)
for layer in self.layers:
out = layer(out, enc_out, src_mask, tgt_mask)
return self.fc_out(out)
- 输入嵌入和位置编码:与编码器类似,将目标序列的词索引转化为嵌入向量,并添加位置信息。
- 多层解码器块的堆叠:堆叠多个解码器块,每个块包含自注意力和编码器-解码器注意力。
- 输出层:将解码器输出映射到目标词汇表大小,用于生成目标序列的下一个词。
编码器-解码器块的核心组件
1. EncoderBlock 的实现
编码器块(EncoderBlock
)由自注意力机制、多层前馈神经网络和残差连接组成。
class EncoderBlock(nn.Module):
def __init__(self, embed_size, heads, forward_expansion, dropout):
super(EncoderBlock, self).__init__()
self.attention = MultiHeadAttention(embed_size, heads)
self.norm1 = nn.LayerNorm(embed_size)
self.norm2 = nn.LayerNorm(embed_size)
self.feed_forward = FeedForward(embed_size, forward_expansion)
self.dropout = nn.Dropout(dropout)
def forward(self, x, mask):
attention = self.attention(x, x, x, mask)
x = self.dropout(self.norm1(attention + x))
forward = self.feed_forward(x)
out = self.dropout(self.norm2(forward + x))
return out
- 多头自注意力层:捕捉序列中词与词之间的关系,帮助模型理解上下文信息。
- 残差连接和正则化:保持梯度稳定,避免梯度消失,并防止模型过拟合。
- 前馈神经网络:用于进一步提取特征信息。
2. DecoderBlock 的实现
解码器块(DecoderBlock
)相比编码器块多了一个“编码器-解码器注意力层”,用于将编码器的输出信息整合进解码器的生成过程中。
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:生成每个目标词时只能关注到当前和之前的词,确保生成词的顺序一致。
- 编码器-解码器注意力层:根据编码器的输出,结合当前词的上下文信息生成目标词。
- 前馈神经网络和残差连接:增强模型的非线性表达能力,确保梯度流畅传递。
测试 Transformer 模型
以下代码用于测试 Transformer
模型
的整体结构是否正确,确保编码器和解码器的搭配工作正常。
# 测试代码
src_vocab_size = 10000
tgt_vocab_size = 10000
embed_size = 512
num_layers = 6
heads = 8
forward_expansion = 4
dropout = 0.1
max_length = 100
src_seq_length, tgt_seq_length, batch_size = 20, 20, 2
src = torch.randint(0, src_vocab_size, (batch_size, src_seq_length))
tgt = torch.randint(0, tgt_vocab_size, (batch_size, tgt_seq_length))
src_mask, tgt_mask = None, None
# 实例化 Transformer 模型并进行前向传播
model = Transformer(src_vocab_size, tgt_vocab_size, embed_size, num_layers, heads, forward_expansion, dropout, max_length)
out = model(src, tgt, src_mask, tgt_mask)
print("Transformer 模型输出形状:", out.shape)
- 预期输出:
(batch_size, tgt_seq_length, tgt_vocab_size)
,例如(2, 20, 10000)
。
总结
我们完成了 Transformer 模型中编码器和解码器的构建,并将它们组合成完整的模型。编码器负责将输入序列转化为高维特征,解码器在生成每个目标词时参考编码器输出,从而生成语义一致的输出序列。了解 Transformer 的内部结构有助于我们进一步优化模型,适用于各种 NLP 任务,如机器翻译和文本生成等。希望本文能帮助你理解 Transformer 编码器和解码器的核心设计和实现流程。