2021年人工神经网络第四次作业 - 第二题MNIST手写体识别

Posted 卓晴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021年人工神经网络第四次作业 - 第二题MNIST手写体识别相关的知识,希望对你有一定的参考价值。

简 介: ※MNIST数据集合是深度学习基础训练数据集合。改数据集合可以使用稠密前馈神经网络训练,也可以使用CNN。本文采用了单隐层BP网络和LeNet网络对于MNIST数据集合进行测试。实验结果标明,使用CNN网络的识别效果比BP网络好。

关键词 MNISTLENET

作业准备
文章目录
作业要求
AI Studio测试
MNIST数据库
手写数字识别
利用LeNet
识别MNIST
作业总结

 

§01 业准备


1.1 作业要求

  根据 2021年人工神经网络第四次作业要求 要求,对于MNIST手写体数字进行分类。

▲ 图1.1.1 MNIST 手写体数字识别

1.1.1 实验要求

  ① 构造两类深度学习网络对MNIST数据集合完成数字分类任务。一类是由全连接层构成的深度学习网络;另一类是带有卷积层的神经网络。

  ② 讨论两类神经网络在不同的网络参数下的训练收敛情况、测试精度的变化情况。

  ③ 探索寻找到一个能够兼顾网络模型大小与识别性能相对优化的网络模型,即模型参数少,识别性能下架不多。

 

§02 AI Studio测试


  百度的PaddlePaddle的深度学习环境 AI Studio进行这道题的实验。在AI Studio存在改MNIST数据集合。可以直接在paddle.visition 中的自带数据库进行实验。

2.1 MNIST数据库

  在 MNIST 中给出了paddle.visition.datasets.MNIST的调用方法。

2.1.1 MNIST数据下载

(1)类

class paddle.visition.datasets.MNIST
 Ⅰ.参数:
  • image_path (str) - 图像文件路径,如果 download 参数设置为 True , image_path 参数可以设置为 None 。默认值为 None 。

  • label_path (str) - 标签文件路径,如果 download 参数设置为 True , label_path 参数可以设置为 None 。默认值为 None 。

  • mode (str) - ‘train’ 或 ‘test’ 模式,默认为 ‘train’ 。

  • download (bool) - 当 data_file 是 None 时,该参数决定是否自动下载数据集文件。默认为 True 。

  • backend(str,可选)- 指定图像的返回类型:PIL.Image 或 numpy.ndarray。应该是'pil','cv2' 之一。如果未设置此选项,将从paddle.vsion.get_image_backend获取,默认为 pil 。 默认值:None。

 Ⅱ.代码示例
from paddle.vision.datasets import MNIST

mnist = MNIST(mode='test')

for i in range(len(mnist)):
    sample = mnist[i]
    print(sample[0].size, sample[1])

(2)查看图片

import sys,os,math,time
import matplotlib.pyplot as plt
from numpy import *

import paddle

from paddle.vision.datasets import MNIST

mnist = MNIST(mode='train')
print(type(mnist))
print(dir(mnist))

