【Pytorch】利用Pytorch+RNN实现基于MNIST数据集的手写字体分类(附源码)

本文是在笔者阅读过少量pytorch入门书后所写,很多知识点还说的不清楚甚至没有提及,欢迎各位读者朋友多加批评指正,共同探讨。

 1.在导入数据进行数据准备工作

        可以直接从torchvision库的datset模块导入MNIST手写字体的训练数据集和测试集,然后使用Data.DataLoader()函数将两个数据集定义为数据加载器。其中用到torchvision.datasets.XXXXX()函数解释为:从指定的路径下获取数据集,其中train参数用于控制所提取的是训练集还是测试集。download参数用于控制是否从互联网上下载数据集。transform参数则用于将输入的图片进行转换(本文将其转化为张量),target_transform参数用于将图片的标签进行转化。关于DataLoader的部分参见我前面的文章即可。

【Pytorch】利用Pytorch+RNN实现基于MNIST数据集的手写字体分类(附源码)_第1张图片

 2.搭建RNN分类器。

        参数input_dim表示输入数据的维度,针对图像分类器,其值等于28;参数hidden_dim表示构建RNN网络层中包含神经元的个数;参数layer_dim表示在RNN网络层在有多少层RNN神经元;参数output_dim则表示在使用全连接层进行分类是输出的维度,可以使用数据的类别数表示(本例子为识别数字 所以out_put值为10)。

        在RNNimc类调用nn.RNN()函数时,参数batch_first表示使用的数据集中batch在数据的第一个维度。在self.rnn()层中的输入有两个参数,第一个参数为要分析的数据x,第二个参数则为初始的隐藏层输入,这里用None替代,表示用全0进行初始化。而输出也包含两个参数,其中out表示RNN最后一层的输出特征,h_n表示隐藏层的输出。在本例中,rnn层时输入数据的维度为28,神经元数目为128的RNN,fc1为输入数据维度为128,神经元数目为10的全连接层。

3.对模型进行训练

        首先利用view(-1,28,28)方法将数据维度变为28(-1则代表在同一batch的数据集内,将数据的后两个维度定义后,第一个维度被默认为含有多少个28*28的数据,view方法中文文档如下)。然后将训练集带入模型中求出训练结果,并根据定义好的损失函数求出损失。进行反向传播。每经过一个epoch的训练后分别在训练集和测试集上计算损失和精度。最后将结果进行可视化。

        【Pytorch】利用Pytorch+RNN实现基于MNIST数据集的手写字体分类(附源码)_第2张图片

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import time
import copy

import torch
from torch import nn
import torch.nn.functional as F
import torch.optim as optim
import torchvision
import torch.utils.data as Data
from torchvision import transforms
import hiddenlayer as hl
## 准备训练数据集Minist
train_data  = torchvision.datasets.MNIST(
    root = "./data/MNIST", # 数据的路径
    train = True, # 只使用训练数据集
    # 将数据转化为torch使用的张量,取汁范围为[0,1]
    transform  = transforms.ToTensor(),
    download= False # 因为数据已经下载过,所以这里不再下载
)
## 定义一个数据加载器
train_loader = Data.DataLoader(
    dataset = train_data, ## 使用的数据集
    batch_size=64, # 批处理样本大小
    shuffle = True, # 每次迭代前打乱数据
    num_workers = 2, # 使用两个进程 
)

##  可视化训练数据集的一个batch的样本来查看图像内容
for step, (b_x, b_y) in enumerate(train_loader):  
    if step > 0:
        break

## 输出训练图像的尺寸和标签的尺寸,都是torch格式的数据
print(b_x.shape)
print(b_y.shape)
## 准备需要使用的测试数据集
test_data  = torchvision.datasets.MNIST(
    root = "./data/MNIST", # 数据的路径
    train = False, # 不使用训练数据集
    transform  = transforms.ToTensor(),
    download= False # 因为数据已经下载过,所以这里不再下载
)
## 定义一个数据加载器
test_loader = Data.DataLoader(
    dataset = test_data, ## 使用的数据集
    batch_size=64, # 批处理样本大小
    shuffle = True, # 每次迭代前打乱数据
    num_workers = 2, # 使用两个进程 
)
##  可视化训练数据集的一个batch的样本来查看图像内容
for step, (b_x, b_y) in enumerate(test_loader):  
    if step > 0:
        break

