Transformer 是一种基于自注意力机制的深度神经网络模型,常用于处理序列到序列的任务,例如机器翻译、文本摘要、问答系统等。它由 Encoder 和 Decoder 两个主要部分组成,每个部分包含多个相同的 Block。
Transformer 结构图
Transformer 结构
python
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 mask
Encoder 的作用是将输入文本编码成包含上下文信息的向量表示。每个 Block 包含 Multi-Head Attention、Add & Norm 和 Feed Forward 三个子模块。
- Multi-Head Attention 由多个 Self-Attention 子模块组成,用于提取文本的上下文信息。
- Add & Norm 用于连接不同模块的输出,并进行残差连接和归一化处理。
- Feed Forward 是一个两层的全连接网络,进一步学习文本表示。
python
# 定义编码器块类
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 src
Decoder 的作用是根据 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 是一个两层的全连接网络,进一步学习文本表示。
python
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 论文领读 www.youtube.com/watch?v=nzq...