pytorch以及其在DNN、CNN里的基本应用(代码均有含个人理解的较详尽注释)

pytorch以及其在DNN、CNN里的基本应用(代码均有含个人理解的较详尽注释)


之前的一些pytorch使用的word文档笔记,今天复习看了一下顺便整理到markdown里啦,庆祝一哈

参考:

莫烦python:https://www.bilibili.com/video/BV1Vx411j7kT

tensor和Variable

库的导入:

import torch
from torch.autograd import Variable

前言:

torch和numpy

tensor是torch里的一种很重要的数据结构,你可以将他和numpy里的ndarray进行类比,因为他们有很多相似之处。

torch一定程度上可以看作是深度学习中的numpy,为什么这么说呢?

很多人都知道,pytorch是支持GPU加速的,即把张量tensor放在GPU上加速

而很多人(包括几天前的我哈哈哈)都不知道

numpy支持CPU加速,可以将ndarray放在CPU上加速

这样看,numpy和torch是不是很像呢?

事实上,他们的用法也极为相似,且tensor和numpy可以互相转化。

构造tensor<——————>构造ndarray

torch.tensor(iterable可迭代序列)<——————>np.array(iterable)

torch.zeros((Channels,Height,Width))<——————>np.zeros((Channels,Height,Width))

torch.ones((Channels,Height,Width))<——————>np.ones((Channels,Height,Width))

torch.linspace(start,end,numbers)<——————>np.linspace(start,end,numbers))

###tensor和ndarray互相转化
tensor_data = torch.from_numpy(ndarray) #ndarray————>tensor
ndarray = tensor_data.numpy() #tensor————>ndarray

tensor的一些基本计算<——————>ndarray的一些基本计算

①torch.abs()<——————>np.abs()

torch.add()<——————>np.add()

torch.mean()<——————>np.mean()

torch.sin()<——————>np.sin()

②矩阵:

torch.mm(A,B)<——————>np.matmul(A,B)或者np.dot(A,B)或者A @ B #矩阵乘法

注意:torch.dot(A,B)是计算点乘(只能输入一维tensor)

如:A=B=[1,2,3,4]

torch.dot(A,B)=1x1+2x2+3x3+4x4=30

如:A=B=[[1,2],[3,4]]

torch.dot(A,B):RuntimeError: 1D tensors expected, but got 2D and 2D tensors

Variable:变量

需要提前说的是:神经网络中的参数都是Variable变量的形式

变量是什么意思呢?

A:可以更改参数信息

Variable的作用:简单来说,就是把tensor里的数据信息放入Variable变量里,再用Variable变量更新参数信息

示例1:

tensor=torch.FloatTensor([[1,2],[3,4]])
variable = Variable(tensor,requires_grad = True)

可以看到,最大的区别就是requires_grad这个参数,它有什么作用呢?

是否需要求梯度;是否搭建计算图(computing map);是否参与BP反向传播

所以tensor事实上是不能backward的,而Variable可以

示例2:
v_out = torch.mean(variable * variable)
v_out.backward()#对v_out反向传播
print(variable.grad) #打印variable的梯度

那么问题来了,为什么对v_out反向传播却打印variable的梯度

A:v_out是variable的函数,通俗地说,他们两个是“一套体系“的
即:v_out = F(variable)

Variable的一些属性

下面介绍Variable的两个属性:.data和.grad

variable.data即返回一个tensor,里面是variable自变量本身的数值

variable.grad则顾名思义,是他的梯度

