热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

基于LeNet实现拍摄手写数字识别

文章目录1实验内容2实验原理LeNet:3具体实现基于PaddlePaddle实现LeNet加载数据:建立模型:模型训练:模型测试

文章目录

    • 1 实验内容
    • 2 实验原理
      • LeNet:
    • 3 具体实现
      • 基于PaddlePaddle实现LeNet
        • 加载数据:
        • 建立模型:
        • 模型训练:
        • 模型测试:
      • 基于Pytorch实现LeNet5
        • 加载数据:
        • 建立模型:
        • 模型训练:
      • 拍摄手写数字识别
        • 拍照采集手写数字
        • 图片处理
        • 送入网络测试
      • 图片平移、旋转和伸缩处理后


1 实验内容


  • 实现MNIST 数据加载和可视化

  • 阅读LeNet-5 的相关资料和论文,在Keras,Tensorfolow 或Pytorch 任意框架下逐层实现网
    络模型的构建

  • 在MNIST 数据集上实现模型训练,评估模型性能指标

  • 拍摄一张包含多个自己手写数字的照片,在经过图像裁剪、二值化等图像预处理后,使用
    在MNIST 数据集上训练得到的CNN 模型进行分类预测

  • (选做)对MNIST 或自己手写的数据进行不同程度的平移、旋转、(长宽等比例或不等比
    例)伸缩等处理后,观察神经网络的性能变化

  • PPT 汇报(每组3min),提交3-5 页实验报告,需简要叙述方法原理、实验步骤、方法参
    数讨论、实验结果;需明确说明组员分工、给出组内排名(可标注同等贡献#)。


2 实验原理


LeNet:

image-20210930162900607

LeNet是卷积神经网络的祖师爷LeCun在1998年提出,用于解决手写数字识别的视觉任务。自那时起,CNN的最基本的架构就定下来了:卷积层、池化层、全连接层。如今各大深度学习框架中所使用的LeNet都是简化改进过的LeNet-5(-5表示具有5个层),和原始的LeNet有些许不同,比如把激活函数改为了现在很常用的ReLu。

LeNet-5跟现有的conv->pool->ReLU的套路不同,它使用的方式是conv1->pool->conv2->pool2再接全连接层,但是不变的是,卷积层后紧接池化层的模式依旧不变。

以上图为例,对经典的LeNet做深入分析:

首先输入图像是单通道的28*28大小的图像,用矩阵表示就是[b, 1,28,28]

  • 第一个卷积层conv1所用的卷积核尺寸为5*5,滑动步长为1,卷积核数目为6,那么经过该层后图像尺寸变为24,28-5+1=24,输出矩阵为[b, 6,24,24]。

  • 第一个池化层pool核尺寸为2*2,步长2,这是没有重叠的max pooling,池化操作后,图像尺寸减半,变为14×14,输出矩阵为[b, 6,14,14]。

  • 第二个卷积层conv2的卷积核尺寸为5*5,步长1,卷积核数目为16,卷积后图像尺寸变为10,输出矩阵为[b,16,10,10].

  • 第二个池化层pool2核尺寸为2*2,步长2,这是没有重叠的max pooling,池化操作后,图像尺寸减半,变为4×4,输出矩阵为[b,16 ,5, 5]。

  • pool2后面接全连接层fc1,神经元数目为120,再接relu激活函数。

  • 再接fc2,神经元个数为84,再接relu激活函数。

  • 输出层得到10维的特征向量,用于10个数字的分类训练,送入softmax分类,得到分类结果的概率output。


3 具体实现


基于PaddlePaddle实现LeNet


加载数据:

用飞桨框架自带的 paddle.vision.datasets.MNIST 完成mnist数据集的加载与预处理归一化。

transform = Compose([Normalize(mean=[127.5],std=[127.5],data_format='CHW')])
# 使用transform对数据集做归一化
print('download training data and load training data')
train_dataset = paddle.vision.datasets.MNIST(mode='train', transform=transform)
test_dataset = paddle.vision.datasets.MNIST(mode='test', transform=transform)
print('load finished')

这里尝试取训练集中的第666条数据看一下:

import numpy as np
import matplotlib.pyplot as plt
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))
plt.imshow(train_data0, cmap=plt.cm.binary)
print('train_data0 label is: ' + str(train_label_0))

结果如下:

image-20210930170633032

image-20210930170707097

可见数据加载成功。

建立模型:

