深度学习基础:4.pytorch搭建基础网络模型(代码片段)

zstar-_ zstar-_     2022-10-21     111

关键词:

这个专栏停更了一段时间,现在重新开始,巩固基础才能看懂复杂代码。

Torch基本架构

使用Pytorch之前,首先要理清楚Pytorch基本架构。
Pytorch的核心库是torch,根据不同领域细分可以分成计算机视觉、自然语言处理和语音处理,这三个领域分别有自己对应的库,即torchvision、torchtext、torchaudio。


核心库Torch中,根据功能又可以细分成下面几个模块。

正向传播结构

下面就用Pytorch搭建一个简单的正向传播结构。

首先导库,这里需要三个库,torch基本库不必说,nn即neural network,包含了神经网络结构的基本元素。functional 包含了损失函数和激活函数。

import torch
import torch.nn as nn
from torch.nn import functional as F

之后进行数据生成
这里manual_seed是固定人为的随机种子,因为不固定该值,每次运行时神经网络各层的初始权重/偏置会进行随机初始化,导致结果不稳定。
X是生成(500,20)的数据,注意必须指定其数据格式为浮点型(float32),否则默认为整型。
y是随机生成500条(0,3]之间的数,注意y也是浮点型,因为在后面损失函数计算时需要浮点型数据。

torch.random.manual_seed(103)
X = torch.rand((500,20), dtype=torch.float32)
y = torch.randint(low=0,high=3,size=(500,1), dtype=torch.float32)

接下来就到了最核心的搭建网络结构模块

  • 1、定义模型类,注意要继承于nn.Module
  • 2、在初始化函数中继承父类的初始化函数 super(Model,self).__init__(),这是由于python的继承机制不会继承父类的 __init__
  • 3、指定输入输出神经元数目in_featuresout_features,这并不是必须的,但是如果把输入输出作为参数进行传递,会增强模型的通用性。
  • 4、构造Linear线性层,注意一个线性层输出和下一个线性层的输入个数需相等,否则无法计算(原理上就是矩阵相乘)
  • 5、构造forward函数,实现前向传播过程,指定每一层的输入输出和激活函数。
class Model(nn.Module):
    def __init__(self,in_features=10, out_features=2):
        """
        in_features: 输入该神经网络的特征数目(输入层上的神经元的数目)
        out_features:神经网络的输出的数目(输出层上的神经元的数目)
        """
        super(Model,self).__init__()
        self.linear1 = nn.Linear(in_features,13,bias=True)
        self.linear2 = nn.Linear(13,8,bias=True)
        self.output = nn.Linear(8,out_features,bias=True)
    
    def forward(self,x): #神经网络的向前传播
        z1 = self.linear1(x)
        sigma1 = torch.relu(z1)
        z2 = self.linear2(sigma1)
        sigma2 = torch.sigmoid(z2)
        z3 = self.output(sigma2)
        sigma3 = F.softmax(z3,dim=1)
        return sigma3

之后实例化网络,注意在此之前要限定输入输出的个数,这里选择输入即X的特征维度20,输出y不同的数值(假设为分类问题,输出不同的类别)

input_ = X.shape[1]
output_ = len(y.unique())
net = Model(in_features=input_, out_features = output_)

调用模型,实现正向传播有下面两种书写方式:

# 方式一
y_hat = net.forward(X)
# 方式二
y_hat = net(X)

两者的区别是方式一只会调用forward函数内容,方式二回调用除 __init__之外的所有函数内容,因此更推荐第一种写法。
这样执行之后,输入向量维度为(500,20),输出结果为(500,3),即对每一条数据都根据20个特征得到了分类结果。

除此之外,可以用下面的语句查看每一层的参数。比如,查看linear1层的权重和偏置。

# 查看权重
net.linear1.weight
# 查看偏置
net.linear1.bias

使用net.linear1.weight.shape查看linear1层的维度,输出为(13,20),然而linear1层的输入为20,输出为13,这是由于在公式计算中,权重w会被转置再进行矩阵乘法运算。

损失函数

有了正向传播结构之后,就自然需要计算损失,反向传播。在此之前,有必要先了解一些损失函数的API。

回归损失函数

对于回归问题,比较常见的损失函数是SSEMSE,两者的公式如下:


在Pytoch中,可以这样进行调用。

from torch.nn import MSELoss 

# 生成随机数据
yhat = torch.randn(size=(50,),dtype=torch.float32)
y = torch.randn(size=(50,),dtype=torch.float32)
# SSE
criterion = MSELoss(reduction = "sum")
loss = criterion(yhat,y)
# MSE
criterion = MSELoss(reduction = "mean") 
loss = criterion(yhat,y)

分类损失函数

对于分类问题,最常采用的是交叉熵损失,比如二分类交叉熵损失函数如下:

