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')