我们直接用paddle.nn下的API,如Conv2D、MaxPool2D、Linear完成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=120)self.linear2 = paddle.nn.Linear(in_features=120, 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 = F.relu(x)x = self.conv2(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

模型训练:

通过paddle提供的Model 构建实例,使用封装好的训练与测试接口,快速完成模型训练与测试。

from 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=2,batch_size=64,verbose=1)

训练过程如下所示:

image-20211013140721337

模型测试:

使用 Model.evaluate 来预测模型:

结果如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8eap7pPC-1634528724500)(https://i.loli.net/2021/10/13/h5jz6xHeRAOEZqL.png)]

基于Pytorch实现LeNet5


加载数据:

batch_size = 256
train_loader = torch.utils.data.DataLoader(datasets.MNIST('./data', train=True, download=True,transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,), (0.3081,))])),batch_size=batch_size, shuffle=True)
test_loader = torch.utils.data.DataLoader(datasets.MNIST('./data', train=False, transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,), (0.3081,))])),batch_size=1, shuffle=True)

建立模型:

class LeNet5(nn.Module):def __init__(self):super(LeNet5, self).__init__()self.conv1 = nn.Conv2d(1, 6, 5, padding=2)self.pooling = nn.MaxPool2d(2)self.conv2 = nn.Conv2d(6, 16, 5)self.AF = nn.ReLU()self.fc1 = nn.Linear(16*5*5, 120)self.fc2 = nn.Linear(120, 84)self.fc3 = nn.Linear(84, 10)for m in self.modules():if isinstance(m, (nn.Conv3d, nn.Conv2d, nn.Conv1d)):nn.init.xavier_uniform_(m.weight.data)elif isinstance(m, nn.Linear):nn.init.xavier_uniform_(m.weight.data)nn.init.constant_(m.bias.data, 0.0)def forward(self, x):x = self.AF(self.conv1(x))x = self.pooling(x)x = self.AF(self.conv2(x))x = self.pooling(x)x = x.view(x.size(0), -1)x = self.AF(self.fc1(x))x = self.AF(self.fc2(x))x = self.fc3(x)return x

模型训练:

if __name__=="__main__":batch_size = 256train_loader = torch.utils.data.DataLoader(datasets.MNIST('./data', train=True, download=True,transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,), (0.3081,))])),batch_size=batch_size, shuffle=True)test_loader = torch.utils.data.DataLoader(datasets.MNIST('./data', train=False, transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,), (0.3081,))])),batch_size=1, shuffle=True)loss = nn.CrossEntropyLoss()loss.to(device)net =LeNet5()net.to(device)net.train()epoch = 10lr = 1e-2optimizer = optim.SGD(net.parameters(), lr=lr, momentum = 0.9)for i in range(epoch):net.train()for j, (X, y) in enumerate(train_loader):optimizer.zero_grad()X,y = autograd.Variable(X).to(device), autograd.Variable(y).to(device)y_hat = net(X)# print(y_hat)l = loss(y_hat, y)# print(l)l.backward()optimizer.step()test_acc = evaluate_accuracy(net, test_loader)print("epoch:{}, test_acc:{}".format(i,test_acc))

训练过程:

img

拍摄手写数字识别


