本程序采用百度paddlepaddle深度学习框架,并在百度AI Studio平台上运行

目录

1 实验内容

2 实验流程

3 DNN模型

4 LeNet 模型

4.1 LeNet-1模型

4.2 Lenet-4 模型

4.3 LeNet-5 模型

4.4 LeNet 模型的总结

4.5 LeNet 模型与DNN模型比较

5 模型的应用

5.1 自己的手写数字图片

5.2将手写的图片进行预处理

5.3调用训练好的模型进行预测

5.4 总结


1 实验内容

本次实验采用构造 DNN 模型与 LeNet 模型进行手写数字识别实验,采用经典手写数字识别数据集 MINIST,MINIST 数据集包含60000个训练集与10000个测试集。数据集分为图片与标签,其中图片是28*28的像素矩阵,标签为 0~9 共10个数字。该数据集的官方网址为MNIST handwritten digit database, Yann LeCun, Corinna Cortes and Chris Burges

2 实验流程

在实验过程中为确保最终训练的神经网络拥有较强的泛化能力,本次实验会在最后对自己手写的一些数字图片进行识别。

3 DNN模型

以下的代码判断就是定义一个简单的 DNN模型(多层感知器),一共有三层,两个大小为100的隐层和一个大小为10的输出层,因为MNIST数据集是手写0到9的灰度图像,类别有10个,所以最后的输出大小是10。最后输出层的激活函数是Softmax,所以最后的输出层相当于一个分类器。加上一个输入层的话,多层感知器的结构是:输入层-->>隐层-->>隐层-->>输出层。神经网络结构如下

利用 paddlepaddle 的动态图对初始的 DNN 模型进行定义,代码如下

# 定义多层感知器
#动态图定义多层感知器
class multilayer_perceptron(fluid.dygraph.Layer):def __init__(self):super(multilayer_perceptron,self).__init__()self.fc1 = Linear(input_dim=28*28, output_dim=100, act='relu')self.fc2 = Linear(input_dim=100, output_dim=100, act='relu')self.fc3 = Linear(input_dim=100, output_dim=10,act="softmax")def forward(self,input_):x = fluid.layers.reshape(input_, [input_.shape[0], -1])x = self.fc1(x)x = self.fc2(x)y = self.fc3(x)return y

经过一段时间的调参最终选择 optimizer 为 Adam,learning rate 为0.001,batch_size 为64,epoch为5,损失函数选择softmax,最终训练曲线与在验证集上的准确率如下

由以上结果可以看出DNN模型在经过调参后在测试集的准确率较高,但是由于这种三层全连接神经网络的结构过于简单,并且经典数据集量较少,所以 loss曲线与acc曲线的震荡都比较厉害,可见模型在预测时的稳定性较差,因此接下来将采用 LeNet 模型进行识别。

4 LeNet 模型

4.1 LeNet-1模型

在Lenet-1中, 28*28 的输入图像矩阵 --> 经过卷积(卷积层4层,卷积核size为5*5,步长为1) --> 4个24*24 feature maps -->平均池化层(2*2 size,步长为2)-->4个12*12 feature maps -->经过卷积(卷积层3层,卷积核size为5*5,步长为1)--> 12个8*8 feature maps平均池化层(2*2 size,步长为2)-->12个4*4 feature maps --> 直接全连接到10个输出。示意图如下

定义 LeNet-1 模型的代码如下

import paddle
import paddle.nn.functional as F
class LeNet(paddle.nn.Layer):def __init__(self):super(LeNet, self).__init__()self.conv1 = paddle.nn.Conv2D(in_channels=1, out_channels=4, kernel_size=5, stride=1, padding=2)self.Max_pool1 = paddle.nn.MaxPool2D(kernel_size=2,  stride=2)self.conv2 = paddle.nn.Conv2D(in_channels=4, out_channels=12, kernel_size=5, stride=1)self.Max_pool2 = paddle.nn.MaxPool2D(kernel_size=2, stride=2)self.linear1 = paddle.nn.Linear(in_features=12*5*5, out_features=10)
def forward(self, x):x = self.conv1(x)x = F.relu(x)x = self.Max_pool1(x)x = self.conv2(x)x = F.relu(x)x = self.Max_pool2(x)x = paddle.flatten(x, start_axis=1,stop_axis=-1)x = self.linear1(x)return x