## 输出训练图像的尺寸和标签的尺寸,都是torch格式的数据
print(b_x.shape)
print(b_y.shape)
class RNNimc(nn.Module):
    def __init__(self, input_dim, hidden_dim, layer_dim, output_dim):
        """
        input_dim:输入数据的维度(图片每行的数据像素点)
        hidden_dim: RNN神经元个数
        layer_dim: RNN的层数
        output_dim:隐藏层输出的维度(分类的数量)
        """
        super(RNNimc, self).__init__()
        self.hidden_dim = hidden_dim ## RNN神经元个数
        self.layer_dim = layer_dim ## RNN的层数
        # RNN
        self.rnn = nn.RNN(input_dim, hidden_dim, layer_dim,
                          batch_first=True, nonlinearity='relu')
        
        # 连接全连阶层
        self.fc1 = nn.Linear(hidden_dim, output_dim)
    def forward(self, x):
        # x:[batch, time_step, input_dim]
        # 本例中time_step=图像所有像素数量/input_dim
        # out:[batch, time_step, output_size]
        # h_n:[layer_dim, batch, hidden_dim]
        out, h_n = self.rnn(x, None) # None表示h0会使用全0进行初始化
        # 选取最后一个时间点的out输出
        out = self.fc1(out[:, -1, :]) 
        return out
   ## 模型的调用
input_dim=28   # 图片每行的像素数量
hidden_dim=128  # RNN神经元个数
layer_dim = 1  # RNN的层数
output_dim=10  # 隐藏层输出的维度(10类图像)
MyRNNimc = RNNimc(input_dim, hidden_dim, layer_dim, output_dim)
print(MyRNNimc)
hl_graph = hl.build_graph(MyRNNimc, torch.zeros([1, 28, 28]))
hl_graph.theme = hl.graph.THEMES["blue"].copy()  
print(hl_graph)
hl_graph.save("data/chap7/MyRNNimc_hl.png", format="png")
## 对模型进行训练
optimizer = torch.optim.RMSprop(MyRNNimc.parameters(), lr=0.0003)  
criterion = nn.CrossEntropyLoss()   # 损失函数
train_loss_all = []
train_acc_all = []
test_loss_all = []
test_acc_all = []
num_epochs = 30
for epoch in range(num_epochs):
    print('Epoch {}/{}'.format(epoch, num_epochs - 1))
    MyRNNimc.train() ## 设置模型为训练模式
    corrects = 0
    train_num  = 0
    for step,(b_x, b_y) in enumerate(train_loader):
        # input :[batch, time_step, input_dim]
        xdata = b_x.view(-1, 28, 28)
        output = MyRNNimc(xdata)     
        pre_lab = torch.argmax(output,1)
        loss = criterion(output, b_y) 
        optimizer.zero_grad()        
        loss.backward()       
        optimizer.step()  
        loss += loss.item() * b_x.size(0)
        corrects += torch.sum(pre_lab == b_y.data)
        train_num += b_x.size(0)
    ## 计算经过一个epoch的训练后在训练集上的损失和精度
    train_loss_all.append(loss / train_num)
    train_acc_all.append(corrects.double().item()/train_num)
    print('{} Train Loss: {:.4f}  Train Acc: {:.4f}'.format(
        epoch, train_loss_all[-1], train_acc_all[-1]))
    ## 设置模型为验证模式
    MyRNNimc.eval()
    corrects = 0
    test_num  = 0
    for step,(b_x, b_y) in enumerate(test_loader):
        # input :[batch, time_step, input_dim]
        xdata = b_x.view(-1, 28, 28)
        output = MyRNNimc(xdata)     
        pre_lab = torch.argmax(output,1)
        loss = criterion(output, b_y) 
        loss += loss.item() * b_x.size(0)
        corrects += torch.sum(pre_lab == b_y.data)
        test_num += b_x.size(0)
    ## 计算经过一个epoch的训练后在测试集上的损失和精度
    test_loss_all.append(loss / test_num)
    test_acc_all.append(corrects.double().item()/test_num)
    print('{} Test Loss: {:.4f}  Test Acc: {:.4f}'.format(
        epoch, test_loss_all[-1], test_acc_all[-1]))
## 可视化模型训练过程中
plt.figure(figsize=(14,5))
plt.subplot(1,2,1)
plt.plot(train_loss_all,"ro-",label = "Train loss")
plt.plot(test_loss_all,"bs-",label = "Test loss")
plt.legend()
plt.xlabel("epoch")
plt.ylabel("Loss")
plt.subplot(1,2,2)
plt.plot(train_acc_all,"ro-",label = "Train acc")
plt.plot(test_acc_all,"bs-",label = "Test acc")
plt.xlabel("epoch")
plt.ylabel("acc")
plt.legend()
plt.show()

你可能感兴趣的:(Pytorch,RNN,深度学习,pytorch,机器学习)