拍照采集手写数字

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gIOYbwtf-1634528724502)(https://i.loli.net/2021/10/12/OnFLr1f3xiJPuW7.jpg)]

通过截图裁剪保存为单个图片

test4

图片处理

转为灰度图、改变图像大小

from PIL import Image
import numpy as np
import matplotlib.pyplot as pltdef load_image(file):im = Image.open(file).convert('L')im = im.resize((28, 28), Image.ANTIALIAS)im = np.array(im).reshape(1, 1, 28, 28).astype(np.float32)im = im / 255.0 * 2.0 - 1.0return im

image-20211012194344800

送入网络测试

files = os.listdir('testpic')for file in files:img = load_image('testpic/' + file)plt.imshow(img[0][0], cmap=plt.cm.gray)plt.show()from Mnist_paddlepaddle import LeNetmodel = paddle.Model(LeNet())model.load('mnist_checkpoint/test')result = model.predict_batch(img)print("Inference result of image is:{}".format(np.argmax(result)), end=' ')print("The real label is:{}".format(file[4]))

结果:

image-20211012202034122

image-20211012202545281

可见错了很多,观察Mnist数据集发现,应该是截图中数字比例太小

重新截了一组图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5seZ14rH-1634528724508)(https://i.loli.net/2021/10/12/k9hDOrHtP3Cgoa8.png)]

测试结果:

image-20211012204252378

本次只错了一个。

图片平移、旋转和伸缩处理后

以数字2为例。

原始图片:

image-20211012214424732

image-20211012220733957

结果:

image-20211012222403216

数字5:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pFxQwCd3-1634528724512)(https://i.loli.net/2021/10/12/631miPgd5WZlMew.png)]

结果:

image-20211012222644092

可见:

image-20211012212420402

所以,需要data augmentation与Spatial Transformer Layer来解决此类问题。


推荐阅读
  • 本文探讨了图像标签的多种分类场景及其在以图搜图技术中的应用,涵盖了从基础理论到实际项目实施的全面解析。 ... [详细]
  • 毕业设计:基于机器学习与深度学习的垃圾邮件(短信)分类算法实现
    本文详细介绍了如何使用机器学习和深度学习技术对垃圾邮件和短信进行分类。内容涵盖从数据集介绍、预处理、特征提取到模型训练与评估的完整流程,并提供了具体的代码示例和实验结果。 ... [详细]
  • 尽管深度学习带来了广泛的应用前景,其训练通常需要强大的计算资源。然而,并非所有开发者都能负担得起高性能服务器或专用硬件。本文探讨了如何在有限的硬件条件下(如ARM CPU)高效运行深度神经网络,特别是通过选择合适的工具和框架来加速模型推理。 ... [详细]
  • 尽管使用TensorFlow和PyTorch等成熟框架可以显著降低实现递归神经网络(RNN)的门槛,但对于初学者来说,理解其底层原理至关重要。本文将引导您使用NumPy从头构建一个用于自然语言处理(NLP)的RNN模型。 ... [详细]
  • 深入浅出TensorFlow数据读写机制
    本文详细介绍TensorFlow中的数据读写操作,包括TFRecord文件的创建与读取,以及数据集(dataset)的相关概念和使用方法。 ... [详细]
  • 基于2-channelnetwork的图片相似度判别一、相关理论本篇博文主要讲解2015年CVPR的一篇关于图像相似度计算的文章:《LearningtoCompar ... [详细]
  • 利用Java与Tesseract-OCR实现数字识别
    本文深入探讨了如何利用Java语言结合Tesseract-OCR技术来实现图像中的数字识别功能,旨在为开发者提供详细的指导和实践案例。 ... [详细]
  • 本文探讨了卷积神经网络(CNN)中感受野的概念及其与锚框(anchor box)的关系。感受野定义了特征图上每个像素点对应的输入图像区域大小,而锚框则是在每个像素中心生成的多个不同尺寸和宽高比的边界框。两者在目标检测任务中起到关键作用。 ... [详细]
  • 本文探讨了如何在 PHP 的 Eloquent ORM 中实现数据表之间的关联查询,并通过具体示例详细解释了如何将关联数据嵌入到查询结果中。这不仅提高了数据查询的效率,还简化了代码逻辑。 ... [详细]
  • 深入解析 Apache Shiro 安全框架架构
    本文详细介绍了 Apache Shiro,一个强大且灵活的开源安全框架。Shiro 专注于简化身份验证、授权、会话管理和加密等复杂的安全操作,使开发者能够更轻松地保护应用程序。其核心目标是提供易于使用和理解的API,同时确保高度的安全性和灵活性。 ... [详细]
  • 自己用过的一些比较有用的css3新属性【HTML】
    web前端|html教程自己用过的一些比较用的css3新属性web前端-html教程css3刚推出不久,虽然大多数的css3属性在很多流行的浏览器中不支持,但我个人觉得还是要尽量开 ... [详细]
  • 探索电路与系统的起源与发展
    本文回顾了电路与系统的发展历程,从电的早期发现到现代电子器件的应用。文章不仅涵盖了基础理论和关键发明,还探讨了这一学科对计算机、人工智能及物联网等领域的深远影响。 ... [详细]
  • 本文探讨了亚马逊Go如何通过技术创新推动零售业的发展,以及面临的市场和隐私挑战。同时,介绍了亚马逊最新的‘刷手支付’技术及其潜在影响。 ... [详细]
  • 回顾与学习是进步的阶梯。再次审视卷积神经网络(CNNs),我对之前不甚明了的概念有了更深的理解。本文旨在分享这些新的见解,并探讨CNNs在图像识别和自然语言处理等领域中的实际应用。 ... [详细]
  • 李宏毅机器学习笔记:无监督学习之线性方法
    无监督学习主要涵盖两大类别:一是聚类与降维,旨在简化数据结构;二是生成模型,用于从编码生成新的数据样本。本文深入探讨了这些技术的具体应用和理论基础。 ... [详细]
author-avatar
Y死一般的痛过
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有