使用 PyTorch 实现 MLP 并在 MNIST 数据集上验证方式


Posted in Python onJanuary 08, 2020

简介

这是深度学习课程的第一个实验,主要目的就是熟悉 Pytorch 框架。MLP 是多层感知器,我这次实现的是四层感知器,代码和思路参考了网上的很多文章。个人认为,感知器的代码大同小异,尤其是用 Pytorch 实现,除了层数和参数外,代码都很相似。

Pytorch 写神经网络的主要步骤主要有以下几步:

1 构建网络结构

2 加载数据集

3 训练神经网络(包括优化器的选择和 Loss 的计算)

4 测试神经网络

下面将从这四个方面介绍 Pytorch 搭建 MLP 的过程。

项目代码地址:lab1

过程

构建网络结构

神经网络最重要的就是搭建网络,第一步就是定义网络结构。我这里是创建了一个四层的感知器,参数是根据 MNIST 数据集设定的,网络结构如下:

# 建立一个四层感知机网络
class MLP(torch.nn.Module):  # 继承 torch 的 Module
  def __init__(self):
    super(MLP,self).__init__()  # 
    # 初始化三层神经网络 两个全连接的隐藏层,一个输出层
    self.fc1 = torch.nn.Linear(784,512) # 第一个隐含层 
    self.fc2 = torch.nn.Linear(512,128) # 第二个隐含层
    self.fc3 = torch.nn.Linear(128,10)  # 输出层
    
  def forward(self,din):
    # 前向传播, 输入值:din, 返回值 dout
    din = din.view(-1,28*28)    # 将一个多行的Tensor,拼接成一行
    dout = F.relu(self.fc1(din))  # 使用 relu 激活函数
    dout = F.relu(self.fc2(dout))
    dout = F.softmax(self.fc3(dout), dim=1) # 输出层使用 softmax 激活函数
    # 10个数字实际上是10个类别,输出是概率分布,最后选取概率最大的作为预测值输出
    return dout

网络结构其实很简单,设置了三层 Linear。隐含层激活函数使用 Relu; 输出层使用 Softmax。网上还有其他的结构使用了 droupout,我觉得入门的话有点高级,而且放在这里并没有什么用,搞得很麻烦还不能提高准确率。

加载数据集

第二步就是定义全局变量,并加载 MNIST 数据集:

# 定义全局变量
n_epochs = 10   # epoch 的数目
batch_size = 20 # 决定每次读取多少图片

# 定义训练集个测试集,如果找不到数据,就下载
train_data = datasets.MNIST(root = './data', train = True, download = True, transform = transforms.ToTensor())
test_data = datasets.MNIST(root = './data', train = True, download = True, transform = transforms.ToTensor())
# 创建加载器
train_loader = torch.utils.data.DataLoader(train_data, batch_size = batch_size, num_workers = 0)
test_loader = torch.utils.data.DataLoader(test_data, batch_size = batch_size, num_workers = 0)

这里参数很多,所以就有很多需要注意的地方了:

root 参数的文件夹即使不存在也没关系,会自动创建

transform 参数,如果不知道要对数据集进行什么变化,这里可自动忽略

batch_size 参数的大小决定了一次训练多少数据,相当于定义了每个 epoch 中反向传播的次数

num_workers 参数默认是 0,即不并行处理数据;我这里设置大于 0 的时候,总是报错,建议设成默认值

如果不理解 epoch 和 batch_size,可以上网查一下资料。(我刚开始学深度学习的时候也是不懂的)

训练神经网络

第三步就是训练网络了,代码如下:

# 训练神经网络
def train():
  # 定义损失函数和优化器
  lossfunc = torch.nn.CrossEntropyLoss()
  optimizer = torch.optim.SGD(params = model.parameters(), lr = 0.01)
  # 开始训练
  for epoch in range(n_epochs):
    train_loss = 0.0
    for data,target in train_loader:
      optimizer.zero_grad()  # 清空上一步的残余更新参数值
      output = model(data)  # 得到预测值
      loss = lossfunc(output,target) # 计算两者的误差
      loss.backward()     # 误差反向传播, 计算参数更新值
      optimizer.step()    # 将参数更新值施加到 net 的 parameters 上
      train_loss += loss.item()*data.size(0)
    train_loss = train_loss / len(train_loader.dataset)
    print('Epoch: {} \tTraining Loss: {:.6f}'.format(epoch + 1, train_loss))

训练之前要定义损失函数和优化器,这里其实有很多学问,但本文就不讲了,理论太多了。