最终 LeNet-1模型对MINIST测试集的评估结果如下(准确率达到98.05%)

4.2 Lenet-4 模型

在Lenet-4中, 32*32 的输入图像矩阵 --> 经过卷积(卷积层4层,卷积核size为5*5,步长为1) --> 4个28*28 feature maps -->平均池化层(2*2 size,步长为2)-->4个14*14 feature maps -->经过卷积(卷积层16层,卷积核size为5*5,步长为1)--> 16个10*10 feature maps平均池化层(2*2 size,步长为2)-->16个5*5 feature maps --> 直接全连接到120个神经元 --> 直接全连接到10个输出。示意图如下

定义 LeNet-4 模型的代码如下

import paddle
import paddle.nn.functional as F
class LeNet(paddle.nn.Layer):def __init__(self):super(LeNet, self).__init__()self.conv1 = paddle.nn.Conv2D(in_channels=1, out_channels=6, kernel_size=5, stride=1, padding=2)self.max_pool1 = paddle.nn.MaxPool2D(kernel_size=2,  stride=2)self.conv2 = paddle.nn.Conv2D(in_channels=6, out_channels=16, kernel_size=5, stride=1)self.max_pool2 = paddle.nn.MaxPool2D(kernel_size=2, stride=2)self.linear1 = paddle.nn.Linear(in_features=16*5*5, out_features=120)self.linear2 = paddle.nn.Linear(in_features=120, out_features=10)
def forward(self, x):x = self.conv1(x)x = F.relu(x)x = self.max_pool1(x)x = self.conv2(x)x = F.relu(x)x = self.max_pool2(x)x = paddle.flatten(x, start_axis=1,stop_axis=-1)x = self.linear1(x)x = F.relu(x)x = self.linear2(x)return x

最终 LeNet-1模型对MINIST测试集的评估结果如下(准确率达到98.54%)

4.3 LeNet-5 模型

在Lenet-4中, 32*32 的输入图像矩阵 --> 经过卷积(卷积层6层,卷积核size为5*5,步长为1) --> 4个28*28 feature maps -->平均池化层(2*2 size,步长为2)-->4个14*14 feature maps -->经过卷积(卷积层16层,卷积核size为5*5,步长为1)--> 16个10*10 feature maps平均池化层(2*2 size,步长为2)-->16个5*5 feature maps --> 直接全连接到120个神经元 --> 直接全连接到84个输出 --> 直接全连接到10个输出。示意图如下

定义 LeNet-5 模型的代码如下


import paddle
import paddle.nn.functional as F
class LeNet(paddle.nn.Layer):def __init__(self):super(LeNet, self).__init__()self.conv1 = paddle.nn.Conv2D(in_channels=1, out_channels=6, kernel_size=5, stride=1, padding=2)self.max_pool1 = paddle.nn.MaxPool2D(kernel_size=2,  stride=2)self.conv2 = paddle.nn.Conv2D(in_channels=6, out_channels=16, kernel_size=5, stride=1)self.max_pool2 = paddle.nn.MaxPool2D(kernel_size=2, stride=2)self.linear1 = paddle.nn.Linear(in_features=16*5*5, out_features=100)self.linear2 = paddle.nn.Linear(in_features=100, out_features=84)self.linear3 = paddle.nn.Linear(in_features=84, out_features=10)def forward(self, x):x = self.conv1(x)x = F.relu(x)x = self.max_pool1(x)x = self.conv2(x)x = F.relu(x)x = self.max_pool2(x)x = paddle.flatten(x, start_axis=1,stop_axis=-1)x = self.linear1(x)x = F.relu(x)x = self.linear2(x)x = F.relu(x)x = self.linear3(x)return x