Pytorch中,BCELossBCEWithLogitsLoss均能实现此功能,但后者的精度更高,不过一般来说,BCELoss基本够用。

from torch.nn import BCELoss, BCEWithLogitsLoss

# 生成随机数据
yhat = torch.randint(low=0,high=2,size=(10,1),dtype=torch.float32)
y = torch.randint(low=0,high=2,size=(10,1),dtype=torch.float32)
# 方式一
criterion = BCELoss()
loss = criterion(yhat,y)
# 方式二
criterion = BCEWithLogitsLoss()
loss = criterion(yhat,y)

MSELoss类似,BCELoss也有summean可选参数,功能和前面类似。

对于多分类问题,Pytorch提供了CrossEntropyLoss这个函数,使用实例如下:

from torch.nn import CrossEntropyLoss

# 生成随机数据
yhat = torch.randint(low=0,high=2,size=(10,2),dtype=torch.float32)
y = torch.randint(low=0,high=2,size=(10,),dtype=torch.float32)
# 多元交叉熵损失
criterion = CrossEntropyLoss()
loss = criterion(yhat, y.long())

使用注意:1、yhat必须>=2维,如果是1维数据会报错。2、CrossEntropyLoss计算时要求标签必须是整型数据,因此用y.long()将浮点型转换成整型。

实现反向传播

有了损失函数之后,在Pytorch中就可以用一行命令实现反向传播,即loss.backward()
把损失函数和反向传播添加到前向传播过程中,就形成了一轮简单的神经网络训练过程。

import torch
import torch.nn as nn
from torch.nn import functional as F

#确定数据
torch.random.manual_seed(103)
X = torch.rand((500,20), dtype=torch.float32)
y = torch.randint(low=0,high=3,size=(500,1), dtype=torch.float32)

input_ = X.shape[1]
output_ = len(y.unique())

class Model(nn.Module):
    def __init__(self,in_features=10, out_features=2):
        """
        in_features: 输入该神经网络的特征数目(输入层上的神经元的数目)
        out_features:神经网络的输出的数目(输出层上的神经元的数目)
        """
        super(Model,self).__init__()
        self.linear1 = nn.Linear(in_features,13,bias=True)
        self.linear2 = nn.Linear(13,8,bias=True)
        self.output = nn.Linear(8,out_features,bias=True)
    
    def forward(self,x): #神经网络的向前传播
        z1 = self.linear1(x)
        sigma1 = torch.relu(z1)
        z2 = self.linear2(sigma1)
        sigma2 = torch.sigmoid(z2)
        z3 = self.output(sigma2)
        sigma3 = F.softmax(z3,dim=1)
        return sigma3
     
net = Model(in_features=input_, out_features = output_)  # 实例化神经网络
y_hat = net.forward(X)  # 向前传播
criterion = nn.CrossEntropyLoss()
loss = criterion(y_hat,y.reshape(500).long())
loss.backward()
# loss.backward(retain_graph=True)

注意:Pytorch的反向传播底层是基于一个动态的计算图,每次执行完backward之后,这个计算图会从内存中自动销毁,如果想要保留这张图,以便进行多次反向传播,可以设置参数retain_graph=True
上述模型计算图可视化如下:

使用优化器

上面实现了一个最基本正向传播和反向传播的过程,然而,如果要应用更加复杂优化算法,直接手写就非常麻烦。Pytorch提供了一个优化器(optim),其内部封装了大量优化算法,可以方便开发者快速调用。

例如,实现随机梯度下降,可以调用optim的SGD接口,调用接口如下:

class torch.optim.SGD(params, lr=, momentum=0, dampening=0, weight_decay=0, nesterov=False)

相关参数解释:

