本文是吴恩达深度学习第四课:卷积神经网络。本次课程将会告诉大家如何构造卷积神经网络并应用到图像数据上。从中你会学到如何构建一个卷积神经网络、如何应用卷积神经网络到图像识别和目标检测上、学习如何使用神经风格转换去生成艺术作品、能将这些算法应用到更广泛的图像应用上,比如2D、3D数据和视频。
第四课有以下四个部分,本文是第一部分。
受益于深度学习,计算机视觉(Computer Vision,CV)是目前快速发展的领域之一。
计算机视觉能帮助自动驾驶汽车、也使面部识别比以前要更好、还可来进行相似图片搜索等。
下面列出将在本系列课程学习的计算机视觉问题的例子。
我们已经见过图像识别(图像分类)的例子了。
这是目标检测的例子,如果能识别图像里的汽车,这样你的车就能避开它们。
上面是神经风格转换(神经风格迁移)的例子,你把一张美女的图片用毕加索的画作尝试重绘,就可以创造出新的艺术作品。
计算机视觉问题的一个挑战是输入可以任意大,比如第一个图像分类的例子,输入是 64 × 64 × 3 = 12288 64\times 64 \times 3=12288 64×64×3=12288,因为是彩色RGB图像。 但是 64 × 64 64\times 64 64×64实际上是一个非常小的图片,像素点不够多,
如果用更大的图像,比如1M大小的图片,输入就是 1000 × 1000 × 3 = 3000 , 000 1000 \times 1000 \times 3=3000,000 1000×1000×3=3000,000。
如果你有300万的输入特征,
这里用 3 m 3m 3m来表示300万,假设你隐藏层有1000个单元,就意味着你会有 1000 × 3000 , 000 = 3 ∗ 1 0 10 1000 \times 3000,000 = 3*10^{10} 1000×3000,000=3∗1010 30亿个参数!
有这么多参数很难获得足够的数据以避免神经网络过拟合,同时训练一个有30亿个参数的神经网络不知道需要多强的计算量和多大的内存。
为了解决这个问题,需要用到卷积运算,下面用边缘检测的例子来阐述卷积运算。
卷积运算是卷积神经网络的基础组成单元之一,我们用边缘检测的例子来阐述卷积运算。
在前面的文章中我们已经知道神经网络的前几层是如何检测边缘的,我们看一下后面的几层,后面的几层可能会检测目标对象的某些部分,再后面的几层可能会检测到整个目标对象。比如此例中的人脸。
在本节你将看到如何在一个图像中进行边缘检测,举个例子来看。
给出一张这样的图像,让电脑算出这张图片中的物体是什么。
那么做的第一件事情可能是检测图片中的垂直边缘,
比如在这个图像中垂直的线是栅栏所在的地方,还有行人的轮廓也比较垂直,因此在这个垂直边缘检测结果中它们被检测出来了。
你也可能要检测水平边缘,
比如一个非常明显的水平线段是在栅栏栏杆的地方,如上图绿线所示。
那么你怎样才能在这样的图像中检测边缘呢,我们来看一个例子。
这里是一个 6 × 6 × 1 6\times 6 \times 1 6×6×1的灰度图像,为了检测这个图像中的垂直边缘,你可以建立一个 3 × 3 3 \times 3 3×3的矩阵,用卷积神经网络中的术语来说它被叫做过滤器(filter)。
对这个 6 × 6 6 \times 6 6×6的图像,进行卷积运算(convolution operation,这里用*
表示),这个卷积运算的输出将会是一个 4 × 4 4 \times 4 4×4的矩阵,你可以看成是一个 4 × 4 4 \times 4 4×4的图像。
为了计算第一个元素,我们使用这个 3 × 3 3 \times 3 3×3的过滤器,将其覆盖在输入图像上上面的 3 × 3 3 \times 3 3×3区域,然后用被覆盖的那块区域与过滤器做元素乘法(对应元素相乘,然后相加)运算,结果是 − 5 -5 −5,然后写到 4 × 4 4 \times 4 4×4矩阵的左上角第一个元素位置。
接下来要计算第二个元素的值,做法是把蓝色的方块向右移动一步。然后进行同样的运算即可。
继续右移一步,就得到第三个元素的值。
这样就可以得到第一行的结果,接下来为了得到下一行的元素,要做的是把蓝色方块下移,注意下移的方式。
重复这个运算得到 − 10 -10 −10,以此类推,就可以得到这个 4 × 4 4 \times 4 4×4的结果。
因此 6 × 6 6 \times 6 6×6的矩阵和 3 × 3 3 \times 3 3×3的矩阵进行卷积运算得到的是 4 × 4 4 \times 4 4×4的矩阵。
这个 4 × 4 4 \times 4 4×4的矩阵我们可以理解为是另一张图片,可以把这个过滤器看成是垂直边缘检测器。
为什么这个可以做垂直边缘检测呢,我们来看一个简化的例子,
假设有张这样的图片,它的左边都是10,右边都是0。看起来是这样的:
在这个图片中间有一个明显的垂线。所以当你用一个 3 × 3 3 \times 3 3×3的过滤器进行卷积运行时,这个过滤器可视化为下面这个样子。
卷积运算后你得到下图右边这样一个 4 × 4 4\times 4 4×4的矩阵:
如果把这个矩阵可视化为图像的话:
中间有一块亮一点的区域,对应检测到这个 6 × 6 6 \times 6 6×6图像中间的垂直边缘。
但是这里的维数似乎不对,因为看起来检测到的边缘太粗了。这是因为在这个例子中,图片太小了。如果用一个大一点的图片,你会看到确实可以很好地检测到垂直边缘。
从这个边缘检测例子可以得到的启发是,过滤器左边是一个比较亮的区域,中间的不需要考虑,右边是深色的区域。
在这个 6 × 6 6 \times 6 6×6图像中匹配到的上图所示的部分,被视为一个垂直边缘。
这是上节介绍的垂直边缘检测例子,左边比较亮,而右边比较暗;那如果把颜色翻转一下,结果会如何呢
用同样的过滤器进行卷积的话,最后得到的中间部分是 − 30 -30 −30而不是 30 30 30。可视化的结果就是这部分颜色比较深,表明这是由暗向亮过渡。
我们已经知道这个过滤器可以检测垂直边缘,那如果要检测水平边缘呢,不难猜到:
将垂直边缘的过滤器“扳倒”就行了。
这种写法的水平边缘,表示上方较亮而下方较暗。
这个给个更复杂的例子,它的左上方和右下方都是亮度为10的点,可视化的结果是这样的:
如果与水平边缘过滤器做卷积就会得到下面这个:
结果矩阵中绿框框出来的30是用原图绿框框出来的部分计算的
在绿框这块区域确实是上边较亮而下边较暗。而紫框框出的-30则相反,是上边较暗而下边较亮。
因为我们的原图只是 6 × 6 6 \times 6 6×6大小的,假如是 1000 × 1000 1000 \times 1000 1000×1000非常大的图像,就不会出现上图橙框中的10这种过渡带了。
总之,使用不同的过滤器可以让你找出垂直或水平边缘。
实际上这里我们只用了一种数字组合,人们曾经争论过使用哪种数字组合才是最好的。
随着深度学习的发展,你可以把这里面的数字当成参数,让算法去自己学习。
通常算法学习到数字值的过滤器甚至比人们设置的过滤器表现更好,相比垂直和水平边缘检测器,它甚至可以检测出倾斜一定角度(比如45°或75°)的边缘。
还有一个构建卷积神经网络的基本操作是填充,
我们之前图像是 6 × 6 6 \times 6 6×6的,用一个 3 × 3 3 \times 3 3×3的过滤器做卷积,可以得到 4 × 4 4 \times 4 4×4的结果矩阵。
这背后有一个数学公式,如果我们有一个 n × n n \times n n×n的图像,用一个 f × f f \times f f×f的过滤器做卷积,那么得到的结果矩阵大小将是 ( n − f + 1 ) × ( n − f + 1 ) (n - f +1) \times (n - f +1) (n−f+1)×(n−f+1)
这样其实有两个缺点,第一个是你每次做卷积后你的图像都会变小,第二个缺点是角落边的像素点只被一个输出所使用,或者说只经历过一次运算。
而中间部分的像素点会被计算多次,这意味着你丢掉了边缘部分的很多信息。
为了解决这两个问题,你可以在对原图进行卷积运算前,填充这幅图像,比如沿着边缘填充一层像素。
那么 6 × 6 6 \times 6 6×6的图像就会被填充成 8 × 8 8 \times 8 8×8的图像。
如果用这个 8 × 8 8 \times 8 8×8与 3 × 3 3 \times 3 3×3过滤器做卷积的话,就得到一个 6 × 6 6 \times 6 6×6的和原图大小一样的矩阵。
那填充出来的像素点的值是什么呢,一般是 0 0 0。
这里 p p p记为填充的数量,我们这个例子中是 p = 1 p=1 p=1。因为我们在原图周围都填充了一个像素点。
那么输出大小公式就变成了 ( n + 2 p − f + 1 ) × ( n + 2 p − f + 1 ) (n + 2p -f + 1) \times (n + 2p -f + 1) (n+2p−f+1)×(n+2p−f+1)
这样原来角落部分的像素点也能被计算多次了。
我们这里填充了1个像素,那一般需要填充多少个呢。通常有两个选择,叫Valid卷积和Same卷积。
Valid卷积 就是不填充,而Same卷积就是填充后输出大小要和原图大小保持一致(Same)。
可以用 n + 2 p − f + 1 n + 2p -f + 1 n+2p−f+1(输出大小)这个公式来计算需要填充的个数。
令输出大小等于原大小:
n + 2 p − f + 1 = n 2 p = f − 1 p = f − 1 2 n + 2p -f + 1 = n \\ 2p = f - 1\\ p = \frac{f-1}{2} n+2p−f+1=n2p=f−1p=2f−1
当 f f f是奇数的时候,只要选择相应的填充大小,就能确保得到和输入相同大小。
因此 f f f通常都是奇数的。
卷积步长(或步幅,stride)是另一个构建卷积神经网络的基本操作。
假设原图大小是 7 × 7 7 \times 7 7×7,此时我们设步长为 2 2 2。
第一步还是一样,计算出来结果为 91 91 91,但移动的时候,我们要移动两步。
移动了两步后,计算出结果是 100 100 100,写到结果矩阵第2个元素处。
最后还是得到了一个 3 × 3 3 \times 3 3×3的输出矩阵。
此时计算输出矩阵大小的公式是什么呢,如果你有个 n × n n \times n n×n的原图,填充 p p p,步长为 s s s,那么得到的输出大小为:
( n + 2 p − f s + 1 ) × ( n + 2 p − f s + 1 ) (\frac{n + 2p - f}{s} + 1) \times (\frac{n + 2p - f}{s} + 1) (sn+2p−f+1)×(sn+2p−f+1)
这个例子中是 7 + 0 − 3 2 + 1 = 3 \frac{7 + 0 -3}{2} + 1 =3 27+0−3+1=3
如果上面那个分数结果不是整数怎么办,此时我们要向下取整,向下取整有个简单的写法是(x+1) // 2
这里注意我们对上面整个式子向下取整:
它的谁想啊是如果蓝框移动到了外面,则不进行卷积运算。
我们已经知道如何对二维图像做卷积了,那如果对三维立体做卷积了。
还是举个例子吧,如果你想检测RGB图像的特征,那么RGB会有三个通道(红绿蓝):
此时原图的大小变成了 6 × 6 × 3 6 \times 6 \times 3 6×6×3,这就是三维的。
为了检测图像的边缘,不是把它与原来的 3 × 3 3\times 3 3×3的过滤器做卷积,而是根一个三维的过滤器 3 × 3 × 3 3 \times 3 \times 3 3×3×3做卷积。
上面一直说的通道是啥意思,下面来说明一下。
原图 6 × 6 × 3 6 \times 6 \times 3 6×6×3中的两个 6 6 6分别是高和宽, 3 3 3就是通道数,过滤器的大小也是这么命名的,这里要注意的是,过滤器的通道数必须和原图的通道数一致。
整个卷积的结果是一个 4 × 4 4 \times 4 4×4的二维矩阵,下面我们看是如何计算的。
首先画的好看一点。为了简化这个过滤器的图像,通常不把它画成三个矩阵的堆叠,而是一个立方体。
为了计算这个卷积操作的输出,你要做的是把这个 3 × 3 × 3 3 \times 3 \times 3 3×3×3的过滤器,先放到最左上角的位置。
这个过滤器有27个数,依次取这27个数,与红绿蓝通道中对应的数字相乘,最后还是把这个数字都加起来,就得到一个数字作为结果。
然后把这个立方体右移一步,就得到输出矩阵的第二个元素,最后就可以计算出整个卷积结果。
那么这个能干什么呢?
如果你想检测图像红色通道的边缘,那么你可以将过滤器红色通道设成:
而过滤器的绿色和蓝色通道都为零:
这就是一个只对红色通道有用的垂直边缘检测器。
现在如果我们想同时检测垂直和水平边缘要怎么办呢
只要再加上一个过滤器,然后假设第一个过滤器得到的是紫色二维矩阵,第二个过滤器得到的是蓝色二维矩阵。
我们把这两个矩阵堆叠到一起,变成了一个 4 × 4 × 2 4 \times 4 \times 2 4×4×2的立方体,这里的 2 2 2表示由两个过滤器计算而来的。
这样我们就能同时检测多个特征。
我们已经知道如何对立方体做卷积了,下面来看下如何实现一个简单的单层卷积网络。
我们已经知道如何计算多个过滤器的输出了,最终我们要把这些输出变成单层卷积神经网络,还需要对每一个输出添加一个实数偏差,然后应用ReLU激活函数,输出结果就是一个 4 × 4 4 \times 4 4×4的矩阵。
这两个过滤器就会得到两个 4 × 4 4 \times 4 4×4的矩阵,我们然后把它们堆叠起来,就得到了 4 × 4 × 2 4 \times 4 \times 2 4×4×2的输出,这就是卷积神经网络的一层所做的事情。
现在我们把这个例子和普通的非卷积单层前向传播神经网络对应起来,
这些公式应该很熟悉了,这里的 a [ 0 ] a^{[0]} a[0]就是原图这个矩阵。
然后过滤器的作用和普通神经网络的 W [ 1 ] W^{[1]} W[1]类似
然后通过卷积运算得到 4 × 4 4 \times 4 4×4的矩阵,这个操作类似 W [ 1 ] a [ 0 ] W^{[1]} a^{[0]} W[1]a[0]
蓝色方框里面的计算和计算 z [ 1 ] z^{[1]} z[1]类似。
然后应用激活函数得到输出 a [ 0 ] a^{[0]} a[0]
这就是从 a [ 0 ] a^{[0]} a[0]计算出 a [ 1 ] a^{[1]} a[1]的过程。
在这个例子中我们有 2 2 2个过滤器,也就是两个特征,得到的结果是 4 × 4 × 2 4 \times 4 \times 2 4×4×2。
如果你的单层神经网络有10个 3 × 3 × 3 3 \times 3 \times 3 3×3×3的过滤器,那么该层有多少个参数?
一个过滤器有 3 × 3 × 3 = 27 3 \times 3 \times 3 = 27 3×3×3=27个参数,加上一个偏置,共 28 28 28个参数。
现在我们有 10 10 10个过滤器,因此有 280 280 280个参数。
这里的参数数量是与输入图像的大小无关的,这个特征使得卷积神经网络不容易过拟合。
现在我们来总结一下符号标记。
f [ l ] f^{[l]} f[l]表示第 l l l层的过滤器大小( f [ l ] × f [ l ] f^{[l]} \times f^{[l]} f[l]×f[l])。
p [ l ] p^{[l]} p[l]表示第 l l l层的填充大小。
s [ l ] s^{[l]} s[l]表示第 l l l层的步长大小。
对于第 l l l层的输入来说, n H [ l − 1 ] n_H^{[l-1]} nH[l−1]表示前一层( l − 1 l-1 l−1层)的高度, n W [ l − 1 ] n_W^{[l-1]} nW[l−1]表示前一层的宽度, n c [ l − 1 ] n_c^{[l-1]} nc[l−1]表示前一层的通道数,因为当前层的输入大小是和前一层的输出大小有关的。这里把宽度和高度有两个符号表示,说明图像可以不是正方形的。
那这一层的输出就是
这里的输出高度大小由下面这个公式得到:
我们上面介绍过这个公式,注意符号上面的层数标记。如果要计算宽度,把 H H H换为 W W W即可。
那通道数 n c n_c nc是哪来的?
我们知道输出图片也有通道数 n c [ l ] n_c^{[l]} nc[l],它等于该层过滤器的数量。
下面我们来思考下如何确定过滤器的大小呢,每层的过滤器大小为:
激活值的大小就是输出的大小:
当执行梯度下降法是,如果有 m m m个样本,就有 m m m个激活值的集合。
那么这 m m m个样本的激活值大小就是:
下面权重参数 W W W,我们知道这里的权重大小和过滤器一致,同时有多个过滤器的话,就成了:
最后是偏差,每个过滤器都只有一个偏差(实数),因此大小为:
最后汇总一下
了解了一层卷积神经网络的工作原理,我们就可以把它堆叠起来形成一个简单的卷积神经网络。
假设我们用卷积神经网络来做图片识别,识别某张图片中有没有猫。
这是输入图片 x x x的大小,假设第一层我们用10个 3 × 3 3 \times 3 3×3的过滤器来提取特征。
那么神经网络的下一层的激活值 a [ 1 ] a^{[1]} a[1]大小为 37 × 37 × 10 37 \times 37 \times 10 37×37×10
这里的 37 37 37是通过公式
计算出来的结果。那么就可以标记第一层的高度、宽度和通道数。
接着还有另一层卷积层,假设有 20 20 20个 5 × 5 5 \times 5 5×5的过滤器,步长为 2 2 2,填充为 0 0 0:
它的输出将会是一个新的图像,大小为 17 × 17 × 20 17 \times 17 \times 20 17×17×20, 20 20 20就等于过滤器的数量。
我们再构建一个卷积层,我们这次用 40 40 40个 5 × 5 5 \times 5 5×5的过滤器,步长还是 2 2 2:
这样,这张 39 × 39 × 3 39 \times 39 \times 3 39×39×3的输入图像就处理完毕了,为图片提取了 7 × 7 × 40 = 1960 7 \times 7 \times 40= 1960 7×7×40=1960个特征,然后重点来了,我们对该卷积层进行处理,将其扁平展开为 1960 1960 1960个单元。
这里展开为 1960 × 1 1960 \times 1 1960×1的向量,然后可以将这个向量喂给逻辑回归单元或Softmax回归单元,看你是想做二分类还是多分类问题。
最终得到输出 y ^ \hat y y^。
在设计卷积神经网络时,确定这些超参数比较费工夫,像过滤器大小、步长、填充大小以及使用多少个过滤器。
这个问题后面的文章会提到。
本节我们知道一张原本比较大的图片 ( 39 × 39 × 3 ) (39 \times 39 \times 3) (39×39×3),随着网络深度的加深而逐渐减小,最终得到一个比较小的特征 ( 7 × 7 × 40 ) (7 \times 7 \times 40) (7×7×40)。
注意这里通道数是逐渐增加的,从 10 10 10到 20 20 20再到 40 40 40。
其实一个典型的卷积神经网络有三层:
下面我们介绍剩下的这两个概念。
还是来看一个例子,
假设输入是一个 4 × 4 4 \times 4 4×4的矩阵,用到的池化类型是最大池化(max pooling),输出是一个 2 × 2 2 \times 2 2×2的矩阵。
整个过程很简单,把 4 × 4 4 \times 4 4×4的输入拆分成不同的区域,每个区域取最大值作为输出:
就像应用了一个大小为 2 × 2 2 \times 2 2×2,步长为 2 2 2的过滤器。
你可以把这个4 \times 4$的输入看作是某些特征的集合,最大值意味着可能提取了某些特定特征。
最大化运算的实际作用是,如果在过滤器中提取到某个特征,那么保留其最大值;如果没有提取到这个特征,那么最大值还是会很小。这是对最大池化的直观理解。
其中有一个有意思的特定就是,它有一组超参数,但是不需要学习,一旦确定了 f , s f,s f,s,它就是一个固定运算,梯度下降不需要改变任何值。
我们来看一个有不同超参数的例子。
有一个 5 × 5 5 \times 5 5×5的输入矩阵,用的最大池化过滤器大小是 3 × 3 3 \times 3 3×3,步长为 1 1 1,最终得到 3 × 3 3 \times 3 3×3的矩阵。
同样是通过上面这个公式计算输出大小,我们来看下最大池化的过程:
第一个元素是这个方块内的最大值,也就是 9 9 9,然后移动一步,
这一次最大值同样是 9 9 9,依次类推,得到最终输出:
上面的输入是二维的,如果输入是三维的,那么你就会得到一个三维的输出。
还有一种不太常用的池化类型——平均池化,顾名思义,对每个分隔区域取平均值而不是最大值:
总结下池化的超参数:
做最大池化时很少用到填充参数 p p p。
需要注意的是,池化过程没有需要学习的参数,这些超参数需要手动设置或通过交叉验证设置。
这就是池化,下面我们引入全连接层来实现一个更复杂的卷积神经网络。
假设有一张 32 × 32 × 3 32 \times 32 \times 3 32×32×3的手写数字图片 7 7 7。
我们构建一个卷积神经网络来实现它,这个网络的许多参数和LeNet-5类似。
第一层用了 6 6 6个 5 × 5 5 \times 5 5×5的过滤器,步长为 1 1 1,得到一个 28 × 28 × 6 28 \times 28 \times 6 28×28×6的卷积输出。
然后用一个 2 × 2 2 \times 2 2×2,步长为 2 2 2的最大池化过滤器,得到一个 14 × 14 × 6 14 \times 14 \times 6 14×14×6的池化输出。
这里把卷积层和池化层放到一起作为一层。
接着在 14 × 14 × 6 14 \times 14 \times 6 14×14×6的基础上再做一层卷积。
这次使用了 16 16 16个过滤器。加上最大池化层,得到 5 × 5 × 16 5 \times 5 \times 16 5×5×16的输出,把这个矩阵拉平变成 400 × 1 400 \times 1 400×1的向量。把这个向量作为下一层的输入。
下一层有 F C 3 FC3 FC3有120个单元,这一层就是第一个全连接层,它的权重 W [ 3 ] W^{[3]} W[3]大小为 ( 120 , 400 ) (120,400) (120,400)。
我们对这一层再添加一个单元数更少,只有 84 84 84个的全连接层,最后加上一个softmax单元,得到10个输出,分别表示每个数字的概率大小。
看上去这个网络有很多超参数,这里建议不要自己去设置超参数,而是看文献中别人采用了哪些超参数,通常也可能会适用你自己的应用。
这里有一个维度变化的规律是,随着网络深度的加深,高度和宽度通常都会减少,而通道数会增加。
下面我们看看这个网络的各维度大小。
这里要注意的是,池化层没有参数。卷积层的参数越来越少,大多数参数都在全连接层上。
随着网络的加深,激活值的输入大小会逐渐变小。
和全连接层相比,卷积层的两个主要优势在于参数共享和稀疏矩阵。
拿上小节的例子来看,如果我们用全连接神经网络来构造,其中一层层有 3072 3072 3072个单元,而下一层有 4704 4704 4704个单元,把它们相连的话,大约需要1400万个参数。
而如果是卷积层的话, 6 6 6个 5 × 5 5 \times 5 5×5的过滤器,每个过滤器有一个偏差参数,只需要 ( 5 × 5 × 3 + 1 ) × 6 = 456 (5 \times 5 \times 3+1) \times 6 = 456 (5×5×3+1)×6=456个参数。
过滤器的通道数要与输入的通道数一致
卷积神经网络参数这么少的原因有两个。
这个网络有卷积层和全连接层,要训练这样一个网络,先要定义损失函数。
我们随机化 W , b W,b W,b的值可以计算 J J J的值。
接下来使用梯度下降法,来优化参数从而减少 J J J的值。
这样就可以建立一个非常有效的猫分类器。