前言

PyTorch、TensorFlow都是主流的深度学习框架,今天主要讲解一下如何快速使用pytorch搭建自己的模型。至于为什么选择讲解pytorch,这里我就简单说明一下自己的使用感受(相对TensorFlow来说),也就是pytorch对比TensorFlow有哪些区别。

二者区别

  1. pytorch是一个动态的框架,而TensorFlow是一个静态的框

何为静态的框架呢?我们知道,TensorFlow的特性是,首先我们需要先构建一个TensorFlow的计算图,构建好计算图之后,这样一个计算图是不能够变的了,然后我们再传入不同的数据进去,进行计算。这就带来一个问题,就是固定了计算图的流程,这样开发就不灵活性,如果我们要改变计算的逻辑,这样的动态计算TensorFlow是实现不了的,或者是很麻烦。那么只有面临重构的命运,就是重新构建一个TensorFlow的计算图。但是pytorch就是一个动态的框架,这就和python的逻辑是一样的,要对变量做任何操作都是灵活的。

2. 封装模块层次不同

TensorFlow包含了二个层次:ensor,Module ;而pytorch包括了三个层次:tensor,variable,Module。为什么多了一个variable了,其实variable只是tensor的一个封装,这样一个封装,最重要的目的,就是能够保存住该variable在整个计算图中的位置,详细来说就是:能够知道计算图中各个变量之间的相互依赖关系。而主要的目的也是为了反向求梯度了;而Module,是一个更高的层次,如果使用这个Module,那可厉害了,这是一个神经网络的层次,可以直接调用全连接层,卷积层,等等神经网络。

关于pytorch和TensorFlow对比,具体可以参考Jamie_Wu大佬的基于pytorch的风格迁移实战,归纳的十分详细,这是他的细化导图:

说了这么多,接下来就介绍一下如何快速用python搭建模型吧。

pytorch快速搭建模型       

和TensorFlow很像,Pytorch也通过继承父类来搭建自定义模型,同样也是实现两个方法。在TF中是__init__()和call(),在Pytorch中则是__init__()和forward()。功能类似,都分别是初始化模型内部结构和进行推理。其它功能比如计算loss和训练函数,你也可以继承在里面,当然这是可选的,下面就以搭建一个判别MNIST手写字的Demo做简单介绍:

1.模型定义   

  •   获取设备,以方便后面的模型与变量进行内存迁移,设备名只有两种:'cuda'和'cpu'。通常是在你有GPU的情况下需要这样显式进行设备的设置,从而在需要时,你可以将变量从主存迁移到显存中。如果没有GPU,不获取也没事,pytorch会默认将参数都保存在主存中。代码如下:
  • 模型中层的定义,可以使用Sequential将想要统一管理的层集中表示为一层。
import numpy as np
import matplotlib.pyplot as plt
import torch
#引入nn和optim优化模块
from torch import nn,optim
from torchsummary import summary
from keras.datasets import mnist
from keras.utils import to_categorical#自定义类,并引入nn.Module模块
class TorchModelTest(nn.Module):def __init__(self,device):super().__init__() #Sequential管理所有层self.layer1 = nn.Sequential(nn.Flatten(),nn.Linear(28*28,512),nn.ReLU())self.layer2 = nn.Sequential(nn.Linear(512,512),nn.ReLU()) self.layer3 = nn.Sequential(nn.Linear(512,512),nn.ReLU())self.layer4 = nn.Sequential(nn.Linear(512,10),nn.Softmax()) 
  • 在初始化中将模型参数迁移到GPU显存中,加速运算,当然你也可以在需要时在外部执行model.to(device)进行迁移。
 self.to(device)
  • 定义模型的优化器

和TensorFlow不同,pytorch需要在定义时就将需要梯度下降的参数传入,也就是其中的self.parameters(),表示当前模型的所有参数。实际上你不用担心定义优化器和模型参数的顺序问题,因为self.parameters()的输出并不是模型参数的实例,而是整个模型参数对象的指针,所以即使你在定义优化器之后又定义了一个层,它依然能优化到。当然优化器你也可以在外部定义,传入model.parameters()即可。这里定义了一个随机梯度下降。