注意区分:
print(variable) #打印Variable对象
print(variable.data) #variable里的tensor数据信息
print(variable.data.numpy() #tensor数据信息转ndarray
但不能variable.numpy(),Variable对象没有这个方法,无法直接转换成ndarray

pytorch里的损失函数

导入库

import torch.nn.functional as F

哪些函数:

relu、sigmoid、tanh、softplus等

示例:

y_relu = F.relu(x).data

可以看到,和python里def写的函数用法是完全一致的

神经网络的搭建、训练:(由每一层到整个神经网络)

导入库

import torch.nn as nn

全连接层,卷积层,池化层,BN层以及激活函数的搭建方法

全连接层:nn.Linear(in_features,out _features) #第一个参数是该层输入神经元个数,第二个参数是该层输出神经元个数

卷积层: nn.Conv2d(in_channels,out _channels,kernel _size,stride=1,padding=0,dilation=1,groups=1,bias=True)

参数介绍:

in_channels:输入通道数

out_channels:输出通道数

kernel_size:卷积核的大小 可以接收int或者tuple元组 若接收到int则默认为正方形卷积核,接收元组则要规定卷积核的H和W(Height和Width)

stride:卷积核滑动窗口的步长,默认为1

padding :是否需要进行填充,默认为0

dilation :是否需要进行空洞卷积,默认为1,即不进行

bias:是否需要偏移,默认为True

池化层(这里只介绍Max Pooling):
nn.MaxPool2d(kernel_size,stride = None,padding =0)

kernel_size:也是可接收int或tuple,与Conv2d里一致

stride: 默认与kernel_size一致

BN层:(注意:要添加在激活函数前

nn.BatchNorm2d(num_features,eps,momentum,affine)

参数介绍(这里只介绍num_features,eps和affine):

num_features:输入batch中图像的channels数目(代表输入数据中的channel,求均值和方差是对mini-batch中各通道分别求,这里指定通道数)

eps:防止分母为0,所以加在分母上的很小的数,一般用默认值

affine: 为True则r和b可学习,为False则r和b为固定值(r和b是Batch Normalization里的两个可学习的参数,详情可以看原论文)

激活函数

如:

nn.ReLU()

nn.Sigmoid()

nn.Tanh()

搭建神经网络模板(以一个简单DNN为例):

class Net(nn.Module):#继承nn.Module这个父类
	def __init__(self,n_features,n_hidden,n_output):#初始化,构建神经网络(这里要写神经网络各层)
		super(Net,self).__init__()#继承父类的init方法
		...#书写神经网络各层
		如:
		self.hidden = nn.Linear(n_features,n_hidden)#全连接层的搭建函数
		self.relu = nn.ReLU()
		self.predict = nn.Linear(n_hidden,n_output)

	def forward(self,x): #前向传播(这里写神经网络前向传播过程,即一个输入传进来,经历各层,一直到输出)
		x = self.hidden(x)
		x = self.relu(x)
		x = self.predict(x)
		return x

建立神经网络分为两部分:

①设计搭建:在init方法中完成对神经网络结构的设计和搭建,即神经网络的每一层都要搭建好

②前向传播:依据搭建好的每一层的神经网络,用一个合适的维度的输入,进入神经网络,先后经历搭建好的神经网络的每一层,最终得到一个输出

用nn.Sequential()快速搭建简单神经网络

这一方法同时包含了上面两个搭建步骤
示例:

net2 =nn.Sequential(
		nn.Linear(2,10),
		nn.ReLU(),
		nn.Linear(10,2),
)

神经网络的训练:

步骤①:规定优化器optimizer(后续会讲到)以及损失函数loss function

这里先采用stochastic gradient descent随机梯度下降进行参数的更新

optimizer = torch.optim.SGD(net.parameters(),lr=0.001)#第一个参数传入神经网络的所有参数,第二个参数传入学习率learning rate
loss_func = nn.MSEloss() #这里将均方误差函数作为损失函数进行优化

注意:如果选择nn.CrossEntropyloss()作为损失函数,output layer 自带softmax!!!

步骤②:数据载入 load data 以及数据增强 data augmentation(这里主要粘贴了莫烦python里的一些代码,只给了自己对于代码的简单注释,主要作为个人记录,建议阅读官方文档或观看教学视频)

导入库

import torch.utils.data as Data

载入数据
torch_dataset = Data.TensorDataset(x,y) #x是data,y是label
dataloader = Data.DataLoader(
dataset = torch_dataset, # 数据集载入
batch_size = BATCH_SIZE, # 批的大小
shuffle = True, # 为True则随机打乱数据
)

这里的Dataset,如果要自己制作,一定要写init,getitem和len这三个魔法方法才行

训练时读数据

for epoch in range(100):
	for step,(batch_x,batch_y) in enumerate(dataloader):
		......

一次读入batch_size个数据,如果不足,则剩多少读多少

数据增强
如:
import torchvision
transform = torchvision.transforms.ToTensor()

用手写数字辨识MNIST数据集(torchvision里有)

train_data = torchvision.datasets.MNIST(
	root = './mnist', # 根目录
	train = True, # 是不是Train_data,为false则为Test_data
	transfrom = torchvision.transforms.ToTensor(), #数据增强
	download = True #如果已经下载,则选False
)
print(train_data.data)#.data属性
print(train_data.target) #.target属性

步骤③:误差反向传播更新参数 不断迭代训练神经网络

较通用代码如下:

net.train() # 神经网络进入训练模式(会进行BN,dropout等操作)
for epoch in range(100): # 100次迭代
	for step,(batch_x,batch_y) in enumerate(dataloader):
		prediction = net(batch_x) #神经网络得到输出
		loss = loss_func(prediction,batch_y) #计算输出与label之间的误差(一定要神经网络输出在前,label在后)
		optimizer.zero_grad() #每次迭代都要将优化器梯度归零,不然会保留有上次迭代中计算的梯度
		loss.backward() # 误差的反向传播
		optimizer.step() # 优化器更新参数

补充:如果要进行验证,要先:

net.eval() # 网络进入验证状态,不进行BN、dropout等操作
with torch.no_grad(): # 不计算梯度
.......

优化器的使用:

这里主要是几种常用优化器的使用代码,不涉及不涉及不涉及原理解释!

opt_SGD = torch.optim.SGD(net.parameters(),lr = LR)
opt_Momentum =  torch.optim.SGD(net.parameters(),lr = LR,momentum = 0.8)
opt_RMSprop = torch.optim.RMSprop(net.parameters(),lr = LR,alpha = 0.9)
opt_Adam = torch.optim_Adam(net.parameters(),lr=LR,betas = (0.9,0.99))

模型的载入和保存

包含网络结构、权重:

torch.save(net,'net.pth')


net1 = torch.load('net.pth')

不包含网络结构,只包含权重(这样就需要先写好网络的结构,再进行load)

torch.save(net.state_dict(),'net_parameters.pth')


torch.load_state_dict(torch.load('net_parameters.pth')
上一篇:pyTorch基础入门练习


下一篇:【Jmeter学习】jmeter获取JDBC响应做接口关联