最终 LeNet-5模型对MINIST测试集的评估结果如下(准确率达到98.89%)

4.4 LeNet 模型的总结

由上述三个模型的对比可知

(1)神经网络在层数增加时会有更好的识别能力,也就是为什么深层的网络泛化能力更好

(2)最大池化比平均池化的效果更好,因为捕捉更尖锐的特征是识别时更关注的

(3)LeNet-4与LeNet-5通过padding=2使28*28的图变成32*32的图,像素更大,识别会更精确

(4)在实际代码中我采用了最大池化,与原始模型不同,目的是加速收敛,激活函数采用relu, 因为relu的拟合能力更强

(5)LeNet-5效果最好,也是通常LeNet模型所指向的版本

4.5 LeNet 模型与DNN模型比较

LeNet采用卷积神经网络,通过卷积对图像的特征提取能力更强,通过共享参数使图像的平移不变性得到保证,通过池化来减少过拟合,总之在图像处理预测的问题上卷积神经网络具有更强大的能力。

5 模型的应用

5.1 自己的手写数字图片

              

5.2将手写的图片进行预处理

为了保证训练数据的一致性(不受光照等因素影响),将图片转变成黑白图片,代码如下

#读取图片进行预处理
def load_image(infer_path):image=Image.open(infer_path).convert('L')image=image.resize((28, 28), Image.ANTIALIAS)image=np.array(image).reshape(28,28).astype(np.float32)image=image/255*2-1#将图片转化为黑白图for i in range(image.shape[0]):for j in range(image.shape[1]):if image[i][j]>0.1:image[i][j]=-1else:image[i][j]=1plt.imshow(image.reshape(28,28),cmap='gray')plt.show()return image.reshape(1,1,28,28)         

5.3调用训练好的模型进行预测

代码如下

infer_path='微信图片_20220331172616.jpg'
#获取图片
test_data, test_label= load_image(infer_path),0 #标签值自己设定
test_data = test_data.reshape([28,28])
plt.figure(figsize=(2,2))
#展示图片
print(plt.imshow(test_data, cmap=plt.cm.binary))
print('test_data 的标签为: ' + str(test_label))
#模型预测
result = model.predict([test_data.reshape(1,1,28,28)])
#打印模型预测的结果
print('预测值为:%d' %np.argmax(result))

预测结果如下图

5.4 总结

虽然此次识别都正确,但是在真正的生活场景中,训练好的神经网络又不再适用,因为数字大小、位置、背景、光照、颜色等因素影响比较大,在MINIST数据集与自己手写导入的数据中,图片都是分辨率较低,外界的影响都比较相似,所以要获得一个适用于较广场景的数字手写识别神经网络,需要有包含各种环境的庞大数据集,并且还需要设计更复杂的网络模型。

5.5 完整 LeNet 模型源程序

