框架:Pytorch
语言:Python
IDE:jupyter notebook
PyTorch构建神经网络
前言
Pytorch:pytorch是一个基于Numpy的科学计算包,向用户提供两大功能:
- 作为Numpy的替代者,向用户提供使用GPU强大功能的能力。
- 作为一款深度学习框架,向用户提供最大的灵活性和速度。
零、安装Pytorch
一、Pytorch的基本元素操作
- Tensors张量:张量的概念类似于Numpy中的ndarray数据结构,最大的区别在于Tensor可以利用GPU的加速功能。
- 我们使用Pytorch的时候,常规步骤是先将torch引用进来:
from __future__ import print_function
import torch
- 创建矩阵的操作
注意:当声明一个未初始化的矩阵时,它本身不包含任何确切数据的值,当创建一个未初始化的矩阵时,分配给矩阵的内存中有什么数值就赋值给了这个矩阵,本质上是毫无意义的数据。
第一个张量初始化类型是double,第二个类型是float两个张量尺寸相同都是5行3列
x.new_ones(m,n,dtype=touch.double() #新生成:m行n列类型为double的张量
注意:torch函数本质上返回的是一个tuple(元组),因此它支持一切元组操作
二、Pytorch基本运算操作
算术操作
索引操作(接上面的代码)
一定保证数据个数不变:否则出错
item():
Torch Tensor 和Numpy array之间的相互转换
Torch Tensor和Numpy array共享底层的内存空间,因此改变其中一个的值,另一个也会随之改变
Numpy array转换成Torch Tensor: 所有在CPU上的Tensors,出了Char Tensor都可以转换为Numpy array并可以反向转换。
关于CUDA Tensor:Tensor可以用.to()方法来将其移动到任意设备
三、torch.Tensor类中的相关应用
Pytorch中的autograd
在整个Pytorch框架中,所有的神经网络本质上都是一个autograd package(自动求导工具包)。autograd package 提供了一个对Tensors(张量)上所有的操作进行自动微分的功能。
torch.Tensor
torch.Tensor是整个package中的核心类,如果将属性requires_grad设置为True,它将追踪在这个类上定义的所有操作。(例:定义一个矩阵,一直追踪该矩阵的操作)当代码要进行反向传播时的时候。直接调用.backward()就可以自动计算所有梯度。在这个Tensor上的所有梯度将被累加进属性.grad中。
如果想终止一个Tensor在计算图中的回溯,只要执行.detach()就可以将该Tensor从计算图中撇下,在未来的回溯计算中也不会再有该Tensor。
除了.detach(),如果想终止对计算图的回溯,也就是不再进行方向传播求导过程,也可以采用代码块的方式with torch.no_grad()。这种方式非常适用于对模型进行预测的时候。因为预测阶段不再需要对梯度进行计算。
torch.Function
Function类是和Tensor类同等重要的一个核心类,它和Tensor共同构建了一个完整的类,每一个Tensor拥有一个.grad_fn属性,代表引用了哪个具体的Function创建了Tensor.
如果某个张量Tensor是用户自定义的,则具对应的grad_fn is None.
关于Tensor的操作
所有包含下划线 _ 的操作为inplace操作(原地操作)
应该说rand是从0-1的均匀分布中随机抽样,randn是从正态分布中抽样
关于梯度Gradients
在Pytorch中,反向传播是依靠.backward()实现的
说明:
- 建议大量使用代码块的限制requires_grad,不建议大量使用.detach(),方便项目中做调试
- x.grad_fn用来输出运算的属性(此时进行了什么运算)
- a.requires_grad_(True)直接改变requires_grad属性
- x.grad输出梯度
- 可以通过.detach()获得一个新的Tensor,拥有相同的内容但不需要自动求导(见上例x和y)
四、PyTorch初步应用(构建神经网络、构建分类器)
使用Pytorch构建一个神经网络
使用Pytorch来构建神经网络,主要的工具都在torch.nn包中 (nn:Neural Network)
nn依赖autograd来定义模型,并对其自动求导
构建神经网络典型流程:
- 定义一个拥有可学习参数的神经网络 (Cass Net)
- 遍历训练数据集
- 处理输入数据使其流经神经网络 (把数据灌入神经网络中)
- 计算损失值 (计算前选择损失函数)
- 将网络参数的梯度进行反向传播
loss.backward()
- 以一定的规则更新网络的权重 (SGD、Adam…)
代码实例:一共5层,两个卷积层,3个全连接层 初始化函数、前项forward函数必写
kernel_size :卷积核; stride:步长; in_features:输入维度; out_features:输出维度
模型中所有的可训练参数,可以通过net.parameters()来获得
注意:torch.nn构建的神经网络只支持mini-batches的输入,不支持单一样本输入(只接受一批次一批次输入,不能一条一条往里输入)
比如:nn.Conv2d需要一个 4DTensors形状为(nSamples,nChannels,Height,Width)(样本个数,几个通道,高,宽)。如果你的输入只有单一样本形式(后三维(高,宽,输入通道3),则需要执行input.unsqueeze(0),第零个维度增加一个维度即(3,32,32)改为(1,3,32,32),主动将3DTensor扩充成4DTensor。
损失函数
损失函数的输入是一个输入的对:(output,target)(神经网络输出,真实标签),然后计算出一个数值来评估output(预测)和target(目标标签)之间的差距大小。
在torch.nn中有若干个不同的损失函数可供使用,比如nn.MSELoss就是通过计算均方差损失来评估输入和目标值之间的差距。
总结:
- torch.nn.MSELoss()计算均方误差
- 当通过loss.backward()进行反向传播计算时,整张计算图将loss进行自动求导,所有属性require_grad=True的Tensors都将参与梯度求导运算,并将梯度累加到Tensors中的grad属性中
反向传播
在Pytorch中执行反向传播非常简便,全部操作就是loss.backward()
在执行反向传播之前,要先将梯度清零代码:net.zero_grad()
,否则梯度会在不同的批次数据之间被累加
更新网络参数
更新参数最简单的算法是SGD(随机梯度下降)
具体的算法公式是为:weight = weight - learning_rate(学习率) * gradient
#更新参数最简单的算法是SGD(随机梯度下降)
#具体的算法公式是为:weight = weight - learning_rate(学习率) * gradient
learning_rate = 0.01
for f in net.parameters(): #遍历所有参数 sub_表示就地做减法运算
f.date.sub_(f.grad.data * learning_rate) # weight = f.grad.data
#参数的更新方法重要:
#创建优化器对象 所有参数net.parameters() lr给一个学习率
optimizer = optim.SGD(net.parameters(), lr = 0.01)
#通过优化器来执行具体的参数更新
optimizer.step()
使用Pytorch构建一个分类器
分类器任务和数据介绍
分类器任务: 构造一个将不同图像进行分类的神经网络分类器,对输入的图片进行辨别并完成分类(单一分类,每一个数据一个标签)
数据集: CIFA10数据集
CIFAR10数据集介绍:数据集中每张图片的尺寸是 3 * 32 * 32 彩色图,3代表彩色三通道
CIFAR10数据集共有 10种 不同的分类,分别是"airplane",“automobile”,“bird”,“cat”,“deer”,“dog”,“frog”,“horse”,“ship”,“truck”。
分类器步骤(五步骤):
- 使用torchvision下载CIFAR10数据集
- 定义卷积神经网路 (class Net)
- 定义损失函数
nn.CrossEntropyLoss()
- 在训练集上训练模型
- 在测试集上测试模型
使用torchvision下载CIFAR10数据集
导入torchvision包来辅助下载数据集
如果下的慢可以直接点结果中的链接使用其他下载方式下载,之后放到指定位置,重新运行代码(因为代码中需要编码)shuffle=True
意思就是数据顺序是打乱的
展示数据
定义卷积神经网络
仿照前边的类构造此处的类,唯一的区别是是此处采用3通道3-channel
2个卷积 1个池化 3个全连接
定义损失函数
采用交叉熵损失函数和随机梯度下降优化器
#定义损失函数
#采用交叉熵损失函数和随机梯度下降优化器
import torch.optim as optim #官方推荐使用的优化器包
#定义损失函数
criterion = nn.CrossEntropyLoss() #交叉熵损失函数
#定义优化器 选择随机梯度下降优化器 三个参数 所有可训练的参数net.parameters() lr学习率(越小越好),momentum=0.9动量不要太小(不一定需要)
optimizer = optim.SGD(net.parameters(),lr=0.001,momentum=0.9)
在训练集上训练模型
采用基于梯度下降的优化算法,都需要很多个轮次的迭代训练 ,从结果上显示loss损失在下降
注意:保存的是状态字典 net.state_dict()
训练时CPU会飞速转!!!
训练的模型会生成在规定的路径下
在测试集上测试模型
打印测试集 %5s标签超不过5个字母
加载模型并对测试图片进行预测 根据结果显示,模型有错误,还不完美
重要:net.load_state_dict(torch.load(PATH))
先把原先的模型文件(torch.save(net.state_dict(),PATH)
)load进来,再从文件里把dict字典load进来
看一下在全部测试集上的表现,准确率55%
分析结果: 对于拥有10个类别的数据集,随机猜测的准确率是10%,模型达到了55%,说明模型学到了真实的东西!如果10%或9%等等,说明没学到什么!
分别测试不同类别的模型准确率。不同类别差别差别巨大
在GPU上训练模型
验证GPU
当训练模型的时候,只需要将模型转移到GPU上,同时将输入的图片和标签页转移到GPU上即可
#当训练模型的时候,只需要将模型转移到GPU上,同时将输入的图片和标签页转移到GPU上即可
#将模型转移到GPU上
net.to(device)
#将输入的图片张量和标签张量转移到GPU上
inputs,labels = data[0].to(device),data[1].to(device)
总结
以上就是简单的深度学习PyTorch框架构建神经网络、分类器