【TensorFlow小记】CNN初探

介绍卷积神经网络(CNN)的概念、网络结构、基本模块、特点等等。

一、介绍

  CNN的全拼是Convolutional Neural Networks,直译过来就是卷积神经网络
  CNN最初主要用来做图片分类、目标检测等图像相关的任务。

1. 什么是卷积

  简单介绍一下卷积运算,卷积运算作用就是用滤波器来学习或者检测图片的特征。
convolution_operation_static.png
  看上图,左边是一张5×5的黑白图片,现在是矩阵的形式,每个格子代表一个像素点。中间的3×3的矩阵叫做滤波器,也可以叫做卷积核。星号代表的就是卷积运算,用滤波器对左边的图片做卷积运算,得出3×3的矩阵。
  具体怎么算呢?先说结果的第一个元素:就是用滤波器,覆盖在图片的左上角,对应的每格元素相乘,得到9个数字,最后把这9个数字相加,就得到了第一个元素。滤波器在图片上右移一格,再计算就得到了第二个元素,之后的元素同理。
  通过滑动卷积核,就可以得到整张图片的卷积结果,如下图所示:
convolution_operation_gif.gif
  卷积公式如下,其中S SS代表运算结果,I II是原始图片,K KK是卷积核,m mm、n nn是卷积核的高和宽,括号中的两个值代表元素的位置:
convolution_formula.png

其实该函数叫互相关函数(cross-correlation),和卷积函数几乎一样,只是没有对卷积核进行翻转,很多深度学习的库实现的都是这个函数而并非真正的卷积函数。在深度学习中我们默认它为卷积函数。

2. 卷积神经网络结构

  现在知道卷积运算了,那么CNN呢?我们知道神经网络的结构是这样的:
neural_network.jpg
  其实卷积神经网络依旧是层级网络,只是层的功能和形式做了变化,可以说是传统神经网络的一个改进。比如下图(识别交通工具)中就多了许多传统神经网络没有的层次。
cnn_traffic.jpg

二、CNN基本模块

  CNN由输入和输出层以及多个隐藏层组成,隐藏层可分为卷积层池化层ReLU激励层全连接层

1. 输入层

  CNN的输入一般是二维向量,可以有高度,比如,RGB图像。如果是黑白图片,高度是1;如果是彩色图片,高度是3。

2. 卷积层

  卷积层是CNN的核心,可以简单理解为:卷积层用于对输入层进行卷积,提取更高层次的特征。
  在这个卷积层,有两个关键操作:
  • 局部关联。每个神经元看做一个滤波器(filter)
  • 窗口(receptive field)滑动,filter对局部数据计算

  先介绍卷积层遇到的几个名词:
  • 深度/depth(解释见下图)
  • 步长/stride(每隔多少步采集一下,设置为1就是全采样)
  • 填充值/zero-padding
cnn_conv_layer.png
  图中的滑动窗口,就是一个过滤器。过滤器会从左上角到右下角一点一点移动,采集图片的信息(类似用一个手电筒去一格一格地扫描)。

  填充值是什么呢?以下图为例子,比如有这么一个 5*5 的图片(一个格子一个像素),我们滑动窗口取 2*2,步长取2,那么我们发现还剩下1个像素没法滑完,那怎么办呢?
cnn_zero_padding_01.png
  那我们在原先的矩阵加了一层填充值,使得变成 6*6 的矩阵,那么窗口就可以刚好把所有像素遍历完。这就是填充值的作用。
cnn_zero_padding_02.png

  讲下比较重要的卷积的计算。如果大学里《线性代数》学的不错的话,这里会比较好理解。
  下面的动态图形象地展示了卷积层的计算过程:
  蓝色矩阵就是输入的图像,它周围有一圈灰色的框,那些就是上面所说到的填充值。
  粉色矩阵就是卷积层的神经元,这里表示了有两个神经元(w0, w1)。
  绿色矩阵就是经过卷积运算后的输出矩阵,这里的步长设置为2。
  蓝色的矩阵(输入图像)对粉色的矩阵(filter)进行矩阵内积计算并将三个内积运算的结果与偏置值b相加,计算后的值就是绿框矩阵的一个元素。
