我来详细对比Transformer和Diffusion这两种中央的深度学习模型。
1 基本概念对比
|
特性 |
Transformer |
Diffusion |
|
模型类型 |
判别式模型 |
生成式模型 |
|
主要应用 |
NLP,CV 序列建模 |
图像生成,音频生成,数据合成 |
|
核心思想 |
自注意力机制 |
渐进式去噪过程 |
2 架构对比
Transformer架构核心
import torch
import torch.nn as nn
import math
class TransformerBlock(nn.Module):
//Transformer基础块
def __init__(self, d_model, nhead, dim_feedforward=2048, dropout=0.1):
super().__init__()
#多头自注意力机制
self.self_attn = nn.MultiheadAttention(d_mode, nhead, dropout=dropout)
#前馈神经网络
self.linear1 = nn.Linear(d_model, dim_feedforward)
self.linear2 = nn.Linear(dim_feedforward, d_model)
#层归一化
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.dropout = nn.Dropout(dropout)
self.activeation = nn.ReLU()
def forward(self, src):
#自注意力 + 参差链接 + 层归一化
src2 = self.self_attn(src, src, src)[0]
src = self.norm1(src + self.dropout(src2))
#前馈网络 + 参差链接 + 层归一化
src2 = self.linear2(self.dropout(self.activeation(self.linear1(src))))
src = self.norm2(src + self.dropout(src2))
return src
Diffusion 架构核心
#导入torch库,这是主要的深度学习框架
import torch
#导入torch.nn模块,包含了构建神经网络所需的各种类,如Module, Linear
import torch.nn as nn
#导入math库,用于数学运算,如开方,对数
import math
#定义位置编码类,继承自nn.Module,使其成为一个Pytorch模块
class PositionalEncoding(nn.Module):
/*
位置编码-为输入序列添加位置信息
Transformer本身没有位置信息,需要额外添加
*/
#类的初始化方法,定义模型结构
def __init__(self, d_model, max_len=5000):
#调用父类nn.Module的初始化方法
super(PositionalEncoding, self).__init__()
#创建一个全零张量,形状为(最大序列长度,模型特征维度),用于存储位置编码
pe = torch.zeros(max_len, d_model)
#生成一个从0到max_len - 1的序列,并转换为服点类型,然后增加一个维度使其变为列向量
position - torch.arange(0, max_len, dtype=torch)
#计算位置编码公式中的除数项,目的是为不同维度生成不同的频率
#torch.arange(0, d_model, 2) 生成偶数索引[0,2,4,...,d_model-2]
#公式为 exp(-log(10000)/d_model * i) 其中i为维度索引
div_term = torch.exp(torch.aragen(0, d_model, 2).float() * (-math.log(10000)/d_model))
#对偶数维度位置(0,2,4...)使用正弦函数计算位置编码
pe[:,0::2] = torch.sin(position * div_term) #切片[:,0::2]表示所有行,列从0开始,步长尾2
#对奇数维度位置(1,3,5...)使用余弦函数计算位置编码
pe[:,1::2] = torch.cos(position * div_term) #切片 [:,1::2]表示所有行,列从1开始,步长为2
#为位置编码张量增加维度并转置,使其形状从(max_len, d_model)变为(max_len, 1, d_model)
#这样便于后续与输入张量进行广播相加
pe = pe.unsqueeze(0).transpose(0,1)
#将位置编码张量注册为模型的缓冲区buffer,缓冲区是模型的一部分,会随模型保存和加载,
#但不被视为可训练参数 既不参与梯度下降更新
self.register_buffer('pe', pe)
#定义前向传播方法,描述数据如何通过该模块
def forward(self, x):
#x (seq_len, batch_size, d_model)
#将位置编码加到输入张量上,slef.pe[:x.size(0),:]取前seq_len个位置编码
#Pytorch会自动进行广播,将位置编码加到每个batch的每个序列位置上
x = x + self.pe[:x.size(0),:]
#返回添加了位置信息的张量
return x
#定义简单的Transformer编码器模型,用于序列分类
class SimpleTransformer(nn.Module):
/*
简单的Transformer模型,用于序列分类任务
*/
def __init__(self, input_size, d_model, nhead, nunm_layers, num_classes, max_len=100):
#调用父类初始化
super(SimpleTransformer, self).__init__()
#将模型特征维度保存为实例变量,供后续使用
self.d_model = d_model
#定义输入嵌入层:一个线性层,将输入特征维度(input_size)映射到模型特征维度d_model
self.embedding = nn.Linear(input_size, d_model)
#实例化位置编码层
self.pos_encoder = PositionalEncoding(d_model, max_len)
#创建一个Transformer编码器层,构成Transformer堆叠块的基本单元
encoder_layer = nn.TransformerENcoderLayer(
d_model = d_model, #输入和输出的特征维度
nhead = nhead, #多头注意力机制中头的数量
dim_feedforward=512, #前馈神经网络中间层的维度
dropout=0.1 #dropout概率,用于防止过拟合
activation='relu' #前馈神经网络中使用的激活函数
)
#创建完整的Transformer编码器,由多个NUM_LAYERS个,上述编码器层堆叠而成
self.transformer_encoder = nn.TransformerEncoder(
encoder_layer,
num_layers=num_layers #堆叠的层数
)
#定义分类器头:一个线性层,将Transformer输出的特征d_model映射到类别数量num_classes
self.classifier=nn.Linear(d_model, num_classes)
#定义Dropout层, 在分类前随机丢弃一部分神经元,增强泛化能力
self.dropout = nn.Dropout(0.3)
#定义前向传播
def forward(self, x):
#x的输入形状, batch_size, seq_len, input_size
#获取输入张量的批量大小,徐磊长度,下划线表示忽略特征维度即Input_size
batch_size, seq_len, _ = x.shape
#通过嵌入层将输入特征投影到d_model维度
x = self.embedding(x * math.sqrt(self.d_model) #乘以sqrt(d_model)是对嵌入进行缩放,有助于稳定训练
#调整张量维度顺序,PyTorch的Transformer模块期望输入形状为seq_len, batch_size, d_model
x = x.transpose(0, 1)
#为序列添加位置编码信息
x = self.pos_encoder(x)
#将数据通过堆叠的Transformer编码器层进行处理
#注意:输入形状需为(seq_len,batch_size, d_model)
x = self.transformer_encoder(x)
#输出x的形状仍为(seq_len, batch_size,d_model)
#取输出序列中第一个位置 索引0 的特征向量作为整个序列的聚合表示
#这类似于BERT中的[CLS]token, 常用于分类任务
x=x[0,:,:]#输出形状变为 batch_size, d_model
#应用Dropout
x = self.dropout(x)
#通过分类器线性层得到最终分类分数logits
x = self.classifier(x)
#返回输出,形状为batch_size, num_classes
return x
#定义序列到序列Seq2Seq的Transformer模型,常用于机器翻译等任务
class TransformerForSequenceToSequence(nn.Module):
/*
序列到序列的Transformer模型 如机器翻译
*/
def __init__(self, src_vocab_size, tgt_vocab_size, d_model, nhead, num_layers):
super(TransformerForSequenceToSequence, self).__init__()
#编码器部分
#源语言词嵌入层:将源语言词汇索引映射为d_model维的向量
self.encoder_embedding = nn.Embedding(src_vocab_size, d_model)
#编码器位置编码
self.pos_encoder = PositionalEncoding(d_model)
#创建编码器层
encoder_layer = nn.TransformerEncoderLayer(d_model, nhead, 512, 0.1)
#创建堆叠的编码器
self.encoder = nn.TransformerEncoder(encoder_layer, num_layers)
#解码器部分
#目标语言词嵌入层,将目标语言词汇索引映射为d_model维的向量
self.decoder_embedding = nn.Embedding(tgt_vocab_size, d_model)
#解码器位置编码
self.pos_decoder = PositionalEncoding(d_model)
#创建解码器层
decoder_layer = nn.TransformerDecoderLayer(d_model, nhead, 512, 0.1)
#创建堆叠的解码器
self.decoder = nn.TransformerDecoder(decoder_layer, num_layers)
#输出层,一个线性层,将解码器输出的d_model维向量映射回目标语言词汇表大小
#得到每个位置是每个词的概率
self.output_layer = nn.Linear(d_model, tgt_vocab_size)
def forward(self, src, tgt):
#src 源语言序列,形状通常为seq_len, batch_size
#tgt 目标语言序列,形状通常为seq_len, batch_size
#编码器前向传播
#对原序列进行词嵌入闭并缩放
src_embed = self.encoder_embedding(src) * math.sqrt(self.d_model)
#添加位置编码
src_embed=self.pos_encoder(src_embed)
#通过编码器,得到记忆memory,供解码器在生成时关注
memory = self.encoder(src_embed)
#输出形状src_seq_len, batch_size, d_model
#解码器前向传播
#对目标序列进行词嵌入并缩放,注意,在训练时,tgt时完整的目标序列,但回做偏移
tgt_embed = self.decoder_embedding(tgt) * math.sqrt(self.d_model)
#添加位置编码
tgt_embed = self.pos_decoder(tgt_embed)
#解码器前向传播,接收
#1 tgt_embed 目标序列嵌入,自注意力部分关注自身历史信息
#2 memory 编码器输出 交叉注意力部分关注源语言信息
output = self.decoder(tgt_embed, memory)#输出形状
#输出层
#将解码器输出的每个位置的向量映射到词汇表维度,得到每个词的分数
output = self.output_layer(output) #输出形状,tgt_seq_len, batch_size, tgt_vocab_size
return output
#定义演示函数,展示如何使用SimpleTransformer模型
def demo_transformer():
#参数设置
batch_szie=32 #批量大小,即一次处理多少样本
seq_len = 20 #每个样本序列的长度
input_size=16 #输入数据的原始特征维度
d_model=128 #Transformer内部的特征维度 模型宽度
nhead=8 #多头注意力中头的数量
num_layers=3 #Transforerm编码器堆叠的层数 模型深度
num_classes = 5 #分类任务的类别总数
#实例化SimpleTransformer模型
model = SimpleTransformer(input_size, d_model, nhead, num_layers, num_classes)
#模拟 随机生成 -一批输入数据
#形状为 batch_size, seq_len, input_size
x = torch.randn(batch_size, seq_len, input_size)
#将输入数据传入模型进行前向传播,得到输出
output = model(x)
#打印输入和输出的张量形状, 便于理解数据流
#返回模型和输出,供外部可能的进一步使用
return mdel, output
#程序入口,如果直接运行此脚本,则执行演示函数
if __name__ == '__main__':
#运行Transformer示例,获取模型和输出
transformer_model, transformer_output = demo_transformer()
8763

被折叠的 条评论
为什么被折叠?