参数描述
params (iterable)待优化参数的iterable或者是定义了参数组的dict
lr (float)学习率
momentum (float, 可选)动量因子(默认:0,通常设置为0.9,0.8)
weight_decay (float, 可选)权重衰减(L2惩罚)(默认:0)
dampening (float, 可选)动量的抑制因子(默认:0)
nesterov (bool, 可选)使用Nesterov动量(默认:False

optim更多接口参数解释,看到这篇博客记录比较详细,放置链接如下:
Link:https://blog.csdn.net/xq151750111/article/details/123602946

下面还是以之前的网络模型为例,实现一个带动量参数的SGD优化器

import torch
import torch.nn as nn
import torch.optim as optim
from torch.nn import functional as F

torch.manual_seed(103)
X = torch.rand((500,20),dtype=torch.float32) * 100
y = torch.randint(low=0,high=3,size=(500,),dtype=torch.float32)
lr = 0.1  # 学习率
gamma = 0.9 # 动量
class Model(nn.Module):
    def __init__(self,in_features=10,out_features=2):
        super(Model,self).__init__() 
        self.linear1 = nn.Linear(in_features,13,bias=True) 
        self.linear2 = nn.Linear(13,8,bias=True)
        self.output = nn.Linear(8,out_features,bias=True)
        
    def forward(self, x):
        sigma1 = torch.relu(self.linear1(x))
        sigma2 = torch.sigmoid(self.linear2(sigma1))
        zhat = self.output(sigma2)
        return zhat
    
input_ = X.shape[1] #特征的数目
output_ = len(y.unique()) #分类的数目
net = Model(in_features=input_, out_features=output_) #实例化网络
criterion = nn.CrossEntropyLoss() #定义损失函数
opt = optim.SGD(net.parameters(),lr = lr,momentum = gamma)
yhat = net.forward(X) 
loss = criterion(yhat, y.long()) #计算损失函数
loss.backward()
opt.step() #走一步,更新权重w,更新动量v
opt.zero_grad() #清除原来储存好的,基于上一个坐标点计算的梯度,为下一次计算梯度腾出空间

这一段代码就是实现了梯度下降中的一步,加上循环,就形成了常见的深度学习过程。

数据加载器

在数据量少时,上面的代码能够完成训练。然而,当数据量变大时,就比较依赖硬件性能。比如,如果使用的CPU版本的Pytorch,数据会被加载进内存,如果内存无法容纳所有数据就会产生爆内存的问题,严重点可能会导致死机。如果使用GPU版本的Pytorch,数据可以选择加载进显存,如果显存不够大,会产生爆显存的Bug。

为了解决这个问题,可以将大批量的数据进行切分,每次只送一批数据到模型中进行训练,这批数据的大小就叫batch_size

Pytorch为了数据切分提供了两个工具,TensorDatasetDataLoader
之前输入模型的数据和标签是分开的,但是在后面的数据加载器DataLoader中,需要输入数据和标签的整体。python中的zip函数能够实现打包功能,Pytorch的TensorDataset函数功能也类似。不过对于tensor数据而言,pytorch提供的函数通常比python原生函数运算更快一些。

TensorDataset的使用示例如下:

from torch.utils.data import TensorDataset

a = torch.randn(500,3,4,5) #四维数据 - 图像
b = torch.randn(500,1) #二维数据 - 标签
c = TensorDataset(a,b)

直接打印c,不会输出具体的值,可以用下面的方式进行查看:

for x in c:
    print(x)
    break

输出c中的第一项如图所示:

里面包含两个tensor,第一个是数据,第二个是标签。

有了tensor之后,就可以直接将数据输入到DataLoader之中。DataLoader是处理训练前的数据加载器,它可以接受任意形式的数组、张量作为输入,并把他们一次性转换为神经网络可以接入的tensor。

DataLoader有很多参数,这里使用三个:

  • batch_size
    指定每一批(batch)数据的大小
  • shuffle
    是否对数据进行打乱
  • drop_last
    是否将最后一批不满足batch_size大小的数据丢弃
from torch.utils.data import DataLoader

dataset = DataLoader(c
          , batch_size = 120
          , shuffle = True #随机打乱数据
          , drop_last = True #是否舍弃最后一个batch
          )

打印出每个TensorDataset大小查看:

for i in dataset:
    print(i[0].shape) # i[0]是数据,i[1]是标签


如图所示,500条数据,每个batch_size为120并舍弃最后一个batch,因此输出四个batch。

在实际使用中,通常这样进行调用。

for batch_idx, (x,y) in enumerate(dataset):
    yhat = net(x)
    loss = criterion(yhat, y)
    loss.backward()
    opt.step()
    opt.zero_grad()

4.1pytorch纯手工构建模型并训练(代码片段)

欢迎订阅本专栏:《PyTorch深度学习实践》订阅地址:https://blog.csdn.net/sinat_33761963/category_9720080.html第二章:认识Tensor的类型、创建、存储、api等,打好Tensor的基础,是进行PyTorch深度学习实践的重中之重的基础... 查看详情

4.6pytorch使用损失函数(代码片段)

欢迎订阅本专栏:《PyTorch深度学习实践》订阅地址:https://blog.csdn.net/sinat_33761963/category_9720080.html第二章:认识Tensor的类型、创建、存储、api等,打好Tensor的基础,是进行PyTorch深度学习实践的重中之重的基础... 查看详情

「深度学习一遍过」必修10:pytorch框架的使用(代码片段)

...作形状查看形状更改增加维度压缩维度3 Tensor其他操作4 Pytorch网络定义与优化4.1基础网络定义接口 查看详情

4.5pytorch批量梯度下降(代码片段)

欢迎订阅本专栏:《PyTorch深度学习实践》订阅地址:https://blog.csdn.net/sinat_33761963/category_9720080.html第二章:认识Tensor的类型、创建、存储、api等,打好Tensor的基础,是进行PyTorch深度学习实践的重中之重的基础... 查看详情

4.7pytorch如何使用gpu(代码片段)

欢迎订阅本专栏:《PyTorch深度学习实践》订阅地址:https://blog.csdn.net/sinat_33761963/category_9720080.html第二章:认识Tensor的类型、创建、存储、api等,打好Tensor的基础,是进行PyTorch深度学习实践的重中之重的基础... 查看详情

4.3pytorch便利的优化器(代码片段)

欢迎订阅本专栏:《PyTorch深度学习实践》订阅地址:https://blog.csdn.net/sinat_33761963/category_9720080.html第二章:认识Tensor的类型、创建、存储、api等,打好Tensor的基础,是进行PyTorch深度学习实践的重中之重的基础... 查看详情

[人工智能-深度学习-8]:神经网络基础-机器学习深度学习模型模型训练

...目录第1章白话机器学习第2章机器学习的模型与步骤 2.1 深度学习与机器学习2.2 机器学习的模型第3章建模步骤1-1&# 查看详情

4.4pytorch迭代过程中的评估(代码片段)

欢迎订阅本专栏:《PyTorch深度学习实践》订阅地址:https://blog.csdn.net/sinat_33761963/category_9720080.html第二章:认识Tensor的类型、创建、存储、api等,打好Tensor的基础,是进行PyTorch深度学习实践的重中之重的基础... 查看详情

深度学习基础知识-21加快深度学习模型训练速度的方法(代码片段)

在深度学习任务中,虽然可以通过堆叠参数、设计更复杂的结构来提高模型的表征能力,但这也会导致模型的计算量增加,训练时间延长,大大降低模型的产出效率。这篇文章根据博主的经验简单介绍一些加快模... 查看详情

人工智能与深度学习基于能量的模型

【人工智能与深度学习】基于能量的模型概述能量基础模型(EBM)方法定义解决方案:基于梯度的推理有潜在变量的能量基础模型推理例子能量基础模型和机率模型的对比自由能(FreeEnergy)概述我们现在介绍一个新框架来定义模型。... 查看详情

keras深度学习实战(42)——强化学习基础(代码片段)

Keras深度学习实战(42)——强化学习基础0.前言1.强化学习基础1.1基本概念1.2马尔科夫决策过程1.3目标函数2.在具有非负奖励的模拟游戏中获取最佳动作2.1问题设定2.2模型分析2.3模型构建与训练3.在模拟游戏中获取最佳动... 查看详情

零基础入门深度学习1-1:图像数据建模流程示例

文章目录一、准备数据1.导入数据2配置数据集3.数据可视化二、定义模型三、训练模型四、评估模型1.混淆矩阵2.指标评估五、保存及加载模型六、模型预测 查看详情

深度学习基础:7.模型的保存与加载/学习率调度(代码片段)

...存和加载,本质上都是针对模型的参数。模型参数在Pytorch中,可以使用state_dict()查看模型的参数信息。例如:输入model.state_dict()输出OrderedDict([('linear1.weight',tensor([[0.2365,-0.1118,-0.3801,0.0275,0.4168 查看详情

相关名词

...练处属于自己的AI人工智能时代学习进度安排神经网络和深度学习学习神经网路和深度学习的基础与案例改善深层神经网络的理解最前沿的深度学习方法学会搭建自己的神经网络结构化机器学习项目学会诊断机器学习项目训练属... 查看详情

深度学习基础面试知识(代码片段)

目录学习率的高低影响图像尺寸变大,CNN网络参数会变不?变为几倍?数据不平衡处理(正1000:负100)Epoch、Barch、Iteration模型参数最佳模型梯度爆炸、梯度消失学习率的高低影响如果在训练模型时,... 查看详情

深度学习r-cnn网络基础

目录1Overfeat模型2RCNN模型2.1算法流程2.1.1候选区域生成2.1.2CNN网络提取特征2.1.3目标分类(SVM)2.1.4目标定位2.1.5预测过程2.2算法总结3FastRCNN模型3.1算法流程3.1.1ROIPooling3.1.2目标分类和回归3.2模型训练3.3模型预测3.4模型总结4... 查看详情

项目实战解析:基于深度学习搭建卷积神经网络模型算法,实现图像识别分类(代码片段)

...、图像识别分类总结前言随着人工智能的不断发展,深度学习这门技术也越来越重要,很多人都开启了学习机器学习,本文将通过项目开发实例,带领大家从零开始设计实现一款基于深度学习的图像识别算法。学... 查看详情

深度学习算法工程师常用基础面试题汇集

目录1.模型评估方法2.基本方法3.优化方法4.深度学习基础5.CNN6.RNN7. 查看详情