cnn_conv_calc.gif

  参数共享机制
  • 在卷积层中每个神经元连接数据窗的权重是固定的,每个神经元只关注一个特性。神经元就是图像处理中的滤波器,比如边缘检测专用的Sobel滤波器,即卷积层的每个滤波器都会有自己所关注一个图像特征,比如垂直边缘,水平边缘,颜色,纹理等等,这些所有神经元加起来就好比就是整张图像的特征提取器集合。
  • 需要估算的权重个数减少: AlexNet 1亿 => 3.5w
  • 一组固定的权重和不同窗口内数据做内积: 卷积
cnn_filters.png

3. ReLU激励层

  作用:把卷积层输出结果做非线性映射。
  看了这句话其实比较懵。
  一言以蔽之,其实,relu函数的作用就是增加了神经网络各层之间的非线性关系,否则,如果没有激活函数,层与层之间是简单的线性关系,每层都相当于矩阵相乘,这样怎么能够完成我们需要神经网络完成的复杂任务。
  我们利用神经网络去解决图像分割,边界探测,超分辨等问题时候,我们的输入(假设为x),与期望的输出(假设为y)之间的关系究竟是什么?也就是 y=f(x) 中,f是什么,我们也不清楚,但是我们对一点很确信,那就是f不是一个简单的线性函数,应该是一个抽象的复杂的关系,那么利用神经网络就是去学习这个关系,存放在model中,利用得到的model去推测训练集之外的数据,得到期望的结果
  
  这里我为什么直接叫ReLU激励层呢,因为CNN采用的激励函数一般为ReLU(The Rectified Linear Unit/修正线性单元),它的特点是收敛快,求梯度简单。
  当然ReLU只是一种选择,还有选LeakyReLU等等,目前我只是初学,就不深究了,参考别人的一个实践经验:
  ① 不要用sigmoid!不要用sigmoid!不要用sigmoid!(强调了三次)
  ② 首先试ReLU,因为快,但要小心点
  ③ 如果②失效,请用LeakyReLU或者Maxout
  ④ 某些情况下tanh倒是有不错的结果,但是很少

4. 池化层

  池化层又称亚采样,它夹在连续的卷积层中间,用于压缩数据和参数的量,减小过拟合,同时保留有用信息。
  简而言之,如果输入是图像的话,那么池化层的最主要作用就是压缩图像。
  它是怎么做到的呢?
  通常池化层是每邻域四个像素中的最大值变为一个像素(就是后面会讲到的max_pooling),为什么可以这么做呢?这是因为卷积已经提取出特征,相邻区域的特征是类似、近乎不变的,这时池化只是选出最能表征特征的像素,缩减了数据量,同时保留了特征,何乐而不为呢?池化层的作用可以描述为模糊图像,丢掉了一些不是那么重要的特征。
  下面这张图就是描述了池化的作用:
cnn_pooling_layers.jpg
  这里再展开叙述池化层的具体作用。
  • 特征不变性,也就是我们在图像处理中经常提到的特征的尺度不变性,池化操作就是图像的resize,平时一张狗的图像被缩小了一倍我们还能认出这是一张狗的照片,这说明这张图像中仍保留着狗最重要的特征,我们一看就能判断图像中画的是一只狗,图像压缩时去掉的信息只是一些无关紧要的信息,而留下的信息则是具有尺度不变性的特征,是最能表达图像的特征。
  • 特征降维,我们知道一幅图像含有的信息是很大的,特征也很多,但是有些信息对于我们做图像任务时没有太多用途或者有重复,我们可以把这类冗余信息去除,把最重要的特征抽取出来,这也是池化操作的一大作用。
  • 在一定程度上防止过拟合,更方便优化。
cnn_downsampling.jpg
  池化层用的方法有 max_pooling 和 average_pooling,而实际用的较多的是max_pooling。
  这里就说一下max_pooling,其实思想非常简单。
  对于每个 2*2 的窗口选出最大的数作为输出矩阵的相应元素的值,比如输入矩阵第一个 2*2 窗口中最大的数是6,那么输出矩阵的第一个元素就是6,如此类推。(见前面的图)

5. 全连接层

  这个层就是一个常规的神经网络,它的作用是对经过多次卷积层和多次池化层所得出来的高级特征进行全连接(全连接就是常规神经网络的性质),算出最后的预测值。
  通常全连接层在卷积神经网络尾部。也就是跟传统的神经网络神经元的连接方式是一样的:
neural_network.jpg