#导入需要的包
import zipfile
import os
import random
import paddle
import matplotlib.pyplot as plt
from paddle.nn import MaxPool2D,Conv2D,BatchNorm
from paddle.nn import Linear
import sys
import numpy as np
from PIL import Image
from PIL import ImageEnhance
import paddle
from multiprocessing import cpu_count
import matplotlib.pyplot as plt
import json #导入数据集Compose的作用是将用于数据集预处理的接口以列表的方式进行组合。
#导入数据集Normalize的作用是图像归一化处理,支持两种方式: 1. 用统一的均值和标准差值对图像的每个通道进行归一化处理; 2. 对每个通道指定不同的均值和标准差值进行归一化处理。
from paddle.vision.transforms import Compose, Normalize
transform = Compose([Normalize(mean=[127.5],std=[127.5],data_format='CHW')])
# 使用transform对数据集做归一化
print('下载并加载训练数据')
train_dataset = paddle.vision.datasets.MNIST(mode='train', transform=transform)
test_dataset = paddle.vision.datasets.MNIST(mode='test', transform=transform)
print('加载完成')#让我们一起看看数据集中的图片是什么样子的
train_data0, train_label_0 = train_dataset[0][0],train_dataset[0][1]
train_data0 = train_data0.reshape([28,28])
plt.figure(figsize=(2,2))
print(plt.imshow(train_data0, cmap=plt.cm.binary))
print('train_data0 的标签为: ' + str(train_label_0))#定义LeNet
import paddle
import paddle.nn.functional as F
class LeNet(paddle.nn.Layer):def __init__(self):super(LeNet, self).__init__()self.conv1 = paddle.nn.Conv2D(in_channels=1, out_channels=6, kernel_size=5, stride=1, padding=2)self.max_pool1 = paddle.nn.MaxPool2D(kernel_size=2,  stride=2)self.conv2 = paddle.nn.Conv2D(in_channels=6, out_channels=16, kernel_size=5, stride=1)self.max_pool2 = paddle.nn.MaxPool2D(kernel_size=2, stride=2)self.linear1 = paddle.nn.Linear(in_features=16*5*5, out_features=100)self.linear2 = paddle.nn.Linear(in_features=100, out_features=84)self.linear3 = paddle.nn.Linear(in_features=84, out_features=10)def forward(self, x):x = self.conv1(x)x = F.relu(x)x = self.max_pool1(x)x = self.conv2(x)x = F.relu(x)x = self.max_pool2(x)x = paddle.flatten(x, start_axis=1,stop_axis=-1)x = self.linear1(x)x = F.relu(x)x = self.linear2(x)x = F.relu(x)x = self.linear3(x)return xfrom paddle.metric import Accuracy
model = paddle.Model(LeNet())   # 用Model封装模型
optim = paddle.optimizer.Adam(learning_rate=0.001, parameters=model.parameters())# 配置模型
model.prepare(optim,paddle.nn.CrossEntropyLoss(),Accuracy())model.fit(train_dataset,epochs=4,batch_size=128,verbose=1)model.evaluate(test_dataset, batch_size=64, verbose=1)#读取图片进行预处理
def load_image(infer_path):image=Image.open(infer_path).convert('L')image=image.resize((28, 28), Image.ANTIALIAS)image=np.array(image).reshape(28,28).astype(np.float32)image=image/255*2-1#将图片转化为黑白图for i in range(image.shape[0]):for j in range(image.shape[1]):if image[i][j]>0.1:image[i][j]=-1else:image[i][j]=1plt.imshow(image.reshape(28,28),cmap='gray')plt.show()return image.reshape(1,1,28,28)            infer_path='xxxx.jpg'#填写照片路径
#获取图片
test_data, test_label= load_image(infer_path),0
test_data = test_data.reshape([28,28])
plt.figure(figsize=(2,2))
#展示图片
print(plt.imshow(test_data, cmap=plt.cm.binary))
print('test_data 的标签为: ' + str(test_label))
#模型预测
result = model.predict([test_data.reshape(1,1,28,28)])
#打印模型预测的结果
print('预测值为:%d' %np.argmax(result))