self.opt = optim.SGD(self.parameters(),lr=0.01)
  • 模型的前向传播,和TensorFlow的call()类似,定义好model()所执行的就是这个函数。
import numpy as np
import matplotlib.pyplot as plt
import torch
#引入nn和optim优化模块
from torch import nn,optim
from torchsummary import summary
from keras.datasets import mnist
from keras.utils import to_categorical#自定义类,并引入nn.Module模块
class TorchModelTest(nn.Module):def __init__(self,device):super().__init__() #Sequential管理所有层self.layer1 = nn.Sequential(nn.Flatten(),nn.Linear(28*28,512),nn.ReLU())self.layer2 = nn.Sequential(nn.Linear(512,512),nn.ReLU()) self.layer3 = nn.Sequential(nn.Linear(512,512),nn.ReLU())self.layer4 = nn.Sequential(nn.Linear(512,10),nn.Softmax()) #模型的前向传播def forward(self,inputs): x = self.layer1(inputs)x = self.layer2(x)x = self.layer3(x)x = self.layer4(x)return x
  • 将获取loss的函数集成在了模型中,这里计算的是真实标签和预测标签之间的交叉熵。
 def get_loss(self,true_labels,predicts): loss = -true_labels * torch.log(predicts)loss = torch.mean(loss)
  • 在TensorFlow中,参数梯度是保存在梯度带中的,而在pytorch中,参数梯度是各自集成在对应的参数中的,可以使用tensor.grad来查看。每次对loss执行backward(),pytorch都会将参与loss计算的所有可训练参数关于loss的梯度叠加进去(直接相加)。所以如果我们没有叠加梯度的意愿的话,那就要在backward()之前先把之前的梯度删除。又因为我们前面已经把待训练的参数都传入了优化器,所以,对优化器使用zero_grad(),就能把所有待训练参数中已存在的梯度都清零。那么梯度叠加什么时候用到呢?比如批量梯度下降,当内存不够直接计算整个批量的梯度时,我们只能将批量分成一部分一部分来计算,每算一个部分得到loss就backward()一次,从而得到整个批量的梯度。梯度计算好后,再执行优化器的step(),优化器根据可训练参数的梯度对其执行一步优化 。
 def train(self,imgs,labels): predicts = model(imgs) loss = self.get_loss(labels,predicts)self.opt.zero_grad()loss.backward()self.opt.step()
  • 使用torchsummary函数显示模型结构。注意:不把这个继承在torch里面,要重新安装一个torchsummary库。
model = TorchModelTest(device)
summary(model,(1,28,28),3,device='cuda')

支持第一步模型的定义就完成了,完整的代码如下:

import numpy as np
import matplotlib.pyplot as plt
import torch
from torch import nn,optim
from torchsummary import summary
from keras.datasets import mnist
from keras.utils import to_categorical
device = torch.device('cuda') #——————1——————class TorchModelTest(nn.Module):def __init__(self,device):super().__init__() self.layer1 = nn.Sequential(nn.Flatten(),nn.Linear(28*28,512),nn.ReLU())#——————2——————self.layer2 = nn.Sequential(nn.Linear(512,512),nn.ReLU()) self.layer3 = nn.Sequential(nn.Linear(512,512),nn.ReLU())self.layer4 = nn.Sequential(nn.Linear(512,10),nn.Softmax()) self.to(device) #——————3——————self.opt = optim.SGD(self.parameters(),lr=0.01)#——————4——————def forward(self,inputs): #——————5——————x = self.layer1(inputs)x = self.layer2(x)x = self.layer3(x)x = self.layer4(x)return x def get_loss(self,true_labels,predicts): loss = -true_labels * torch.log(predicts) #——————6——————loss = torch.mean(loss)return lossdef train(self,imgs,labels): predicts = model(imgs) loss = self.get_loss(labels,predicts)self.opt.zero_grad()#——————7——————loss.backward()#——————8——————self.opt.step()#——————9——————
model = TorchModelTest(device)
summary(model,(1,28,28),3,device='cuda') #——————10——————

2.模型的训练以及可视化 

