LeNet-5 数字识别(上)

2021SC@SDUSC

一、背景介绍

当我们学习编程的时候,编写的第一个程序一般是实现打印"Hello World"。而机器学习(或深度学习)的入门教程,一般都是 MNIST 数据库上的手写识别问题。原因是手写识别属于典型的图像分类问题,比较简单,同时MNIST数据集也很完备。MNIST数据集作为一个简单的计算机视觉数据集,包含一系列如图1所示的手写数字图片和对应的标签。图片是28x28的像素矩阵,标签则对应着0~9的10个数字。每张图片都经过了大小归一化和居中处理。

请添加图片描述
MNIST数据集是从 NIST 的Special Database 3(SD-3)和Special Database 1(SD-1)构建而来。由于SD-3是由美国人口调查局的员工进行标注,SD-1是由美国高中生进行标注,因此SD-3比SD-1更干净也更容易识别。Yann LeCun等人从SD-1和SD-3中各取一半作为MNIST的训练集(60000条数据)和测试集(10000条数据),其中训练集来自250位不同的标注员,此外还保证了训练集和测试集的标注员是不完全相同的。

MNIST吸引了大量的科学家基于此数据集训练模型,1998年,LeCun分别用单层线性分类器、多层感知器(Multilayer Perceptron, MLP)和多层卷积神经网络LeNet进行实验,使得测试集上的误差不断下降(从12%下降到0.7%)。在研究过程中,LeCun提出了卷积神经网络(Convolutional Neural Network),大幅度地提高了手写字符的识别能力,也因此成为了深度学习领域的奠基人之一。此后,科学家们又基于K近邻(K-Nearest Neighbors)算法、支持向量机(SVM)、神经网络和Boosting方法[8]等做了大量实验,并采用多种预处理方法(如去除歪曲、去噪、模糊等)来提高识别的准确率。

如今的深度学习领域,卷积神经网络占据了至关重要的地位,从最早Yann LeCun提出的简单LeNet,到如今ImageNet大赛上的优胜模型VGGNet、GoogLeNet、ResNet等,人们在图像分类领域,利用卷积神经网络得到了一系列惊人的结果。

二、模型概览

基于MNIST数据集训练一个分类器,在介绍本教程使用的三个基本图像分类网络前,我们先给出一些定义:

·X是输入:MNIST图片是28×28 的二维图像,为了进行计算,我们将其转化为784维向量,即X=(x0,x1,…,x783)。

·Y是输出:分类器的输出是10类数字(0-9),即Y=(y0,y1,…,y9),每一维yi代表图片分类为第i类数字的概率。

·Label是图片的真实标签:Label=(l0,l1,…,l9)也是10维,但只有一维为1,其他都为0。例如某张图片上的数字为2,则它的标签为(0,0,1,0,…,0)。

三、数据介绍

PaddlePaddle在API中提供了自动加载MNIST数据的模块paddle.dataset.mnist。加载后的数据位于/home/username/.cache/paddle/dataset/mnist下:
在这里插入图片描述
三、Fluid API 概述
演示将使用最新的 Fluid API。Fluid API是最新的 PaddlePaddle API。它在不牺牲性能的情况下简化了模型配置。

下面是 Fluid API 中几个重要概念的概述:

1.inference_program:指定如何从数据输入中获得预测的函数, 这是指定网络流的地方。

2.train_program:指定如何从 inference_program 和标签值中获取 loss 的函数, 这是指定损失计算的地方。

3.optimizer_func: 指定优化器配置的函数,优化器负责减少损失并驱动训练,Paddle 支持多种不同的优化器。

四、配置说明
加载 PaddlePaddle 的 Fluid API 包。

from __future__ import print_function # 将python3中的print特性导入当前版本
import os
from PIL import Image # 导入图像处理模块
import matplotlib.pyplot as plt
import numpy
import paddle # 导入paddle模块
import paddle.fluid as fluid

Program Functions 配置
我们需要设置 inference_program 函数。我们想用这个程序来演示三个不同的分类器,每个分类器都定义为 Python 函数。 我们需要将图像数据输入到分类器中。Paddle 为读取数据提供了一个特殊的层 layer.data 层。 让我们创建一个数据层来读取图像并将其连接到分类网络。