训练过程就是两层 for 循环:外层是遍历训练集的次数;内层是每次的批次(batch)。最后,输出每个 epoch 的 loss。(每次训练的目的是使 loss 函数减小,以达到训练集上更高的准确率)

测试神经网络

最后,就是在测试集上进行测试,代码如下:

# 在数据集上测试神经网络
def test():
  correct = 0
  total = 0
  with torch.no_grad(): # 训练集中不需要反向传播
    for data in test_loader:
      images, labels = data
      outputs = model(images)
      _, predicted = torch.max(outputs.data, 1)
      total += labels.size(0)
      correct += (predicted == labels).sum().item()
  print('Accuracy of the network on the test images: %d %%' % (
    100 * correct / total))
  return 100.0 * correct / total

这个测试的代码是同学给我的,我觉得这个测试的代码特别好,很简洁,一直用的这个。

代码首先设置 torch.no_grad(),定义后面的代码不需要计算梯度,能够节省一些内存空间。然后,对测试集中的每个 batch 进行测试,统计总数和准确数,最后计算准确率并输出。

通常是选择边训练边测试的,这里先就按步骤一步一步来做。

有的测试代码前面要加上 model.eval(),表示这是训练状态。但这里不需要,如果没有 Batch Normalization 和 Dropout 方法,加和不加的效果是一样的。

完整代码

'''
系统环境: Windows10
Python版本: 3.7
PyTorch版本: 1.1.0
cuda: no
'''
import torch
import torch.nn.functional as F  # 激励函数的库
from torchvision import datasets
import torchvision.transforms as transforms
import numpy as np

# 定义全局变量
n_epochs = 10   # epoch 的数目
batch_size = 20 # 决定每次读取多少图片

# 定义训练集个测试集,如果找不到数据,就下载
train_data = datasets.MNIST(root = './data', train = True, download = True, transform = transforms.ToTensor())
test_data = datasets.MNIST(root = './data', train = True, download = True, transform = transforms.ToTensor())
# 创建加载器
train_loader = torch.utils.data.DataLoader(train_data, batch_size = batch_size, num_workers = 0)
test_loader = torch.utils.data.DataLoader(test_data, batch_size = batch_size, num_workers = 0)


# 建立一个四层感知机网络
class MLP(torch.nn.Module):  # 继承 torch 的 Module
  def __init__(self):
    super(MLP,self).__init__()  # 
    # 初始化三层神经网络 两个全连接的隐藏层,一个输出层
    self.fc1 = torch.nn.Linear(784,512) # 第一个隐含层 
    self.fc2 = torch.nn.Linear(512,128) # 第二个隐含层
    self.fc3 = torch.nn.Linear(128,10)  # 输出层
    
  def forward(self,din):
    # 前向传播, 输入值:din, 返回值 dout
    din = din.view(-1,28*28)    # 将一个多行的Tensor,拼接成一行
    dout = F.relu(self.fc1(din))  # 使用 relu 激活函数
    dout = F.relu(self.fc2(dout))
    dout = F.softmax(self.fc3(dout), dim=1) # 输出层使用 softmax 激活函数
    # 10个数字实际上是10个类别,输出是概率分布,最后选取概率最大的作为预测值输出
    return dout

# 训练神经网络
def train():
  #定义损失函数和优化器
  lossfunc = torch.nn.CrossEntropyLoss()
  optimizer = torch.optim.SGD(params = model.parameters(), lr = 0.01)
  # 开始训练
  for epoch in range(n_epochs):
    train_loss = 0.0
    for data,target in train_loader:
      optimizer.zero_grad()  # 清空上一步的残余更新参数值
      output = model(data)  # 得到预测值
      loss = lossfunc(output,target) # 计算两者的误差
      loss.backward()     # 误差反向传播, 计算参数更新值
      optimizer.step()    # 将参数更新值施加到 net 的 parameters 上
      train_loss += loss.item()*data.size(0)
    train_loss = train_loss / len(train_loader.dataset)
    print('Epoch: {} \tTraining Loss: {:.6f}'.format(epoch + 1, train_loss))
    # 每遍历一遍数据集,测试一下准确率
    test()

# 在数据集上测试神经网络
def test():
  correct = 0
  total = 0
  with torch.no_grad(): # 训练集中不需要反向传播
    for data in test_loader:
      images, labels = data
      outputs = model(images)
      _, predicted = torch.max(outputs.data, 1)
      total += labels.size(0)
      correct += (predicted == labels).sum().item()
  print('Accuracy of the network on the test images: %d %%' % (
    100 * correct / total))
  return 100.0 * correct / total