定义好模型后,就要使用模型进行训练,因为pytorch自带的MNIST数据集并不好用,所以我使用的是Keras自带的,定义了一个获取数据的生成器。下面是完整的训练及绘图代码(100次迭代记录一次准确率),代码如下

import numpy as np
import matplotlib.pyplot as plt
import torch
from torch import nn,optim
from torchsummary import summary
from keras.datasets import mnist
from keras.utils import to_categorical
device = torch.device('cuda') class TorchModelTest(nn.Module):def __init__(self,device):super().__init__() self.layer1 = nn.Sequential(nn.Flatten(),nn.Linear(28*28,512),nn.ReLU())self.layer2 = nn.Sequential(nn.Linear(512,512),nn.ReLU()) self.layer3 = nn.Sequential(nn.Linear(512,512),nn.ReLU())self.layer4 = nn.Sequential(nn.Linear(512,10),nn.Softmax()) self.to(device) self.opt = optim.SGD(self.parameters(),lr=0.01)def forward(self,inputs): x = self.layer1(inputs)x = self.layer2(x)x = self.layer3(x)x = self.layer4(x)return x def get_loss(self,true_labels,predicts): loss = -true_labels * torch.log(predicts) loss = torch.mean(loss)return lossdef train(self,imgs,labels): predicts = model(imgs) loss = self.get_loss(labels,predicts)self.opt.zero_grad()loss.backward()self.opt.step()
def get_data(device,is_train = True, batch = 1024, num = 10000):train_data,test_data = mnist.load_data()if is_train:imgs,labels = train_dataelse:imgs,labels = test_data imgs = (imgs/255*2-1)[:,np.newaxis,...]labels = to_categorical(labels,10) imgs = torch.tensor(imgs,dtype=torch.float32).to(device)labels = torch.tensor(labels,dtype=torch.float32).to(device)i = 0while(True):i += batchif i > num:i = batch yield imgs[i-batch:i],labels[i-batch:i]
train_dg = get_data(device, True,batch=4096,num=60000)
test_dg = get_data(device, False,batch=5000,num=10000) model = TorchModelTest(device)
summary(model,(1,28,28),11,device='cuda')
ACCs = []
import time
start = time.time()
for j in range(20000):#训练imgs,labels = next(train_dg)model.train(imgs,labels)#验证img,label = next(test_dg)predicts = model(img) acc = 1 - torch.count_nonzero(torch.argmax(predicts,axis=1) - torch.argmax(label,axis=1))/label.shape[0]if j % 50 == 0:t = time.time() - startstart = time.time()ACCs.append(acc.cpu().numpy())print(j,t,'ACC: ',acc)
#绘图
x = np.linspace(0,len(ACCs),len(ACCs))
plt.plot(x,ACCs)

好了,看一下最终的准确率变化图:


3.常用优化技巧

  • 3.1  tensor与array

  需要注意的是,pytorch的tensor基于numpy的array,它们是共享内存的。也就是说,如果你把tensor直接插入一个列表,当你修改这个tensor时,列表中的这个tensor也会被修改;更容易被忽略的是,即使你用tensor.detach.numpy(),先将tensor转换为array类型,再插入列表,当你修改原本的tensor时,列表中的这个array也依然会被修改。所以如果我们只是想保存tensor的值而不是整个对象,就要使用np.array(tensor)将tensor的值复制出来。

  • 3.2  自定义层

    在TensorFlow中,自定义模型通常继承keras的Model,而自定义层则是继承layers.Layer,继承不同的父类通常会造成初学者的困扰。而在pytorch中,自定义层与自定义模型一样,都是继承nn.Module。Pytorch将层与模型都看成了模块,这很容易理解。的确,层与模型之间本来也没有什么明确的界限。并且定义方式与上面定义模型的方式一样,也是实现两个函数即可。分别是__init__和forward

首先,自定义一个全连接层。层中可训练参数的定义是使用nn.Parameter,如果直接使用torch.tensor是无法在#5中遍历到的;接着,输入并计算loss,然后反向传播计算参数梯度;最后,输出完成反向传播后层参数的梯度。

只要按照以上三步定义的层,这样就可以和pytorch自带的层一样直接插入模型中使用。完整demo代码如下:

