pytorch实现的transformer代码分析

news/2025/12/14 15:01:37/文章来源:https://www.cnblogs.com/pythonClub/p/19348911

 

CheersGrant/nlp-tutorial: Natural Language Processing Tutorial for Deep Learning Researchers

 

https://github.com/CheersGrant/nlp-tutorial

 

 

一些基础变量和参数:

复制代码
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
from torch.autograd import Variable
import matplotlib.pyplot as pltdtype = torch.FloatTensor
# S: Symbol that shows starting of decoding input
# E: Symbol that shows starting of decoding output
# P: Symbol that will fill in blank sequence if current batch data size is short than time steps
sentences = ['ich mochte ein bier P', 'S i want a beer', 'i want a beer E']# Transformer Parameters
# Padding Should be Zero
src_vocab = {'P' : 0, 'ich' : 1, 'mochte' : 2, 'ein' : 3, 'bier' : 4}
src_vocab_size = len(src_vocab)tgt_vocab = {'P' : 0, 'i' : 1, 'want' : 2, 'a' : 3, 'beer' : 4, 'S' : 5, 'E' : 6}
number_dict = {i: w for i, w in enumerate(tgt_vocab)}
tgt_vocab_size = len(tgt_vocab)src_len = 5
tgt_len = 5d_model = 512  # Embedding Size
d_ff = 2048 # FeedForward dimension
d_k = d_v = 64  # dimension of K(=Q), V
n_layers = 6  # number of Encoder of Decoder Layer
n_heads = 8  # number of heads in Multi-Head Attention
复制代码

函数一:将句子转换成向量

复制代码
def make_batch(sentences):input_batch = [[src_vocab[n] for n in sentences[0].split()]]output_batch = [[tgt_vocab[n] for n in sentences[1].split()]]target_batch = [[tgt_vocab[n] for n in sentences[2].split()]]return Variable(torch.LongTensor(input_batch)), Variable(torch.LongTensor(output_batch)), Variable(torch.LongTensor(target_batch))
复制代码
input_batch,output_batch,target_batch=make_batch(sentences)
input_batch,output_batch,target_batch
输出:
(tensor([[1, 2, 3, 4, 0]]),tensor([[5, 1, 2, 3, 4]]),tensor([[1, 2, 3, 4, 6]]))

函数二:位置嵌入