<class 'paddle.vision.datasets.mnist.MNIST'>
['NAME', 'TEST_IMAGE_MD5', 'TEST_IMAGE_URL', 'TEST_LABEL_MD5', 'TEST_LABEL_URL', 'TRAIN_IMAGE_MD5', 'TRAIN_IMAGE_URL', 'TRAIN_LABEL_MD5', 'TRAIN_LABEL_URL', 'URL_PREFIX', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__len__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_parse_dataset', 'backend', 'dtype', 'image_path', 'images', 'label_path', 'labels', 'mode', 'transform']

print(type(mnist.images), type(mnist.labels))
print(len(mnist.images), len(mnist.labels))

<class 'list'>
<class 'list'>
60000
60000

image1 = mnist.images[0]
print(type(image1),shape(image1))

<class 'numpy.ndarray'>
(784,)

PIC_ROW         = 6
PIC_COL         = 10
plt.figure(figsize=(10,8))
for j in range(PIC_ROW):
    for i in range(PIC_COL):
        id = i+j*PIC_COL
        plt.subplot(PIC_ROW, PIC_COL, id+1)
        plt.axis('off')
        plt.imshow(mnist.images[id].reshape(28,28), cmap=plt.cm.gray)
        plt.title(str(mnist.labels[id]), fontsize=12, color='blue')

▲ 图2.1.1 显示mnist.images中的图片

2.2 手写数字识别

  根据 10分钟快速上手飞桨(PaddlePaddle) 介绍的实验的方法,来构建稠密神经网络对MNIST进行 识别。

2.2.1 调入数据

import paddle.vision.transforms as T

transform = T.Normalize(mean=[127.5], std=[127.5], data_format='CHW')
train_dataset = paddle.vision.datasets.MNIST(mode ='train', transform=transform)
test_dataset = paddle.vision.datasets.MNIST(mode = 'test', transform=transform)

2.2.2 搭建模型

import paddle
mnist = paddle.nn.Sequential(
    paddle.nn.Flatten(),
    paddle.nn.Linear(784,512),
    paddle.nn.ReLU(),
    paddle.nn.Dropout(0.2),
    paddle.nn.Linear(512, 10)
)

model = paddle.Model(mnist)

model.prepare(paddle.optimizer.Adam(parameters=model.parameters()),
              paddle.nn.CrossEntropyLoss(),
              paddle.metric.Accuracy())

2.2.3 训练模型

(1)训练过程

model.fit(train_dataset, epochs=5, batch_size=64, verbose=1)

  训练过程:

▲ 图2.2.1 训练过程

(2)模型大小

model.summary()
---------------------------------------------------------------------------
 Layer (type)       Input Shape          Output Shape         Param #    
===========================================================================
   Flatten-1     [[64, 1, 28, 28]]        [64, 784]              0       
   Linear-1         [[64, 784]]           [64, 512]           401,920    
    ReLU-1          [[64, 512]]           [64, 512]              0       
   Dropout-1        [[64, 512]]           [64, 512]              0       
   Linear-2         [[64, 512]]            [64, 10]            5,130     
===========================================================================
Total params: 407,050
Trainable params: 407,050
Non-trainable params: 0
---------------------------------------------------------------------------
Input size (MB): 0.19
Forward/backward pass size (MB): 1.14
Params size (MB): 1.55
Estimated Total Size (MB): 2.88
---------------------------------------------------------------------------

'total_params': 407050, 'trainable_params': 407050

2.2.4 模型评估

model.evaluate(test_dataset, verbose=0)
'loss': [0.0], 'acc': 0.9774

  可以看到模型在测试集合上的精度为97%。

2.2.5 查看错误结果

(1)寻找识别错误的数字

testout = mnist(paddle.to_tensor(test_dataset.images, dtype='float32'))
testtarget = paddle.fluid.layers.argmax(testout, axis=1)
print(testtarget.numpy())

[7 2 1 ... 4 5 6]

errorid = where(testtarget.numpy() != labels)[0]
print(len(errorid))

646

  在10000个测试数字集合中,识别错误的数字有646个,错误比例为6.46%。

(2)查看识别错误的数字

PIC_ROW         = 5
PIC_COL         = 10
plt.figure(figsize=(15,12))
for j in range(PIC_ROW):
    for i in range(PIC_COL):
        id = i+j*PIC_COL
        plt.subplot(PIC_ROW, PIC_COL, id+1)
        plt.axis('off')

        eid = errorid[id]
        tid = testtarget.numpy()[eid]
        plt.imshow(test_dataset.images[eid].reshape(28,28), cmap=plt.cm.gray)
        plt.title('%d->%d'%(test_dataset.labels[eid], tid), fontsize=12, color='blue')

  识别错误的数字机:

▲ 图2.2.2 识别错误的数字机

2.3 利用LeNet识别MNIST

2.3.1 构建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 = 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

(1)训练过程

import paddle.nn.functional as F
train_loader = paddle.io.DataLoader(train_dataset, batch_size=64, shuffle=True)
def train(model):
    model.train()
    epochs = 2
    optim = paddle.optimizer.Adam(learning_rate=0.001, parameters=model.parameters())
    # 用Adam作为优化函数
    for epoch in range(epochs):
        for batch_id, data in enumerate(train_loader()):
            x_data = data[0]
            y_data = data[1]
            predicts = model(x_data)
            loss = F.cross_entropy(predicts, y_data)
            # 计算损失
            acc = paddle.metric.accuracy(predicts, y_data)
            loss.backward()
            if batch_id % 300 == 0:
                print("epoch: , batch_id: , loss is: , acc is: ".format(epoch, batch_id, loss.numpy(), acc.numpy()))
            optim.step()
            optim.clear_grad()
model = LeNet()
train(model)

  训练过程:

▲ 图2.3.1 训练过程

(2)网络模型

---------------------------------

以上是关于2021年人工神经网络第四次作业 - 第二题MNIST手写体识别的主要内容,如果未能解决你的问题,请参考以下文章

2021年人工神经网络第四次作业要求

2021年人工神经网络第四次作业-第四题:旋转的数字

2021年人工神经网络第四次作业要求:第七题

2021年人工神经网络第四次作业 - 第三题Cifar10

2021年人工神经网络第四次作业-第五题:危险品识别

2021年人工神经网络第四次作业-第一题:LeNet对于水果与动物进行分类