import torch
from torch import nn class CustomLayerDeconv(nn.Module):def __init__(self,in_n,out_n):super().__init__() self.w = nn.Parameter(torch.normal(0,0.01,size = [in_n,out_n]),requires_grad=True)self.b = nn.Parameter(torch.normal(0,0.01,size = [out_n]),requires_grad=True) def forward(self,inputs):x = torch.matmul(inputs,self.w)x = x + self.breturn x
layer = CustomLayerDeconv(2,3)
y = layer(torch.ones(100,2))
loss = torch.sum(y)
loss.backward()
for i in layer.parameters():print(i.grad)
  • 3.3  保存/加载
  • 3.3.1 模型的 保存/加载

模型保存/加载有俩种方法,一种是保存模型的参数,如下所示:

torch.save(model.state_dict(), PATH)         #保存
model.load_state_dict(torch.load(PATH),strict=True) #加载

注意: 这种加载方式需要先定义模型,然后再加载参数。如果你定义的模型参数名与保存的参数对不上,就会出错。但如果把strict修改成False,不严格匹配,它就会只匹配对应上的键值,不会因多出或缺少的参数而报错。

另一种是直接保存模型。如下所示:

torch.save(model, PATH) #保存
model = torch.load(PATH) #加载

注意:这种方式看似方便,实际上更容易出错。因为python不能保存整个模型的类,所以它只能保存定义类的代码文件位置,以在加载时获取类的结构。如果你改变了定义类的代码位置,就有可能因为找不到类而出错。

  • 3.3.2 保存训练点

当你要保存某个训练阶段的状态,比如包含优化器参数、模型参数、训练迭代次数等,可以进行如下操作:

#保存训练点
torch.save({'epoch': epoch,'model_state_dict': model.state_dict(),'optimizer_state_dict': optimizer.state_dict(),'loss': loss}, PATH)
#加载训练点
model = TheModelClass(*args, **kwargs)
optimizer = TheOptimizerClass(*args, **kwargs)checkpoint = torch.load(PATH)model.load_state_dict(checkpoint['model_state_dict'])
optimizer.load_state_dict(checkpoint['optimizer_state_dict'])
epoch = checkpoint['epoch']
loss = checkpoint['loss']

 注意:

和保存模型一样,也是使用torch.save()。它很灵活,可以保存字典,因此读取的时候也按照字典索引读取即可。当然要注意,并不是任何类型都能保存的,这里保存的四个类型分别是:

  1. int

2. collections.OrderedDict

  3. collections.OrderedDict

  4. list

  • 3.4  修改模型参数

Pytorch没有提供额外的方式让我们修改模型参数,我们可以使用上面加载模型参数的方式来修改参数。对于某个参数,我们只要把键值和对应要修改的值放在字典中传入load_state_dict即可。如果没传入所有的参数,记得把strict设为False。

model.load_state_dict({'weight':torch.tensor([0.])},strict=False) #修改模型参数

注意:参数名,也就是键值,和对应的参数shape可以通过model.state_dict()查看

4:总结

以上就是使用Pytorch搭建模型的详细内容,只需要简单三步就完成了。更多关于Pytorch知识后期会不断完善,在接下来,将会讲解使用pytorch搭建一维线性回归模型和多维线性回归模型。

