数据准备
torch.utils.data.Datasets是PyTorch用来表示数据集的类,它是用PyTorch进行手写数字识别的关键。 下面是加载mnist数据集并对其可视化的代码
from torchvision import datasets
from torchvision.datasets import MNIST
from matplotlib import pyplot as plt
import numpy as np
mnist = datasets.MNIST(root='C:/Users/WSY/Desktop/用pytorch进行手写数字识别',
train=True,download=True)
for i, j in enumerate(np.random.randint(0,len(mnist),(10,))):
data, label = mnist[j]
plt.subplot(2,5,i+1)
plt.imshow(data)
这段代码中,首先实例化了Datasets对象mnist ,datasets.MNIST能够自动下载数据集保存到本地磁盘的root位置(自己设置),参数train默认为True,用于控制加载的数据集是训练集还是测试集。for循环中,使用len(mnist)调用了__len__方法,使用mnist[j]调用了__getitem__方法(在我们自己建立数据集时,需要继承Dataset,并且覆写__len__和__getitem__两个方法)。最后两行代码绘制了MNIST手写数字数据集。 运行代码,查看数据集的部分数据可视化结果 在变量浏览器中可以看到有关变量的内容,其中mnist就是实例化的数据集对象,它包含6000张图像内容,在for循环过程中,data读取的是28×28的Image类型图像,label是该图像对应的标签,也就是图像上表示的数字。 由于数据预处理是非常重要的步骤,所以PyTorch提供了torchvision.transforms用于处理数据及数据增强。在这里我们使用了torchvision.transforms.ToTensor将PIL Image或者numpy.ndarray类型的数据转换为Tensor,并且它会将数据从【0,255】映射到【0,1】。torchvision.transforms.Normalize会将数据标准化,加速模型在训练中的收敛速率。在使用中,可利用torchvision.transforms.Compose将多个transforms组合在一起,被包含的transforms会顺序执行。 数据流程处理准备完善后开始读取用于训练的数据,torch.utils.data.DataLoader提供了迭代数据、随机抽取数据、批量化数据。 下面的代码中实例化了mnist对象,定义了transforms方法trans并将其使用到数据集的实例化过程中,用于对数据集进行处理。然后定义了函数imshow,函数体的的第一行代码将数据从标准化的数据中恢复,第二行代码将Tensor类型转换为ndarray,这样才可以用matplotlib绘制出来,绘制的结果如下图所示。函数体最后一行使用transpose函数将矩阵维度从(C,W,H)转换为(W,H,C),这样才符合正常的通道顺序。
import torchvision
from torchvision import datasets,transforms
from torchvision.datasets import MNIST
from matplotlib import pyplot as plt
import numpy as np
import torch
trans = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])
mnist = datasets.MNIST(root='C:/Users/WSY/Desktop/用pytorch进行手写数字识别',
train=True,download=True,transform=trans)
def imshow(img):
img = img * 0.3081 + 0.1307
npimg = img.numpy()
plt.imshow(np.transpose(npimg, (1,2,0)))
dataloader = torch.utils.data.DataLoader(mnist, batch_size=4, shuffle=True, num_workers=0)
images, labels = next(iter(dataloader))
imshow(torchvision.utils.make_grid(images))
运行代码得到的变量情况及绘制结果如下图
网络模型
下面构建用于识别手写数字的神经网络模型
import torch.nn as nn
class MLP(nn.Module):
def __init__(self):
super(MLP, self).__init__()
self.inputlayer = nn.Sequential(nn.Linear(28*28, 256),
nn.ReLU(),
nn.Dropout(0.2))
self.hiddenlayer = nn.Sequential(nn.Linear(256, 256),
nn.ReLU(),
nn.Dropout(0.2))
self.outlayer = nn.Sequential(nn.Linear(256, 10))
def forward(self, x):
x = x.view(x.size(0), -1)
x = self.inputlayer(x)
x = self.hiddenlayer(x)
x = self.outlayer(x)
return x
通过nn.Module对象看到其网络结构,如下
In [12]: print(MLP())
MLP(
(inputlayer): Sequential(
(0): Linear(in_features=784, out_features=256, bias=True)
(1): ReLU()
(2): Dropout(p=0.2, inplace=False)
)
(hiddenlayer): Sequential(
(0): Linear(in_features=256, out_features=256, bias=True)
(1): ReLU()
(2): Dropout(p=0.2, inplace=False)
)
(outlayer): Sequential(
(0): Linear(in_features=256, out_features=10, bias=True)
)
)
完整实现
准备好数据和模型后,就可以进行训练模型了。下面分别定义了数据处理和加载流程、模型、优化器、损失函数以及用准确率评估模型能力。训练过程持续10个epoch
import torch
import torch.nn as nn
from torch.utils.data import DataLoader
from torch import optim
from tqdm import tqdm
from torchvision import datasets,transforms
import matplotlib.pylab as plt
trans = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])
mnist_train = datasets.MNIST(root='C:/Users/WSY/Desktop/用pytorch进行手写数字识别',
train=True,download=True,transform=trans)
mnist_val = datasets.MNIST(root='C:/Users/WSY/Desktop/用pytorch进行手写数字识别',
train=False,download=True,transform=trans)
trainloader = DataLoader(mnist_train, batch_size=16, shuffle=True, num_workers=0)
valloader = DataLoader(mnist_val, batch_size=16, shuffle=True, num_workers=0)
class MLP(nn.Module):
def __init__(self):
super(MLP, self).__init__()
self.inputlayer = nn.Sequential(nn.Linear(28*28, 256),
nn.ReLU(),
nn.Dropout(0.2))
self.hiddenlayer = nn.Sequential(nn.Linear(256, 256),
nn.ReLU(),
nn.Dropout(0.2))
self.outlayer = nn.Sequential(nn.Linear(256, 10))
def forward(self, x):
x = x.view(x.size(0), -1)
x = self.inputlayer(x)
x = self.hiddenlayer(x)
x = self.outlayer(x)
return x
model = MLP()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
celoss = nn.CrossEntropyLoss()
def accuracy(pred, target):
pred_label = torch.argmax(pred, 1)
correct = sum(pred_label == target).to(torch.float)
return correct, len(pred)
acc = {'train':[], 'val':[]}
loss_all = {'train':[], 'val':[]}
for epoch in tqdm(range(10)):
model.eval()
numer_val, denumer_val, loss_tr = 0., 0., 0.
with torch.no_grad():
for data, target in valloader:
output = model(data)
loss = celoss(output, target)
loss_tr += loss.data
num, denum = accuracy(output, target)
numer_val += num
denumer_val += denum
model.train()
numer_tr, denumer_tr, loss_val = 0., 0., 0.
for data, target in trainloader:
optimizer.zero_grad()
output = model(data)
loss = celoss(output, target)
loss_val += loss.data
loss.backward()
optimizer.step()
num, denum = accuracy(output, target)
numer_tr += num
denumer_tr += denum
loss_all['train'].append(loss_tr/len(trainloader))
loss_all['val'].append(loss_val/len(valloader))
acc['train'].append(numer_tr/denumer_tr)
acc['val'].append(numer_val/denumer_val)
运行完成,如下 设计到的变量情况如下 查看模型训练迭代过程的损失图像
plt.plot(loss_all['train'])
plt.plot(loss_all['val'])
查看训练迭代过程的准确率图
plt.plot(acc['train'])
plt.plot(acc['val'])
O V E R !
|