6. 输出层

  输出层就不用介绍了,就是对结果的预测值,一般会加一个softmax层。
  softmax:分类器,应用于分类问题,位于卷积神经网络层的最后一层。
  softmax意义:输出输入图片,对应概率最大的类别,以及属于该类别的可能性概率。

三、CNN的特点

  这里主要讨论CNN相比与传统的神经网络的不同之处,CNN主要有三大特色,分别是局部感知权重共享多卷积核

1. 局部感知

  局部感知就是我们上面说的感受野,实际上就是卷积核和图像卷积的时候,每次卷积核所覆盖的像素只是一小部分,是局部特征,所以说是局部感知。CNN是一个从局部到整体的过程(局部到整体的实现是在全连通层),而传统的神经网络是整体的过程。

2. 权重共享

  传统的神经网络的参数量是非常巨大的,比如1000X1000像素的图片,映射到和自己相同的大小,需要(1000X1000)的平方,也就是10的12次方,参数量太大了,而CNN除全连接层外,卷积层的参数完全取决于滤波器的设置大小,比如10x10的滤波器,这样只有100个参数,当然滤波器的个数不止一个,也就是下面要说的多卷积核。但与传统的神经网络相比,参数量小,计算量小。整个图片共享一组滤波器的参数。

3. 多卷积核

  一种卷积核代表的是一种特征,为获得更多不同的特征集合,卷积层会有多个卷积核,生成不同的特征,这也是为什么卷积后的图片的高,每一个图片代表不同的特征。

四、CNN实现架构

  这里以LeNet-5为例,一个典型的用来识别数字的卷积网络,当年美国大多数银行就是用它来识别支票上面的手写数字的。能够达到这种商用的地步,它的准确性可想而知。
  LeNet-5主要有7层(不包括输入和输出),具体框架如图:
cnn_LeNet-5.png
  流程: 输入层——>第一层卷积层——>第一层池化层——>第二层卷积层——>第二层池化层——>三层全连通层——>输出层
  详解: 输入是一个2维的图片,大小32X32,经过第一层卷积层,得到了C1层的6个28X28的特征映射图,6个说明了第一层卷积层用了6个卷积核。这里卷积后大小变成28X28,这是因为卷积有两种,一种有填充,卷积后与原图像大小一样,另一种不带填充,卷积后结果与原图像相比,小了一些。然后经过第一层池化层,28X28变成了14X14,一般是每邻域四个像素中的最大值变为一个像素,相应图片的长和宽各缩小两倍。然后又经过一个卷积层,变成了C3层的16个10X10的特征映射图,然后又经过一个池化层,得到S4层的16个5X5的特征映射,然后将这16个5X5的特征映射送到3层的常规神经网络,得出最后的结果。
  总结: 我们可以这样想,前面的卷积层和池化层是为了提取输入的高级特征,送到全连通层的输入,然后训练出最后的结果。

五、dropout

  dropout是一种正则化的方法,应用在CNN中,主要解决CNN过拟合的问题。
  怎么理解这个东西呢,首先我们要知道为什么过拟合?这是因为神经网络的神经元过多,参数过多,导致训练集拟合得太好了,为此,我们想dropout(丢掉)一些神经元,让它不产生影响。
  具体做法: 在每个隐藏层的输入进行一个概率判决,比如我们设置概率为0.5(通常命名为keep_prob),根据0.5,我们生成一个跟隐藏层神经元个数的向量,true:false的比例是1:1(因为keep_prob=0.5),与隐藏层的输入进行相乘,那么会有一半隐藏层的神经元被丢掉,不起作用,整个网络变得简单了,就会从过拟合过渡到just right 。这是组合派的说法,andrew也是这么讲的,文末链接中还有一派噪声派的说法,也很有意思,可以看看!
  图形理解(这个keep_prob等于0.4,即2/5):
cnn_dropout.png

六、总结

  这篇主要是CNN初探后的学习笔记,理解一些基础概念、知道大体的运行流程。当中有很多地方需要进一步研究,第一步先了解到这里。


参考
https://www.cnblogs.com/fydeblog/p/7450413.html
https://www.cnblogs.com/skyfsm/p/6790245.html
https://www.cnblogs.com/zf-blog/p/7794490.html
https://blog.csdn.net/fate_fjh/article/details/52882134


  转载请注明: 文渊博客 【TF小记】CNN初探

  目录