ImageNet冠军带你入门计算机视觉:卷积神经网络

本文由 【AI前线】原创,原文连接:t.cn/RYs9U26git


AI 前线导语: “在第一篇文章《ImageNet 冠军带你入门计算机视觉:监督学习与神经网络的简单实现》中,咱们介绍了神经网络的基本概念以及 Tensorflow 的基本用法。 本文为系列的第二篇文章,将会介绍卷积神经网络。重点介绍经典的卷积神经网络,全卷积网络的基本概念和基本单元,以及卷积神经网络与神经网络的异同。最后经过实现一个在实际中有普遍应用的人脸关键点检测算法,介绍如何用 TensorFlow 构建卷积神经网络”。github


神经网络的发展历史算法

卷积神经网络(Convolutional Neural Network, CNN)的起源能够追溯到上世纪 60 年代。生物学研究代表,视觉信息从视网膜传递到大脑中是经过多个层次的感觉野 (Receptive Field) 激发完成的,并提出了 Neocognitron 等早期模型。1998 年,深度学习三巨头之一的 Lecun 等,正式提出了 CNN,并设计了以下图所示的 LeNet-5 模型。该模型在手写字符识别等领域取得了不错的结果。微信

因为计算资源等缘由,CNN 在很长时间内处于被遗忘的状态。二十多年后的 ImageNet 比赛中,基于 CNN 的 AlexNet 在比赛中大放异彩,并引领了 CNN 的复兴,此后 CNN 的研究进入了高速发展期。目前卷积神经网络的发展有两个主要方向:网络

  • 如何提升模型的性能。这个方向的一大重点是如何训练更宽、更深的网络。沿着这一思路涌现出了包括 GoogleNet,VGG,ResNet,ResNext 在内的不少经典模型。
  • 如何提升模型的速度。提升速度对 CNN 在移动端的部署相当重要。经过去掉 max pooling,改用 stride 卷积,使用 group 卷积,定点化等方法,人脸检测、先后背景分割等 CNN 应用已经在手机上大规模部署。

目前,CNN 是计算机视觉领域最重要的算法,在不少问题上都取得了良好的效果。由于篇幅关系,本文将主要介绍卷积神经网络的基础知识。框架


神经网络 vs 卷积神经网络ide

上篇文章中咱们介绍了神经网络。神经网络在大数据处理,语言识别等领域都有着普遍的应用。但在处理图像问题时会许多问题:模块化

参数爆炸函数

以 200x200x3 的图像为例,若是输入层以后的 hidden layer 有 100 个神经元,那么参数量会达到 200x200x3x100=1200 万。显然有如此多参数的模型是难以训练且容易过拟合的。性能

平移不变性

对不少图像问题,咱们但愿模型知足必定的平移不变性。 例如对图像分类问题,咱们但愿物体出如今图片的任何位置上,模型都能正确识别出物体。

局部相关性

在大数据等问题中,输入维度之间不存在显式的拓扑关系,所以适合使用神经网络(全链接层)进行建模。但对于计算机视觉的问题,输入图片的相邻像素之间存在自然的拓扑关系。例如,判断图片中某个位置是否有物体时,咱们只须要考虑这个位置周边的像素就能够了,而不须要像传统神经网络那样将图片中全部像素的信息做为输入。

为了克服神经网络的上述问题,在视觉领域,咱们须要一种更合理的网络结构。卷积神经网络,在设计时经过局部链接和参数共享的方式,克服了神经网络的上述问题,于是在图像领域取得了惊人的效果。接下来咱们将详细介绍卷积神经网络的原理。


卷积神经网络

网络结构

卷积神经网络和传统神经网络的总体结构大体相同。以下图所示,含有 2 层全链接层的传统神经网络和含有 2 层卷积层的卷积神经网络都是由基本单元堆叠而成,前一层的输出做为后一层的输入。最终层的输出,做为模型的预测值。两者的主要差异在于基本单元不一样,卷积神经网络使用卷积层代替了神经网络中的全链接层。



和全链接层同样,卷积层中也含有能够学习的参数 weight 和 bias。模型的参数,能够按上一篇文章介绍的方法,在监督学习的框架下定义损失函数,经过反向传播进行优化。

卷积 (Convolution)

