Press "Enter" to skip to content

pytorch手写数字识别【源码实现-小清新版】

 

手写数字识别,也就是让机器能够习得图片中的手写数字,并能正确归类。

本文使用 pytorch 搭建一个简单的神经网络,实现手写数字的识别,

 

从本文,你可了解到:

 

1、搭建神经网络的流程

 

2、完成手写数字识别模型

 

3、pytorch基本库

 

1.准备数据

 

''' 1. 导人必要的模块 '''
import numpy as np
import torch
# 导入 pytorch 内置的 mnist 数据
from torchvision.datasets import mnist 
#导入预处理模块
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
#导入nn及优化器
import torch.nn.functional as F
import torch.optim as optim
from torch import nn

 

其中,torch.nn 是 pytorch 中重要的神经网络高级封装,其封装了:常见的网络层,如:卷积,以及优化器等。

 

我们这里使用 mnist 数据集 ,其里面就包括了 手写数字识别的数据集。

 

transforms 和 DataLoader 主要用来做数据的下载和预处理。

 

torch.optim 是我们使用的优化器

 

下面我们定义一些超参数:

 

''' 2. 定义一些超参数 '''
train_batch_size = 64     # 训练批次
test_batch_size = 128    # 测试批次
learning_rate = 0.01       # 学习率
num_epoches = 20        
lr = 0.01
momentum = 0.5

 

接下来,下载 mnist 数据集,并封装到 DataLoader 中:

 

''' 3. 下载数据并对数据进行预处理 '''
#定义预处理函数,这些预处理依次放在Compose函数中。
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize([0.5], [0.5])])
#下载数据,并对数据进行预处理
train_dataset = mnist.MNIST('/Users/zhouzhan/Documents/to_github/NLPLearn/Deep-Learning/data', train=True, transform=transform, download=True)
test_dataset = mnist.MNIST('/Users/zhouzhan/Documents/to_github/NLPLearn/Deep-Learning/data', train=False, transform=transform)
#dataloader是一个可迭代对象,可以使用迭代器一样使用。
train_loader = DataLoader(train_dataset, batch_size=train_batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=test_batch_size, shuffle=False)

 

2.可视化数据源

 

下载成功后,我们看一下数据集长什幺样:

 

import matplotlib.pyplot as plt
%matplotlib inline
 
examples = enumerate(test_loader)
batch_idx, (example_data, example_targets) = next(examples)
 
fig = plt.figure()
for i in range(6):
  plt.subplot(2,3,i+1)
  plt.tight_layout()
  plt.imshow(example_data[i][0], cmap='gray', interpolation='none')
  plt.title("Ground Truth: {}".format(example_targets[i]))
  plt.xticks([])
  plt.yticks([])

 

运行结果:

3.构建模型

 

构建模型,即:构建神经网络模型

 

其搭建神经网络所需组件:

 

 

    1. 层:神经网络的层级

 

    1. 模型:层构成的网络

 

    1. 损失函数:学习过程中的目标函数,即:损失函数最小化

 

    1. 优化器:如何使损失函数最小化的方法

 

 

首先,是构建网络模型,模型是由层构成的网络,我们的模型有2个隐藏层,且每层都含有一个激活函数 ReLU,最后使用 torch.max(out,1) 找出张量 out 最大值对应索引作为预测值:

代码如下:

 

''' 1. 构建网络 '''
class Net(nn.Module):
    """
    使用sequential构建网络,Sequential()函数的功能是将网络的层组合到一起
    """
    def __init__(self, in_dim, n_hidden_1, n_hidden_2, out_dim):
        super(Net, self).__init__()
        # 第一层网络
        self.layer1 = nn.Sequential(nn.Linear(in_dim, n_hidden_1),nn.BatchNorm1d(n_hidden_1))
        # 第二层网络
        self.layer2 = nn.Sequential(nn.Linear(n_hidden_1, n_hidden_2),nn.BatchNorm1d(n_hidden_2))
        # 输出层
        self.layer3 = nn.Sequential(nn.Linear(n_hidden_2, out_dim))
        
    def forward(self, x):
        x = F.relu(self.layer1(x))
        x = F.relu(self.layer2(x))
        x = self.layer3(x)
        return x

 

我们定义了一个 class Net,它继承 nn.Module 类(它是所有网络的基类)

 

nn.Module 类里面定义了很多模型,如:卷积层、全连接层、池化层等,一般定义网络都需基层该类。

 

