二、深度学习
深度学习源于机器学习,两者均需要不断的迭代来获取经验来实现系统要求。机器学习需要预先为系统提供相应的定义和条件(进行手动编码),而现实世界往往会出现很多抽象的概念,我们很难或无法提供具体的定义和结构,这时,深度学习的诞生就解决了这一问题——将定义的过程也交给计算机。用更数学的方式表达来说,我们遇到的大多数问题往往是非线性的,深度学习比以前的机器学习算法具有更好的非线性拟合。
此外,深度学习解决了定义过程后依然会由于以下问题失败: 用于训练的优化算法可能找不到所需函数的参数值;训练算法可能由于过度拟合而选择错误的函数。因此,深度学习还需要解决模型优化问题,防止欠拟合或过拟合的出现导致训练失败。
网站:a Neural Network
2.1 神经网络分类
依靠深度学习的快速发展,已经出现了许多神经网络架构来解决多种多样的复杂难题。他们可以主要分为四个类别,分别是标准网络(DNN)、卷积网络(CNN)、循环网络(RNN)、和自编码器(Auto Encoder)。
https://medium.com/analytics-vidhya/11-essential-neural-network-architectures-visualized-explained-7fc7da3486d8
标准网络 | 卷积网络 | 循环网络 | 自编码器 |
---|---|---|---|
感知器、 前馈网络、 残差网络、 回声状态 |
卷积神经网络 反卷积神经网络 生成对抗网络 |
循环神经网络 长短时记忆网络 回声状态网络 |
自动编码器 变分自动编码器 |
2.2 卷积神经网络 CNN
由于图像具有非常高的维数,因此训练标准前馈网络来识别图像将需要数十万个输入神经元,除了极高的计算费用外,这还可能导致许多与神经网络中的维度诅咒相关的问题。卷积神经网络(CNN)通过利用卷积层和池化层来帮助降低图像的维数,从而提供了解决方案。由于卷积层是可训练的,但参数明显少于标准隐藏层,因此它能够突出显示图像的重要部分并向前传递每个部分。传统上,在CNN中,最后几层是隐藏层,它们处理“压缩的图像信息”。
卷积神经网络在执行图像识别分类的任务时表现非常不错,因此非常适合本次实验。
卷积神经网络模型
2.3 计算机视觉图像分类模型
一般常见的网络模型均可以按照如下内容表示:
神经网络模型演进过程
2.3.1 LeNet-5
LeNet 是1998年 LeCun 发表的用来识别手写数字的经典卷积神经网络模型,上世纪美国许多银行采用了这个模型来识别支票上的手写数字。这个网络的诞生为深度学习在图像识别上的使用给出了方向,定义了 CNN 的基础构造,在深度学习的发展史上具有举足轻重的地位。
LeNet结构图
2.3.2 AlexNet
AlexNet 在2012年 ImageNet ILSVRC challenge 中的出色表现让深度学习和卷积神经网络一炮而红,自此开始深度学习的研究愈加红火。这种网络模型的结构与 LeNet 具有很高的相似度,但是拥有了更深的网络和更广的数据,也对激活函数(ReLU)、丢弃(Dropout)和局部响应归一化层(LRU)等做了修改。
AlexNet 模型结构图
上图AlexNet架构的网络前5层为卷积层,后三层为全连接层,最终 softmax 输出是1000类。
2.3.3 VGGNet
VGGNet 在 2014 年由牛津大学的 VGG(Visual Geometry Group)提出,在当年的 ImageNet 竞赛夺得了第二名,它比 AlexNet 采用了更深的基础网络。其最大的特点是采用了小卷积核的方案。
VGGNet 网络模型全部采用 3x3 的小卷积核。因为卷积不仅涉及计算,还会影响感受野。前者关系到部署到移动终端是否方便、是否能满足实时处理、是否易于训练等,而后者关系到参数更新、特征图的大小、特征提取是否足够、模型的复杂程度和参数个数等。小卷积核主要带来了以下几个优点:更多的激活函数、更丰富的特征,更强的辨别能力;减少了卷积层的参数;大卷积核被小卷积核替代后,其正则作用带来了性能提升;多个小卷积核堆叠后,使其在分类精度上比单个大卷积要好。
VGG-16网络模型结构
由上图看出,VGG-16 的结构非常整洁,深度较 AlexNet 深得多,里面包含多个 conv->conv->max_pool这类的结构,VGG的卷积层都是 same 的卷积,即卷积过后的输出图像的尺寸与输入是一致的,它的下采样完全是由max pooling来实现。由于其一目了然的结构,相对更加简洁的代码,而且非常适合简单的场景,因此,本次实验选用了 VGGNet 作为本次的网络模型。
2.3.4 GoogLeNet
GoogLeNet 作为 2014 年 ImageNet 比赛上击败 VGG-Net 的模型,其也有着独特的思路,通过精巧的网络结构设计,在保持一定计算开销的前提下增加了网络深度和宽度,有效提高了网络内计算资源的利用效率。
GoogLeNet 的主要特点是:引出了 Inception 结构;增加了中间层的辅助 LOSS 单元;将后面的全连接层全部替换为简单的全局平均 pooling 。
2.3.5 ResNet
何凯明在 2015 年提出的 ResNet 也是一个里程碑式的创新,论文中选了不同的普通网络、残差网络进行测试。 ResNet 中“深度残差学习”框架的设计解决了梯度消失的难题,给出了训练深层网络的方案。
梯度消失:增加网络深度性能却下降了
2.3.6 DenseNet
三、建立果蔬识别模型
3.1 构建深度学习图像数据集
目前可以使用的获取用于训练的图像数据集的方法有如下几个
- 从网络平台的开放数据集下载;
- 利用摄像设备拍摄所需图像;
- 利用图像搜索引擎批量获取图像。
为了更快的获取所需的实验结果,我首先选择了从各大开放数据集平台获取所需的数据集,水果蔬菜作为生活中较为常见的事物,在网络平台上能较为方便的检索到。
同时公开数据集有着非常明显的优势,其数据集往往是经过处理的,不需要经过繁杂的预处理。
但随着实验的继续进行,很快发现了问题。虽然实验的训练数据显示准确率非常高,能轻松达到 80% ~ 90% 以上,但在实际操作后,当选择生活中的真实果蔬进行测试时,准确率却极低,往往难以正确识别出相对应的结果。
测试初期,目光集中在了神经网络模型,认为其可能的原因是模型不够完善完整,但经过反复的测试讨论与研究,发现问题并非出现在所搭建的模型中,而是更可能出现在数据集的选择上。在经过对数据集的研究分析后,我得到了如下结论,当前问题产生的原因为:
1. 数据集并非国人制作,其中的水果蔬菜的品种与风格更接近西方;
2. 每个品类的数据集较为单一,均是同一个水果蔬菜的不同角度的照片;
3. 数据集内水果蔬菜的个数均为一个,而更多的应用场景拍摄到的角色往往是成捆、成群、成盘的。
因此,我选择尝试了自己拍摄水果蔬菜和利用图像搜索引擎检索进行构建数据集,由于自己拍摄的过程相对过于繁琐,很快被抛弃,而利用百度图像,Google Image 进行检索抓取也是一个繁杂的手动过程,两者皆无法实现很快获取所需的数据集图像照片。于是我积极的寻找一种能通过设计程序的方法来下载图像的解决方案,很快,我发现了百度图像搜索API和必应图像搜索API,为了获取更加符合东方特征的水果蔬菜,实验选用了百度图像搜索API,并利用 Python 设计脚本程序快速下载所需要的图像数据并保存在 dataset 目录。
蔬菜水果数据集由12种不同的水果和蔬菜组成,分别是:苹果、香蕉、胡萝卜、土豆、圣女果、黄瓜、大白菜、大葱、韭菜、芒果、梨、马铃薯、西红柿。所用照片经随机挑选并剔除了重复度较高、特征不明显图片来降低样本相关性。为了减少 API 使用次数的开销、减少实验训练时间、简化程序,水果与蔬菜共保存了 850 张训练数据。由于数据集制作所需时间空间的限制,训练集中暂不包括其他果蔬。
果蔬名称 | 苹果 | 香蕉 | 胡萝卜 | 圣女果 | 大白菜 | 黄瓜 |
---|---|---|---|---|---|---|
数量 | 79 | 50 | 74 | 65 | 101 | 83 |
果蔬名称 | 大葱 | 芒果 | 韭菜 | 梨 | 土豆 | 西红柿 |
数量 | 65 | 53 | 73 | 68 | 79 | 60 |
以下内容展示了各个种类随机选取的样本范例。
同时,将不同种类果蔬图片所在目录命名为果蔬英文,以便于标记label。dataset的目录结构是 dataset/{CLASS_LABEL}/{FILENAME}.png
3.2 数据加载与预处理
自定义数据集要想实现训练卷积神经网络以实现识别和分类成功果蔬农产品,首要任务就是对图像进行相应的预处理,以便于后续的加载图像,识别训练。
采用提升模型精度和加速网络训练的常规做法,对训练数据进行了剪裁和变预处理操作,按照模型输入图片要求进行调整。输入图片的尺寸为96×96像素。提取路径名称用于保存标签,用scikit-learn的LabelBinarizer二值化标签。使用80%的数据进行训练并将其余20%的数据用于测试,将数据划分为训练组和测试组,最后将数据进行放大。
3.3 搭建CNN卷积神经网络模型
本次实验选用的 CNN 网络架构为 VGGNet 的变体,其更小且更紧凑。类 VGGNet 的体系结构往往具有如下几个特点:
- 仅使用 3*3 的卷积核,相比更大尺寸的卷积核增加了更多层的非线性函数,计算量相对较低,适合计算性能相对较差的环境;
- 通过最大池化来减少体积;
- 在 softmax 分类器之前,存在一层全连接层。
正是由于 VGGNet 的几个特性,使得其更适合小型训练场景,更便于进行个人实验,能够减少所需耗费的时间与所耗费的计算性能。
首先,第一步,在目录结构中定义一个新的类 VGGNet 。完成该类的构建方式需要四个参数,分别为图像宽度尺寸(width)、图像高度尺寸(height)、图像的通道数(即深度 depth)以及数据集中的种类数量(classes)。为了方便快捷的完成项目内容,本次实验选择了宽高 96 * 96 、通道数为 3 的图像作为输入。
经过调查与分析后,本次实验选用 Keras(TensorFlow) 作为训练神经网络模型的后端,相比于Theano 等具有明显的优点,其优势在于:
1. 易于操作,提供更多方便的库函数,使编辑代码更加简洁和方便;
2. Keras 提供了相对更加流畅的 GPU 训练支持,也得到了 NVIDIA 公司产品的支持;
3. 能够支持分布式集群训练。
第二步,向实验模型中添加层(layer)。模型的第一部分由一层卷积层、一层激活函数层、一层BN层和一层池化层构成,卷积层中包含了带有内核的筛选器,然后利用激活函数,实现批量规范化,图像经过第一部分之后,其空间维度由(96, 96, 3)转为(32, 32, 32)。模型的第二个部分由两层卷积层和一层池化层构成,由于空间维度的减小,该部分增大了过滤器(32->64),同时为了保证不会造成空间维度减小的过快,减小了该部分的最大池化值,图像经过第二部分后,其空间维度变为(16, 16, 64)。然后,模型的第三个部分与第二部分相同,依然由两层卷积层和一层池化层构成,图像经过后的空间维度变为(8, 8, 128)。然后,在模型上添加全连接层,全连接层通过整流线性单元激活和批量归一化来指定,此时空间维度变为(1024),已经转为线性。最后,添加 softmax 分类器用以完善模型,返回每种类别的标签的预测概率。
值得提出的是,网络模型的每个部分最后我都使用了 dropout 用于丢弃数据,这种在训练批次期间随机断开连接的过程有助于自然地将冗余引入模型中,这种方式能够有效的解决过拟合的问题,可以在一定程度上达到正则化的效果。其中,卷积部分的 dropout 设置为 25% 的数据用于丢弃,全连接层部分设置 50% 的数据用于丢弃,主要原因在于卷积层自身相对稀疏化,而全连接层的参数更多,更容易出现过拟合。(Dropout的工作原理是将当前层的部分节点随机断开到下一层的连接,从而实现丢弃。)
3.4 使用模型进行训练
模型参数设置:
- EPOCHS: 本次实验将训练网络的纪元总数(即,本次实验的网络“看到”每个训练示例并从中学习模式的次数)。
- INIT_LR: 初始学习速率 — 值 1e-3 是 Adam 优化器的默认值,本次实验将使用该优化器来训练网络。
- BS: 本次实验将批量图像传递到神经网络中进行训练。每个时代有多个批次。该值控制批大小。
- IMAGE_DIMS: 在这里,本次实验提供输入图像的空间维度。本次实验将要求输入图像是带有通道的像素(即RGB)。
由于本次实验使用的数据点数量有限(每个种类 < 100 张图像),因此本次实验将在训练过程中利用数据增强来为模型提供更多图像(基于现有图像)进行训练。
本次实验选用 Adam 优化器来训练神经网络,2014年12月,Kingma和Lei Ba两位学者提出了Adam优化器,结合AdaGrad和RMSProp两种优化算法的优点,即 Adam 优化算法。对梯度的一阶矩估计(First Moment Estimation,即梯度的均值)和二阶矩估计(Second Moment Estimation,即梯度的未中心化的方差)进行综合考虑,计算出更新步长。主要包含以下几个显著的优点:
1. 实现简单,计算高效,对内存需求少
2. 参数的更新不受梯度的伸缩变换影响
3. 超参数具有很好的解释性,且通常无需调整或仅需很少的微调
4. 更新的步长能够被限制在大致的范围内(初始学习率)
5. 能自然地实现步长退火过程(自动调整学习率)
6. 很适合应用于大规模的数据及参数的场景
7. 适用于不稳定目标函数
8. 适用于梯度稀疏或梯度存在很大噪声的问题
综合Adam在很多情况下算作默认工作性能比较优秀的优化器。
最后,我们可以绘制我们的训练和损失准确性,训练损失/准确性图如下:
如图 3 所示,我对模型进行了 100 个 epoch 的训练,并在有限的过拟合下实现了低损耗。当然如果通过一些额外的训练数据,也能够获得更高的准确性。可以发现训练准确率(accuracy)随着模型的不断迭代逐渐接近 1 ,训练丢失部分(loss)逐渐靠近 0 ,表明模型结果可用。
下图为测试分类结果:
代码结构:
dataset 训练集
examples 测试用图片
pyimagesearch cnn识别接口
—smallervggnet.py 识别网络
app.py 用于调用识别结果的flask服务端
classify.py 识别测试文件
lb.pickle 存放标签
plot.png 训练损失和准确性图片
resize.py 调整dataset图片大小
signvegetable.model 训练结果
train.py 开始训练