卷积层是整个卷积神经网络的基础。2D 卷积操做,能够看做是一个相似模板匹配的过程。以下图所示,将尺寸为 h × w × d 的模板,经过滑动窗口的方式和输入进行匹配。滑动过程当中,输入中对应位置的值和模板的权重的内积加一个偏移量 b,做为对应输出位置的值。w,h 是模板的大小,统称为 kernel size,在 CNN 中,w 和 h 通常会取相同的值。d 是模板的 channel 数量,和输入的 channel 数相同,例如对 RGB 图像,channel 数为 3。

模板在卷积神经网络中常被称为卷积核( K )或者过滤器(filter)。在标准卷积中,输出位置 (x,y) 对应的输出值能够表示成:

在 CNN 中,除了描述单个 filter 的 h ,w ,d 这 3 个参数以外,还有 3 个重要的参数 depth, stride 和 padding:

  • depth 指的是输出 channel 的数量, 对应于卷积层中 filter 的数量
  • stride 指的是 filter 每次滑动的步长
  • padding 指的是在输入四周补 0 的宽度。使用 padding 主要是为了控制输出的尺寸。若是不添加 padding,使用 kernel size 大于 1 的 filter 会使输尺寸出比输入小。在实际中常常会增长 padding,使得输入和输出的尺寸一致。

以下图所示,对 1D 的状况,假设输入尺寸为 W ,filter 的尺寸为 F,stride 为 S,padding 为 P ,那么输出的尺寸为 (W - F + 2P)/S + 1为。 经过设定 P=(F-1)/2,当 S=1 时,输入和输出的尺寸会保持一致。2D 卷积的计算和 1D 卷积相似。

对比传统神经网络中的全链接层,卷积层实际上能够当作是全链接层的一种特例。首先是局部链接性,经过利用输入自带的空间拓扑结构,卷积神经网络只需考虑在空间上和输出节点距离在 filter 范围内的输入节点,其余边的权重都为 0。此外,对于不一样的输出节点,咱们强制 filter 的参数彻底一致。但经过这种 局部链接参数共享,卷积层能够更好的利用图像中内在的拓扑关系及平移不变形,大大减小了参数,从而获得一个更好的局部最优解,使其在图像问题上有更好的性能。

在 tensorflow 中实现卷积层很是简单,能够直接调用tf.nn.conv2d

池化 (Pooling)

在 CNN 网络中,除了大量的卷积层,咱们也会根据须要,插入适量的池化层。池化层能够用来减小输入的尺寸,从而减小后续网络的参数与计算量。常见的池化操做(如 max pooling,average pooling),一般也能够提供必定的平移不变性。

咱们以 max pooling 举例,max pooling 对 kernel size 范围内的全部值取 max,结果做为对应位置的输出。pooling 一般是对每一个 channel 单独操做,所以输出的 channel 数和输入相同。池化层和卷积层相似,pooling 操做也能够理解为采用滑动窗口的方式,所以也有和卷积对应的步长 stride 和 padding 等概念。 下图所示就是一个 kernel size 和 stride 都为 2 的 max pooling 操做:

实际当中,池化层的参数有两种比较常见的配置,一种是 kernel size 和 stride 都为 2 的,这种设置池化过程当中无重叠区域。另外一种是 kernel size 为 3,stride 为 2 的有重叠 pooling。在 tensorflow 中实现池化层也很是简单:

卷积神经网络的经典网络结构

介绍了卷积神经网络的基本组成模块以后,咱们接下来介绍一下卷积神经网络的经典网络结构。从 1998 的 LeNet-5 开始,到 Imagenet 2012 的 AlexNet 模型,再到后来的 VGG 等一系列经典模型,基本都听从了这个经典结构。

为了清晰,咱们省略了卷积和全链接层以后的非线性激活函数。如上图所示,经典的卷积神经网络,能够分为三个部分:

  • 一系列级联的 conv+pooling 层(有时会省略掉 pooling 层)。在级联的过程当中,输入的尺寸逐渐变小,同时输出的 channel 逐渐变多,完成对信息从低级到高级的抽象。
  • 一系列级联的全链接层。在卷积层到全链接层的交界处,卷积层的输出转化成一维的输入送入全链接层。以后根据任务的复杂程度,级联一系列全链接层。
  • 最后的输出层,根据任务的须要,决定输出的形式。 如多分类问题,最后会接一个 softmax 层。