其中,__ init __ 方法,用于定义网络;forward 方法,实现前向传播。

 

forward函数:任务是把输入层、网络层、输出层链接起来,实现信息的前向传导。

 

nn.Sequential:一个有序的容器,它可将神经网络模块依次添加到计算图中执行。

 

实例化网络:

 

''' 2. 实例化网络 '''
#检测是否有可用的GPU,有则使用,否则使用CPU
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
#实例化网络
model = Net(28 * 28, 300, 100, 10)
model.to(device)

 

最后,我们定义损失函数和优化器,则网络构造完毕:

 

# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=lr, momentum=momentum

 

criterion: 交叉熵损失

 

optimizer:SGD优化器(随机梯度下降算法)

 

4.训练模型

 

训练模型的代码有点长,

 

根据之前设置的 num_epoches 进行多次训练和预测,

 

其目的是通过训练,学习到适合的参数,动态修改学习率

 

其步骤如下:

 

 

    1. 动态修改学习率;

 

    1. model.train(),将模型设置为训练模式;

 

    1. 前向传播;

 

    1. 反向传播;

 

    1. 计算训练误差;

 

    1. model.eval(),将模型设置为预测模式;

 

    1. 预测模型;

 

    1. 计算预测误差。

 

 

根据以上步骤,其代码实现如下:

 

''' 1. 训练模型 '''
# 开始训练
losses = []
acces = []
eval_losses = []
eval_acces = []
for epoch in range(num_epoches):
   train_loss = 0
   train_acc = 0
   model.train()
   #动态修改参数学习率
   if epoch%5==0:
       optimizer.param_groups[0]['lr']*=0.1
   for img, label in train_loader:
       img=img.to(device)
       label = label.to(device)
       img = img.view(img.size(0), -1)
       # 前向传播
       out = model(img)
       loss = criterion(out, label)
       # 反向传播
       optimizer.zero_grad()
       loss.backward()
       optimizer.step()
       # 记录误差
       train_loss += loss.item()
       # 计算分类的准确率
       _, pred = out.max(1)
       num_correct = (pred == label).sum().item()
       acc = num_correct / img.shape[0]
       train_acc += acc
       
   losses.append(train_loss / len(train_loader))
   acces.append(train_acc / len(train_loader))
   # 在测试集上检验效果
   eval_loss = 0
   eval_acc = 0
   # 将模型改为预测模式
   model.eval()
   for img, label in test_loader:
       img=img.to(device)
       label = label.to(device)
       img = img.view(img.size(0), -1)
       out = model(img)
       loss = criterion(out, label)
       # 记录误差
       eval_loss += loss.item()
       # 记录准确率
       _, pred = out.max(1)
       num_correct = (pred == label).sum().item()
       acc = num_correct / img.shape[0]
       eval_acc += acc
       
   eval_losses.append(eval_loss / len(test_loader))
   eval_acces.append(eval_acc / len(test_loader))
   print('epoch: {}, Train Loss: {:.4f}, Train Acc: {:.4f}, Test Loss: {:.4f}, Test Acc: {:.4f}'
         .format(epoch, train_loss / len(train_loader), train_acc / len(train_loader), 
                    eval_loss / len(test_loader), eval_acc / len(test_loader)))

 

下面进行关键代码解释:

 

前向传播,就是将图片输入到模型中,得出结果,并计算出损失值

 

# 前向传播
out = model(img)
loss = criterion(out, label)

 

反向传播,

 

zero_grad():将梯度清零,因为缺省情况下梯度是累加的,所以需要手动清零;

 

backward():自动生成梯度;

 

step():执行优化器,把梯度传播回每个网络。

 

# 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()

 

最后的结果:

我们看看损失函数:

 

''' 2. 可视化训练及测试损失值 '''
plt.title('train loss')
plt.plot(np.arange(len(losses)), losses)
plt.legend(['Train Loss'], loc='upper right')

 

 

从这个例子中,我们学到了:

 

mnist 数据集

    1. 是一个不错的入门学习数据集;

 

    1. 数据集的下载与预处理,可使用:transforms 和 DataLoader 来完成;

 

    1. 使用 matplotlib.pyplot 来做可视化操作;

 

    1. 通过继承 nn.Module 来构建神经网络模型;

 

    1. 训练模型,最后得出结果

 

最后,你可以根据本文,自己手写代码完成,学习效果更佳哦~

Be First to Comment

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注