在PyTorch中有两个核心的包,分别是torch和torchvision。在前面的文章中介绍了torch包的一些情况,现在介绍一下torchvision包的一些情况:主要功能是实现数据的处理、导入和预览等,主要处理计算机视觉相关问题的处理工作。
下面进入手写数字识别的主要介绍:
1.从 torchvison 中导入两个子包 datasets和transforms
import torch
import numpy
import torchvision
import matplotlib.pyplot as plt
%matplotlib inline
from torchvision import datasets, transforms
from torch.autograd import Variable
2.导入对应数据
此时如果我们想使用MNIST就从datasets中导入MNIST,同理其他的数据集例如COCO、ImageNet、CIFCAR等都可以通过这个方法进行下载和载入。
data_train = datasets.MNIST(root = './data/',
transform = transform,
train = True,
download = True)
data_test = datasets.MNIST(root = './data/',
transform = transform,
train = False)
3.数据增强处理torch.transforms
torch.transforms中有大量的数据变换类,其中有很大一部分可以 用于实现数据增强(Data Argumentation)。如果我们参与到模型中的图片数据有限,就可以对有限的 图片数据进行变换,生成新的训练集。
transform = transforms.Compose([transforms.ToTensor(),
transforms.Normalize(mean=[0.5,0.5,0.5],
std = [0.5,0.5,0.5])])
torchvision.transforms.Compose类看作一种容器,它能够同时对多种数据变换进行组合。传入的参数是一个列表, 列表中的元素就是对载入的数据进行的各种变换操作。
transforms.ToTensor是一个类型的转换变换,将对应类型转变为Tensor类型。
transforms.Normalize是一个数据标准换变换。具体的变换为:
使用原始数据的均值(Mean)和标准差(Standard Deviation)来进行数据的标准化,在经过标准化变换之后,数据全部符 合均值为0、标准差为1的标准正态分布。
计算公式如下:
4.数据预览与数据装载
在数据下载完成并且载入后,我们还需要对数据进行装载。在装载时通过batch_size的值来确认每个包的大小,通过shuffle的值 来确认是否在装载的过程中打乱图片的顺序。
data_loader_train = torch.utils.data.DataLoader(dataset = data_train,
batch_size = 64,
shuffle = True)
data_loader_test = torch.utils.data.DataLoader(dataset = data_test,
batch_size = 64,
shuffle = True)
torch.utils.data.DataLoader类用于装载数据
dataset参数用于指定我们载入的数据集名称
batch_size参数设置了包中图片的数据个数,64代表64张图片
shuffle表示在装载过程是否打乱顺序
在装载完成后,我们可以选取其中一个批次的数据进行预览。进行 数据预览的代码如下:
images,labels = next(iter(data_loader_train)) #images 的顺序为 (batch_size,channel,height,weight,)
img = torchvision.utils.make_grid(images)#img 输出的顺序为(channel,height,weight)
img = img.numpy().transpose(1,2,0) # 转为(height,weight,channel)
std = [0.5,0.5,0.5]
mean = [0.5,0.5,0.5]
img = img * std + mean # 将上面Normalize后的图像还原
print([labels[i].item for i in range(64)]) #labels为tensor,使用item显示对应值
plt.imshow(img)
使用iter和next来获取一个批次的图片数据和其对应 的图片标签
使用torchvision.utils中的make_grid类方法将一个批次的图片构造成网格模式
make_grid传入的参数为(数据个数,图片通道数,图片高度,图片宽度)--->会将图片维度转变为(通道数,高度,宽度)
完整代码:
import torch
import numpy
import torchvision
import matplotlib.pyplot as plt
%matplotlib inline
from torchvision import datasets, transforms # torchvision包的主要功能是实现数据的处理、导入和预览等
from torch.autograd import Variable
transform = transforms.Compose([transforms.ToTensor(),
transforms.Normalize(mean=[0.5,0.5,0.5],
std = [0.5,0.5,0.5])])
data_train = datasets.MNIST(root = './data/',
transform = transform,
train = True,
download = True)
data_test = datasets.MNIST(root = './data/',
transform = transform,
train = False)
data_loader_train = torch.utils.data.DataLoader(dataset = data_train,
batch_size = 64,
shuffle = True)
data_loader_test = torch.utils.data.DataLoader(dataset = data_test,
batch_size = 64,
shuffle = True)
images,labels = next(iter(data_loader_train)) #images 的顺序为 (batch_size,channel,height,weight,)
img = torchvision.utils.make_grid(images)#img 输出的顺序为(channel,height,weight)
img = img.numpy().transpose(1,2,0) # 转为(height,weight,channel)
std = [0.5,0.5,0.5]
mean = [0.5,0.5,0.5]
img = img * std + mean # 将上面Normalize后的图像还原
print([labels[i].item() for i in range(64)]) #labels为tensor,使用item()显示对应值
plt.imshow(img)
输出结果:
[2, 9, 4, 0, 2, 1, 1, 2, 7, 0, 0, 5, 5, 2, 2, 7, 6, 2, 7, 7, 8, 7, 3, 6, 9, 2, 9, 3, 4, 3, 1, 4, 2, 7, 7, 9, 8, 8, 8, 0, 6, 3, 8, 0, 7, 0, 1, 3, 9, 9, 2, 1, 8, 9, 1, 4, 4, 7, 7, 6, 6, 7, 4, 7]
5.模型搭建
完成数据装载后,我们就可以开始编写卷积神经网络模型的 搭建和参数优化的代码了。
具体代码如下:
class Model(torch.nn.Module):
def __init__(self):
super(Model,self).__init__()
self.conv1 = torch.nn.Sequential(
torch.nn.Conv2d(1,64,kernel_size=3,stride=1,padding=1),
torch.nn.ReLU(),
torch.nn.Conv2d(64,128,kernel_size=3,stride=1,padding = 1),
torch.nn.ReLU(),
torch.nn.MaxPool2d(stride=2,kernel_size=2)
)
self.dense = torch.nn.Sequential(
torch.nn.Linear(14*14*128,1024),
torch.nn.ReLU(),
torch.nn.Dropout(p=0.5),
torch.nn.Linear(1024,10)
)
def forward(self,x):
x = self.conv1(x) #对数据进行卷积处理
x = x.view(-1,14*14*128) #对参数实现扁平化
x= self.dense(x) #紧接着的就是全连接层
return x
在结构上使用了两个卷积层:一个最大池化 层和两个全连接层,这里对其具体的使用方法进行补充说明。
(1)torch.nn.Conv2d:
用于搭建卷积神经网络卷积层,主要参数为(输入通道、输出通道、卷积核大小、步长、填充)其中所有都是整形,
输入通道数-->确定输入数 据的层数
输出通道数-->确定输出数据的层数
卷积核kernel_size-->确定卷积核大小
移动步长stride-->确定每次移动的步长
填充padding-->添加层数大小,值为0时表示不进行边界像素的填充,如果值大于0,那么增加数字所对应的边界像素层数。
(2)torch.nn.MaxPool2d:
用于实现卷积神经网络中的最大池化 层,主要的输入参数是(移动步长、填充大小)。
池化窗口步长stride-->于确定池化窗口每次移动的步长
填充大小padding-->添加层数大小
(3)torch.nn.Dropout:
用于防止卷积神经网络 在训练的过程中发生过拟合,其工作原理简单来说就是在模型训练的过 程中,以一定的随机概率将卷积神经网络模型的部分参数归零,以达到减少相邻两层神经连接的目的。
上图中打叉的神经节点就是被随机抽中并丢弃的神经连接,由于每次打乱都是随机的,因此可以保证最后训练出来的模型对各部分的权 重参数不产生过度依赖,从而防止过拟合。如果不做任何设置,就使用默认的概率值0.5。
(4)forward函数中的内容
x = self.conv1(x) #对数据进行卷积处理
x = x.view(-1,14*14*128) #对参数实现扁平化
x= self.dense(x) #紧接着的就是全连接层
如果不进行扁平化,则 全连接层的实际输出的参数维度和其定义输入的维度将不匹配,程序会报错;最后,通过self.dense定义的全连接进行最后的分类。
6.参数优化
具体代码:
model = Model()
cost = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters())
print(model)
损失函数使用的是交叉熵,优化函数使用的是Adam自适应优化算法
搭建整体代码:
class Model(torch.nn.Module):
def __init__(self):
super(Model,self).__init__()
self.conv1 = torch.nn.Sequential(
torch.nn.Conv2d(1,64,kernel_size=3,stride=1,padding=1),
torch.nn.ReLU(),
torch.nn.Conv2d(64,128,kernel_size=3,stride=1,padding = 1),
torch.nn.ReLU(),
torch.nn.MaxPool2d(stride=2,kernel_size=2)
)
self.dense = torch.nn.Sequential(
torch.nn.Linear(14*14*128,1024),
torch.nn.ReLU(),
torch.nn.Dropout(p=0.5),
torch.nn.Linear(1024,10)
)
def forward(self,x):
x = self.conv1(x) #对数据进行卷积处理
x = x.view(-1,14*14*128) #对参数实现扁平化
x= self.dense(x) #紧接着的就是全连接层
return x
model = Model()
cost = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters())
print(model)
输出结果:
Model(
(conv1): Sequential(
(0): Conv2d(1, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): ReLU()
(2): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(3): ReLU()
(4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(dense): Sequential(
(0): Linear(in_features=25088, out_features=1024, bias=True)
(1): ReLU()
(2): Dropout(p=0.5)
(3): Linear(in_features=1024, out_features=10, bias=True)
)
)