仅仅使用pytorch来手撕transformer架构(4):解码器和解码器模块类的实现和向前传播
仅仅使用pytorch来手撕transformer架构(1):位置编码的类的实现和向前传播
最适合小白入门的Transformer介绍
仅仅使用pytorch来手撕transformer架构(2):多头注意力MultiHeadAttention类的实现和向前传播
仅仅使用pytorch来手撕transformer架构(3):编码器模块和编码器类的实现和向前传播
话不多说,直接上代码
# Transformer 解码器模块
class DecoderBlock(nn.Module):def __init__(self, embed_size, heads, forward_expansion, dropout, device):super(DecoderBlock, self).__init__()self.attention = MultiHeadAttention(embed_size, heads)self.norm = nn.LayerNorm(embed_size)self.transformer_block = TransformerBlock(embed_size, heads, dropout, forward_expansion)def forward(self, x, value, key, src_mask, trg_mask):attention = self.attention(x, x, x, trg_mask)query = self.dropout(self.norm(attention + x))out = self.transformer_block(value, key, query, src_mask)return out# 解码器
class Decoder(nn.Module):def __init__(self, trg_vocab_size, embed_size, num_layers, heads, forward_expansion, dropout, device, max_length):super(Decoder, self).__init__()self.device = deviceself.word_embedding = nn.Embedding(trg_vocab_size, embed_size)self.position_embedding = PositionalEncoding(embed_size, dropout, max_length)self.layers = nn.ModuleList([DecoderBlock(embed_size, heads, forward_expansion, dropout, device)for _ in range(num_layers)])self.fc_out = nn.Linear(embed_size, trg_vocab_size)self.dropout = nn.Dropout(dropout)def forward(self, x, enc_out, src_mask, trg_mask):N, seq_length = x.shapex = self.dropout(self.position_embedding(self.word_embedding(x)))for layer in self.layers:x = layer(x, enc_out, enc_out, src_mask, trg_mask)out = self.fc_out(x)return out
一.DecoderBlock
的结构
1. DecoderBlock
的结构
Transformer 解码器中的一个基本模块——DecoderBlock
。每个 DecoderBlock
包含两个主要部分:掩码多头自注意力(Masked Multi-Head Self-Attention) 和 Transformer 块(TransformerBlock)。
(1)掩码多头自注意力(MultiHeadAttention
)
self.attention = MultiHeadAttention(embed_size, heads)
- 作用:这部分实现了掩码多头自注意力机制。
- 输入:
x
(解码器的输入序列)。 - 掩码:
trg_mask
(目标序列的掩码,用于防止解码器看到未来的信息)。 - 输出:经过掩码多头自注意力处理后的张量。
(2)归一化(nn.LayerNorm
)
self.norm = nn.LayerNorm(embed_size)
- 作用:对注意力输出进行归一化,以稳定训练。
- 输入:
attention + x
(注意力输出与输入的残差连接)。 - 输出:归一化后的张量。
(3)Transformer 块(TransformerBlock
)
self.transformer_block = TransformerBlock(embed_size, heads, dropout, forward_expansion)
- 作用:这部分实现了标准的 Transformer 块,包含多头注意力和前馈网络。
- 输入:
value
和key
:来自编码器的输出(编码器的上下文信息)。query
:经过归一化的解码器输入。src_mask
:编码器的掩码(用于忽略填充部分)。
- 输出:经过 Transformer 块处理后的张量。
2. DecoderBlock
的前向传播(forward
方法)
def forward(self, x, value, key, src_mask, trg_mask):attention = self.attention(x, x, x, trg_mask)query = self.dropout(self.norm(attention + x))out = self.transformer_block(value, key, query, src_mask)return out
(1)掩码多头自注意力
attention = self.attention(x, x, x, trg_mask)
- 输入:
x
:解码器的输入序列(通常是目标序列的嵌入表示)。trg_mask
:目标序列的掩码,用于防止解码器看到未来的信息。
- 作用:计算解码器内部的自注意力,同时通过掩码避免看到未来的信息。
- 输出:经过掩码多头自注意力处理后的张量。
(2)归一化和残差连接
query = self.dropout(self.norm(attention + x))
- 作用:
- 将注意力输出与输入
x
进行残差连接(attention + x
),以保留输入的信息。 - 使用
LayerNorm
对残差连接的结果进行归一化。 - 应用
Dropout
进行正则化。
- 将注意力输出与输入
- 输出:归一化后的张量,作为查询(
query
)传递到下一个模块。
(3)Transformer 块
out = self.transformer_block(value, key, query, src_mask)
- 输入:
value
和key
:来自编码器的输出(编码器的上下文信息)。query
:经过归一化的解码器输入。src_mask
:编码器的掩码(用于忽略填充部分)。
- 作用:结合编码器的上下文信息和解码器的查询,通过 Transformer 块进行进一步处理。
- 输出:经过 Transformer 块处理后的张量。
3. DecoderBlock
的作用
DecoderBlock
是 Transformer 解码器的核心模块,它结合了以下两个主要功能:
- 掩码多头自注意力:
- 用于处理解码器内部的序列,同时通过掩码避免看到未来的信息。
- 编码器-解码器注意力:
- 通过
TransformerBlock
,结合编码器的上下文信息(value
和key
)和解码器的查询(query
),生成最终的输出。
- 通过
4. 总结
DecoderBlock
是 Transformer 解码器中的一个模块,它包含:
- 掩码多头自注意力:处理解码器内部的序列。
- 归一化和残差连接:稳定训练并保留输入信息。
- Transformer 块:结合编码器的上下文信息和解码器的查询,生成最终输出。
通过多个 DecoderBlock
的堆叠,解码器能够逐步生成目标序列,同时利用编码器提供的上下文信息。
二、编码器
Transformer 的解码器(Decoder
)部分,它是整个 Transformer 模型的关键组件之一,用于生成目标序列(例如,在机器翻译任务中生成翻译后的句子)。以下是对代码的详细解析:
1. 解码器的结构
(1)词嵌入(nn.Embedding
)
self.word_embedding = nn.Embedding(trg_vocab_size, embed_size)
- 作用:将目标序列中的单词索引转换为固定大小的嵌入向量。
- 参数:
trg_vocab_size
:目标词汇表的大小。embed_size
:嵌入向量的维度。
- 输出:形状为
(N, seq_length, embed_size)
的张量,其中N
是批量大小,seq_length
是目标序列的长度。
(2)位置编码(PositionalEncoding
)
self.position_embedding = PositionalEncoding(embed_size, dropout, max_length)
- 作用:为嵌入向量添加位置信息,使得模型能够感知序列中的位置。
- 参数:
embed_size
:嵌入向量的维度。dropout
:Dropout 概率,用于正则化。max_length
:模型能够处理的最大序列长度。
- 输出:形状为
(N, seq_length, embed_size)
的张量,包含位置信息的嵌入向量。
(3)多层解码器模块(DecoderBlock
)
self.layers = nn.ModuleList([DecoderBlock(embed_size, heads, forward_expansion, dropout, device)for _ in range(num_layers)]
)
- 作用:堆叠多个
DecoderBlock
,每个块包含掩码多头自注意力和 Transformer 块。 - 参数:
num_layers
:解码器中模块的数量。- 每个
DecoderBlock
的参数:embed_size
:嵌入向量的维度。heads
:多头注意力中的头数。forward_expansion
:前馈网络中的扩展因子。dropout
:Dropout 概率。device
:设备(CPU 或 GPU)。
- 输出:经过多层解码器模块处理后的张量。
(4)输出层(nn.Linear
)
self.fc_out = nn.Linear(embed_size, trg_vocab_size)
- 作用:将解码器的输出转换为目标词汇表的大小,用于生成最终的预测。
- 参数:
- 输入维度:
embed_size
。 - 输出维度:
trg_vocab_size
。
- 输入维度:
- 输出:形状为
(N, seq_length, trg_vocab_size)
的张量,表示目标序列中每个位置的单词预测概率。
(5)Dropout
self.dropout = nn.Dropout(dropout)
- 作用:在嵌入向量上应用 Dropout,以防止过拟合。
2. 解码器的前向传播(forward
方法)
def forward(self, x, enc_out, src_mask, trg_mask):N, seq_length = x.shapex = self.dropout(self.position_embedding(self.word_embedding(x)))for layer in self.layers:x = layer(x, enc_out, enc_out, src_mask, trg_mask)out = self.fc_out(x)return out
(1)嵌入和位置编码
x = self.dropout(self.position_embedding(self.word_embedding(x)))
- 作用:
- 将目标序列的单词索引通过词嵌入层转换为嵌入向量。
- 添加位置编码以引入位置信息。
- 应用 Dropout 进行正则化。
- 输出:形状为
(N, seq_length, embed_size)
的张量。
(2)多层解码器模块
for layer in self.layers:x = layer(x, enc_out, enc_out, src_mask, trg_mask)
- 作用:
- 逐层传递输入
x
,结合编码器的输出enc_out
。 - 每个
DecoderBlock
包含:- 掩码多头自注意力:处理目标序列内部的依赖关系,同时通过
trg_mask
防止看到未来的信息。 - 编码器-解码器注意力:结合编码器的上下文信息(
enc_out
)和解码器的查询(x
)。 - 前馈网络:进一步处理特征。
- 掩码多头自注意力:处理目标序列内部的依赖关系,同时通过
- 逐层传递输入
- 输出:经过多层解码器模块处理后的张量。
(3)输出层
out = self.fc_out(x)
- 作用:将解码器的输出转换为目标词汇表的大小,生成最终的预测。
- 输出:形状为
(N, seq_length, trg_vocab_size)
的张量,表示目标序列中每个位置的单词预测概率。
3. 解码器的作用
解码器的主要任务是根据编码器的上下文信息(enc_out
)和目标序列的输入(x
),逐步生成目标序列。它通过以下步骤实现:
- 词嵌入和位置编码:将目标序列的单词索引转换为嵌入向量,并添加位置信息。
- 多层解码器模块:通过多个
DecoderBlock
,逐步处理目标序列,结合编码器的上下文信息。 - 输出层:将解码器的输出转换为目标词汇表的大小,生成最终的预测。
4. 总结
解码器是 Transformer 模型中的关键部分,它通过以下组件实现目标序列的生成:
- 词嵌入和位置编码:引入单词和位置信息。
- 多层解码器模块:结合掩码多头自注意力和编码器-解码器注意力,逐步处理目标序列。
- 输出层:生成目标词汇表的预测概率。
通过堆叠多个 DecoderBlock
,解码器能够有效地捕捉目标序列中的依赖关系,并利用编码器提供的上下文信息生成高质量的输出。
作者码字不易,觉得有用的话不妨点个赞吧,关注我,持续为您更新AI的优质内容。