7 卷积神经网络
如果你现在有一张图片,其只是一个二值图或是灰度图,那么它的通道数是1,也就是说,每一张图实际上都是一个矩阵(二维张量);但是遇见彩色的RGB三通道图你怎么处理呢?当我们仅仅通过将图像数据展成一维向量而忽略了每个图像的空间结构信息,将数据送入一个全连接的多层感知机中。因为这些网络特征元素的顺序是不变的,因此最优的结果是利用先验知识,即利用相近像素之间的相互关联性,从 图像数据中学习得到有效地模型。
本章介绍的卷积神经网络
是一类强大的、为处理图像数据而设计的神经网络。基于卷积神经网络架构的模型在计算机视觉(compute vision)领域中已经占主导地位,当今几乎所有的图像识别、目标检测或语义分割相关的学术竞赛和商业应用都以这种方法为基础。
如检测任务:
如分类和检索任务:
超分辨率重构:
医学任务等:
无人驾驶:
人脸识别:
卷积神经网络需要的参数少于我们前面学的那种全连接架构的网络例如多层感知机那样的,而且卷积也很容易用GPU并行运算。因此卷积神经网络除了能够高效地采样从而获得精确的模型,还能够高效地计算。所以不管是语音识别还是自然语言处理还是图像识别,从事相关工作人员都喜欢用CNN去处理。
在本讲中,我们将介绍构成所有卷积网络包含的基本元素。这包括卷积层
本身、填充(padding)
和步幅(stride)
的基本细节,还有用于在相邻区域集聚信息的汇聚层(pooling)
,在每一层中多通道(channel)
的使用,以及有关现代卷积网络架构的仔细讨论。
7.1 卷积网络和传统网络的区别
以下是传统网络和卷积神经网络的对比。
相比于传统的神经网络,卷积神经网络的输出不再是一维的张量,而是三维张量。
让我们来看看卷积神经网络的整体架构:
在前面openCV的学习中,我们学过高斯滤波器。实际上,高斯滤波器可以看做是一个卷积核。卷积层一般由卷积核提取图像特征,经由卷积核提取后的图像数据称为卷积层
;有时提取特征后的卷积层图像数据可能过于庞大,需要做压缩,此时就会用一个汇聚窗口去扫描卷积层的图像,使之输出称为池化层(汇聚层);当以上的图片处理过程结束后,后面再跟上一个多层感知机,就能够很好地处理图像数据。
7.2 卷积
7.2.1 卷积过程画大饼
我们来通过下面的图来看看卷积神经网络中的卷积干了一件什么事。
让我们回忆一下在之前openCV的学习中,我们曾经用Sobel算子和原图像进行互相关运算
,使不同的区域边缘特征增强,从而获得边缘检测的效果。
那么如果我们要在卷积神经网络网络中我们如何进行特征提取?我们姑且谈论灰度图或二值图,因为通道数为1。我们首先是将一张图像分为若干个区域,每个区域的大小和扫描的卷积核大小一样大。假设我们用一个3×3的卷积核去扫描原图像,那么在这个卷积核上带有一组权重参数,它能够和原图像中的某一块区域像素值x进行互相关计算,使得计算出一个值y,这个值让我们姑且称呼它为特征对应的评分
吧。
如果你还指定了偏置b,那么上述过程实际上符合前面的线性模型:y = wx+b。对于图像中每一个像素点,我们都把他当做特征,与卷积核上的权重参数w做内积(互相关运算),所得结果加上偏置b后则称为我们的输出值y,对于卷积层,无非就是按位置排列好的关于y的多维矩阵。
7.2.2 图像的不变性
让我们思考上述卷积过程的一些细节。
如果是你自己,抛开这个学科不讲,就你自己,你如果想在一张图片中找到某个物体,拿到一张图片,我们可以知道的绝对是:物体和所在位置无关。比如说猪会飞,飞机会下海,哥斯拉会出现在你家门口,这些实际上在图片中是不奇怪的。
让我们看一下下面的图:
果给你这张图,要你在里面找一个人,你能找到吗?你要怎么找?按照卷积的过程,如果你想找到这个人,你可以把这种图片切割成n份,然后给每份的区域打个分(表示这个人可能在这部分被切割区域的可能性)。
对此,我们说卷积过程是保持两个特性的:
- 平移不变性:不管检测对象出现在图片的哪个位置,神经网络的前面几层应该对相同的图像区域反应都一样,你不能说猪就不能上天了是吧。
- 局部性:神经网络的前面几层应该只探索输出图像的局部区域(也就是图片被分割的那一小块),而不是过度去在意图像中相隔较远区域的关系。也就是说,我们如果是想找到一个人,那么我们只需要在分割的区域中找到人就行,而不是直接在图像的整体找到人。
7.2.3 互相关运算*(补充)
严格来说,卷积层是个错误的叫法,因为它所表达的运算其实是互相关运算,而不是卷积运算,在卷积层中,输入张量
和卷积核张量
通过互相关运算
产生输出张量
。
首先我们暂且忽略通道这一要素,看看如何处理二维图像数据和隐藏表示。假如现在输入是高度为3,、宽度为3的二维张量。卷积核高度和宽度都是2,而卷积核的输出结果由内核的高度和宽度决定。如下图所示:
上图说明了,卷积层上的19是根据卷积核去扫描输入图像然后做计算得出的结果。
根据上面的原理,我们可以知道,输出大小等于输入$n_h×n_w$减去卷积核大小$k_h×k_w$,(注:h为height长度,w为weight宽度)即:
$(n_h-k_h+1)×(n_w-k_w+1)$
这是因为我们需要足够的空间在图像上“移动”卷积核。稍后,我们将看到如何通过在图像边界周围填充零(零填充)来保证有足够的空间移动内核,从而保持输出大小不变。
7.2.4 图像颜色通道*(补充)
这一部分实际上在openCV的学习中应该就很明了了,如果你不是很清楚,可以看一下下面。
对于一张彩色图片来说,通常是由三色通道叠加而成,如下所示:
由此可见,图片不是一个二维张量,而是一个由高度、宽度和颜色组成的三维张量。
比如一张包含1024×1024×3个像素。那么实际上就是表示这个图片的长和宽都是1024个像素点,且有三个通道。
比如这张图片的RGB值是(0,255,0),则表明这张图片的R(红色)和B(蓝色)最暗,而G(绿色)最亮。也就是说,在RGB的值中,值越大,说明对应的通道颜色越亮。
那在卷积中是怎么处理多通道的图片的?同样地,它也是用一个多层卷积核去扫描原图像,由于图像是多通道,所以用同一个卷积核的不同层对每一层通道的同一个位置扫描得出的结果进行相加。如图所示:
上面可能有点晦涩难懂,让我们看一下全局过程。
对于Output Volume中的3是怎么来的?原图像有三层,所以我们也要选择一个三层的卷积核。在上述的过程中,我们选定用3×3×3的卷积核$Filter W_0$去扫描图像,卷积核的第一层扫描图像第一层的第一块区域时,卷积核上的权重参数和图像中的像素做互相关运算,所得结果为-1+1 = 0,卷积核的第二层扫描图像第二层的第一块区域时,所得结果为2;同理第三层所的结果为0。又因为我们的线性模型是wx+b,我们又指定了b的初始化值为1,则对于y即卷积层为该为0+2+0+1 = 3。
那上面怎么还有一个$FilterW_1$?而且Output Volume有两层?这是因为有时候卷积层可以不止一层。
我们在平时谈论的时候,相对于提取特征来说,我们把输出的结果叫做特征图
;而当相对于卷积核时,我们把输出的结果叫做卷积层
。
特征图可以有多个,当我们用多个相同大小的卷积核
去扫描图像时,就可以得到更多的特征图。如下所示:
以上这些特征图堆叠而成了卷积层。
7.2.5 步幅
卷积核移动的步幅决定了输出的特征图的大小。
一般来说,我们默认滑动卷积核都是一步。但是有时候为了高效计算或是缩减采样次数,卷积核可以每次滑动多个元素。
还是拿以上的这幅图来说,为什么我们输出的Output Volume才3×3,正是因为每次卷积核滑动的步幅为2。
7.2.6 多次卷积
以上的步骤中,我们都是对原图像做了一次卷积。那么对原图像仅仅只做一次卷积就够用了吗?
在CNN中,对输入进来的图像仅仅只做一次卷积是不够的。在第一次卷积后得出的特征图中,我们需要在这张特征图再一次进行卷积操作,多次提取特征。
当然,卷积次数不是说越多越好,到了某个程度就停了。在后面的小节中我们再去讨论这个问题。
7.2.7 边缘填充
如果进行多次卷积的话,很容易丢失边缘像素。还是这幅图:
对于以上这幅图,我们在原图像的外围实际上进行了零填充,即最外圈填充了一圈零。而对于最外圈的像素点来说,它能够被卷积核扫描到的次数只有一次。也就是说,图片最外圈的特征可能在逐次的卷积中慢慢的卷没了;而对于图片较内区域的像素点,它可以被卷积核多次扫过,特征保留较完整。
假设图像的大小为nxn,过滤器是fxf,那么卷积运算的结果为(n-f+1)x(n-f+1)。
- 卷积运算后图像会缩小,经过若干次卷积运算图像和图像的特征可能会缩小
- 卷积运算中覆盖边缘和角落的像素点比中间像素点少,导致丢失图像边缘信息
为了解决这一问题,引入填充Padding。
填充在一般来说都是在边缘填充0,我们也叫零填充
。当然,也可以不是0。当我们在最外圈填充了数值之后,拿零举例,填充后的图片如下所示:
这样的话,对于原图片边缘的特征像素点,能够被卷积核扫描的次数就变多了。
当然,零填充也有好处。如果你不是用0而是用1去填充,那么很可能在做互相关运算时,输出的结果会影响到特征图,而是如果你用0,互相关的结果仍然是0,不会过度影响最终结果。
当然,填充也可以不止填充一圈,也可以填充多圈,看需求而定。
7.2.8 特征图的大小
特征图的大小是有计算公式的:
- 长度:$H2 = \frac{H_1-F_H+2P}{S}+1$
- 宽度:$W2 = \frac{W_1-F_W+2P}{S}+1$
其中$W_1、H_1$表示输入的宽度、长度;$W_2、H_2$表示输出特征图的宽度、、长度;F表示卷积核长和宽的大小,S表示滑动窗口的步长,P表示边界填充(加了几圈)。
7.2.9 卷积参数共享
有时候我们可能会有些疑问,对于一张图片不同的区域,我们不用不同的卷积核去扫呢?
如果采用不同的卷积核,就意味着卷积核中的权重参数不一样,也就意味着w要变多。记得我们前面提到的过拟合吗?导致过拟合的原因之一就是参数过多。所以为了防止过拟合,也为了高效计算,我们采用同一个卷积核扫遍整张图片。
对于32×32×3的图像,如果用10个5×5×3的卷积核来卷积,那么所需的参数为750个,而且这还不算上b,如果每个卷积核都有一个对应的偏置参数,最终需要750+10 = 760个参数。
记得我们前面还讲过全连接开销非常大吗?如果不用卷积参数共享来做卷积,那么使用全连接的话,就是32×32×3 = 3072个参数,恐怖如斯,开销巨大,这也是为什么在多层感知机中我们采用暂退法通过减少结点来减少参数的缘故。
7.3 池化
如果一张图片的像素点非常多,在做完一次卷积后仍然保留有非常多的像素点(特征),那么使用池化(汇聚)就能够压缩图片的特征。
图片的特征压缩不是随便说丢就丢了,需按照一定的规律。按照不同的规律进行池化,我们可以把池化分为两类。
与卷积核类似,池化也是用一个固定形状的窗口组成,该窗口根据其步幅大小在输入的所有区域上滑动,为固定形状窗口(有时称为汇聚窗口)遍历的每个位置计算一个输出。然而,不同于卷积层中的输入和卷积核之间的互相关计算,汇聚窗口不包含参数,我们通常计算汇聚窗口中所有元素的最大值或平均值,所得的输出结果我们称为汇聚层(池化层)
,而这些操作分别称为最大汇聚(最大池化)
和平均汇聚层(平均池化)
。
在这两种情况下,汇聚窗口都是从输入张量的左上角开始,从左往右、从上往下的在输入张量内滑动。在汇聚窗口到达的每个位置,它计算该窗口中输入子张量的最大值或平均值。计算最大值或平均值是取决于使用了最大汇聚层还是平均汇聚层。
举个例子,用2×2的汇聚窗口去扫描,如果窗口内的值是
max(0,1,3,4)=4,
max(1,2,4,5)=5,
max(3,4,6,7)=7,
max(4,5,7,8)=8。
汇聚窗口形状为p×q的汇聚层称为p×q汇聚层
,汇聚操作称为p×q汇聚
。
7.4 整体网络架构
CNN完整的网络架构可以用下面的图片来描述:
对于一张输入而来的图片,我们会经过多次卷积和多次池化。需要知道的是,在每次卷积后,我们都会用ReLu修正线性单元来激活。而对于卷积核池化,实际上都是在处理图片而已,如果要做出最终分类的效果,我们需要将处理好的图片输入全连接层。
全连接层无法接收多维的图片,所以在输入前,多维图片会被拉伸成一维的特征向量来输入到全连接层中,后面的操作和前面分类的操作完全一样,这里不再赘述。
我们在谈论一个网络多少层时,一般看他带不带参数计算。如上面的例子,实际上只有6层卷积层和1层全连接层,为七层神经网络。
在整体网络的运行时,特征图的变化如下:
7.5 后话
相信经过上面的学习,你应该是对卷积神经网络在做啥事有个大局观了。在后面的学习中,我们会看到多个经典的卷积神经网络如Alexnet、VGG等。当然这都是后话,今天你也累了,早点休息。