MATLAB基于卷积神经网络的口罩检测
.引言
1.1目的和意义
2020年新冠肺炎席卷全球,新型冠状病毒可以通过呼吸道飞沫等方式传播,正确佩戴口罩可以有效切断新冠肺炎病毒的传播途径,是预防感染的有效措施。国内公众场合要求佩戴口罩。而商场、餐饮、地铁等人员密集型的场所对人流量高峰时段的应对措施往往令人力不从心,会消耗大量的人力资源且容易漏检,因此实现口罩人脸检测与识别能够自动检测是否佩戴口罩,减少防疫工作人员工作量。人脸识别核验身份,抓拍的数据可对接公安平台,进行人员布控和人员聚集管控,也适用于公安抓捕遮挡面部的逃犯等安防场景。
针对该问题,本系统是在复杂场景下的口罩佩戴检测算法,可以自动准确且快速地识别图片或视频中人物是否佩戴口罩,有着重要的应用场景和市场前景。
1.2研究领域现况
1.2.1 卷积神经网络领域现况
卷积神经网络是一种前馈神经网络,它的人工神经元可以响应一部分覆盖范围内的周围单元,对于大型图像处理有出色表现。
DenseNet(2018)
传统的卷积网络在一个前向过程中每层只有一个连接,ResNet 增加了残差连接从而增加了信息从一层到下一层的流动。FractalNets 重复组合几个有不同卷积块数量的并行层序列,增加名义上的深度,却保持着网络前向传播短的路径。相类似的操作还有 Stochastic depth 和 Highway Networks 等。
这些模型都显示一个共有的特征,缩短前面层与后面层的路径,其主要的目的都是为了增加不同层之间的信息流动。
图1.1
使用这个密集连接构建了Dense Block。
图1.2
基于信息流动的方式,DenseNet 创新之处有:
传统 L 层的网络仅有 L 个连接,在 DenseNet 中使用了 L(L+1)/2 个连接。这样做有几个明显的优点:避免了梯度消失问题,加强了特征传播,实现特征复用(feature reuse),以及实质上减少了参数量。
下图展示了从2010年起ILVRC(ImageNet Large-Scale Visual Recognition Challenge)历年精确度最高的网络名称和精确度:
图1.3
2021年top1的算法主要使用了EfficientNetV2网络,精确度为90.88%。
EfficientNetV2,它比以前的模型具有更快的训练速度和更好的参数效率。EfficientNetV2在ImageNet和CIFAR/Cars/Flowers数据集上的性能明显优于以前的模型。通过在相同的ImageNet 21k上进行预训练,我们的EfficientNetV2在ImageNet ILSVRC2012上实现了87.3%的top-1精度,比最近的ViT提高了2.0%的精度,同时使用相同的计算资源训练速度加快了5-11倍。
(a)Training efficiency
(b)Parameter efficiency
ImageNet ILSVRC2012 top-1精度与训练时间和参数的对比。标记为21k的模型在ImageNet 21k上进行预训练,其他模型直接在ImageNet ILSVRC2012上进行训练。训练时间是用32TPU核来衡量的。所有EfficientNetV2模型都经过渐进式学习培训。我们的EfficientNetV2训练速度比其他模型快5-11倍,同时使用的参数少6.8倍。
1.2.2 口罩佩戴检测领域领先水平状况
基于2018年百度收录于国际顶级计算机视觉会议ECCV的论文PyramidBox研发,可以在人流密集的公共场景检测海量人脸的同时,将佩戴口罩和未佩戴口罩的人脸快速识别标注。基于此预训练模型,开发者仅需使用少量自有数据,便可快速完成自有场景的模型开发。
口罩人脸检测及分类模型,由两个功能单元组成,可以分别完成口罩人脸的检测和口罩人脸的分类。经测试,模型的人脸检测算法基于faceboxes的主干网络加入了超过10万张口罩人脸数据训练,可在准确率98%的情况下,召回率显著提升30%。而人脸口罩判断模型可实现对人脸是否佩戴口罩的判定,口罩判别准确率达到96.5%,满足常规口罩检测需求。开发者基于自有场景数据还可进行二次模型优化,可进一步提升模型准确率和召回率。
新模型采用了超过十万张图片的训练数据,确保样本量足够且有效。对于实际场景中的光照、口罩遮挡、表情变化、尺度变化等问题,模型具有鲁棒性,并且能够在多种不同端、云设备上实时检测,在落地过程中做到真正实用。
目前,百度提供了两个预训练模型,即服务器端口罩人脸检测及分类模型「pyramidbox_lite_server_mask」、以及移动端口罩人脸检测及分类模型「pyramidbox_lite_mobile_mask」,这两者能满足各种下游任务。
腾讯在人脸检测方面,基于优图开源的DSFD人脸检测算法,针对戴口罩场景下的五官遮挡,腾讯优图在模型设计上进行局部特征增强,提升可见区域权重。同时针对口罩种类丰富、佩戴位置多样等问题,在数据增强方面设计相应策略,提升模型鲁棒性。目前,口罩场景下的人脸检测算法准确率超过99%,召回率超过98%。
在人脸配准(关键点定位)方面,为解决口罩带来的面部区域大范围遮挡问题,基于优图自研的多分支轻量神经网络,优图快速通过图像编辑技术合成海量人脸口罩数据用于算法优化提升,实现戴口罩人员的精准五官定位,有效辅助后续算法模块的效果提升。
在口罩属性识别方面,目前优图算法可精细识别以下五种情形:未佩戴口罩、错误佩戴口罩且遮挡嘴部、错误佩戴口罩且遮挡下巴、错误佩戴口罩未遮挡面部、正确佩戴口罩。该属性识别基于优图开源的FAN属性识别,并针对口罩可能分布的人脸位置,加入更多的attention机制,可精准识别人脸是否正确佩戴。目前,对有无口罩佩戴的识别准确率超过99%。
在戴口罩人脸识别方面,优图提供了一套灵活兼具安全与便利的算法解决方案。利用优图人脸质量模型对被口罩遮挡的人脸进行口罩遮挡判断以及遮挡区域提取两类分析。其中,口罩遮挡判断目前已达99.5%以上准确率。
.原理及网络结构
2.1算法原理
2.1.1 基本原理
CNN 由许多神经网络层组成。卷积和池化这两种不同类型的层通常是交替的。网络中每个滤波器的深度从左到右增加。最后通常由一个或多个全连接的层组成。
Convnets 背后有三个关键动机:局部感受野、共享权重和池化。
(1)局部感受野
如果想保留图像中的空间信息,那么用像素矩阵表示每个图像是很方便的。然后,编码局部结构的简单方法是将相邻输入神经元的子矩阵连接成属于下一层的单隐藏层神经元。这个单隐藏层神经元代表一个局部感受野。请注意,此操作名为“卷积”,此类网络也因此而得名。
(2)共享权重和偏置
假设想要从原始像素表示中获得移除与输入图像中位置信息无关的相同特征的能力。一个简单的直觉就是对隐藏层中的所有神经元使用相同的权重和偏置。通过这种方式,每层将从图像中学习到独立于位置信息的潜在特征。
理解卷积的一个简单方法是考虑作用于矩阵的滑动窗函数。在下面的例子中,给定输入矩阵 I 和核 K,得到卷积输出。将 3×3 核 K(有时称为滤波器或特征检测器)与输入矩阵逐元素地相乘以得到输出卷积矩阵中的一个元素。
(3)池化层
假设我们要总结一个特征映射的输出。我们可以使用从单个特征映射产生的输出的空间邻接性,并将子矩阵的值聚合成单个输出值,从而合成地描述与该物理区域相关联的含义。
2.1.2 网络中采用的组件
神经网络核心组件包括:
1)层:神经网络的基本结构,将输入张量转换为输出张量
2)模型:层构成的网络
3)损失函数:参数学习的目标函数,通过最小化损失函数来学习各种参数
4)优化器:如何使损失函数最小,这就涉及到优化器
当然这些核心组件不是独立的,它们之间,以及它们与神经网络其他组件之间有密切的关系。
多个层链接在一起组成了网络,将输入数据映射为预测值。然后损失函数将这些预测值与目标进行比较,得到损失值,用于衡量网络预测值与预期结果的匹配程度。优化器使用这个损失值来更新网络的权重。
它们的关系如图所示:
图2.1网络、层、损失函数和优化器之间的关系
层:深度学习的基础组件
神经网络的基本数据结构是层。层是一个数据处理模块,将一个或多个输入张量转换为一个或多个输出张量。
无状态的层:比如池化,没有权重参数
有状态的层:比如dense,Conv2D,有权重参数
根据处理的张量数据不同分类: - 全连接层(fully connected layer):密集连接层(densely connected layer)/密集层(dense layer):简单的向量数据保存在形状为 (samples, features) 的 2D 张量。对应于 Keras 的 Dense 类 - 循环层(recurrent layer):序列数据保存在形状为 (samples, timesteps, features) 的 3D 张量中, Keras 的 LSTM 层 - 卷积层:图像数据保存在 4D 张量中,Keras 的 Conv2D。
2.2网络结构
2.2.1神经网络
基本结构:输入层、隐藏层、输出层。 图2.1中,最左边的层称为输入层,用于数据输入;最右边的层称为输出层,用于预测结果输出。输出层的节点数目是根本实际问题的要求而设定的。 输入层和输出层之间,是逻辑推理层,从用户角度而言是不可见的,因此被称为隐藏层。图2.1的神经网络只含有一个隐藏层,图2.2的网络含有两个隐藏层。在设计神经网络时,隐藏层的层数一般跟问题的复杂度成正比。即,解决复杂的问题,需要更多的隐藏层。
图2.2 图2.3
2.2.2 神经元
在神经网络中,神经元是一个包含输入、计算和输出功能的模型。图3展示了一个典型的神经元模型,包含了3个输入,1个输出和2个运算。箭头线表示神经元之间的“连接”,每个连接上都有1个权重值。 一个神经网络的训练算法就是让权重调整到最佳,以使得网络的预测或分类效果最好。
图2.4
2.2.3卷积神经网络
卷积神经网络(Convolutional Neural Networks, CNN)是一类包含卷积计算且具有深度结构的前馈神经网络(Feedforward Neural Networks)。
卷积神经网络主要是用于计算机视觉领域,它指的是一类网络,而不是某一种,其包含很多不同种结构的网络。不同的网络结构通常表现会不一样。
一个简单的卷积神经网络是由各种层按照顺序排列组成,网络中的每个层使用一个可微分的函数将数据从一层传递到下一层。卷积神经网络主要由三种类型的层构成:卷积层,池化层和全连接层。通过将这些层叠加起来,就可以构建一个完整的卷积神经网络。
(1)卷积层
卷积层是卷积神经网络的核心,每个卷积层由多个卷积核组成。当输入图像经过卷积核时,每个通道的图像会与每个卷积核进行卷积操作。前一层的特征图与一个可学习的卷积核进行卷积运算,卷积的结果经过激活函数后的输出形成这一层的神经元,从而构成该层特征图,也称特征提取层,每个神经元的输入与前一层的局部感受野相连接,并提取该局部的特征,一旦该局部特征被提取,它与其它特征之间的位置关系就被确定。
进行卷积运算时,运算结果取决于卷积核覆盖的区域,这个区域之外的其它输入值都不会影响输出值,该区域就是感受野。随着图像数据的下采样,感受野会变大。
对于Keras 的Conv2D 层,这些参数都是向层传入的前几个参数:Conv2D(output_depth, (window_height, window_width))。
卷积的工作原理:在 3D 输入特征图上滑动(slide)这些 3×3 或 5×5 的窗口,在每个可能 的位置停止并提取周围特征的 3D 图块[形状为 (window_height, window_width, input_ depth)]。然后每个 3D 图块与学到的同一个权重矩阵[叫作卷积核(convolution kernel)]做 2 张量积,转换成形状为 (output_depth,) 的 1D 向量。然后对所有这些向量进行空间重组, 使其转换为形状为 (height, width, output_depth) 的 3D 输出特征图。输出特征图中的 每个空间位置都对应于输入特征图中的相同位置(比如输出的右下角包含了输入右下角的信 息)。举个例子,利用 3×3 的窗口,向量 output[i, j, :] 来自 3D 图块 input[i-1:i+1, j-1:j+1, :]。整个过程详见图 2.1。
图2.5 卷积的工作原理
注意,输出的宽度和高度可能与输入的宽度和高度不同。不同的原因可能有两点。
.边界效应,可以通过对输入特征图进行填充来抵消。
a. 理解边界效应与填充
假设有一个 5×5 的特征图(共 25 个方块)。其中只有 9 个方块可以作为中心放入一个 3×3 的窗口,这 9 个方块形成一个 3×3 的网格(见图 5-5)。因此,输出特征图的尺寸是 3×3。 它比输入尺寸小了一点,在本例中沿着每个维度都正好缩小了 2 个方块。在前一个例子中你也 可以看到这种边界效应的作用:开始的输入尺寸为 28×28,经过第一个卷积层之后尺寸变为 26×26,如图2.6所示:
图2.6
图2.2 在 5×5 的输入特征图中,可以提取 3×3 图块的有效位置
如果希望输出特征图的空间维度与输入相同,那么可以使用填充(padding)。填充是在 输入特征图的每一边添加适当数目的行和列,使得每个输入方块都能作为卷积窗口的中心。对 于 3×3 的窗口,在左右各添加一列,在上下各添加一行。对于 5×5 的窗口,各添加两行和两列(见图 2.7)。
图2.7
图2.3 对 5×5 的输入进行填充,以便能够提取出 25 个 3×3 的图块
对于 Conv2D 层,可以通过 padding 参数来设置填充,这个参数有两个取值:"valid" 表 示不使用填充(只使用有效的窗口位置);"same" 表示“填充后输出的宽度和高度与输入相同”。 padding 参数的默认值为 "valid"。
(2)非线性激活单元
引入非线性激活函数的主要目的是增加神经网络的非线性性。因为如果没有非线性激活函数的话,每一层输出都是上层输入的线性函数,因此,无论神经网络有多少层,得到的输出都是线性函数,这就是原始的感知机模型,这种线性性不利于发挥神经网络的优势。
常用的非线性激活单元如图4所示。目前比较常用的有ReLu和LReLu,Logistic(Sigmoid)单元由于其饱和区特性导致整个网络梯度消失而逐渐退出历史舞台(有的时候最后一层会用Sigmoid将输出限制在0.0-1.0)。
图2.8
(3)池化层
通常,在连续的卷积层之间会周期性地插入一个池化层。对卷积层学习到的特征图进行下采样(subsampling)处理,它的作用是逐渐降低数据体的空间尺寸,这样的话就能减少网络中参数的数量,使得计算资源耗费变少,也能有效控制过拟合。
主要有两种:
A.最大池化:Max Pooling,取窗口内的最大值作为输出,倾向于保留突出纹理特征
图2.9 最大池化
B.平均池化:Avg Pooling,取窗口内的所有值的均值作为输出,倾向于保留突出背景特征
图2.10 平均池化
池化的结果使得网络参数减少,感受野变大,从而能够获得更全局的特征;同时,为模型提供了一定的缩放、平移和旋转不变性。
池化的超参数包括池化核大小和步长,通常取size=2*2,stride=2
图2.11 池化核大小 图2.12 步长
(4)全连接层
所谓全连接层即是传统的神经网络,每一个神经单元都和上一层所有的神经单元密集连接。如今,全连接层由于其巨大的参数量易过拟合以及不符合人类对图像的局部感知原理,一般不参与图像的特征提取(已由卷积层替代),只用于最后的线性分类, 相当于在提取的高层特征向量上进行线性组合并且输出最后的预测结果。全连接层存在的问题是参数冗余(仅全连接层参数就可占整个网络参数80%左右),降低了训练的速度,容易过拟合。
.模型训练
3.1数据采集和处理
3.1.1 构建数据集
(1)数据集来源:
训练集使用Prajan Bhandary在Github上开源提供的口罩数据集,这个数据集包括大约1376幅图像,其中690幅包含戴口罩的人,686幅图像包含没有戴口罩的人。
验证集使用Prajan Bhandary在Github上开源提供的口罩数据集,这个数据集包括大约563幅图像,其中282幅包含戴口罩的人,281幅图像包含没有戴口罩的人。
数据集分为训练集和验证集,图片数量比例为3:1。
(2)数据预处理:使用Kearas中提供的ImageDataGenerator类实现对图片的预处理操作,包括数据增强(旋转、扭曲、翻转、归一化等)、生成一个批次一个批次的图片,以生成器的形式给模型训练。再使用ImageDataGenerator类中的flow_from_directory函数实现对图片数据的读取和处理,以及图片标签的生成、该方法以训练图片文件夹为路径,生成经过数据增强/归一化的数据,在一个无限循环中生成无限产生batch数据供给模型进行训练。
具体代码如下:
.print("The number of images with facemask labelled 'yes':",len(os.listdir(r'D:\pythonproject\06_Face-Mask-Detection-master\Data\facemask-dataset\train\with_mask')))
接下来开始构建数据集,为了使用神经网络进行训练,我们需要做如下几步:
a.将图片构建成同样的大小,这是由于一般的卷积神经网络需要输入图片的大小固定。
b.对每张图片构建数据标签,对于口罩检测,人未戴口罩标记为without_mask,人戴口罩标记为with_mask。
c.将数据集分为训练集和验证集,一般比例为3:1。为了防止过拟合,需要在训练集上训练,之后在验证集测试,当训练集和验证集最终表现差不多时,可以认为模型没有过拟合,而最终的结果也需要使用验证集上的准确率。
d.分批次,对于深度学习,一般使用小批次梯度下降法,所以需要确定每个批次图片的数量,数量需要根据CPU的内存容量来决定,这次项目中取64张图片为一个批次。
具体代码如下所示:
.print("The number of images with facemask labelled 'yes':",len(os.listdir(r'D:\pythonproject\06_Face-Mask-Detection-master\Data\facemask-dataset\train\with_mask')))
.print("The number of images with facemask labelled 'no':",len(os.listdir(r'D:\pythonproject\06_Face-Mask-Detection-master\Data\facemask-dataset\train\without_mask')))
.#新增
.print("The number of images with facemask labelled 'yes':",len(os.listdir(r'D:\pythonproject\06_Face-Mask-Detection-master\Data\facemask-dataset\validation\with_mask')))
.print("The number of images with facemask labelled 'no':",len(os.listdir(r'D:\pythonproject\06_Face-Mask-Detection-master\Data\facemask-dataset\validation\without_mask')))
.#数据集
.TRAINING_DIR = r"D:\pythonproject\06_Face-Mask-Detection-master\Data\facemask-dataset\train"
.#新增
.VALIDATION_DIR=r'D:\pythonproject\06_Face-Mask-Detection-master\Data\facemask-dataset\validation'
.#数据集处理:数据增强
.train_datagen = ImageDataGenerator(rescale=1.0/255,
.rotation_range=40,
.width_shift_range=0.2,
.height_shift_range=0.2,
.shear_range=0.2,
.zoom_range=0.2,
.horizontal_flip=True,
.fill_mode='nearest')
.#新增
.validation_datagen = ImageDataGenerator(rescale=1.0/255,)
.#标签生成,批次定义
.train_generator = train_datagen.flow_from_directory(TRAINING_DIR,# 目标目录
.batch_size=64,#表示批次大小
.classes=['with_mask','without_mask'],
.target_size=(150, 150))# 将所有图像的大小调整为 150×150
.print(train_generator)
.#新增
.validation_generator = validation_datagen.flow_from_directory(VALIDATION_DIR,
.batch_size=64,#表示批次大小
.classes=['with_mask','without_mask'],
.target_size=(150, 150))
.print(validation_generator)
3.1.2 搭建神经网络
为了检测是否佩戴口罩,我们搭建一个7层:Conv2D->MaxPooling2D->Conv2D->Maxpooling2D->Flatten->Dense->Dense的顺序浅层CNN模型用来预测,这个模型实际上就是实现二分类,佩戴口罩with_mask和without_mask,使用的损失函数是二元交叉熵损失binary_crossentropy,网络结构图如图3.1所示:
图3.1网络结构图
创建模型代码如下:
.#创建模型
.model = tf.keras.models.Sequential([
.tf.keras.layers.Conv2D(100, (3,3), activation='relu', input_shape=(150, 150, 3)),
.tf.keras.layers.MaxPooling2D(2,2),
.tf.keras.layers.Conv2D(100, (3,3), activation='relu'),
.tf.keras.layers.MaxPooling2D(2,2),
.tf.keras.layers.Flatten(),
.tf.keras.layers.Dropout(0.3),
.tf.keras.layers.Dense(50, activation='relu'),
.tf.keras.layers.Dense(2, activation='softmax')
.])
在本次项目中,最初搭建如下的神经网络,如图3.2所示:
图3.2神经网络结构及各层参数情况
神经网络结构及各层参数具体情况如下:
第一层:3×3的卷积层,100个输出通道,输入形状为图片的形状:150×150×3,填充1个像素,激活函数为relu()。
第二层:2×2的最大池化层。
第三层:3×3的卷积层,100个输出通道,填充1个像素,激活函数为relu()。
第四层:2×2的最大池化层。
第五层:拉平层,多维的输入一维化,常用在从卷积层到全连接层的过渡,在本层中,形状(36,36,100)的输出被展平为形状(129600,)的向量。
第六层:输出为50维的全连接层,激活函数为relu()。
第七层:输出为2维的全连接层,激活函数为softmax ()。
经过多次调整,在本次项目中,最后搭建如下的神经网络,如图3.3所示:
为了降低过拟合问题的概率,我们添加了两层dropout层。对dense层使用dropout,是在训练过程中随机将该层的一些输出特征舍弃,dropout比率通常在0.2-0.5范围内。
图3.3 神经网络结构及各层参数情况
神经网络结构及各层参数具体情况如下:
第一层:3×3的卷积层,100个输出通道,输入形状为图片的形状:150×150×3,填充1个像素,激活函数为relu()。
第二层:2×2的最大池化层。
第三层:3×3的卷积层,100个输出通道,填充1个像素,激活函数为relu()。
第四层:2×2的最大池化层。
第五层:拉平层,多维的输入一维化,常用在从卷积层到全连接层的过渡,在本层中,形状(36,36,100)的输出被展平为形状(129600,)的向量。
第六层:输出为50维的全连接层,激活函数为relu()。
第七层:输出为2维的全连接层,激活函数为softmax ()。
3.2实验方法
3.2.1 训练模型
这次项目中,我们选择了 Adam优化器,因为Adam优化器的优点主要在于经过偏置校正后,每一次迭代学习率都有一个确定范围,这样可以使得参数更新比较平稳。损失函数我们选择交叉熵损失,因为我们的项目是二分类问题,网络输出是一个概率值,但对于输出概率值的模型,交叉熵(crossentropy)往往是最好的选择。交叉熵是来自于信息论领域的概念,用于衡量概率分布之间的距离,在这个项目中就是真实分布与预测值之间的距离。所以在本次项目中我们使用二分类交叉熵。
利用生成器,我们让模型对数据进行拟合。我们将使用 fit_generator 方法来拟合,它在数据生成器上的效果和 fit 相同。它的第一个参数应该是一个 Python 生成器,可以不停地生成输入和目标组成的批量,比如 train_generator。因为数据是不断生成的,所以 Keras 模型要知道每一轮需要从生成器中抽取多少个样本。这是 epochs 参数的作用:从生成器中抽取 epoch 个批量后(即运行了epoch 次梯度下降),拟合过程将进入下一个轮次。
使用 fit_generator 时,我们传入了一个 validation_data 参数,其作用和在 fit 方法中类似。值得注意的是,这个参数是一个数据生成器。如果向 validation_data 传入一个生成器,那么这个生成器应该能够不停地生成验证数据批量,因此我们还需要指定 validation_steps 参数,说明需要从验证生成器中抽取多少个批次用于评估,这里我们使用validation_generator参数。
具体代码如下:
.#编译模型
.#选择adam优化器,损失函数:使用二分类交叉熵binary_crossentropy
.model.compile(optimizer='adam',
.loss='binary_crossentropy',
.metrics=['mse','acc'])
.#模型训练记录
.checkpoint = ModelCheckpoint('model-{epoch:03d}.model',monitor='val_loss',verbose=0,save_best_only=True,mode='auto')
.#训练模型
.history = model.fit_generator(train_generator,
.epochs=8,
.validation_data=validation_generator,
.callbacks=[checkpoint])
.#模型保存
.model.save(filepath=r'D:\pythonproject\06_Face-Mask-Detection-master\mask_model.h5') #保存模型到那个文件路径
.解决过拟合问题
过拟合的特点:训练的损失值足够小,而测试的损失值很大。
为了解决过拟合问题,在本次口罩检测项目中,我们使用了两种方法,分别是进行数据增强和dropout正则化。
.进行数据增强
过拟合的原因是学习样本太少,导致无法训练出能够泛化到新数据的模型。如果拥有无限的数据,那么模型能够观察到数据分布的所有内容,这样就永远不会过拟合。
数据增强是从现有的训练样本中生成更多的训练数据,方法是利用多种能够生成可信图像的随机变换来增加样本。其目标是,模型在训练时不会两次查看完全相同的图像。这让模型能够观察到数据的更多内容,从而具有更好的泛化能力。
数据增强的作用有以下四点:
1) 避免过拟合。当数据集具有某种明显的特征,例如数据集中图片基本在同一个场景中拍摄,使用 Cutout 方法和风格迁移变化等相关方法可避免模型学到跟目标无关的信息。
2)提升模型鲁棒性,降低模型对图像的敏感度。当训练数据都属于比较理想的状态,碰到一些特殊情况,如遮挡,亮度,模糊等情况容易识别错误,对训练数据加上噪声,掩码等方法可提升模型鲁棒性。
3)增加训练数据,提高模型泛化能力。
4)避免样本不均衡。在工业缺陷检测方面,医疗疾病识别方面,容易出现正负样本极度不平衡的情况,通过对少样本进行一些数据增强方法,降低样本不均衡比例。
在 Keras 中,这可以通过对 ImageDataGenerator 实例读取的图像执行多次随机变换来实现。
代码如下所示:
.train_datagen = ImageDataGenerator(rescale=1.0/255,
.rotation_range=40,
.width_shift_range=0.2,
.height_shift_range=0.2,
.shear_range=0.2,
.zoom_range=0.2,
.horizontal_flip=True,
.fill_mode='nearest')
.#新增
.validation_datagen = ImageDataGenerator(rescale=1.0/255,)
在这次数据增强过程中,我们只选择了如下的参数:
1)rescale的作用是对图片的每个像素值均乘上这个放缩因子,这个操作在所有其它变换操作之前执行,因此设置放缩因子为1/255,把像素值放缩到0和1之间有利于模型的收敛,避免神经元“死亡”。
2)rotation_range 是角度值(在 0~180 范围内),表示图像随机旋转的角度范围。
3)width_shift_range是指水平平移图像,height_shift_range是上下平移图像;参数(0,1)之间或大于1。
4)shear_range指的是倾斜变形。
5)zoom_range是缩放(而参数大于0小于1时,执行的是放大操作,当参数大于1时,执行的是缩小操作),
6)horizontal_flip指的是随机对图片执行水平翻转操作
7)fill_mode为填充模式,当对图片进行平移、放缩、错切等操作时,图片中会出现一些缺失的地方,那这些缺失的地方用就fill_mode补全,参数包括:“constant”、“nearest”(默认)、“reflect”和“wrap”。
b.添加dropout层
如果我们使用这种数据增强来训练一个新网络,那么网络将不会两次看到同样的输入。但网络看到的输入仍然是高度相关的,因为这些输入都来自于少量的原始图像。你无法生成新信息,而只能混合现有信息。因此,这种方法可能不足以完全消除过拟合。为了进一步降低过拟合,我们还需要向模型中添加一个 Dropout 层,添加到全连接分类器之前。
.实验结果及分析
在这次项目中,一共进行了十四次模型训练,具体训练过程描述如下:
通过plot()函数绘制曲线,如图4.1所示。图中横坐标代表训练代数(Eopch),因为横坐标从0开始,所以实际对应的代数应该为横坐标值加1。图中纵坐标代表模型识别图像的准确率。图中有两条线,红色线accuracy代表训练集准确率,绿色线loss代表训练集损失值。
第一次训练:
本次训练模型的超参数设置如下:
学习率 优化器 Epoch Batch_size 激活函数 dropout
× Adam 8 8 Relu()Softmax() 0.5
表1
本次训练中,激活函数relu在第一个和第二个Conv2D和第一个Dense层中使用,激活函数softmax在第二个Dense层中使用,dropout层设置在第二个Conv2D层前,其值为0.5。
通过变化曲线图4.1,可以看到准确率在上升,损失值在下降,且有坡度。因为只有训练集的准确率和损失值,不足以说明模型的好坏,说明模型还可以进一步优化,比如添加测试集。
图4.1
通过图4.2,可以看到损失值为0.23,准确值为0.91。
图4.2
通过plot()函数绘制曲线,如图4.2所示。图中横坐标代表训练代数(Eopch),因为横坐标从0开始,所以实际对应的代数应该为横坐标值加1。图中纵坐标代表模型识别图像的准确率。本次训练相比前面一次多添加了验证集。图中有三条线,红色线accuracy代表训练集准确率,绿色线loss代表训练集损失值,蓝色线val_loss代表测试集损失值。
第二次训练:
本次训练模型的超参数设置如下:
学习率 优化器 Epoch Batch_size 激活函数 dropout
× Adam 8 8 Relu()Softmax() 0.5
表2
本次训练中,激活函数relu在第一个和第二个Conv2D和第一个Dense层中使用,激活函数softmax在第二个Dense层中使用,dropout层设置在第二个Conv2D层前,其值为0.5。相比第一次训练加入了测试集。
通过变化曲线图4.3,可以看到加入测试集后,测试集损失值的波动很大,且整体趋势是上升,训练集的损失值整体趋势是下降,说明训练超参数设置不当,需要进行调整。
图4.3
通过图4.2,可以看到损失值为0.23,准确值为0.91;验证损失为0.80,验证精确为0.68.
图4.4
第三次训练:
本次训练模型的超参数设置如下:相比第二次训练添加了参数学习率为0.001。
学习率 优化器 Epoch Batch_size 激活函数 dropout
0.001 Adam 8 8 Relu()Softmax() 0.5
表3
本次训练中,激活函数relu在第一个和第二个Conv2D和第一个Dense层中使用,激活函数softmax在第二个Dense层中使用,dropout层设置在第二个Conv2D层前,其值为0.5。
加入超参数学习率,数值为0.001。这时发现图像拟合不理想,这便说明模型训练的学习率过大,此时应减小学习率从头训练。
通过变化曲线图4.5,可以看到加入测试集后,测试集损失值的波动很大,且整体趋势上升,训练集的损失值整体趋势下降,说明训练学习率设置不当,需要进行调整。
图4.5
通过图4.6,可以看到损失值为0.24,准确值为0.90;验证损失为0.60,验证精确为0.72。
图4.6
第四次训练:
本次训练模型的超参数设置如下:将学习率缩小为第三次训练的1/10,为0.0001。
学习率 优化器 Epoch Batch_size 激活函数 dropout
0.0001 Adam 8 8 Relu()Softmax() 0.5
表4
本次训练中,激活函数relu在第一个和第二个Conv2D和第一个Dense层中使用,激活函数softmax在第二个Dense层中使用,dropout层设置在第二个Conv2D层前,其值为0.5。
通过变化曲线图4.7,可以看到加入测试集后,测试集损失值整体趋势平稳,训练集的损失值整体趋势下降,说明图像需要进行调整。
图4.7
通过图4.8,可以看到损失值为0.20,准确值为0.92;验证损失为0.54,验证精确为0.72。
图4.8
第五次训练:
本次训练模型的超参数设置如下:相较第四次训练将Epoch增加一代。
学习率 优化器 Epoch Batch_size 激活函数 dropout
0.0001 Adam 9 8 Relu()Softmax() 0.5
表5
本次训练中,激活函数relu在第一个和第二个Conv2D和第一个Dense层中使用,激活函数softmax在第二个Dense层中使用,dropout层设置在第二个Conv2D层前,其值为0.5。
通过变化曲线图4.9,可以看到加入测试集后,测试集损失值整体趋势平稳,训练集的损失值整体趋势下降,说明图像需要进行调整。
图4.9
通过图4.10,可以看到损失值为0.16,准确值为0.94;验证损失为0.45,验证精确为0.76。
图4.10
第六次训练:
本次训练模型的超参数设置如下:相较于第五次训练将Epoch增加一代。
学习率 优化器 Epoch Batch_size 激活函数 dropout
0.0001 Adam 10 8 Relu()Softmax() 0.5
表6
本次训练中,激活函数relu在第一个和第二个Conv2D和第一个Dense层中使用,激活函数softmax在第二个Dense层中使用,dropout层设置在第二个Conv2D层前,其值为0.5。
通过变化曲线图4.11,可以看到加入测试集后,测试集损失值整体趋势平稳,训练集的损失值整体趋势下降,说明图像需要进行调整。
图4.11
通过图4.12,可以看到损失值为0.19,准确值为0.93;验证损失为0.49,验证精确为0.74。
图4.12
第七次训练:
本次训练模型的超参数设置如下:在第一个全连接层前添加了一个参数为0.5的Dropout层。Epoch为9。
学习率 优化器 Epoch Batch_size 激活函数 dropout
0.0001 Adam 9 8 Relu()Softmax() 0.5
表7
本次训练中,激活函数relu在第一个和第二个Conv2D和第一个Dense层中使用,激活函数softmax在第二个Dense层中使用,dropout层设置在第二个Conv2D层和第一个Dense层前,其值为0.5。
在本次训练中,我们添加了dropout层,对dense层使用dropout,是在训练过程中随机将该层的一些输出特征舍弃,dropout比率通常在0.2-0.5范围内。
通过变化曲线图4.13,可以看到加入测试集后,测试集损失值整体趋势平稳,训练集的损失值整体趋势下降,说明图像需要进行调整,添加了dropout层,发现效果并不好。
图4.13
通过图4.14,可以看到损失值为0.21,准确值为0.91;验证损失为0.49,验证精确为0.75。
图4.14
第八次训练:
本次训练模型的超参数设置如下:相比第七次训练更改了第二个Dense层前的dropout,值为0.3。
学习率 优化器 Epoch Batch_size 激活函数 dropout
0.0001 Adam 9 8 Relu()Softmax() 0.50.3
表8
本次训练中,激活函数relu在第一个和第二个Conv2D和第一个Dense层中使用,激活函数softmax在第二个Dense层中使用,dropout层设置在第二个Conv2D层前,值为0.5;设置在第一个Dense层前,值为0.5;设置在第二个Dense层前,值为0.3。
通过变化曲线图4.15,可以看到加入测试集后,测试集损失值整体趋势平稳,训练集的损失值整体趋势下降,说明图像需要进行调整。
图4.15
通过图4.16,可以看到损失值为0.24,准确值为0.91;验证损失为0.51,验证精确为0.77。
图4.16
第九次训练:
本次训练模型的超参数设置如下:相比第八次训练更改了第二个Dense层前的dropout,值为0.4。
学习率 优化器 Epoch Batch_size 激活函数 dropout
0.0001 Adam 10 8 Relu()Softmax() 0.50.4
表9
本次训练中,激活函数relu在第一个和第二个Conv2D和第一个Dense层中使用,激活函数softmax在第二个Dense层中使用,dropout层设置在第二个Conv2D层前,值为0.5;设置在第一个Dense层前,值为0.5;设置在第二个Dense层前,值为0.4。
通过变化曲线图4.17,可以看到加入测试集后,测试集损失值整体趋势平稳,训练集的损失值整体趋势下降,说明图像需要进行调整,添加了dropout层,发现效果并不好。
图4.17
通过图4.18,可以看到损失值为0.23,准确值为0.91;验证损失为0.55,验证精确为0.71。
图4.18
第十次训练:
本次训练模型的超参数设置如下:相比第九次训练更改了第二个Dense层前的dropout,值为0.5。
学习率 优化器 Epoch Batch_size 激活函数 dropout
0.0001 Adam 10 8 Relu()Softmax() 0.5
表10
本次训练中,激活函数relu在第一个和第二个Conv2D和第一个Dense层中使用,激活函数softmax在第二个Dense层中使用,dropout层设置在第二个Conv2D层前,值为0.5;设置在第一个Dense层前,值为0.5;设置在第二个Dense层前,值为0.5。
通过变化曲线图4.19,可以看到加入测试集后,测试集损失值先下降,后来逐渐平稳,训练集的损失值整体趋势下降,说明图像需要进行调整。
图4.19
通过图4.20,可以看到损失值为0.28,准确值为0.88;验证损失为0.52,验证精确为0.74。
图4.20
第十一次训练:
本次训练模型的超参数设置如下:相比前面几次训练,本次将Batch_size由8改为了64。
学习率 优化器 Epoch Batch_size 激活函数 dropout
0.0001 Adam 10 64 Relu()Softmax() 0.5
表11
本次训练中,激活函数relu在第一个和第二个Conv2D和第一个Dense层中使用,激活函数softmax在第二个Dense层中使用,dropout层设置在第二个Conv2D层前,值为0.5;设置在第一个Dense层前,值为0.5;设置在第二个Dense层前,值为0.5。
通过变化曲线图4.21,可以看到加入测试集后,测试集损失值剧烈下降,训练集的损失值整体趋势下降,说明图像问题得到缓解,还需要进行调整。
图4.21
通过图4.22,可以看到损失值为0.31,准确值为0.87;验证损失为0.49,验证精确为0.74。
图4.22
第十二次训练:
本次训练模型的超参数设置如下:
学习率 优化器 Epoch Batch_size 激活函数 dropout
0.0001 Adam 10 64 Relu()Softmax() 0.5
表12
本次训练中,激活函数relu在第一个和第二个Conv2D和第一个Dense层中使用,激活函数softmax在第二个Dense层中使用,dropout层设置在第二个Conv2D层前,值为0.5;设置在第二个Dense层前,值为0.5。
通过变化曲线图4.23,可以看到加入测试集后,测试集损失值下降,训练集的损失值整体趋势下降,说明图像过拟合问题得到缓解,需要进行调整。
图4.23
通过图4.24,可以看到损失值为0.48,准确值为0.77;验证损失为0.57,验证精确为0.74。
图4.24
第十三次训练:
本次训练模型的超参数设置如下:
学习率 优化器 Epoch Batch_size 激活函数 dropout
0.0001 Adam 11 64 Relu()Sigmoid () 0.5
表13
本次训练中,激活函数relu在第一个和第二个Conv2D和第一个Dense层中使用,激活函数Sigmoid在第二个Dense层中使用,dropout层设置在第二个Conv2D层前,值为0.5;设置在第二个Dense层前,值为0.5。
通过变化曲线图4.25,可以看到加入测试集后,测试集损失值下降,训练集的损失值整体趋势下降,说明图像过拟合问题得到缓解,需要进行调整。
图4.25
loss: 0.3971 - mean_squared_error: 0.1249 - acc: 0.8471 - val_loss: 0.5112 - val_mean_squared_error: 0.1683 - val_acc: 0.7747
可以看到损失值为0.39,准确值为0.84;验证损失为0.51,验证精确为0.77。
第十四次训练:
本次训练模型的超参数设置如下:相较于第十三次训练将sigmoid激活函数
改成了softmax函数。
学习率 优化器 Epoch Batch_size 激活函数 dropout
0.0001 Adam 11 64 Relu()Softmax() 0.5
表14
本次训练中,激活函数relu在第一个和第二个Conv2D和第一个Dense层中使用,激活函数softmax在第二个Dense层中使用,dropout层设置在第二个Conv2D层前,值为0.5;设置在第二个Dense层前,值为0.5。
通过变化曲线图4.26,可以看到加入测试集后,测试集损失值下降,训练集的损失值整体趋势下降,说明图像问题得到缓解。
图4.26
- loss: 0.1575 - mean_squared_error: 0.1208 - acc: 0.8380 - val_loss: 0.5178 - val_mean_squared_error: 0.1688 - val_acc: 0.7918
可以看到损失值为0.15,准确值为0.83;验证损失为0.51,验证精确为0.79。
参考文献
[1] 余海林、翟中华.《计算机视觉-基于OpenCV与TensorFlow的深度学习方法》[M].清华大学出版社,2021.4
[2] 李航.《统计学习方法》[M].清华大学出版社,2022.3
[3] 黄文坚.《TensorFlow实战》[M].电子工业出版社,2017.2
[4] 周志华.《机器学习》[M].清华大学出版社,2016.1