# 声明感知器网络
model = MLP()

if __name__ == '__main__':
  train()

10 个 epoch 的训练效果,最后能达到大约 85% 的准确率。可以适当增加 epoch,但代码里没有用 gpu 运行,可能会比较慢。

以上这篇使用 PyTorch 实现 MLP 并在 MNIST 数据集上验证方式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python计算最小优先级队列代码分享
Dec 18 Python
python安装与使用redis的方法
Apr 19 Python
Python IDLE入门简介
Dec 08 Python
Python实现找出数组中第2大数字的方法示例
Mar 26 Python
带你认识Django
Jan 15 Python
python粘包问题及socket套接字编程详解
Jun 29 Python
Python3分析处理声音数据的例子
Aug 27 Python
浅谈pycharm使用及设置方法
Sep 09 Python
PyQt5中多线程模块QThread使用方法的实现
Jan 31 Python
python_mask_array的用法
Feb 18 Python
对python中各个response的使用说明
Mar 28 Python
python3.7 openpyxl 在excel单元格中写入数据实例
Sep 01 Python
Pycharm 2020最新永久激活码(附最新激活码和插件)
Sep 17 #Python
将matplotlib绘图嵌入pyqt的方法示例
Jan 08 #Python
pyinstaller还原python代码过程图解
Jan 08 #Python
python Tensor和Array对比分析
Jan 08 #Python
Pycharm小白级简单使用教程
Jan 08 #Python
python如何实现不可变字典inmutabledict
Jan 08 #Python
PyQt5 closeEvent关闭事件退出提示框原理解析
Jan 08 #Python
You might like
Yii2――使用数据库操作汇总(增删查改、事务)
2016/12/19 PHP
php mysql_real_escape_string addslashes及mysql绑定参数防SQL注入攻击
2016/12/23 PHP
ThinkPHP框架实现的微信支付接口开发完整示例
2019/04/10 PHP
Yii2框架中一些折磨人的坑
2019/12/15 PHP
PHP safe_mode开启对于PHP系统函数有什么影响
2020/11/10 PHP
script标签属性type与language使用选择
2012/12/02 Javascript
javascript SpiderMonkey中的函数序列化如何进行
2012/12/05 Javascript
jquery实现页面图片等比例放大缩小功能
2014/02/12 Javascript
使用jquery prev()方法找到同级的前一个元素
2014/07/11 Javascript
javascript学习笔记(八)正则表达式
2014/10/08 Javascript
js获取checkbox值的方法
2015/01/28 Javascript
Bootstrap3制作搜索框样式的方法
2016/07/11 Javascript
javascript 秒表计时器实现代码
2017/03/09 Javascript
JS判断非空至少输入两个字符的简单实现方法
2017/06/23 Javascript
使用travis-ci如何持续部署node.js应用详解
2017/07/30 Javascript
解决node修改后需频繁手动重启的问题
2018/05/13 Javascript
浅谈webpack 构建性能优化策略小结
2018/06/13 Javascript
JavaScript实现HSL拾色器
2020/05/21 Javascript
在antd中setFieldsValue和defaultVal的用法
2020/10/29 Javascript
windows下wxPython开发环境安装与配置方法
2014/06/28 Python
python通过pil将图片转换成黑白效果的方法
2015/03/16 Python
python3爬取各类天气信息
2018/02/24 Python
使用python生成目录树
2018/03/29 Python
python中字符串内置函数的用法总结
2018/09/13 Python
python中partial()基础用法说明
2018/12/30 Python
Flask框架单例模式实现方法详解
2019/07/31 Python
社区活动邀请函范文
2014/01/29 职场文书
中秋寄语大全
2014/04/11 职场文书
小学生感恩演讲稿
2014/04/25 职场文书
八项规定个人对照检查材料思想汇报
2014/09/25 职场文书
Python趣味挑战之用pygame实现简单的金币旋转效果
2021/05/31 Python
浅谈Python数学建模之数据导入
2021/06/23 Python
Spring Boot 启动、停止、重启、状态脚本
2021/06/26 Java/Android
springboot集成springCloud中gateway时启动报错的解决
2021/07/16 Java/Android
特别篇动画《总之就是非常可爱 ~制服~》PV公开,2022年夏季播出
2022/04/04 日漫
Java中的继承、多态以及封装
2022/04/11 Java/Android