前言

        本文是作者处于学习的目的,使用Python和Pytorch,基于CNN模型开发图像识别系统,代码原创,点击此处直接下载。运行程序出了问题先看README.md文件,还有疑问可以私聊我或者在评论区讨论。

一、简述

1.卷积神经网络(CNN)

        对于表格类数据,传统的机器学习中的多层感知机可以处理,它的特征是将图像数据展平为一维向量,但是却忽略了每个图象的空间结构信息。对于高维感知数据,这种缺少结构的网络可能会不太够用,这种就引出了本文的主角——CNN。卷积神经网络是一种模拟生物视觉系统,特鄙是猫的视觉皮层而设计的人工神经网络,被广泛运用于图像识别、计算机视觉和语音识别等领域。CNN的核心思想是通过卷积操作捕获输入数据中的空间结构信息,同时通过池化操作降低数据维度,最终通过全连接层进行分类或回归任务。接下来将分别介绍这些不同层。

  1. 卷积层(互相关运算层):卷积操作的作用是提取输入数据的特征。那么特征是如何提取的呢?一张图片中,相邻的像素具有更强的相关性,使用一个或多个滑动的卷积核(卷积核的高度和宽度一般都是奇数),从输入张量的左上角开始,按照从左到右、从上到下的顺序滑动。当卷积窗口滑动到新位置时,窗口内的部分张量与核张量对应元素相乘并求和。
  2. 填充(padding):由于卷积核的宽度和高度一般都大于1,在进行连续的卷积后得到的数据对比原始数据已经损失了一些有用信息。填充,就是解决该问题的有效办法。所谓填充,就是在输入图像的边缘填充元素(通常填充元素为0)。如下图所示,在一个3*3的边界填充到5*5,其输出就会变成4*4,这就保存了一部分不想丢失的有效信息。这里也能够解释在第一点中为什么说卷积核的高度和宽度一般都是奇数,这种情况下我们可以在顶部和底部填充相同数量的行,在左侧和右侧补充相同数量的列。
    当一个卷积核满足:卷积核大小为奇数、每条边的填充行数和列数相同、输入与输出具有相同高度和宽度时,可以得出:输出Y[i,j]是通过输入X[i,j]为中心,与卷积核进行互相关计算得到的。
  3.  步幅:滑动卷积窗口每次滑动元素的数量就叫做步幅。
  4. 池化层(汇聚层):简单来说,池化层就是压缩数据,保留关键特征。与卷积层是类似的,池化层运算符也有一个固定形状的窗口组成。比较方便的是,池化层的运算是确定性的,一般是计算汇聚窗口所有元素的最大值和平均值,对应的池化层也被成为最大池化层和平均池化层。汇聚窗口的移动同样是从左到右、从上到下在输入张量内滑动。
  5.  全连接层:全连接层的作用就是将卷积层提取的特征映射到输出类别。

2.MNIST数据集介绍

        MNIST数据集,全称Mixed National Institute of Standards and Technology database,是一个用来训练各种图像处理系统的二进制图像数据集。这个数据集是由美国国家标准技术研究所在1998年发布的,当时他们写了一篇论文想要证明在模式识别问题上,基于CNN的方法可以取代之前基于手工特征的方法。

数据集详细信息

  1. 图像数据:MNIST数据集中的图像都是28*28像素的灰度图像,每个像素的灰度范围在0-255之间。
  2. 手写数字符号:每张图像都对应了一个手写的数字符号0-9.
  3. 训练集和测试集:数据集中包含了60000张图像作为训练集,10000张图像作为测试集

        MNIST数据集相对简单,并且容易使用,因此它被认为是入门级图像分类问题的理想数据集,本文案例中使用的就是MNIST数据集。

二、实验案例分析

实验环境

操作系统:Windows

开发环境:Python 3.10.11,Pytorch

数据集:MNIST手写数字符号数据集

案例分析

        本文设计的用于图像识别系统中的卷积神经网络,由两个卷积层、两个全连接层组成,其整体框架如下图所示。

pytorch查看模型数据流动维度_机器学习