·Softmax回归:只通过一层简单的以softmax为激活函数的全连接层,就可以得到分类的结果。

def softmax_regression():
    """
    定义softmax分类器:
        一个以softmax为激活函数的全连接层
    Return:
        predict_image -- 分类的结果
    """
    # 输入的原始图像数据,大小为28*28*1
    img = fluid.data(name='img', shape=[None, 1, 28, 28], dtype='float32')
    # 以softmax为激活函数的全连接层,输出层的大小必须为数字的个数10
    predict = fluid.layers.fc(
        input=img, size=10, act='softmax')
    return predict

·多层感知器:下面代码实现了一个含有两个隐藏层(即全连接层)的多层感知器。其中两个隐藏层的激活函数均采用ReLU,输出层的激活函数用Softmax。

def multilayer_perceptron():
    """
    定义多层感知机分类器:
        含有两个隐藏层(全连接层)的多层感知器
        其中前两个隐藏层的激活函数采用 ReLU,输出层的激活函数用 Softmax

    Return:
        predict_image -- 分类的结果
    """
    # 输入的原始图像数据,大小为28*28*1
    img = fluid.data(name='img', shape=[None, 1, 28, 28], dtype='float32')
    # 第一个全连接层,激活函数为ReLU
    hidden = fluid.layers.fc(input=img, size=200, act='relu')
    # 第二个全连接层,激活函数为ReLU
    hidden = fluid.layers.fc(input=hidden, size=200, act='relu')
    # 以softmax为激活函数的全连接输出层,输出层的大小必须为数字的个数10
    prediction = fluid.layers.fc(input=hidden, size=10, act='softmax')
    return prediction

·卷积池化层:在LeNet-5中会出现多个卷积-池化的操作,为避免代码重复书写,将串联的卷积-池化写成conv_pool函数。

def conv_pool(input, num_filters, filter_size, pool_size, pool_stride, act="relu"):
    """
    定义卷积池化层:
        含有一个卷积层和一个池化层
    Args:
        input —— 网络输入
        num_filters —— 卷积核的个数
        filter_size —— 卷积核的大小
        pool_size —— 池化核的大小
        pool_stride —— 池化的步长
        act —— 卷积层的激活函数

    Return:
        out -- 经过卷积池化后的特征图
    """
    conv_out = fluid.layers.conv2d(
        input=input,
        num_filters=num_filters,
        filter_size=filter_size,
        act=act)
    out = fluid.layers.pool2d(
        input=conv_out,
        pool_size=pool_size,
        pool_stride=pool_stride)
    return out

·卷积神经网络LeNet-5: 输入的二维图像,首先经过两次卷积层到池化层,再经过全连接层,最后使用以softmax为激活函数的全连接层作为输出层。

def convolutional_neural_network():
    """
    定义卷积神经网络分类器:
        输入的二维图像,经过两个卷积-池化层,使用以softmax为激活函数的全连接层作为输出层

    Return:
        predict -- 分类的结果
    """
    # 输入的原始图像数据,大小为28*28*1
    img = fluid.data(name='img', shape=[None, 1, 28, 28], dtype='float32')
    # 第一个卷积-池化层
    # 使用20个5*5的滤波器,池化大小为2,池化步长为2,激活函数为Relu
    conv_pool_1 = conv_pool(
        input=img,
        filter_size=5,
        num_filters=20,
        pool_size=2,
        pool_stride=2,
        act="relu")
    conv_pool_1 = fluid.layers.batch_norm(conv_pool_1)
    # 第二个卷积-池化层
    # 使用50个5*5的滤波器,池化大小为2,池化步长为2,激活函数为Relu
    conv_pool_2 = conv_pool(
        input=conv_pool_1,
        filter_size=5,
        num_filters=50,
        pool_size=2,
        pool_stride=2,
        act="relu")
    # 以softmax为激活函数的全连接输出层,输出层的大小必须为数字的个数10
    prediction = fluid.layers.fc(input=conv_pool_2, size=10, act='softmax')
    return prediction

配置和训练见下一篇

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值