MNIST虽然很简单,但是值得我们学习的东西还是有很多的。

项目虽然简单,但是个人建议还是将各个模块分开创建,特别是对于新人而言,模块化的创建会让读者更加清晰、易懂。

  • CNN模块:卷积神经网络的组成;
  • train模块:利用CNN模型 对 MNIST数据集 进行训练并保存模型
  • test模块:加载训练好的模型对测试集数据进行测试
  • cnn.pt : train 的CNN模型

注意!
有GPU的小伙伴尽量使用GPU训练,GPU的训练速度比CPU的训练速度高许多倍,可以节约大量训练时间

文章目录

  • 1、CNN 模块
    • CNN 模块分析
  • 2、train 模块
  • 3、test 模块

1、CNN 模块

MNIST的识别算法有很多,在此提供的是 卷积神经网络CNN ,其他算法也同样可以取得很好的识别效果,有兴趣的小伙伴可以自己尝试下。

在此就不得不提 Pytorch的优势了,都知道 Pytorch 是动态计算模型。但是何为动态计算模型呢?

  • 在此对比 Tensorflow。在流行的神经网络架构中, Tensorflow 就是最典型的静态计算架构。使用 Tensorflow 就必须先搭建好这样一个计算系统, 一旦搭建好了, 就不能改动了 (也有例外), 所有的计算都会在这种图中流动, 当然很多情况下这样就够了, 我们不需要改动什么结构。
  • 不动结构当然可以提高效率. 但是一旦计算流程不是静态的, 计算图要变动. 最典型的例子就是 RNN, 有时候 RNN 的 time step 不会一样, 或者在 training 和 testing 的时候, batch_size 和 time_step 也不一样, 这时, Tensorflow 就头疼了。
  • 如果用一个动态计算图的 Pytorch, 我们就好理解多了, 写起来也简单多了. PyTorch 支持在运行过程中根据运行参数动态改变应用模型。可以简单理解为:一种是先定义后使用,另一种是边使用边定义。动态计算图模式是 PyTorch 的天然优势之一,Google 2019年 3 月份发布的 TensorFlow 2.0 Alpha 版本中的 Eager Execution,被认为是在动态计算图模式上追赶 PyTorch 的举措。

如果暂时看不懂的小伙伴,可以先不管,先往后学习,等将来需要的时候再回头思考这段话。

CNN 模块分析

CNN 模块主要分为两个部分,一个是定义CNN模块,另一个是将各个模块组成前向传播通道

  • super() 函数: 是用于调用父类(超类)的一个方法。
    用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。
    super(SimpleCNN, self) 首先找到 SimpleCNN 的父类(就是类 nn.Module ),然后把类 SimpleCNN 的对象转换为类 nn.Module 的对象

  • nn.Sequential(): 是一个有顺序的容器,将神经网络模块 按照传入构造器的顺序依次被添加到计算图中执行。由于每一个神经网络模块都继承于nn.Module,通过索引的方式利用add_module函数将 nn.Sequential()模块 添加到现有模块中。

  • forward(): 是前向传播函数,将之前定义好的每层神经网络模块串联起来,同时也定义了模型的输入参数

  • x.view() & x.reshape(): 其实两者的作用并没有太大区别,作用都是调整张量的类型大小,view() 出现的更早些,而 reshape() 则是为了与 Numpy对齐,在 Pytorch 0.3版本之后添加的,两者作用没有太大区别;

#  !/usr/bin/env  python
#  -*- coding:utf-8 -*-
# @Time   :  2020.
# @Author :  绿色羽毛
# @Email  :  lvseyumao@foxmail.com
# @Blog   :  https://blog.csdn.net/ViatorSun
# @Note   :  from torch import nnclass SimpleCNN(nn.Module):def __init__(self):super(SimpleCNN, self).__init__()self.layer1 = nn.Sequential( nn.Conv2d(1,16,kernel_size=3) ,nn.BatchNorm2d(16) ,nn.ReLU(inplace=True))self.layer2 = nn.Sequential( nn.Conv2d(16,32,kernel_size=3) ,nn.BatchNorm2d(32) ,nn.ReLU(inplace=True) ,nn.MaxPool2d(kernel_size=2 , stride=2))self.layer3 = nn.Sequential( nn.Conv2d(32,64,kernel_size=3) ,nn.BatchNorm2d(64) ,nn.ReLU(inplace=True))self.layer4 = nn.Sequential( nn.Conv2d(64,128,kernel_size=3) ,nn.BatchNorm2d(128) ,nn.ReLU(inplace=True) ,nn.MaxPool2d(kernel_size=2 , stride=2))self.fc = nn.Sequential(nn.Linear(128*4*4,1024) ,nn.ReLU(inplace=True) ,nn.Linear(1024,128) ,nn.ReLU(inplace=True) ,nn.Linear(128,10) )def forward( self , x):x = self.layer1(x)x = self.layer2(x)x = self.layer3(x)x = self.layer4(x)# x = x.view(x.size(0) , -1)x = x.reshape(x.size(0) , -1)fc_out = self.fc(x)return fc_out

