Transformer 是一种基于自注意力机制的深度神经网络模型,常用于处理序列到序列的任务,例如机器翻译、文本摘要、问答系统等。它由 Encoder 和 Decoder 两个主要部分组成,每个部分包含多个相同的 Block。
Transformer 结构
import torch import torch.nn as nn # 定义位置编码类 class PositionalEncoding(nn.Module): def __init__(self, d_model, max_len=5000): """ 初始化位置编码器。 参数: - d_model: 模型维度 - max_len: 序列的最大长度 """ super(PositionalEncoding, self).__init__() # 创建一个零张量来存储位置编码 pe = torch.zeros(max_len, d_model) # 生成位置索引张量 position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1) # 计算除数项 div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-torch.log(torch.tensor(10000.0)) / d_model)) # 填充位置编码张量中的奇数和偶数位置 pe[:, 0::2] = torch.sin(position * div_term) pe[:, 1::2] = torch.cos(position * div_term) # 添加批次维度并转置以匹配输入形状 pe = pe.unsqueeze(0).transpose(0, 1) # 将位置编码注册为缓冲区,使其不被视为模型参数 self.register_buffer('pe', pe) def forward(self, x): """ 在输入序列上应用位置编码。 参数: - x: 输入张量,形状为 (seq_len, batch_size, d_model) 返回: - 加上位置编码后的输入张量 """ x = x + self.pe[:x.size(0), :] return x # 定义Transformer模型类 class Transformer(nn.Module): def __init__(self, encoder, decoder, src_vocab_size, tgt_vocab_size, src_pad_idx, tgt_pad_idx, device, d_model): """ 初始化Transformer模型。 参数: - encoder: 编码器层 - decoder: 解码器层 - src_vocab_size: 源语言词汇表大小 - tgt_vocab_size: 目标语言词汇表大小 - src_pad_idx: 源语言填充标记索引 - tgt_pad_idx: 目标语言填充标记索引 - device: 设备类型(CPU/GPU) - d_model: 模型维度 """ super(Transformer, self).__init__() self.encoder = encoder self.decoder = decoder self.src_pad_idx = src_pad_idx self.tgt_pad_idx = tgt_pad_idx self.device = device # 初始化源语言词嵌入层 self.src_token_embedding = nn.Embedding(src_vocab_size, d_model) # 初始化目标语言词嵌入层 self.tgt_token_embedding = nn.Embedding(tgt_vocab_size, d_model) # 初始化位置编码器 self.position_embedding = PositionalEncoding(d_model) self.src_mask = None self.tgt_mask = None def forward(self, src, tgt): """ 执行Transformer模型的前向传播。 参数: - src: 源语言输入序列,形状为 (src_seq_len, batch_size) - tgt: 目标语言输入序列,形状为 (tgt_seq_len, batch_size) 返回: - 解码器输出,形状为 (tgt_seq_len, batch_size, tgt_vocab_size) """ # 创建源语言和目标语言的掩码 src_mask = self.create_padding_mask(src, self.src_pad_idx) tgt_mask = self.create_padding_mask(tgt, self.tgt_pad_idx) # 对源语言输入进行编码 memory = self.encoder(self.src_token_embedding(src) + self.position_embedding(src), src_mask) # 对目标语言输入进行解码 outs = self.decoder(self.tgt_token_embedding(tgt) + self.position_embedding(tgt), memory, tgt_mask) return outs def create_padding_mask(self, src, pad_idx): """ 创建填充掩码。 参数: - src: 输入序列,形状为 (seq_len, batch_size) - pad_idx: 填充标记索引 返回: - 掩码张量,形状为 (batch_size, seq_len) """ mask = (src == pad_idx).transpose(0, 1) mask = mask.float().masked_fill(mask == 0, float('-inf')).masked_fill(mask == 1, float(0.0)) return maskEncoder的作用是将输入文本编码成包含上下文信息的向量表示。每个 Block 包含 Multi-Head Attention、Add & Norm 和 Feed Forward 三个子模块。
- Multi-Head Attention由多个 Self-Attention 子模块组成,用于提取文本的上下文信息。
- Add & Norm用于连接不同模块的输出,并进行残差连接和归一化处理。
- Feed Forward是一个两层的全连接网络,进一步学习文本表示。
# 定义编码器块类 class EncoderBlock(nn.Module): def __init__(self, d_model, n_heads, d_ff, dropout, device): """ 初始化编码器块。 参数: - d_model: 模型维度 - n_heads: 多头注意力机制中的头数 - d_ff: 前馈神经网络中间层的维度 - dropout: Dropout比例 - device: 设备类型(CPU/GPU) """ super(EncoderBlock, self).__init__() # 初始化多头自注意力机制 self.self_attn = MultiHeadAttention(d_model, n_heads, device) # 初始化前馈神经网络 self.feed_forward = FeedForward(d_model, d_ff, dropout) # 初始化第一层归一化层 self.layer_norm1 = nn.LayerNorm(d_model) # 初始化第二层归一化层 self.layer_norm2 = nn.LayerNorm(d_model) # 初始化Dropout层 self.dropout = nn.Dropout(dropout) def forward(self, src, mask): """ 执行编码器块的前向传播。 参数: - src: 输入序列,形状为 (seq_len, batch_size, d_model) - mask: 掩码张量,形状为 (batch_size, seq_len) 返回: - 编码器块的输出,形状为 (seq_len, batch_size, d_model) """ # 层归一化后的输入 src2 = self.layer_norm1(src) # 自注意力机制的查询、键和值均为同一输入 q = k = v = src2 # 应用多头自注意力机制 src2 = self.self_attn(q, k, v, mask) # 将自注意力结果与原始输入相加,并应用Dropout src = src + self.dropout(src2) # 第二次层归一化 src2 = self.layer_norm2(src) # 应用前馈神经网络 src2 = self.feed_forward(src2) # 将前馈网络的结果与之前的输出相加,并应用Dropout src = src + self.dropout(src2) return srcDecoder的作用是根据 Encoder 的输出和前一个 token 预测下一个 token,最终生成目标文本。每个 Block 包含 Masked Multi-Head Attention、Cross-Attention、Add & Norm 和 Feed Forward 四个子模块。
- Masked Multi-Head Attention用于预测下一个 token,同时屏蔽掉当前 token 之后的信息,避免泄露未来信息。
- Cross-Attention将 Encoder 的输出作为 Key 和 Value,Decoder 的输出作为 Query,提取 Encoder 和 Decoder 之间的关联信息,帮助 Decoder 理解输入文本和已有生成文本之间的关系。
- Add & Norm用于连接不同模块的输出,并进行残差连接和归一化处理。
- Feed Forward是一个两层的全连接网络,进一步学习文本表示。
class DecoderBlock(nn.Module): def __init__(self, d_model, n_heads, d_ff, dropout, device): """ 初始化解码器块。 参数: - d_model: 模型维度 - n_heads: 多头注意力机制中的头数 - d_ff: 前馈神经网络中间层的维度 - dropout: Dropout比例 - device: 设备类型(CPU/GPU) """ super(DecoderBlock, self).__init__() # 初始化自注意力机制 self.self_attn = MultiHeadAttention(d_model, n_heads, device) # 初始化交叉注意力机制 self.cross_attn = MultiHeadAttention(d_model, n_heads, device) # 初始化前馈神经网络 self.feed_forward = FeedForward(d_model, d_ff, dropout) # 初始化第一层归一化层 self.layer_norm1 = nn.LayerNorm(d_model) # 初始化第二层归一化层 self.layer_norm2 = nn.LayerNorm(d_model) # 初始化第三层归一化层 self.layer_norm3 = nn.LayerNorm(d_model) # 初始化Dropout层 self.dropout = nn.Dropout(dropout) def forward(self, tgt, memory, tgt_mask, src_mask): """ 执行解码器块的前向传播。 参数: - tgt: 目标语言输入序列,形状为 (tgt_seq_len, batch_size, d_model) - memory: 编码器输出的记忆张量,形状为 (src_seq_len, batch_size, d_model) - tgt_mask: 目标语言掩码张量,形状为 (batch_size, tgt_seq_len) - src_mask: 源语言掩码张量,形状为 (batch_size, src_seq_len) 返回: - 解码器块的输出,形状为 (tgt_seq_len, batch_size, d_model) """ # 层归一化后的目标语言输入 tgt2 = self.layer_norm1(tgt) # 自注意力机制的查询、键和值均为同一输入 q = k = v = tgt2 # 应用自注意力机制 tgt2 = self.self_attn(q, k, v, tgt_mask) # 将自注意力结果与原始输入相加,并应用Dropout tgt = tgt + self.dropout(tgt2) # 第二次层归一化 tgt2 = self.layer_norm2(tgt) # 交叉注意力机制的查询为当前目标语言输入,键和值为编码器输出 q = tgt2 k = v = memory # 应用交叉注意力机制 tgt2 = self.cross_attn(q, k, v, src_mask) # 将交叉注意力结果与之前的输出相加,并应用Dropout tgt = tgt + self.dropout(tgt2) # 第三次层归一化 tgt2 = self.layer_norm3(tgt) # 应用前馈神经网络 tgt2 = self.feed_forward(tgt2) # 将前馈网络的结果与之前的输出相加,并应用Dropout tgt = tgt + self.dropout(tgt2) return tgt输入处理:
- 文本首先经过 Token Embedding 和 Position Embedding,然后将两者相加得到最终的输入向量。
- Token Embedding将文本转换为向量表示,捕捉文本的基本语义信息。
- Position Embedding为每个 token 添加位置信息,使模型能够理解文本中 token 的顺序和位置关系。
Position Embedding:
- Transformer 使用正余弦位置编码,为每个 token 添加位置信息。
- 奇数位置使用余弦函数,偶数位置使用正弦函数。
- 这种方式可以有效地捕捉 token 的相对位置信息。
Attention Mechanism:
- Self-Attention 是 Transformer 的核心机制,用于计算文本中不同 token 之间的相关性。
- Q, K, V 是 Self-Attention 的三个参数矩阵,分别代表 Query, Key 和 Value。
- Attention Score Matrix 通过 Q 和 K 的转置相乘得到,并经过 Softmax 归一化。
- Attention Matrix 通过 Attention Score Matrix 和 V 相乘得到,包含上下文信息。
Multi-Head Attention:
- Multi-Head Attention 将输入向量分别输入多个 Self-Attention 子模块,得到多个 Attention Matrix。
- 将多个 Attention Matrix 拼接并经过全连接层降维,得到最终的输出。
- 这种方式可以捕捉不同方面的信息,提高模型的表达能力。
Add & Norm:
- Add & Norm 用于连接不同模块的输出,并进行残差连接和归一化处理。
- 残差连接可以防止信息丢失,归一化可以加快模型收敛。
Feed Forward:
- Feed Forward 是一个两层的全连接网络,第一层使用 ReLU 激活函数,第二层不使用激活函数。
- 进一步学习文本表示,提高模型的表达能力。
Masking Mechanism:
- Padding Mask 用于屏蔽掉 Padding 位置的信息,避免模型学习到 Padding 位置的特征。
- Sequence Mask 用于屏蔽掉当前 token 之后的信息,避免模型在预测下一个 token 时使用未来信息。
Softmax Layer:
- Softmax Layer 用于预测输出的单词,根据预测结果生成目标文本。
Transformer 模型通过 Encoder 和 Decoder 的协同工作,实现了序列到序列的转换任务。其核心机制 Self-Attention 能够有效地捕捉文本的上下文信息,Multi-Head Attention 和 Feed Forward 等模块则进一步提高了模型的表达能力。
transformer论文领读 https://www.youtube.com/watch?v=nzqlFIcCSWQ