复制代码
def get_sinusoid_encoding_table(n_position, d_model):def cal_angle(position, hid_idx):return position / np.power(10000, 2 * (hid_idx // 2) / d_model)def get_posi_angle_vec(position):return [cal_angle(position, hid_j) for hid_j in range(d_model)]sinusoid_table = np.array([get_posi_angle_vec(pos_i) for pos_i in range(n_position)])sinusoid_table[:, 0::2] = np.sin(sinusoid_table[:, 0::2])  # dim 2isinusoid_table[:, 1::2] = np.cos(sinusoid_table[:, 1::2])  # dim 2i+1return torch.FloatTensor(sinusoid_table)
复制代码
sinusoid_table=get_sinusoid_encoding_table(src_len+1,d_model)
sinusoid_table.shape
torch.Size([6, 512])

sinusoid_table

复制代码
tensor([[ 0.0000e+00,  1.0000e+00,  0.0000e+00,  ...,  1.0000e+00,0.0000e+00,  1.0000e+00],[ 8.4147e-01,  5.4030e-01,  8.2186e-01,  ...,  1.0000e+00,1.0366e-04,  1.0000e+00],[ 9.0930e-01, -4.1615e-01,  9.3641e-01,  ...,  1.0000e+00,2.0733e-04,  1.0000e+00],[ 1.4112e-01, -9.8999e-01,  2.4509e-01,  ...,  1.0000e+00,3.1099e-04,  1.0000e+00],[-7.5680e-01, -6.5364e-01, -6.5717e-01,  ...,  1.0000e+00,4.1465e-04,  1.0000e+00],[-9.5892e-01,  2.8366e-01, -9.9385e-01,  ...,  1.0000e+00,5.1832e-04,  1.0000e+00]])
复制代码

函数三:mask机制

复制代码
def get_attn_pad_mask(seq_q, seq_k):batch_size, len_q = seq_q.size()batch_size, len_k = seq_k.size()# eq(zero) is PAD tokenpad_attn_mask = seq_k.data.eq(0).unsqueeze(1)  # batch_size x 1 x len_k(=len_q), one is maskingreturn pad_attn_mask.expand(batch_size, len_q, len_k)  # batch_size x len_q x len_k
复制代码

函数四:

def get_attn_subsequent_mask(seq):attn_shape = [seq.size(0), seq.size(1), seq.size(1)]subsequent_mask = np.triu(np.ones(attn_shape), k=1)subsequent_mask = torch.from_numpy(subsequent_mask).byte()return subsequent_mask

不同的层:

复制代码
class ScaledDotProductAttention(nn.Module):def __init__(self):super(ScaledDotProductAttention, self).__init__()def forward(self, Q, K, V, attn_mask):scores = torch.matmul(Q, K.transpose(-1, -2)) / np.sqrt(d_k) # scores : [batch_size x n_heads x len_q(=len_k) x len_k(=len_q)]scores.masked_fill_(attn_mask, -1e9) # Fills elements of self tensor with value where mask is one.attn = nn.Softmax(dim=-1)(scores)context = torch.matmul(attn, V)return context, attnclass MultiHeadAttention(nn.Module):def __init__(self):super(MultiHeadAttention, self).__init__()self.W_Q = nn.Linear(d_model, d_k * n_heads)self.W_K = nn.Linear(d_model, d_k * n_heads)self.W_V = nn.Linear(d_model, d_v * n_heads)def forward(self, Q, K, V, attn_mask):# q: [batch_size x len_q x d_model], k: [batch_size x len_k x d_model], v: [batch_size x len_k x d_model]residual, batch_size = Q, Q.size(0)# (B, S, D) -proj-> (B, S, D) -split-> (B, S, H, W) -trans-> (B, H, S, W)q_s = self.W_Q(Q).view(batch_size, -1, n_heads, d_k).transpose(1,2)  # q_s: [batch_size x n_heads x len_q x d_k]k_s = self.W_K(K).view(batch_size, -1, n_heads, d_k).transpose(1,2)  # k_s: [batch_size x n_heads x len_k x d_k]v_s = self.W_V(V).view(batch_size, -1, n_heads, d_v).transpose(1,2)  # v_s: [batch_size x n_heads x len_k x d_v]attn_mask = attn_mask.unsqueeze(1).repeat(1, n_heads, 1, 1) # attn_mask : [batch_size x n_heads x len_q x len_k]# context: [batch_size x n_heads x len_q x d_v], attn: [batch_size x n_heads x len_q(=len_k) x len_k(=len_q)]context, attn = ScaledDotProductAttention()(q_s, k_s, v_s, attn_mask)context = context.transpose(1, 2).contiguous().view(batch_size, -1, n_heads * d_v) # context: [batch_size x len_q x n_heads * d_v]output = nn.Linear(n_heads * d_v, d_model)(context)return nn.LayerNorm(d_model)(output + residual), attn # output: [batch_size x len_q x d_model]class PoswiseFeedForwardNet(nn.Module):def __init__(self):super(PoswiseFeedForwardNet, self).__init__()self.conv1 = nn.Conv1d(in_channels=d_model, out_channels=d_ff, kernel_size=1)self.conv2 = nn.Conv1d(in_channels=d_ff, out_channels=d_model, kernel_size=1)def forward(self, inputs):residual = inputs # inputs : [batch_size, len_q, d_model]output = nn.ReLU()(self.conv1(inputs.transpose(1, 2)))output = self.conv2(output).transpose(1, 2)return nn.LayerNorm(d_model)(output + residual)class EncoderLayer(nn.Module):def __init__(self):super(EncoderLayer, self).__init__()self.enc_self_attn = MultiHeadAttention()self.pos_ffn = PoswiseFeedForwardNet()def forward(self, enc_inputs, enc_self_attn_mask):enc_outputs, attn = self.enc_self_attn(enc_inputs, enc_inputs, enc_inputs, enc_self_attn_mask) # enc_inputs to same Q,K,Venc_outputs = self.pos_ffn(enc_outputs) # enc_outputs: [batch_size x len_q x d_model]return enc_outputs, attnclass DecoderLayer(nn.Module):def __init__(self):super(DecoderLayer, self).__init__()self.dec_self_attn = MultiHeadAttention()self.dec_enc_attn = MultiHeadAttention()self.pos_ffn = PoswiseFeedForwardNet()def forward(self, dec_inputs, enc_outputs, dec_self_attn_mask, dec_enc_attn_mask):dec_outputs, dec_self_attn = self.dec_self_attn(dec_inputs, dec_inputs, dec_inputs, dec_self_attn_mask)dec_outputs, dec_enc_attn = self.dec_enc_attn(dec_outputs, enc_outputs, enc_outputs, dec_enc_attn_mask)dec_outputs = self.pos_ffn(dec_outputs)return dec_outputs, dec_self_attn, dec_enc_attnclass Encoder(nn.Module):def __init__(self):super(Encoder, self).__init__()self.src_emb = nn.Embedding(src_vocab_size, d_model)self.pos_emb = nn.Embedding.from_pretrained(get_sinusoid_encoding_table(src_len+1, d_model),freeze=True)self.layers = nn.ModuleList([EncoderLayer() for _ in range(n_layers)])def forward(self, enc_inputs): # enc_inputs : [batch_size x source_len]enc_outputs = self.src_emb(enc_inputs) + self.pos_emb(torch.LongTensor([[1,2,3,4,0]]))enc_self_attn_mask = get_attn_pad_mask(enc_inputs, enc_inputs)enc_self_attns = []for layer in self.layers:enc_outputs, enc_self_attn = layer(enc_outputs, enc_self_attn_mask)enc_self_attns.append(enc_self_attn)return enc_outputs, enc_self_attnsclass Decoder(nn.Module):def __init__(self):super(Decoder, self).__init__()self.tgt_emb = nn.Embedding(tgt_vocab_size, d_model)self.pos_emb = nn.Embedding.from_pretrained(get_sinusoid_encoding_table(tgt_len+1, d_model),freeze=True)self.layers = nn.ModuleList([DecoderLayer() for _ in range(n_layers)])def forward(self, dec_inputs, enc_inputs, enc_outputs): # dec_inputs : [batch_size x target_len]dec_outputs = self.tgt_emb(dec_inputs) + self.pos_emb(torch.LongTensor([[5,1,2,3,4]]))dec_self_attn_pad_mask = get_attn_pad_mask(dec_inputs, dec_inputs)dec_self_attn_subsequent_mask = get_attn_subsequent_mask(dec_inputs)dec_self_attn_mask = torch.gt((dec_self_attn_pad_mask + dec_self_attn_subsequent_mask), 0)dec_enc_attn_mask = get_attn_pad_mask(dec_inputs, enc_inputs)dec_self_attns, dec_enc_attns = [], []for layer in self.layers:dec_outputs, dec_self_attn, dec_enc_attn = layer(dec_outputs, enc_outputs, dec_self_attn_mask, dec_enc_attn_mask)dec_self_attns.append(dec_self_attn)dec_enc_attns.append(dec_enc_attn)return dec_outputs, dec_self_attns, dec_enc_attnsclass Transformer(nn.Module):def __init__(self):super(Transformer, self).__init__()self.encoder = Encoder()self.decoder = Decoder()self.projection = nn.Linear(d_model, tgt_vocab_size, bias=False)def forward(self, enc_inputs, dec_inputs):enc_outputs, enc_self_attns = self.encoder(enc_inputs)dec_outputs, dec_self_attns, dec_enc_attns = self.decoder(dec_inputs, enc_inputs, enc_outputs)dec_logits = self.projection(dec_outputs) # dec_logits : [batch_size x src_vocab_size x tgt_vocab_size]return dec_logits.view(-1, dec_logits.size(-1)), enc_self_attns, dec_self_attns, dec_enc_attns
复制代码

从Transformer类中慢慢看过来:

model = Transformer()

初始化的时候:构建编码器、解码器、前馈神经网络。

在前向传播的过程中:

编码器输入(源语言)--》编码器输出、编码器自注意力

解码器输入(目标语言、源语言、编码器输出)--》解码器输出、解码器自注意力、解码-编码注意力

前馈神经网络输入(解码器输出)--》dec_logits

分别打印一下每个变量的形状:

model=Transformer()
enc_inputs, dec_inputs, target_batch = make_batch(sentences)
outputs, enc_self_attns, dec_self_attns, dec_enc_attns = model(enc_inputs, dec_inputs)
复制代码
enc_inputs的形状是: torch.Size([1, 5])
enc_inputs的形状是: torch.Size([1, 5])
enc_outputs的形状是: torch.Size([1, 5, 512])
enc_self_attns的形状是: (6,)
dec_outputs的形状是: torch.Size([1, 5, 512])
dec_self_attns的形状是: (6,)
dec_enc_attns的形状是: (6,)
复制代码

其中的细节再看了。

最后是训练和预测:

复制代码
model = Transformer()criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)def showgraph(attn):attn = attn[-1].squeeze(0)[0]attn = attn.squeeze(0).data.numpy()fig = plt.figure(figsize=(n_heads, n_heads)) # [n_heads, n_heads]ax = fig.add_subplot(1, 1, 1)ax.matshow(attn, cmap='viridis')ax.set_xticklabels(['']+sentences[0].split(), fontdict={'fontsize': 14}, rotation=90)ax.set_yticklabels(['']+sentences[2].split(), fontdict={'fontsize': 14})plt.show()for epoch in range(20):optimizer.zero_grad()enc_inputs, dec_inputs, target_batch = make_batch(sentences)outputs, enc_self_attns, dec_self_attns, dec_enc_attns = model(enc_inputs, dec_inputs)loss = criterion(outputs, target_batch.contiguous().view(-1))print('Epoch:', '%04d' % (epoch + 1), 'cost =', '{:.6f}'.format(loss))loss.backward()optimizer.step()# Test
predict, _, _, _ = model(enc_inputs, dec_inputs)
predict = predict.data.max(1, keepdim=True)[1]
print(sentences[0], '->', [number_dict[n.item()] for n in predict.squeeze()])print('first head of last state enc_self_attns')
showgraph(enc_self_attns)print('first head of last state dec_self_attns')
showgraph(dec_self_attns)print('first head of last state dec_enc_attns')
showgraph(dec_enc_attns)
复制代码

结果:

Epoch: 0001 cost = 2.058749
Epoch: 0002 cost = 0.096908
Epoch: 0003 cost = 0.034705
Epoch: 0004 cost = 0.045140
Epoch: 0005 cost = 0.005356
Epoch: 0006 cost = 0.000624
Epoch: 0007 cost = 0.004379
Epoch: 0008 cost = 0.001091
Epoch: 0009 cost = 0.000852
Epoch: 0010 cost = 0.002038
Epoch: 0011 cost = 0.000404
Epoch: 0012 cost = 0.000122
Epoch: 0013 cost = 0.000275
Epoch: 0014 cost = 0.000174
Epoch: 0015 cost = 0.000479
Epoch: 0016 cost = 0.003401
Epoch: 0017 cost = 0.000108
Epoch: 0018 cost = 0.000068
Epoch: 0019 cost = 0.000033
Epoch: 0020 cost = 0.000050
ich mochte ein bier P -> ['i', 'want', 'a', 'beer', 'E']
first head of last state enc_self_attns
first head of last state dec_self_attns
first head of last state dec_enc_attns
 
 
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1013658.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

5分钟搞定抖音无水印下载:douyin_downloader完全指南

5分钟搞定抖音无水印下载:douyin_downloader完全指南 【免费下载链接】douyin_downloader 抖音短视频无水印下载 win编译版本下载:https://www.lanzous.com/i9za5od 项目地址: https://gitcode.com/gh_mirrors/dou/douyin_downloader 还在为抖音视…

AutoGPT在服装搭配建议系统中的风格迁移应用

AutoGPT在服装搭配建议系统中的风格迁移应用 在当今个性化消费日益增长的时代,用户不再满足于“你喜欢什么就推荐什么”的静态推荐模式。尤其是在时尚领域,一套真正打动人心的穿搭建议,不仅要契合场合、气候与身材,更要捕捉到某种…

14、Python在不同场景下的应用与实践

Python在不同场景下的应用与实践 1. 环境与初始化 在Python开发中,涉及到一些特定库的使用。除了 xbmcplugin 、 xbmcgui 和 xbmcaddon 外,其余都是标准Python库,可通过pip从PyPI获取。而XBMC的Python运行时已内置所有组件,无需自行安装。 urllib 和 urllib2 :…

38、深入探索bc计算器、数组及特殊编程技巧

深入探索bc计算器、数组及特殊编程技巧 1. bc - 任意精度计算语言 在进行整数运算时,shell 能够处理多种类型的计算。然而,当需要进行更高级的数学运算或使用浮点数时,shell 就显得力不从心了,这时就需要借助外部程序。其中一种选择是使用专门的计算器程序,比如很多 Linu…

Springboot美食分享网站a73c9(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。

系统程序文件列表项目功能:用户,美食分类,菜谱分类,美食菜谱,饮食计划,热门美食开题报告内容一、选题背景与意义(一)选题背景随着互联网技术的飞速发展和人们生活水平的提高,美食已成为人们日常生活中不可或缺的一部分。越来越多的…

DeBERTa零样本分类终极指南:从技术原理到生产部署的完整攻略

你是否曾为传统分类模型的高昂标注成本而头疼?是否在寻找一个既能理解复杂语义又无需训练数据的智能分类器?DeBERTa-v3-large-zeroshot-v2.0正是为你量身打造的技术利器。这个基于自然语言推理的通用分类器能够在零样本条件下完成任意文本分类任务&#…

Oracle获取SQL执行计划

Oracle查看SQL执行计划以及执行开销 EXPLAIN PLAN是Oracle提供的一种静态分析SQL执行路径的方法,它通过生成逻辑执行计划帮助开发者和DBA预测SQL的性能表现。 注意:EXPLAIN PLAN不会实际执行SQL,而是将优化器生成的执行计划写入PLAN_TABLE&am…

vue基于Spring Boot框架的光辉家政服务评价系统 保洁员预约系统的设计与实现_s3d3g194

目录具体实现截图项目介绍论文大纲核心代码部分展示项目运行指导结论源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作具体实现截图 本系统(程序源码数据库调试部署讲解)同时还支持java、ThinkPHP、Node.js、Spring B…

近视

回过神来 远方已经模糊不清了 街头的灯光突然炸开 好像看到了烟火想 现在想去了解他人的内心 却连前方招牌上的字都看不清 收起

39、高级Shell技巧与特性解析

高级Shell技巧与特性解析 1. 数组索引扩展与排序 在处理数组时,有时需要对数组元素的输出进行排序。由于数组元素的扩展默认是无序的,因此可以将整个循环的输出通过管道传递给 sort 命令。另外,使用 "${!array[@]}" 扩展,可将其扩展为数组索引列表,而非数…

15、Python编程:图像与即时通讯应用开发

Python编程:图像与即时通讯应用开发 1. Python图像处理基础 在Python中,我们可以使用SciPy库对PNG图像进行处理和转换。同时,NumPy库也提供了一些有用的函数来操作数组。 其他有用函数 dtype()函数 :用于找出数组中元素的数据类型。 ndim()函数 :返回数组的维度数。…

VAR视觉自回归模型:技术突破与实战应用全解析

VAR视觉自回归模型:技术突破与实战应用全解析 【免费下载链接】VAR [GPT beats diffusion🔥] [scaling laws in visual generation📈] Official impl. of "Visual Autoregressive Modeling: Scalable Image Generation via Next-Scale P…

20亿参数撬动物理世界交互:Isaac-0.1开启轻量化多模态AI新纪元

导语:Meta前Chameleon团队打造的20亿参数多模态模型Isaac-0.1,以"小而精"的技术路径重新定义物理世界智能交互标准,为边缘设备AI部署提供新范式。 【免费下载链接】Isaac-0.1 项目地址: https://ai.gitcode.com/hf_mirrors/Perc…

vue基于Spring Boot框架的居民小区物业管理系统的设计与实现_m1oe48m7

目录具体实现截图项目介绍论文大纲核心代码部分展示项目运行指导结论源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作具体实现截图 本系统(程序源码数据库调试部署讲解)同时还支持java、ThinkPHP、Node.js、Spring B…

大模型时代的昇腾算子开发:CANN+Ascend C 驱动的高效落地实践

大模型时代的昇腾算子开发:CANNAscend C 驱动的高效落地实践随着大语言模型(LLM)、多模态模型的爆发式发展,AI 算力需求呈现指数级增长,对底层算子的性能、兼容性与扩展性提出了前所未有的高要求。大模型的“大张量、动…

口碑好的家用综合训练器公司

选对专业品牌,口碑好的家用综合训练器如何重塑家庭健身体验"不是所有训练器都叫专业,真正的口碑源于对细节的极致把控。"随着健康意识的提升,越来越多的家庭开始将专业健身设备纳入家居空间。根据上海兽鸟智能科技有限公司市场调研…

9、Ubuntu系统软件使用与配置全攻略

Ubuntu系统软件使用与配置全攻略 1. 软件安装基础 Ubuntu系统自带了一系列软件应用,但你可能还想安装额外的应用程序并探索其他可用软件。好在Ubuntu系统有强大的基础,让软件安装变得简单,只需在Ubuntu软件中心点击操作即可。 另外,运行应用程序除了从“应用程序”菜单中…

3D部件处理实战指南:4种核心文件格式的深度应用

3D部件处理实战指南:4种核心文件格式的深度应用 【免费下载链接】Hunyuan3D-Part 腾讯混元3D-Part 项目地址: https://ai.gitcode.com/tencent_hunyuan/Hunyuan3D-Part 在当今的3D内容创作领域,文件格式的选择直接影响着工作流程的效率和最终成果…

为什么我写的越来越少了

概述 细心的朋友可能发现了,最近博客的更新频率明显降低了。 前几天看到一篇文章《Blogging in 2025: Screaming into the void》,读完之后深有感触。文中提到了“对着虚空呐喊”的感觉,这其实也正是我当下的心境。…

vue基于Spring Boot框架的技术实现的医院住院管理系统_229p8ejv

目录具体实现截图项目介绍论文大纲核心代码部分展示项目运行指导结论源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作具体实现截图 本系统(程序源码数据库调试部署讲解)同时还支持java、ThinkPHP、Node.js、Spring B…