Pytorch搭建自己的模型相关推荐

  1. 【深度学习】——利用pytorch搭建一个完整的深度学习项目(构建模型、加载数据集、参数配置、训练、模型保存、预测)

    目录 一.深度学习项目的基本构成 二.实战(猫狗分类) 1.数据集下载 2.dataset.py文件 3.model.py 4.config.py 5.predict.py 一.深度学习项目的基本构成 ...

  2. python与机器学习(七)上——PyTorch搭建LeNet模型进行MNIST分类

    任务要求:利用PyTorch框架搭建一个LeNet模型,并针对MNIST数据集进行训练和测试. 数据集:MNIST 导入: import torch from torch import nn, opt ...

  3. 利用Pytorch搭建简单的图像分类模型(之二)---搭建网络

    Pytorch搭建网络模型-ResNet 一.ResNet的两个结构 首先来看一下ResNet和一般卷积网络结构上的差异: 图中上面一部分就是ResNet34的网络结构图,下面可以理解为一个含有34层 ...

  4. Diffusion扩散模型学习1——Pytorch搭建DDPM实现图片生成

    Diffusion扩散模型学习1--Pytorch搭建DDPM利用深度卷积神经网络实现图片生成 学习前言 源码下载地址 网络构建 一.什么是Diffusion 1.加噪过程 2.去噪过程 二.DDPM ...

  5. 神经网络学习小记录50——Pytorch 利用efficientnet系列模型搭建yolov3目标检测平台

    神经网络学习小记录50--Pytorch 利用efficientnet系列模型搭建yolov3目标检测平台 学习前言 什么是EfficientNet模型 源码下载 EfficientNet模型的实现思 ...

  6. ResNet网络详解并使用pytorch搭建模型、并基于迁移学习训练

    1.ResNet网络详解 网络中的创新点: (1)超深的网络结构(突破1000层) (2)提出residual模块 (3)使用Batch Normalization加速训练(丢弃dropout) (1 ...

  7. MobileNetv1、v2网络详解、使用pytorch搭建模型MobileNetv2并基于迁移学习训练

    1.MobileNetv1网络详解 传统卷积神经网络专注于移动端或者嵌入式设备中的轻量级CNN网络,相比于传统卷积神经网络,在准确率小幅降低的前提下大大减少模型参数与运算量.(相比VGG16准确率减少 ...

  8. GoogLeNet网络详解并使用pytorch搭建模型

    1.GoogLeNet网络详解 网络中的创新点: (1)引入了Inception结构(融合不同尺度的特征信息) (2)使用1x1的卷积核进行降维以及映射处理 (虽然VGG网络中也有,但该论文介绍的更详 ...

  9. Pytorch一行代码便可以搭建整个transformer模型

    transformer模型是在NLP领域发表的论文attention is all you need中提出的一种语言处理模型,其transformer模型由于加速了模型推理时间与训练精度,越来越受到了 ...

最新文章

  1. SAP UB类型的STO能自动创建交货单?
  2. 数据意识上的“代沟”
  3. Lock和synchronized的选择
  4. Java有哪些常用的转换类,JavaSE——常用类、类型转换
  5. eos java是什么框架_EOS的整体框架
  6. OracleOraDb11g_home1TNSListener 服务启动后停止 某些服务在未由其他服务或程序使用时将自动停止
  7. Microsoft Azure 大计算 – 宣布收购 GreenButton
  8. 电话号码以185****3547显示demo
  9. matlab实现图像的拼接,MATLAB实现图像拼接算法(求助)
  10. 定时执行Python程式
  11. 用计算机求正有理数算术平方根的步骤,用计算器求算数平方根、用有理数估计算数平方根的大小 (2).ppt...
  12. 什么是网络攻击?网络攻击手段有哪些?
  13. Oracle 企业管理器DataBase Control使用说明
  14. 【机器学习】吴恩达机器学习Deeplearning.ai
  15. 跑腿小程序系统,同城闪送、帮买帮送
  16. 杨幂穿搭有三宝:露腿,收腰,配饰亮点,赶快马起来
  17. matlab surf 坐标设置,matlab中3D曲面函数surf的坐标问题
  18. Oracle——删除用户以及用户下数据
  19. robotframework基础入门:(2):常见问题对应方法
  20. WIN10蓝屏崩溃原因查找

热门文章

  1. 【资料】机器学习笔记的github镜像下载(github个人star数量排名175)
  2. linux screen 命令是 ssh 的有效补充
  3. java怎么将图片文件转流并在jsp前端显示_jsp已经被淘汰了吗?
  4. java菜单管理的实现方式_智能停车场管理系统的收费实现方式有哪些?
  5. 支付宝五福活动抢先开始了!原来今年可以提前集
  6. “大胃王”吃播注意了 国家明确禁止发布量大多吃、暴饮暴食等节目
  7. 小米集团:回购460万股,耗资9818万港元
  8. 董明珠再谈“格力10年免费包修”政策:没企业敢跟,实力的象征
  9. 专为中国车主开发,特斯拉计划今年推出数据平台
  10. 超252万市民预约报名 北京数字人民币红包中签结果公布啦