经典卷积神经网络,能够看做是一个输出尺寸固定的非线性函数。它能够将尺寸为 H \times W \times 3 的输入图片转化为最终的维度为 d 的定长向量。经典卷积神经网络在图像分类、回归等问题上取得了巨大的成功。以后的实战部分,咱们会给出一个回归问题的例子。


全卷积网络

(Fully Convolution Network)

经典的卷积神经网络中因为有全链接层的存在,只能接受固定尺寸的图片做为输入,并产生固定尺寸的输出。虽然能够经过使用 adaptive pooling 的方式, 接受变长的输入,但这种处理仍然只能产生固定尺寸的输出。为了克服经典卷积神经网络的这种缺点,在物体分割等输出尺寸可变的应用场景下,咱们再也不使用全链接层。这种主要计算单元所有由卷积层组成的网络,被称为全卷积网络(FCN)。

如上图所示,因为卷积操做对输入尺寸无限制,且输出尺寸由输入决定,所以全卷积网络能够很好的处理如分割等尺寸不固定的问题。全卷积网络,能够当作是一种输出尺寸随输入尺寸线性变化的非线性函数。它能够将尺寸为 H × W × 3 的输入图片转化为最终维度为 H/S ×H/S × d 的输出。 能够转化为这种形式的监督学习问题,基本均可以在全卷积网络的框架下求解。

反卷积(Deconvolution)

在全卷积网络中,标准的卷积 + 池化操做,会使输出的尺寸变小。对于不少问题,咱们须要输出的尺寸和输入图片保持一致,所以咱们须要一种能够扩大输入尺寸的操做。最经常使用的操做就是反卷积。

反卷积能够理解成卷积的逆向操做。这里咱们主要介绍 stride>1 且为整数的反卷积。这种反卷积能够理解为一种广义的差值操做。如下图为例,输入是 3x3 的绿色方格,反卷积的 stride 为 2,kernel size 为 3,padding 为 1。在滑动过程当中,对每一个输入方格,其输出为对应的 3x3 阴影区域,输出值为输入值和 kernel 对应位置值的乘积。最终的输出为滑动过程当中每一个输出位置对应值的累加和。这能够当作是一种以 3x3 kernel 值为权重的差值操做。最外边的一圈白色区域没法进行完整的差值操做,所以能够经过设定 padding 为 1, 将周围的一圈白色区域去掉,最终的输出尺寸为 5x5。


根据上面的描述,stride>1 且为整数的反卷积,若是固定反卷积 kernel 的取值为双线性差值 kernel,反卷积能够等价于双线性差值。而经过学习获得反卷积 kernel,相比固定参数的 kernel,能够更好的适应不一样的问题,所以反卷积能够当作是传统差值的一种推广。和卷积相似,tensorflow 中已经实现了反卷积模块tf.layers.conv2d_transpose


卷积神经网络在视觉识别中的应用

CNN 在视觉识别(Visual Recognition)中有着很是普遍的应用。咱们接下来以视觉识别中的三大经典问题:分类 / 回归、检测和分割为例,介绍如何用 CNN 解决实际问题。

分类 / 回归 (classification/regression)

图像分类是指判别图像属于哪一 / 哪些预先指定的类别,图像回归是指根据图像内容判断图片属性的取值。分类和回归在实际中都有着普遍的应用。从物体分类,人脸识别,再到 12306 的验证码识别等,均可以抽象成标准的分类问题。相似的,人脸的关键点位置预测,人脸的属性预测(如年龄,颜值)等,也均可以抽象为标准的回归问题。目前视觉领域的应用,若是能抽象成输出为定长的分类或者回归问题,在有大量训练数据的状况下,一般均可以采用以前介绍的经典卷积神经网络框架解决。

检测 (detection)

检测问题一般是指判断出图片中是否有物体,以及该物体的位置。检测有 one-stage 和 two-stage 的方法。 由于篇幅关系,咱们重点介绍在 FCN 框架下的 one-stage 方法。

按以前的介绍,FCN 能够看做是将 H × W × 3 的输入图片,转化为 H/S × W/S × d 输出的非线性函数。在 FCN 的框架下解决检测问题,咱们能够预测每个输出位置是否有物体,以及物体左上角、右下角相对于当前输入位置的偏移。 这样对每一个输出位置,须要 5 维的向量来表示是否有物体,即 d=5。 定义了网络的输出以后,咱们人工构造出对应的 ground truth,以后在监督学习的框架下,经过定义损失函数(l2 loss) 并进行反向传播,进行参数的学习。

