图像相比文字可提供更加生动、容易理解及更具艺术感的信息,图像分类是根据图像的语义信息将不同类别图像区分开来,是图像检测、图像分割、物体跟踪、行为分析等其他高层视觉任务的基础。图像分类在安防、交通、互联网、医学等领域有着广泛的应用。
图像相比文字能够提供更生动、容易理解及更具艺术感的信息,图像分类是根据图像的语义信息将不同类别图像区分开来,是图像检测、图像分割、物体跟踪、行为分析等其他高层视觉任务的基础。图像分类在安防、交通、互联网、医学等领域存在广泛的应用。
一般来说,图像分类通过手工提取特征或特征学习方法对整个图像进行全部描述,然后使用分类器判别物体类别,因此如何提取图像的特征至关重要。基于深度学习的图像分类方法,能够最终靠有监督或无监督的方式学习层次化的特征描述,从而取代了手工设计或选择图像特征的工作。深度学习模型中的卷积神经网络 (Convolution Neural Network, CNN) 直接利用图像像素信息作为输入,最大限度上保留了输入图像的所有信息,通过卷积操作进行特征的提取和高层抽象,模型输出直接是图像识别的结果。这种基于输入-输出直接端到端的学习方法取得了非常好的效果。
本教程主要介绍图像分类的深度学习模型,以及怎么样去使用 PaddlePaddle 在 CIFAR10 数据集上快速实现 CNN 模型。
基于 ImageNet 数据集训练的更多图像分类模型,及对应的预训练模型、finetune 操作详情请参照 Github:
图像分类包括通用图像分类、细粒度图像分类等。图 1 展示了通用图像分类效果,即模型可以正确识别图像上的主要物体。
图 2 展示了细粒度图像分类-花卉识别的效果,要求模型可以正确识别花的类别。
一个好的模型既要对不同类别识别正确,同时也应该能够对不同视角、光照、背景、变形或部分遮挡的图像正确识别 (这里我们统一称作图像扰动)。图 3 展示了一些图像的扰动,较好的模型会像聪明的人类一样能够正确识别。
CNN:传统 CNN 包含卷积层、全连接层等组件,并采用 softmax 多类别分类器和多类交叉熵损失函数,一个典型的卷积神经网络如图 4 所示,我们先介绍用来构造 CNN 的常见组件。
• 卷积层 (convolution layer): 执行卷积操作提取底层到高层的特征,发掘出图片局部关联性质和空间不变性质。
• 池化层 (pooling layer): 执行降采样操作。通过取卷积输出特征图中局部区块的最大值 (max-pooling) 或者均值 (avg-pooling)。降采样也是图像处理中常见的一种操作,可以过滤掉一些不重要的高频信息。
• 非线性变化: 卷积层、全连接层后面一般来说都会接非线性变化函数,例如 Sigmoid、Tanh、ReLu 等来增强网络的表达能力,在 CNN 里最常使用的为 ReLu 激活函数。
• Dropout [1] : 在模型训练阶段随机让一些隐层节点权重不工作,提高网络的泛化能力,某些特定的程度上防止过拟合。
VGG:牛津大学 VGG(Visual Geometry Group) 组在 2014 年 ILSVRC 提出的模型被称作 VGG 模型 [2]。该模型相比以往模型进一步加宽和加深了网络结构,它的核心是五组卷积操作,每两组之间做 Max-Pooling 空间降维。同一组内采用多次连续的 3X3 卷积,卷积核的数目由较浅组的 64 增多到最深组的 512,同一组内的卷积核数目是一样的。卷积之后接两层全连接层,之后是分类层。由于每组内卷积层的不同,有 11、13、16、19 层这几种模型,下图展示一个 16 层的网络结构。VGG 模型结构相对简洁,提出之后也有很多文章基于此模型进行研究,如在 ImageNet 上首次公开超过人眼识别的模型 [4] 就是借鉴 VGG 模型的结构。
ResNet:ResNet(Residual Network) [3] 是 2015 年 ImageNet 图像分类、图像物体定位和图像物体检测比赛的冠军。针对随网络训练加深导致准确度下降的问题,ResNet 提出了残差学习方法来减轻训练深层网络的困难。在已有设计思路 (BN, 小卷积核,全卷积网络) 的基础上,引入了残差模块。每个残差模块包含两条路径,其中一条路径是输入特征的直连通路,另一条路径对该特征做两到三次卷积操作得到该特征的残差,最后再将两条路径上的特征相加。
残差模块如图 7 所示,左边是基本模块连接方式,由两个输出通道数相同的 3x3 卷积组成。右边是瓶颈模块 (Bottleneck) 连接方式,之所以称为瓶颈,是因为上面的 1x1 卷积用来降维 (图示例即 256-64),下面的 1x1 卷积用来升维 (图示例即 64-256),这样中间 3x3 卷积的输入和输出通道数都较小 (图示例即 64-64)。
由于 ImageNet 数据集较大,下载和训练较慢,为了方便大家学习,个人会使用 CIFAR10 数据集。CIFAR10 数据集包含 60,000 张 32x32 的彩色图片,10 个类别,每个类包含 6,000 张。其中 50,000 张图片作为训练集,10000 张作为测试集。图 11 从每个类别中随机抽取了 10 张图片,展示了所有的类别。
通过输入 python train.py,就能开始训练模型了,以下小节将详细的介绍 train.py 的相关内容。
首先介绍 VGG 模型结构,由于 CIFAR10 图片大小和数量相比 ImageNet 数据小很多,因此这里的模型针对 CIFAR10 数据做了一定的适配。卷积部分引入了 BN 和 Dropout 操作。VGG 核心模块的输入是数据层,vgg_bn_drop 定义了 16 层 VGG 结构,每层卷积后面引入 BN 层和 Dropout 层,详细的定义如下:
五组卷积操作,即 5 个 conv_block。第一、二组采用两次连续的卷积操作。第三、四、五组采用三次连续的卷积操作。每组最后一个卷积后面 Dropout 概率为 0,即不使用 Dropout 操作。
在这里,VGG 网络首先提取高层特征,随后在全连接层中将其映射到和类别维度大小一致的向量上,最后通过 Softmax 方法计算图片划为每个类别的概率。
先介绍 resnet_cifar10 中的一些基本函数,再介绍网络连接过程。
• shortcut : 残差模块的直连路径,直连实际分两种形式:残差模块输入和输出特征通道数不等时,采用 1x1 卷积的升维操作;残差模块输入和输出通道相等时,采用直连操作。
• basicblock : 一个基础残差模块,即图 9 左边所示,由两组 3x3 卷积组成的路径和一条直连路径组成。
• layer_warp : 一组残差模块,由若干个残差模块堆积而成。每组中第一个残差模块滑动窗口大小与其他可以不同,以用来减少特征图在垂直和水平方向的大小。
然后连接 3 组残差模块即下面配置 3 组 layer_warp,每组采用图 10 左边残差模块组成。
注意:除第一层卷积层和最后一层全连接层之外,要求三组 layer_warp 总的含参层数能够被 6 整除,即 resnet_cifar10 的 depth 要满足
然后我们应该设置训练程序 train_network。它首先从推理程序中进行预测。在训练期间,它将从预测中计算 avg_cost。在有监督训练中要输入图像对应的类别信息,同样通过ers.data 来定义。训练中采用多类交叉熵作为损失函数,并作为网络的输出,预测阶段定义网络的输出为分类器得到的概率信息。
注意: 训练程序应该返回一个数组,第一个返回参数必须是 avg_cost。训练器使用它来计算梯度。
我们需要为训练过程制定一个 main_program, 同样的,还需要为测试程序配置一个 test_program。定义训练的 place,并使用先前定义的优化器。
注意:CPU,每个 Epoch 将花费大约 15~20 分钟。这部分在大多数情况下要一段时间。请随意修改代码,在 GPU 上运行测试,以提高训练速度。
图 13 是训练的分类错误率曲线 个 pass 后基本收敛,最终得到测试集上分类错误率为 8.54%。
可以使用训练好的模型对图片进行分类,下面程序展示了如何加载已经训练好的网络和参数进行推断。
与训练过程类似,inferencer 需要构建相应的过程。我们从 params_dirname 加载网络和经过训练的参数。我们大家可以简单地插入前面定义的推理程序。现在我们准备做预测。
传统图像分类方法由多个阶段构成,框架较为复杂,而端到端的 CNN 模型结构可一步到位,而且大幅度提升了分类准确率。本文我们第一步介绍 VGG、GoogleNet、ResNet 三个经典的模型;然后基于 CIFAR10 数据集,介绍怎么样去使用 PaddlePaddle 配置和训练 CNN 模型,尤其是 VGG 和 ResNet 模型;最后介绍怎么样去使用 PaddlePaddle 的 API 接口对图片进行预测和特征提取。对其他数据集比如 ImageNet,配置和训练流程是同样的,请参照 Github 。
公司地址:北京市朝阳区酒仙桥路4号751 D·Park正东集团院内 C8座105室 极客公园