手把手教你玩转深度学习-PyTorch教程1
文章目录
目录
前言
之前的文章中,我们已经对如何搭建深度学习环境进行了讲述。本文将对如何使用PyTorch环境进行深度学习训练进行介绍,本次以LeNet为出发点,向大家展示如何在PyTorch中搭建LeNet,
并使用LeNet在CIFAR-10数据集上进行图像分类工作。
一、LeNet是什么?
LeNet是由深度学习三巨头之一的LeCun提出的一种卷积神经网络(CNN,Convolutional Neural Networks),其结构中包含了目前CNN中的几种经典的结构,如卷积、池化等等,而且LeNet结构十分简单,
非常适合于初学者学习,因此本次选取LeNet为出发点。由于关于LeNet原理介绍的文章很多,在本文中对LeNet就不予赘述了,需要了解LeNet原理的同学,请移步:
二、CIFAR-10数据集
1.数据集介绍
CIFAR-10数据集是常用的图像分类数据集,其中包含了60000张彩色图像,分为'airplane','automonbile','bird','cat','deer','dog','frog','horse','ship','truck'共10个种类,每类6000张图,图片大小32*32像素。其示意图如下图:
2.下载方式
在使用CIFAR-10数据集的过程中,我们可以选择使用PyTorch中的torchvision自动下载,也可以自行下载,数据集共分为了Python版本、MATLAB版本和二进制版本,一般情况下我们使用python版本。
由于下载数据集的网站在国外,因此建议大家自行下载,以提升效率,下面链接为下载地址:
官网下载地址:
CIFAR-10 and CIFAR-100 datasets
百度网盘下载地址:
链接:https://pan.baidu.com/s/1N3WL5dJd1ANq-eKS0EsOZA
提取码:ioct
下载完成后,将数据集进行解压,可以看到如下文件:
三、使用PyTorch构建并训练LeNet
1.利用PyTorch进行图像分类任务的基本步骤
在使用PyTorch进行图像分类任务时,主要在指定的任务中(即数据集下)针对分类模型进行训练的过程,这个过程可以分为1.引入所需包;2.加载数据集;3.构造网络;4.定义损失函数和优化器;5.模型训练;
6.模型验证共6个部分,下面分别对这些部分进行介绍:
2.引入所需包
任何一个深度学习模型在构建、训练、显示等过程中,都需要其他包的支持,因此我们首先将所需要的包都进行引入,需要引入包如下:
import torch as t #引入pytorch
import torchvision as tv #引入torchvision
import torchvision.transforms as transforms#引入torchvision的transforms,用于数据预处理
import torch.nn as nn #引入神经网络工具箱
import torch.nn.functional as F #引入函数接口
from torch import optim #引入优化器
from torch.autograd import Variable #引入Variable
这里面大家不着急对每个包的作用进行详细了解,先将整个LeNet搭建起来,后面随着搭建的过程,会在过程中及后续的文章中对使用到的各个包进行详细的介绍。
3.加载数据集
深度学习模型的训练依赖于数据,LeNet也不例外,因此我们需要将CIFAR-10数据集进行加载,此时我们使用torchvision工具包进行处理。torchvision为图像操作提供了一些方便工具库,如常用的数据集、模型、转换函数等等。
如果此时已经下载好CIFAR-10数据集,并解压完成,则使用如下代码加载数据集:
#利用torchvision对训练数据集进行设置
trainset = tv.datasets.CIFAR10(root='../dataset/cifar-10-python/',train=True,download=False,transform=transform)
#利用dataloader加载训练数据集,其中shuffle是指在每个epoch开始的时候,对数据进行重新排序;num_workers指使用几个线程参与工作
trainloader = t.utils.data.DataLoader(trainset,batch_size=4,shuffle=True,num_workers=2)
如果此时没有下载好CIFAR-10数据集,只需要将上面代码中的download=False改为True,torchvision会自动对CIFAR-10数据集进行下载,则使用如下代码加载数据集:
#利用torchvision对训练数据集进行设置
trainset = tv.datasets.CIFAR10(root='../dataset/cifar-10-python/',train=True,download=True,transform=transform)
#利用dataloader加载训练数据集,其中shuffle是指在每个epoch开始的时候,对数据进行重新排序;num_workers指使用几个线程参与工作
trainloader = t.utils.data.DataLoader(trainset,batch_size=4,shuffle=True,num_workers=2)
同理,可以用于加载测试数据集,代码如下:
testset = tv.datasets.CIFAR10(root='../dataset/cifar-10-python/',train=False,download=False,transform=transform)
testloader = t.utils.data.DataLoader(trainset,batch_size=4,shuffle=False,num_workers=2)
4.构造LeNet网络
LeNet的网络结构如第一节中介绍,我们将通过PyTorch的神经网络工具箱nn建立网络。建立过程中,定义一个LetNet类,类中包含了init函数和forward函数,其中init函数定了LeNet的基本结构(即包含多少层以及每层是什么等),
forward函数则定义了网络的计算过程,这里要注意的是我们必须定义forward函数,这是由于在神经网络的训练过程中,反向传播是极其重要的计算过程,而只有定义了forward,PyTorch才能自动的进行反向传播的计算。
具体定义代码如下:
class LeNet(nn.Module):
def __init__(self):
super(LeNet,self).__init__()
self.conv1 = nn.Conv2d(3,6,5)
self.conv2 = nn.Conv2d(6,16,5)
self.fc1 = nn.Linear(16*5*5,120)
self.fc2 = nn.Linear(120,84)
self.fc3 = nn.Linear(84,10)
def forward(self,x):
x = F.max_pool2d(F.relu(self.conv1(x)),(2,2))
x = F.max_pool2d(F.relu(self.conv2(x)),2)
x = x.view(x.size()[0],-1)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
定义完成后,我们可以实例化一个对象,并将其进行打印来查看定义好的网络结构:
net = LeNet()
print(net)
会得到如下输出:
LeNet(
(conv1): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))
(conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
(fc1): Linear(in_features=400, out_features=120, bias=True)
(fc2): Linear(in_features=120, out_features=84, bias=True)
(fc3): Linear(in_features=84, out_features=10, bias=True)
)
5.定义损失函数和优化器
pytorch中定义损失函数和优化器十分的方便,神经网络工具箱nn和优化器工具库optim已经将最常用的损失函数和优化器进行了封装,我们只需要调用相应代码即可,如:
#定义使用交叉熵损失函数
criterion = nn.CrossEntropyLoss()
#定义优化器为随机梯度下降SGD
optimizer = optim.SGD(net.parameters(),lr=0.001,momentum=0.9)
6.模型训练
在上述2-4步都完成的情况下,我们就可以用CIFAR-10数据集对LeNet模型进行训练,代码如下:
import torch as t #引入pytorch
import torchvision as tv #引入torchvision
import torchvision.transforms as transforms#引入torchvision的transforms,用于数据预处理
import torch.nn as nn #引入神经网络工具箱
import torch.nn.functional as F #引入函数接口
from torch import optim #引入优化器
from torch.autograd import Variable #引入Variable
#利用torchvision对训练数据集进行设置
trainset = tv.datasets.CIFAR10(root='../dataset/cifar-10-python/',train=True,download=False,transform=transform)
#利用dataloader加载训练数据集,其中shuffle是指在每个epoch开始的时候,对数据进行重新排序;num_workers指使用几个线程参与工作
trainloader = t.utils.data.DataLoader(trainset,batch_size=4,shuffle=True,num_workers=2)
testset = tv.datasets.CIFAR10(root='../dataset/cifar-10-python/',train=False,download=False,transform=transform)
testloader = t.utils.data.DataLoader(trainset,batch_size=4,shuffle=False,num_workers=2)
#定义使用交叉熵损失函数
criterion = nn.CrossEntropyLoss()
#定义优化器为随机梯度下降SGD
optimizer = optim.SGD(net.parameters(),lr=0.001,momentum=0.9)
#定义LetNet
class LeNet(nn.Module):
def __init__(self):
super(LeNet,self).__init__()
self.conv1 = nn.Conv2d(3,6,5)
self.conv2 = nn.Conv2d(6,16,5)
self.fc1 = nn.Linear(16*5*5,120)
self.fc2 = nn.Linear(120,84)
self.fc3 = nn.Linear(84,10)
def forward(self,x):
x = F.max_pool2d(F.relu(self.conv1(x)),(2,2))
x = F.max_pool2d(F.relu(self.conv2(x)),2)
x = x.view(x.size()[0],-1)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
#训练网络
for epoch in range(2):
running_loss = 0.0
for i,data in enumerate(trainloader,0):
inputs,labels = data
inputs,labels = Variable(inputs),Variable(labels)
#梯度清零
optimizer.zero_grad()
outputs = net(inputs)
loss = criterion(outputs,labels)
loss.backward()
#更新参数
optimizer.step()
#打印log
running_loss += loss.item()
if i%2000 == 1999: #每2000个batch打印一次状态
print('[%d,%5d] loss: %.3f' % (epoch+1,i+1,running_loss/2000))
running_loss = 0.0
print("训练完成")
训练完成后会得到如下结果,可以看到随着训练的进行,损失不断降低:
[1, 2000] loss: 2.193
[1, 4000] loss: 1.867
[1, 6000] loss: 1.673
[1, 8000] loss: 1.583
[1,10000] loss: 1.497
[1,12000] loss: 1.453
[2, 2000] loss: 1.388
[2, 4000] loss: 1.348
[2, 6000] loss: 1.314
[2, 8000] loss: 1.293
[2,10000] loss: 1.281
[2,12000] loss: 1.248
训练完成
7.模型验证
模型的训练工作完成后,我们可以通过测试数据集验证一下模型的训练结果,此时我们加载测试数据集,并将测试数据集中的图片输入模型中,计算相应的分类label。具体代码如下:
correct = 0 #存储预测正确的图片数量
total = 0 #总数
for data in testloader:
images,labels = data
outputs = net(Variable(images))
_,predicted = t.max(outputs.data,1)
total += labels.size(0)
correct += (predicted == labels).sum()
print('准确率为:%d %%' %(100 *correct / total))
总结
以上,我们便完成了利用PyTorch搭建LeNet模型,并在CIFAR-10数据集上完成模型的训练及验证的工作,大家可以通过这个例子,先直观的对PyTorch的使用建立一个印象。在后续的文章中,
我们会对PyTorch中的其他知识进行讲解来帮助大家进一步的理解和运用PyTorch。