深度学习(手写数字识别)相关推荐

  1. 深度学习——手写数字识别

    深度学习--手写数字问题 前不久入门学习了Tensorflow深度学习框架,了解一下什么是神经网络和Tensorflow的简单使用.下面通过Tensorflow框架来建造神经网络模型来对手写数字进行训 ...

  2. 深度学习——手写数字识别底层实现

    内容再要 手写数字识别,早在20世纪前,杨立昆(Yann LeCun)就完成这项工作,并在1980年左右利用卷积神经网络完善了手写数字识别 代码实现 import tensorflow as tf i ...

  3. 百度深度学习--手写数字识别之数据处理

    文章目录 概述 前提条件 读入数据并划分数据集 扩展阅读:为什么学术界的模型总在不断精进呢? 训练样本乱序.生成批次数据 校验数据有效性 机器校验 人工校验 封装数据读取与处理函数 异步数据读取 概述 ...

  4. python-机器学习-手写数字识别

    机器学习简单的来说,分为监督式学习和无监督式学习: 对于监督式学习就是需要人为的来告诉计算机这是什么,需要我们给他一个标签(答案). 无监督式学习就是不需要我们给出标签(答案). 图像识别(Image ...

  5. python手写字体程序_深度学习---手写字体识别程序分析(python)

    我想大部分程序员的第一个程序应该都是"hello world",在深度学习领域,这个"hello world"程序就是手写字体识别程序. 这次我们详细的分析下手 ...

  6. 深度学习 手写字体识别

    数据集介绍: mnist数据集使用tensorflow封装好的数据(包含6000张训练数据,1000张测试数据),图片大小为28x28. 在神经网络的结构上,一方面需要使用激活函数去线性化.另一方面需 ...

  7. 深度学习100例 | 第25天-卷积神经网络(CNN):中文手写数字识别

    大家好,我是『K同学啊』! 接着上一篇文章 深度学习100例 | 第24天-卷积神经网络(Xception):动物识别,我用Xception模型实现了对狗.猫.鸡.马等四种动物的识别,带大家了解了Xc ...

  8. 用MXnet实战深度学习之一:安装GPU版mxnet并跑一个MNIST手写数字识别 (zz)

    用MXnet实战深度学习之一:安装GPU版mxnet并跑一个MNIST手写数字识别 我想写一系列深度学习的简单实战教程,用mxnet做实现平台的实例代码简单讲解深度学习常用的一些技术方向和实战样例.这 ...

  9. 深度学习练手项目(一)-----利用PyTorch实现MNIST手写数字识别

    一.前言 MNIST手写数字识别程序就不过多赘述了,这个程序在深度学习中的地位跟C语言中的Hello World地位并驾齐驱,虽然很基础,但很重要,是深度学习入门必备的程序之一. 二.MNIST数据集 ...

  10. Java软件研发工程师转行之深度学习(Deep Learning)进阶:手写数字识别+人脸识别+图像中物体分类+视频分类+图像与文字特征+猫狗分类

    本文适合于对机器学习和数据挖掘有所了解,想深入研究深度学习的读者 1.对概率基本概率有所了解 2.具有微积分和线性代数的基本知识 3.有一定的编程基础(Python) Java软件研发工程师转行之深度 ...

最新文章

  1. html input type=quot;filequot;,科技常识:关于type=quot;filequot;的input框样式修改小结...
  2. 职场5年经验的工程师论述linux真没那么难
  3. 微信开发 提示 Redirect_uri参数错误解决方法
  4. ASP.NET 页面基本优化.
  5. 200922阶段一C++关联容器map
  6. 用户体验改善案例_改善用户体验研究的5种习惯
  7. data.length 提示undefined 问题解决
  8. 云计算之路-阿里云上:Web服务器请求到达量突降
  9. 关于官方Reachability Demo理解
  10. 免费分享20套PHP源码
  11. matlab更改安全密钥,Linux下设置安全密钥登录
  12. 【其他】Windows Media Services 无法启动
  13. MPU6050 六轴传感器实验
  14. 串口信号定义和接线方法-5针串口-9针串口-全功能串口
  15. C++小游戏 苍穹世界2.2 测试版
  16. pandas.plotting.scatter_matrix 参数
  17. 【数据结构——哈夫曼树及其应用】
  18. MACD多周期共振系统TB源码
  19. 云服务器有几种类型,一般要如何选购
  20. 有哪些含金量较高的Python证书?

热门文章

  1. C语言 define 定义函数(多行书写) - C语言零基础入门教程
  2. 位数不足前面补0mysql语句_mysql LPAD 和RPAD不足位数补齐填充函数
  3. 记录一次hive无法删除异常分区问题
  4. 95号段短号码和短消息接入代码的禁止要求是什么?
  5. yum 命令执行出现failed: BDB0113....BDB1507 Thread died in Berkeley DB library
  6. 高德地图 JS Web 添加自定义图标,自定义窗口标记
  7. matlab生成正弦波平fpga,FPGA设计——正弦信号发生器
  8. js实现导入导出Excel(结合js-xlsx)
  9. J型曲线与如何做出正确决策
  10. 秒懂以太网的 MAC 硬件地址