计算机视觉(Computer Vision)的高速发展标志着新型应用产生的可能,例如自动驾驶、人脸识别、创造新的艺术风格。人们对于计算机视觉的研究也催生了很多机算机视觉与其他领域的交叉成果。一般的计算机视觉问题包括以下几类:
下面展示了一个神经风格转换(Neural Style Transfer)的例子:
使用传统神经网络处理机器视觉的一个主要问题是输入层维度很大。 例如一张64x64x3的图片,神经网络输入层的维度为12288。如果图片尺寸较大,例如一张1000x1000x3的图片,神经网络输入层的维度将达到3百万,使得网络权重W非常庞大。这样会造成两个后果:①神经网络结构复杂,数据量相对不够,容易出现过拟合;②所需内存和计算量较大。
因此,一般的神经网络很难处理蕴含着大量数据的图像。解决这一问题的方法就是使用卷积神经网络(CNN)。
我们之前提到过,神经网络由浅层到深层,分别可以检测出图片的边缘特征、局部特征(例如眼睛、鼻子等),到最后面的一层就可以根据前面检测的特征来识别整体面部轮廓。 这些工作都是依托卷积神经网络来实现的。
卷积运算(Convolutional Operation) 是卷积神经网络最基本的组成部分。我们以边缘检测为例,来解释卷积是怎样运算的。
最常检测的图片边缘有两类:一是垂直边缘(vertical edges),二是水平边缘(horizontal edges)。
图片的边缘检测可以通过与相应滤波器(filter)进行卷积来实现。 以垂直边缘检测为例,原始图片尺寸为6x6,滤波器filter尺寸为3x3,卷积后的图片尺寸为4x4,得到结果如下:
上图只显示了卷积后的第一个值和最后一个值。可以看到,卷积运算的求解过程是从左到右,由上到下,每次在原始图片矩阵中取与滤波器同等大小的一部分,每一部分中的值与滤波器中的值对应相乘后求和,将结果组成一个矩阵。
顺便提一下,∗
表示卷积操作。在计算机中这个符号表示一般的乘法,而在不同的深度学习框架中,卷积操作的 API 定义可能不同:在python中,卷积用conv_forward()
表示;tensorflow中,卷积用tf.nn.conv2d()
表示;keras中,卷积用Conv2D()
表示。
Vertical edge detection能够检测图片的垂直方向边缘。下图对应一个垂直边缘检测的例子:
如果将最右边的矩阵当作图像,那么中间一段亮一些的区域对应最左边的图像中间的垂直边缘。
图片边缘有两种渐变方式,一种是由明变暗,另一种是由暗变明。以垂直边缘检测为例,下图展示了两种方式的区别。实际应用中,这两种渐变方式并不影响边缘检测结果,可以对输出图片取绝对值操作,得到同样的结果。
垂直边缘检测和水平边缘检测的滤波器算子如下所示:
下图展示一个水平边缘检测的例子:
其他常用的滤波器还有 Sobel 滤波器和 Scharr 滤波器。它们增加了中间行的权重,以提高结果的稳健性。
上图展示的是垂直边缘检测算子,水平边缘检测算子只需将上图顺时针翻转90度即可。
在深度学习中,如果我们想检测图片的各种边缘特征,而不仅限于垂直边缘和水平边缘,那么filter的数值一般需要通过模型训练得到,类似于标准神经网络中的权重W一样由梯度下降算法反复迭代求得。CNN的主要目的就是计算出这些filter的数值。 确定得到了这些filter后,CNN浅层网络也就实现了对图片所有边缘特征的检测。
假设输入图片的大小为 n × n n×n n×n,而滤波器的大小为 f × f f×f f×f,则卷积后的输出图片大小为 ( n − f + 1 ) × ( n − f + 1 ) (n−f+1)×(n−f+1) (n−f+1)×(n−f+1)。
这样就会有两个问题:①每次卷积运算后,输出图片的尺寸缩小;②原始图片的角落、边缘区像素点在输出中采用较少,输出图片丢失边缘位置的很多信息。
为了解决这些问题,可以在进行卷积操作前,对原始图片在边界上进行填充(Padding),以增加矩阵的大小。通常将 0 作为填充值。
经过padding之后,原始图片尺寸为 ( n + 2 p ) × ( n + 2 p ) (n+2p) × (n+2p) (n+2p)×(n+2p),filter尺寸为 f × f f × f f×f,则卷积后的图片尺寸为 ( n + 2 p − f + 1 ) × ( n + 2 p − f + 1 ) (n+2p-f+1) × (n+2p-f+1) (n+2p−f+1)×(n+2p−f+1)。若要保证卷积前后图片尺寸不变,则p应满足: p = p= p= f − 1 2 {f-1}\over2 2f−1 。
因此,在进行卷积运算时,我们有两种选择:
在计算机视觉领域, f f f 通常为奇数。原因包括Same卷积中 p = p= p= f − 1 2 {f-1}\over2 2f−1 能得到自然数结果,并且滤波器有一个便于表示其所在位置的中心点。
Stride表示filter在原图片中水平方向和垂直方向每次的步进长度。之前我们默认stride=1。若stride=2,则表示filter每次步进长度为2,即隔一点移动一次。
设步长为 s s s,填充长度为 p p p,输入图片大小为 n × n n×n n×n,滤波器大小为 f × f f×f f×f,则卷积后图片的尺寸为:
注意公式中有一个向下取整(取比自己小的最大正整数)的符号,用于处理商不为整数的情况。向下取整反映着当取原始矩阵的图示蓝框完全包括在图像内部时,才对它进行运算。
值得一提的是,互相关(cross-correlations) 与 卷积(convolutions) 之间是有区别的。实际上,真正的卷积运算会先将filter绕其中心旋转180度,然后再将旋转后的filter在原始图片上进行滑动计算。 filter旋转如下所示:
其实,目前为止我们介绍的CNN卷积实际上计算的是相关系数,而不是数学意义上的卷积。但是,为了简化计算,我们一般把CNN中的这种“相关系数”就称作卷积运算。之所以可以这么等效,是因为滤波器算子一般是水平或垂直对称的,180度旋转影响不大; 而且最终滤波器算子需要通过CNN网络梯度下降算法计算得到,旋转部分可以看作是包含在CNN模型算法中。总的来说,忽略旋转运算可以大大提高CNN网络运算速度,而且不影响模型性能。
卷积运算服从结合律: ( A ∗ B ) ∗ C = A ∗ ( B ∗ C ) (A ∗ B) ∗ C = A ∗ (B ∗ C) (A∗B)∗C=A∗(B∗C)
对于3通道的RGB图片,其对应的滤波器算子同样也是3通道的。过程是将每个单通道(R,G,B)与对应的滤波器进行卷积运算求和,然后再将三个通道的和相加,将 27 个乘积的和作为输出图片的一个像素值。例如一个图片是6 x 6 x 3,分别表示图片的高度(height)、宽度(weight)和通道(#channel)。
不同通道的滤波器可以不相同。例如只检测 R 通道的垂直边缘,G 通道和 B 通道不进行边缘检测,则 G 通道和 B 通道的滤波器全部置零。当输入有特定的高、宽和通道数时,滤波器可以有不同的高和宽,但通道数必须和输入一致。
如果想同时检测垂直和水平边缘,或者更多的边缘检测,可以增加更多的滤波器组。例如设置第一个滤波器组实现垂直边缘检测,第二个滤波器组实现水平边缘检测。
若输入图片的尺寸为 n × n × n c n × n × n_c n×n×nc,filter的尺寸为 f × f × n c f × f × n_c f×f×nc,则卷积后的图片尺寸为 ( n − f + 1 ) × ( n − f + 1 ) × n c ′ (n-f+1) × (n-f+1) × n_c' (n−f+1)×(n−f+1)×nc′。其中, n c n_c nc为图片通道数目, n c ′ n_c' nc′为滤波器组的个数。
卷积神经网络的单层结构如下所示:
相比之前的卷积过程,CNN的单层结构多了激活函数ReLU和偏移量b。 整个过程与标准的神经网络单层结构非常类似:
相比之前的卷积过程,滤波器的数值对应着权重 W W W [ l ] [l] [l],卷积运算对应着 W W W [ l ] [l] [l]与 A A A [ l − 1 ] [l-1] [l−1]的乘积运算,所选的激活函数变为 R e L U ReLU ReLU。
我们来计算一下上图中参数的数目:每个滤波器组有3x3x3=27个参数,还有1个偏移量b,则每个滤波器组有27+1=28个参数,两个滤波器组总共包含28x2=56个参数。我们发现,选定滤波器组后,参数数目与输入图片尺寸无关。所以,就不存在由于图片尺寸过大,造成参数过多的情况。 例如一张1000x1000x3的图片,标准神经网络输入层的维度将达到3百万,而在CNN中,参数数目只由滤波器组决定,数目相对来说要少得多,这是CNN的优势之一。
最后,我们总结一下CNN单层结构的所有标记符号,设层数为 l l l。
下面介绍一个简单的CNN网络模型:
该CNN模型各层结构如上图所示。需要注意的是, a a a [ 3 ] [3] [3]的维度是7 x 7 x 40,将 a a a [ 3 ] [3] [3]排列成1列,维度为1960 x 1,然后连接最后一级输出层。输出层可以是一个神经元,即二元分类(logistic);也可以是多个神经元,即多元分类(softmax)。最后得到预测输出。
随着神经网络计算深度不断加深,图片的高度和宽度一般都是逐渐减小,而通道数是不断增加的。
一个典型的卷积神经网络通常包含有三种层:卷积层(Convolution layer)、池化层(Pooling layer)、全连接层(Fully Connected layer)。仅用卷积层也有可能构建出很好的神经网络,但大部分神经网络还是会添加池化层和全连接层,它们更容易设计。
池化层的作用是缩减模型的大小,提高计算速度,同时减小噪声提高所提取特征的稳健性。
采用较多的一种池化过程叫做最大池化(Max Pooling)。将输入拆分成不同的区域,输出的每个元素都是对应区域中元素的最大值,如下图所示:
池化过程类似于卷积过程,上图所示的池化过程中相当于使用了一个大小 f = 2 f=2 f=2的滤波器,且池化步长 s = 2 s=2 s=2。卷积过程中的几个计算大小的公式也都适用于池化过程。如果有多个通道,那么就对每个通道分别执行计算过程。
对最大池化的一种直观解释是,元素值较大可能意味着池化过程之前的卷积过程提取到了某些特定的特征,池化过程中的最大化操作使得只要在一个区域内提取到某个特征,它都会保留在最大池化的输出中。但是,没有足够的证据证明这种直观解释的正确性,而最大池化被使用的主要原因是它在很多实验中的效果都很好。
另一种池化过程是平均池化(Average Pooling),就是从取某个区域的最大值改为求这个区域的平均值:
池化过程的特点之一是,它有一组超参数,但是并没有参数需要学习。池化过程的超参数包括滤波器的大小 f f f、步长 s s s,以及选用最大池化还是平均池化。而填充 p p p则很少用到。
池化过程的输入维度为: n H × n W × n c n_H × n_W × n_c nH×nW×nc
下面介绍一个简单的数字识别的CNN例子:
图中,CON层后面紧接一个POOL层,CONV1和POOL1构成第一层,CONV2和POOL2构成第二层。特别注意的是FC3和FC4为全连接层FC,它跟标准的神经网络结构一致。最后的输出层(softmax)由10个神经元构成。
相比标准神经网络,对于大量的输入数据,卷积过程有效地减少了 CNN 的参数数量,原因有以下两点:
池化过程则在卷积后很好地聚合了特征,通过降维来减少运算量。
由于 CNN 参数数量较小,所需的训练样本就相对较少,因此在一定程度上不容易发生过拟合现象。 并且 CNN 比较擅长捕捉区域位置偏移。即进行物体检测时,不太受物体在图片中位置的影响,增加检测的准确性和系统的健壮性。
参考文档:吴恩达深度学习笔记