2、train 模块

#  !/usr/bin/env  python
#  -*- coding:utf-8 -*-
# @Time   :  2020.
# @Author :  绿色羽毛
# @Email  :  lvseyumao@foxmail.com
# @Blog   :  https://blog.csdn.net/ViatorSun
# @Note   :  import torch
import CNN
from torch import nn , optim
from torchvision import datasets
from torchvision import transforms
from torch.autograd import Variable
from torch.utils.data import DataLoader# 定义超参数
learning_rate = 1e-2      # 学习率
batch_size    = 128       # 批的大小
epoches_num   = 20        # 遍历训练集的次数# 下载训练集 MNIST 手写数字训练集
train_dataset = datasets.MNIST( root='./data', train=True, transform=transforms.ToTensor(), download=True )
train_loader  = DataLoader( train_dataset, batch_size=batch_size, shuffle=True )# 定义model 、loss 、optimizer
model = CNN.SimpleCNN()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD( model.parameters(), lr=learning_rate )if torch.cuda.is_available():print("CUDA is enable!")model = model.cuda()model.train()# 开始训练
for epoch in range(epoches_num):print('*' * 40)train_loss = 0.0train_acc  = 0.0# 训练for i, data in enumerate(train_loader, 1 ):img, label = data# 拥有GPU的小伙伴还是推荐使用GPU训练if torch.cuda.is_available():img   = Variable(img).cuda()label = Variable(label).cuda()else:img   = Variable(img)label = Variable(label)# 前向传播optimizer.zero_grad()out  = model(img)loss = criterion(out, label)# 反向传播loss.backward()optimizer.step()# 损失/准确率计算train_loss += loss.item() * label.size(0)_ , pred    = out.max(1)num_correct = pred.eq(label).sum()accuracy    = pred.eq(label).float().mean()train_acc  += num_correct.item()print('Finish  {}  Loss: {:.6f}, Acc: {:.6f}'.format( epoch+1 , train_loss / len(train_dataset), train_acc / len(train_dataset )))# 保存模型
torch.save(model, 'cnn.pt')

3、test 模块

在模型的使用过程中,有些子模块(如:丢弃层、批次归一化层等)有两种状态,即训练状态和预测状态,在不同时候 Pytorch模型 需要在两种状态中相互转换。

  • model.tran() 方法会将模型(包含所有子模块)中的参数转换成训练状态
  • model.eval() 方法会将模型(包含所有子模块)中的参数转换成预测状态

Pytorch 的模型在不同状态下的预测准确性会有差异,在训练模型的时候需要转换为训练状态,在预测的时候需要转化为预测状态,否则最后模型预测准确性可能会降低,甚至会得到错误的结果。

#  !/usr/bin/env  python
#  -*- coding:utf-8 -*-
# @Time   :  2020.
# @Author :  绿色羽毛
# @Email  :  lvseyumao@foxmail.com
# @Blog   :  https://blog.csdn.net/ViatorSun
# @Note   :  import torch
from torch import nn
from torchvision import datasets
from torchvision import transforms
from torch.autograd import Variable
from torch.utils.data import DataLoader# 定义超参数
batch_size  = 128       # 批的大小# 下载训练集 MNIST 手写数字测试集
test_dataset  = datasets.MNIST( root='./data', train=False, transform=transforms.ToTensor())
test_loader   = DataLoader(test_dataset , batch_size=batch_size, shuffle=False)# 加载 Train 模型
model = torch.load('cnn.pt')
criterion = nn.CrossEntropyLoss()
model.eval()
eval_acc  = 0
eval_loss = 0# 测试
for data in test_loader:img, label = dataif torch.cuda.is_available():img   = Variable(img  ).cuda()label = Variable(label).cuda()else:img   = Variable(img  )label = Variable(label)out  = model(img)loss = criterion(out, label)eval_loss += loss.item() * label.size(0)_ , pred = torch.max(out,1)num_correct = (pred==label).sum()eval_acc += num_correct.item()print('Test Loss: {:.6f}   ,   Acc: {:.6f}'.format( eval_loss/(len(test_dataset)), eval_acc/(len(test_dataset)) ))

