Transformer
-
https://arxiv.org/pdf/1706.03762
https://arxiv.org/pdf/1706.03762
Transformer结构介绍
-
Transformer是一种基于自注意力机制的神经网络架构,用于序列到序列的转换任务。它由编码器(Encoder)和解码器(Decoder)两部分组成,通过自注意力机制实现对输入和输出序列的有效建模。
这里实现完整的Transformer结构,包含编码器和解码器
主要组件包含:
- 编码器(Encoder):处理输入序列并生成上下文表示
- 解码器(Decoder):基于编码器输出和已生成的序列预测下一个token
- 线性层:将解码器输出映射到目标词表空间
最后的softmax因为一般都包含在损失函数中计算所有可实现可不实现,不重要
数学流程
-
Transformer的计算过程可形式化为:
Encoder Output : H e n c = Encoder ( X s r c ) Decoder Output : H d e c = Decoder ( Y d s t , H e n c ) Final Output : P ( y ) = Softmax ( Linear ( H d e c ) ) \begin{aligned} \text{Encoder Output} &: H_{enc} = \text{Encoder}(X_{src}) \\ \text{Decoder Output} &: H_{dec} = \text{Decoder}(Y_{dst}, H_{enc}) \\ \text{Final Output} &: P(y) = \text{Softmax}(\text{Linear}(H_{dec})) \end{aligned} Encoder OutputDecoder OutputFinal Output:Henc=Encoder(Xsrc):Hdec=Decoder(Ydst,Henc):P(y)=Softmax(Linear(Hdec))
其中:- 编码器处理源序列生成上下文表示
- 解码器结合编码器输出和目标序列进行自回归生成
- 线性层将解码器输出映射到词表维度,通过Softmax得到概率分布
代码实现
-
其他层的实现
层名 链接 PositionEncoding https://blog.csdn.net/hbkybkzw/article/details/147431820 calculate_attention https://blog.csdn.net/hbkybkzw/article/details/147462845 MultiHeadAttention https://blog.csdn.net/hbkybkzw/article/details/147490387 FeedForward https://blog.csdn.net/hbkybkzw/article/details/147515883 LayerNorm https://blog.csdn.net/hbkybkzw/article/details/147516529 EncoderLayer https://blog.csdn.net/hbkybkzw/article/details/147591824 Encoder https://blog.csdn.net/hbkybkzw/article/details/147616115 DecoderLayer https://blog.csdn.net/hbkybkzw/article/details/147616556 Decoder https://blog.csdn.net/hbkybkzw/article/details/147628354 下面统一在before.py中导入
-
实现 Transformer 模型
import torch from torch import nn from before import Encoder, Decoder class Transformer(nn.Module): def __init__(self, encode_vocab_size, decode_vocab_size, padding_idx, d_model, n_heads, ffn_hidden, dropout_prob=0.1, num_layers=6, max_seq_len=512): super(Transformer, self).__init__() # 编码器:处理输入序列 self.encoder = Encoder( vocab_size=encode_vocab_size, padding_idx=padding_idx, d_model=d_model, n_heads=n_heads, ffn_hidden=ffn_hidden, dropout_prob=dropout_prob, num_layers=num_layers, max_seq_len=max_seq_len ) # 解码器:生成输出序列 self.decoder = Decoder( vocab_size=decode_vocab_size, padding_idx=padding_idx, d_model=d_model, n_heads=n_heads, ffn_hidden=ffn_hidden, dropout_prob=dropout_prob, num_layers=num_layers, max_seq_len=max_seq_len ) # 输出线性层:映射到目标词表空间 self.linear = nn.Linear(in_features=d_model, out_features=decode_vocab_size) self.padding_idx = padding_idx def generate_mask(self, query, key, is_triu_mask=False): """ 生成注意力掩码矩阵 shape of query,key: [batch_size,seq_len] """ device = query.device batch, seq_q = query.shape _, seq_k = key.shape # 创建padding掩码 mask = (key == self.padding_idx) mask = mask.unsqueeze(1).unsqueeze(2) # [batch,1,1,seq_k] mask = mask.expand(batch, 1, seq_q, seq_k).to(device) # 创建前瞻掩码(解码器中使用) if is_triu_mask: dst_triu_mask = torch.triu( torch.ones(seq_q, seq_k, dtype=torch.bool), diagonal=1 # 需要往右移动一个,因为第一个单词是开始字符 ) # [seq_q,seq_k] dst_triu_mask = dst_triu_mask.unsqueeze(0).unsqueeze(1).expand( batch, 1, seq_q, seq_k ).to(device) return mask | dst_triu_mask # 取并集 return mask def forward(self, src, dst): """ 前向传播过程 :param src: encoder部分的输入 :param dst: decoder部分的输出 """ # 生成编码器的padding掩码 src_mask = self.generate_mask(src, src) # 编码器前向传播 encoder_out = self.encoder(src, src_mask=src_mask) # 生成解码器的掩码(包含padding掩码和前瞻掩码) dst_mask = self.generate_mask(dst, dst, is_triu_mask=True) # 生成编码器-解码器的掩码 src_dst_mask = self.generate_mask(dst, src) # 解码器前向传播 decode_out = self.decoder( dst, encoder_kv=encoder_out, dst_mask=dst_mask, src_dst_mask=src_dst_mask ) # 线性层映射到词表空间 output = self.linear(decode_out) return output
关键组件说明
- 编码器(Encoder):处理输入序列,生成上下文表示
- 解码器(Decoder):结合编码器输出和已生成序列,预测下一个token
- 掩码生成(generate_mask):创建三种掩码:
- 编码器padding掩码:屏蔽填充位置
- 解码器padding+前瞻掩码:屏蔽填充位置和未来位置
- 编码器-解码器掩码:屏蔽编码器输出中的填充位置
- 线性层:将解码器输出映射到目标词表维度
-
维度变化
处理阶段 张量形状变化示例 源序列输入 [batch_size, src_seq_len] 目标序列输入 [batch_size, dst_seq_len] 编码器输出 [batch_size, src_seq_len, d_model] 解码器输出 [batch_size, dst_seq_len, d_model] 线性层输出 [batch_size, dst_seq_len, decode_vocab_size]
使用示例
-
测试用例
if __name__ == "__main__": # 模拟输入:batch_size=4,源序列长度64,目标序列长度32 src = torch.randint(0, 1000, (4, 64)) dst = torch.randint(0, 1000, (4, 32)) # 实例化Transformer:源词表1000,目标词表1000,模型维度512,8头,2048前馈维度 transformer = Transformer( encode_vocab_size=1000, decode_vocab_size=1000, padding_idx=0, d_model=512, n_heads=8, ffn_hidden=2048, num_layers=6 ) # 前向传播 output = transformer(src, dst) # 输出形状检查 print(f"输出形状: {output.shape}") # 预期: [4, 32, 1000]