系统工作流程如下:

  1. 加载MNIST数据集并进行数据预处理,将训练集按照8:2的比例区分为训练集和验证集,将图像转换为张量并进行归一化,随后将处理后的数据输入CNN模型。
  2. 数据在CNN模型中经过两次卷积层、两次最大池化层、两个全连接层后完成训练,输出训练时间和训练过程中的准确率。
  3. CNN模型在测试集数据中进行测试,测试完成后输出测试时间和准确率,并绘制混淆矩阵图。

CNN模型构建 

        MNIST数据集包含了0-9的手写数字灰度图像,每张图像的其大小为28*28像素。因此将第一个卷积层的输入为1,卷积核大小设置为3,步幅为1,卷积核个数为32个,则此层输出的数据大小为:26*26像素。

        池化层都采用2*2池化窗口,步幅为2。经过第一个最大池化层后,宽和高都减半,此时的数据大小为:13*13像素。

        第二个卷积池输入为32,卷积核个数为64,卷积核大小为3,步幅为1,因此此层输出的数据大小为:11*11像素。

        经过第二个最大池化层后,数据大小减半,此时数据大小变为5*5像素。

        在将特征图传递到全连接层之前,需要先将数据展平为一维向量,展平后的大小为64*5*5。

        全连接层由很多个神经元组成,每个神经元会把前面层得到的不同特征整合到一起。如果增加全连接层的层数或者每一层的神经元数量,能够提高模型的学习能力。但模型的学习能力太强也有一些弊端,例如:产生过拟合的情况;运算时间增加,效率变低。因此开发者通常会使用交叉验证的方法,边训练边验证,评估不同神经元数量的模型性能,从而寻找到最佳的神经元数量。作者在实验中设置第一个全连接层的神经元数量为128,没达到会产生过拟合的数量同时也能够拥有不错的学习能力。

        第一个全连接层的输入为64*5*5,输出为128。由于第一个全连接层的神经元数量为128,第二个全连接层的输入即为128;又因为MNIST数据集手写数字有十种类别,因此第二个全连接层输出设置为10。这样第二个全连接层的参数也选择好了。至此,CNN模型不同层次的参数都选择完成,CNN模型构建完成。以上所述的数据量大小变化过程,同样也是模型的前向传播流程。对应的模型构建代码和模型前向传播代码如图所示。

pytorch查看模型数据流动维度_机器学习_02

 

 程序运行结果

        使用训练集训练CNN模型,每次参数更新都会输出一个训练集上的Training Loss值和在验证集上的Validation Loss值。训练过程中获得的Loss曲线如图3.1所示。

pytorch查看模型数据流动维度_pytorch查看模型数据流动维度_03

        横坐标Iteration表示在训练过程中对每个小批量样本进行一次前向传播和反向传播的过程,也就是表示模型参数更新的次数。一个周期(epoch)表示对整个训练数据集进行一次完整的迭代,包含了多次参数更新(Iteration)过程。实验中作者将整个训练集和验证集从MNIST原本的训练集中按8:2的比例区分开,并将训练数据分为了大小为100的小批量。假设在每个周期中会进行N次参数更新,那么N与训练样本总数NUM的关系如下式:

pytorch查看模型数据流动维度_笔记_04

        观察Loss曲线图像可以知道,CNN模型训练成果属于较好的拟合情况,训练集的Loss曲线一直在下降,同时验证集的Loss曲线并没有上升,两条曲线都在收敛,且并没有很大的差距。一般情况下训练集Loss会更小,它们之间产生的间隔就叫做泛化鸿沟(Generalization Gap),表示模型在训练数据上的性能与其在从同一分布中提取的从未见过的数据上的性能之间的差距。

        查看代码输出的CNN模型在测试集中的精确率,这能很直观地体现模型的性能。

pytorch查看模型数据流动维度_pytorch_05

        查看程序绘制的混淆矩阵,混淆矩阵同样也能够反应模型在测试集中的表现,如下图所示。

pytorch查看模型数据流动维度_python_06

        综合混淆矩阵、精确度等指标,可以看出来CNN模型在MNIST数据集上的表现很好。

三、参考文献

  1. 机器学习[M]. 周志华.清华大学出版社.2016.
  2. 张 Zhang, Aston,李沐,美 立顿 Lipton, Zachary C,等.动手学深度学习[M].人民邮电出版社,2019.