详解 Pytorch 实现 MNIST相关推荐

  1. (!详解 Pytorch实战:①)kaggle猫狗数据集二分类:加载(集成/自定义)数据集

    这系列的文章是我对Pytorch入门之后的一个总结,特别是对数据集生成加载这一块加强学习 另外,这里有一些比较常用的数据集,大家可以进行下载: 需要注意的是,本篇文章使用的PyTorch的版本是v0. ...

  2. python中squeeze函数_详解pytorch中squeeze()和unsqueeze()函数介绍

    squeeze的用法主要就是对数据的维度进行压缩或者解压. 先看torch.squeeze() 这个函数主要对数据的维度进行压缩,去掉维数为1的的维度,比如是一行或者一列这种,一个一行三列(1,3)的 ...

  3. YOLOV1详解——Pytorch版

    YOLOV1详解--Pytorch版 1 YOLOV1 1 数据处理 1.1 数据集划分 1.2 读入xml文件 1.3 数据增强 2 训练 2.1 Backbone 2.2 Loss 2.3 tra ...

  4. 超详解pytorch实战Kaggle比赛:房价预测

    详解pytorch实战Kaggle比赛:房价预测 教程名称 教程地址 机器学习/深度学习 [李宏毅]机器学习/深度学习国语教程(双语字幕) 生成对抗网络 [李宏毅]生成对抗网络国语教程(双语字幕) 目 ...

  5. python 动态执行 内存变化_详解Pytorch显存动态分配规律探索

    下面通过实验来探索Pytorch分配显存的方式. 实验显存到主存 我使用VSCode的jupyter来进行实验,首先只导入pytorch,代码如下: import torch 打开任务管理器查看主存与 ...

  6. 详解pytorch实现猫狗识别98%附代码

    详解pytorch实现猫狗识别98%附代码 前言 一.为什么选用pytorch这个框架? 二.实现效果 三.神经网络从头到尾 1.来源:仿照人为处理图片的流程,模拟人们的神经元处理信息的方式 2.总览 ...

  7. 【深度学习】ResNet——CNN经典网络模型详解(pytorch实现)

    建议大家可以实践下,代码都很详细,有不清楚的地方评论区见~ 1.前言 ResNet(Residual Neural Network)由微软研究院的Kaiming He等四名华人提出,通过使用ResNe ...

  8. 一文详解pytorch的“动态图”与“自动微分”技术

    前言 众所周知,Pytorch是一个非常流行且深受好评的深度学习训练框架.这与它的两大特性"动态图"."自动微分"有非常大的关系."动态图" ...

  9. 详解Pytorch中的requires_grad、叶子节点与非叶子节点、with torch.no_grad()、model.eval()、model.train()、BatchNorm层

    requires_grad requires_grad意为是否需要计算梯度 使用backward()函数反向传播计算梯度时,并不是计算所有tensor的梯度,只有满足下面条件的tensor的梯度才会被 ...

最新文章

  1. Django 各类配置选项全集
  2. python hist函数_Python主要数据探索函数
  3. 手撕设计模式之「单例模式」(详细解析)
  4. C++ using namespace
  5. vue --- vue-router(项目模式的导入)
  6. gdb可以查询执行文件的宏, 但是查询不了o文件的宏
  7. RMQ问题:与众不同(st表的高端应用)
  8. 基于Verilog语言的伪随机码的编写
  9. display函数怎么使用_使用网络构建复杂布局超实用的技巧,赶紧收藏吧
  10. pgsql处理文档类型数据_【干货总结】:可能是史上最全的MySQL和PGSQL对比材料
  11. python中属性是什么意思啊_python中的“对象属性”和一般属性是什么?
  12. python怎么返回上一行代码_Python实现判断一行代码是否为注释的方法
  13. python可变类型与不可类型
  14. python爬虫知识点总结(七)PyQuery详解
  15. 悄悄告诉你,在硅谷,有一种工作比程序员挣得多
  16. 递归法:汉诺塔(快速掌握)
  17. 【转贴】谈论 Direct3D10特性预览
  18. uni-app 小程序开发 (一)
  19. 家庭局域网_看教程,自己搭建家庭监控系统!
  20. C2. Skyscrapers (hard version)

热门文章

  1. upload文件上传靶场
  2. HTML开发技术【5】
  3. 获取结构柱的FamilySymbol
  4. 计算机服务项里没有MySQL服务,无法设置开机自启动或者关闭自启动,的解决办法
  5. 从今天起,逃离迷茫与枯燥,做一个与快乐常伴的人
  6. ksh 向脚本传递参数
  7. DCGAN生成二次元头像实战,Anime Faces数据集下载
  8. 序员的搞笑事件(趣图)哈哈哈哈哈
  9. m4v视频如何转换mp4格式,简单操作一学就会
  10. MTK平台,kernel中写EMMC指定分区