使用 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库urllib与urllib2主要区别分析
Jul 13 Python
Python两个整数相除得到浮点数值的方法
Mar 18 Python
python中xrange用法分析
Apr 15 Python
Python中逗号的三种作用实例分析
Jun 08 Python
Python正则表达式经典入门教程
May 22 Python
python主线程捕获子线程的方法
Jun 17 Python
Python检查和同步本地时间(北京时间)的实现方法
Dec 03 Python
解决pyecharts在jupyter notebook中使用报错问题
Apr 23 Python
Python matplotlib画图时图例说明(legend)放到图像外侧详解
May 16 Python
基于Python爬取京东双十一商品价格曲线
Oct 23 Python
python 实用工具状态机transitions
Nov 21 Python
tensorboard 可视化之localhost:6006不显示的解决方案
May 22 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
一步一步学习PHP(7) php 字符串相关应用
2010/03/05 PHP
一个PHP的String类代码
2010/04/20 PHP
PHP session会话操作技巧小结
2016/09/27 PHP
深入理解PHP+Mysql分布式事务与解决方案
2020/12/03 PHP
dojo 之基础篇(三)之向服务器发送数据
2007/03/24 Javascript
学习ExtJS border布局
2009/10/08 Javascript
ASP.NET jQuery 实例9  通过控件hyperlink实现返回顶部效果
2012/02/03 Javascript
javascript一元操作符(递增、递减)使用示例
2013/08/07 Javascript
jquery live()重复绑定的解决方法介绍
2014/01/03 Javascript
javascript时间函数大全
2014/06/30 Javascript
jQuery实现响应浏览器缩放大小并改变背景颜色
2014/10/31 Javascript
JavaScript实现的简单烟花特效代码
2015/10/20 Javascript
ES6中Array.find()和findIndex()函数的用法详解
2017/09/16 Javascript
微信小程序实现换肤功能
2018/03/14 Javascript
vue-router路由模式详解(小结)
2019/08/26 Javascript
Vue+tracking.js 实现前端人脸检测功能
2020/04/16 Javascript
TypeScript 运行时类型检查补充工具
2020/09/28 Javascript
[02:36]DOTA2英雄基础教程 帕格纳
2014/01/20 DOTA
[02:11]完美世界DOTA2联赛10月28日赛事精彩集锦:来吧展示实力强劲
2020/10/29 DOTA
让python的Cookie.py模块支持冒号做key的方法
2010/12/28 Python
Python中MySQL数据迁移到MongoDB脚本的方法
2016/04/28 Python
python 实现红包随机生成算法的简单实例
2017/01/04 Python
Python实现的异步代理爬虫及代理池
2017/03/17 Python
关于torch.optim的灵活使用详解(包括重写SGD,加上L1正则)
2020/02/20 Python
Ubuntu中配置TensorFlow使用环境的方法
2020/04/21 Python
英国百安居装饰建材网上超市:B&Q
2016/09/13 全球购物
法国最大电子商务平台:Cdiscount
2018/03/13 全球购物
如何将整数int转换成字串String
2014/03/21 面试题
幼儿园教师国培感言
2014/02/02 职场文书
经典婚礼主持词
2014/03/13 职场文书
大学中国梦演讲稿
2014/04/23 职场文书
我的教育故事演讲稿
2014/05/04 职场文书
农业局党的群众路线教育实践活动整改方案
2014/09/20 职场文书
2019年妇科护士的自我鉴定(3篇)
2019/09/26 职场文书
Oracle 触发器trigger使用案例
2022/02/24 Oracle
uniapp开发打包多端应用完整方法指南
2022/12/24 Javascript