分割 (segmentation)

分割问题是指给出图片中每一个像素点的类别。 基于 FCN 的分割方法和上面介绍的 one-stage 的检测方法很是相似。 对一个多分类的分割问题,对输出的每个位置,咱们能够判断其所属的类别。 在 FCN 的框架下,对于 N 分类问题,输出为 H/S × W/S × N。以后经过反向传播的方式进行训练。 分割和检测问题有一个区别是咱们有时须要获得和输入图片一样大小的输出(H × W × N),但卷积神经网络为了加速,一般会添加 pooling 层,减少中间卷积层的尺寸。 以下图所示,为了保证输出的尺寸知足要求,咱们能够在网络的最后添加反卷积层进行补偿,从而得到更大尺寸的输出。


实战: 人脸关键点检测

人脸关键点检测是如今视觉领域比较成熟的一项应用,是活体检测,人类美化,人脸识别等高级应用的基础。本文最后经过一我的脸关键点检测的例子,展现如何用 Tensorflow 实现图像回归类的应用。实验数据集采用 Kaggle 比赛中的 Faical Kerypoints Detection 数据集(https://www.kaggle.com/c/facial-keypoints-detection)。该数据集包含了 7094 张训练图片和 1783 张测试图片。数据集中的每一张人脸都有 15 个关键点的标注,图片的尺寸为 96x96。

L2 距离回归

Kaggle 比赛的目标是预测人脸上 15 个关键点的坐标,总共 30 个 float 值,属于标准的回归问题。咱们选择采用最多见的 l2 距离,做为优化的目标。和第一篇文章中神经网络模型的代码结构同样,咱们将代码分红了 3 个主要模块,分别是 Dataset 模块,Net 模块和 Solver 模块。

模型结构

  • inference咱们在 inference 函数中定义网络的主体结构。由于模型会重复用到全链接层和卷积层,所以咱们将他们封装成函数linear_reluconv_relu,从而方便复用代码。 网络结构上咱们采用了比较简单的 3 层卷积,2 层全链接的结构。卷积层的输出经过tf.reshape转化成了全链接层能够接受的格式。由于是回归问题,咱们直接将最后一层全链接层的结果做为输出。
  • loss为了简单,对于标准的回归问题,咱们使用 mse 做为损失函数tf.reduce_mean(tf.square(predictions - labels), name='mse')


测试时,咱们依旧使用 tensorflow 提供了 tf.metrics 模块,自动完成对每一个 batch 的评价,并将全部的评价汇总。在这个例子里,咱们是解决回归问题,所以可使用tf.metrics.mean_squared_error计算均方偏差。

Dataset 部分,咱们使用了 tensorflow 推荐的 tfrecord 格式。经过TFRecordDataset函数读取 tfrecord 文件,并经过parse_example将 tfrecod 转换成模型的输入格式。tfrecord 做为一种定长格式,能够大大加快数据的读取速递。特别在使用 GPU 时,能够防止数据 io 成为性能的瓶颈。

Solver

经过模块化的设计,咱们能够彻底复用第一篇文章中的 Solver 代码,而不须要任何修改,进而提升代码的复用效率。

实验结果

封装好借口以后,咱们能够经过上面简单的代码,完成模型的训练。下图是 tensorboad 中可视化的网络结构、loss 的统计以及模型在测试图片上的效果

能够看到,一个 3 层卷积 +2 层全链接的经典卷积神经网络,就能够很好的解决人脸关键点检测的问题。在实际中,咱们可使用更复杂的网络和一些其余 trick 来进一步提升模型性能。

做者简介

董健,360 高级数据科学家,前 Amazon 研究科学家。 目前主要关注深度学习、强化学习、计算机视觉等方面的科学和技术创新,拥有丰富的大数据、计算机视觉经验。曾经屡次领队参加 Pascal VOC、ImageNet 等世界著名人工智能竞赛并得到冠军。

博士期间在顶级国际学术会议和杂志上发表过多篇学术论文。从 2015 年末加入 360 至今,董健做为主要技术人员参与并领导了多个计算机视觉和大数据项目。

完整代码下载:

https://github.com/Dong--Jian/Vision-Tutorial

关注咱们的微信号"AI前线",后台回复“AI”可得到《AI前线》系列PDF电子书

相关文章
相关标签/搜索