Convolutional Neural Networks---Foundations of Convolutional Neural Networks

–摘自黄海广博士等人笔记,吴恩达的深度学习课程

1.边缘检测示例

Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第1张图片
神经网络的前几层是如何检测边缘的,然后后面的层有可能检测到物体的部分区域,更靠后的一些层可能检测到完整的物体,这个例子中就是人脸。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第2张图片
给了这样一张图片,让电脑去搞清楚这张图片里有什么物体,你可能做的第一件事就是检测图片的垂直边缘。(比如图片中的栏杆就对应垂线,行人的轮廓线也是垂线,这些线是垂直边缘器的输出。)同样,可能也会检测水平边缘线(比如栏杆就是很明显的水平线)。所以如何检测到这些边缘呢?
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第3张图片
这是一个6×6的灰度图像。因为是灰度,所以是个6×6×1的矩阵,而不是6×6×3的,因为没有RGB三通道。为了检测图像中的垂直边缘,你可以构造一个3×3的过滤器(有时候也称为核),像这样 111000111 [ 1 0 − 1 1 0 − 1 1 0 − 1 ]
对这个6×6的图像进行卷积运算,用3×3的过滤器对其进行卷积。卷积运算用“*”表示(在语言中,常被用来表示乘法运算,他是一个重载符号)。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第4张图片
输出将会是一个4×4矩阵,可以看做是4×4的图像。
下面进行元素乘法运算 3×11×12×10×05×07×01×(1)8×(1)2×(1) [ 3 × 1 0 × 0 1 × ( − 1 ) 1 × 1 5 × 0 8 × ( − 1 ) 2 × 1 7 × 0 2 × ( − 1 ) ] = 312000182 [ 3 0 − 1 1 0 − 8 2 0 − 2 ] ,然后将矩阵的中每个元素相加得到左上角的元素,即3 + 1 + 2 + (-1) + (-8) + (-2) = -5。
然后移动一格继续计算其他元素,最终计算出下图。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第5张图片
这个就是垂直边缘检测器。
注意:实现卷积,在TensorFlow下,这个函数叫tf.nn.conv2d
为什么这个可以做垂直边缘检测呢?
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第6张图片
让我们来看另外一个例子。为了讲清楚,我会用一个简单的例子。这是一个简单的 6×6 图像,左边的一半是 10,右边一般是 0。如果你把它当成一个图片,左边那部分看起来是白色的,像素值 10 是比较亮的像素值,右边像素值比较暗,我使用灰色来表示 0,尽管它也可以被画成黑的。图片里,有一个特别明显的垂直边缘在图像中间,这条垂直线是从黑到白的过渡线,或者从白色到深色。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第7张图片
所以,当你用一个 3×3 过滤器进行卷积运算的时候,这个 3×3 的过滤器可视化为下面这个样子,在左边有明亮的像素,然后有一个过渡, 0 在中间,然后右边是深色的。卷积运算后,你得到的是右边的矩阵。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第8张图片
如果把最右边的矩阵当成图像,它是这个样子。在中间有段亮一点的区域,对应检查到这个 6×6 图像中间的垂直边缘。这里的维数似乎有点不正确,检测到的边缘太粗了。因为在这个例子中,图片太小了。如果你用一个 1000×1000 的图像,而不是 6×6 的图片,你会发现其会很好地检测出图像中的垂直边缘。在这个例子中,在输出图像中间的亮处,表示在图像中间有一个特别明显的垂直边缘。从垂直边缘检测中可以得到的启发是,因为我们使用 3×3的矩阵(过滤器),所以垂直边缘是一个 3×3 的区域,左边是明亮的像素,中间的并不需要考虑,右边是深色像素。在这个 6×6 图像的中间部分,明亮的像素在左边,深色的像素在右边,就被视为一个垂直边缘,卷积运算提供了一个方便的方法来发现图像中的垂直边缘。

2.更多边缘检测内容

已经见识到用卷积运算实现垂直边缘检测,接下来,你将学习如何区分正边和负边,这实际就是由亮到暗与由暗到亮的区别,也就是边缘的过渡。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第9张图片
这张 6×6 的图片,左边较亮,而右边较暗,将它与垂直边缘检测滤波器进行卷积,检测结果就显示在了右边这幅图的中间部分。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第10张图片
现在这幅图有什么变化呢?它的颜色被翻转了,变成了左边比较暗,而右边比较亮。现在亮度为 10 的点跑到了右边,为 0 的点则跑到了左边。如果你用它与相同的过滤器进行卷积,最后得到的图中间会是-30,而不是 30。如果你将矩阵转换为图片,就会是该矩阵下面图片的样子。现在中间的过渡部分被翻转了,之前的 30 翻转成了-30,表明是由暗向亮过渡,而不是由亮向暗过渡。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第11张图片
右边这个能让你检测出水平的边缘。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第12张图片
这里还有个更复杂的例子,左上方和右下方都是亮度为 10 的点。如果你将它绘成图片,右上角是比较暗的地方,这边都是亮度为 0 的点,把这些比较暗的区域都加上阴影。而左上方和右下方都会相对较亮。如果你用这幅图与水平边缘过滤器卷积,就会得到右边这个矩阵。
这里的 30(右边矩阵中绿色方框标记元素)代表了左边这块 3×3 的区域(左边矩阵绿色方框标记部分),这块区域确实是上边比较亮,而下边比较暗的,所以它在这里发现了一条正边缘。而这里的-30(右边矩阵中紫色方框标记元素)又代表了左边另一块区域(左边矩阵紫色方框标记部分),这块区域确实是底部比较亮,而上边则比较暗,所以在这里它是一条负边。再次强调,我们现在所使用的都是相对很小的图片,仅有 6×6。但这些中间的数值,比
如说这个 10(右边矩阵中黄色方框标记元素)代表的是左边这块区域(左边 6×6 矩阵中黄色方框标记的部分)。这块区域左边两列是正边,右边一列是负边, 正边和负边的值加在一起得到了一个中间值。但假如这个一个非常大的 1000×1000 的类似这样棋盘风格的大图,就不会出现这些亮度为 10 的过渡带了,因为图片尺寸很大,这些中间值就会变得非常小。
总而言之,通过使用不同的过滤器,你可以找出垂直的或是水平的边缘。但事实上,对于这个 3×3 的过滤器来说,我们使用了其中的一种数字组合。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第13张图片
在计算机视觉的文献中,曾公平地争论过怎样的数字组合才是最好的,比如上图,特点见下表:

过滤器 特点
Sobel(上图中间) 增加了中间一行元素的权重,这使得结果的鲁棒性会更高一些
Scharr(上图右一) 它有着和之前完全不同的特性,实际上也是一种垂直边缘检测,如果你将其翻转 90 度,你就能得到对应水平边缘检测。

随着深度学习的发展,我们学习的其中一件事就是当你真正想去检测出复杂图像的边缘,你不一定要去使用那些研究者们所选择的这九个数字,但你可以从中获益匪浅。把这矩阵中的 9 个数字当成 9 个参数,并且在之后你可以学习使用反向传播算法,其目标就是去理解这9 个参数。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第14张图片
当你得到左边这个 6×6 的图片,将其与这个 3×3 的过滤器进行卷积,将会得到一个出色的边缘检测。这就是你在下节视频中将会看到的,把这 9 个数字当成参数的过滤器,通过反向传播,你可以学习这种过滤器,或者 Sobel 过滤器和 Scharr 过滤器。
还有另一种过滤器,这种过滤器对于数据的捕捉能力甚至可以胜过任何之前这些手写的过滤器。相比这种单纯的垂直边缘和水平边缘,它可以检测出 45°或 70°或 73°,甚至是任何角度的边缘。

所以将矩阵的所有数字都设置为参数,通过数据反馈,让神经网络自动去学习它们,我们会发现神经网络可以学习一些低级的特征,例如这些边缘的特征。尽管比起那些研究者们,我们要更费劲一些,但确实可以动手写出这些东西。不过构成这些计算的基础依然是卷积运算,使得反向传播算法能够让神经网络学习任何它所需要的 3×3 的过滤器,并在整幅图片上去应用它。去输出任何它所检测到的特征,不管是垂直的边缘,水平的边缘,还有其他奇怪角度的边缘,甚至是其它的连名字都没有的过滤器。

所以这种将这 9 个数字当成参数的思想,已经成为计算机视觉中最为有效的思想之一。

3.padding

为了构建深度神经网络,你需要学会使用的一个基本的卷积操作就是padding。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第15张图片
如果你用一个 3×3 的过滤器卷积一个 6×6 的图像,你最后会得
到一个 4×4 的输出,也就是一个 4×4 矩阵。那是因为你的 3×3 过滤器在 6×6 矩阵中,只可能有 4×4 种可能的位置。这背后的数学解释是,如果我们有一个n × n的图像,用f × f的过滤器做卷积,那么输出的维度就是(n − f + 1) × (n − f + 1)。在这个例子里是6 − 3 + 1 = 4,因此得到了一个 4×4 的输出
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第16张图片

这样的话会有两个缺点:
1)每次做卷积操作,你的图像就会缩小,从 6×6 缩小到 4×4,你可能做了几次之后,你的图像就会变得很小了,可能会缩小到只有 1×1 的大小。你可不想让你的图像在每次识别边缘或其他特征时都缩小
2)如果你注意角落边缘的像素,这个像素点(绿色阴影标记)只被一个输出所触碰或者使用,因为它位于这个 3×3 的区域的一角。但如果是在中间的像素点,比如这个(红色方框标记),就会有许多 3×3 的区域与之重叠。所以那些在角落或者边缘区域的像素点在输出中采用较少,意味着你丢掉了图像边缘位置的许多信息

为了解决这两个问题,一是输出缩小。当我们建立深度神经网络时,你就会知道你为什么不希望每进行一步操作图像都会缩小。比如当你有 100 层深层的网络,如果图像每经过一层都缩小的话,经过 100 层网络后,你就会得到一个很小的图像,所以这是个问题。另一个问题是图像边缘的大部分信息都丢失了。Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第17张图片
为了解决这些问题,你可以在卷积操作之前填充这幅图像。在这个案例中,你可以沿着图像边缘再填充一层像素。如果你这样操作了,那么 6×6 的图像就被你填充成了一个 8×8 的图像。如果你用 3×3 的图像对这个 8×8 的图像卷积,你得到的输出就不是 4×4 的,而是 6×6的图像,你就得到了一个尺寸和原始图像 6×6 的图像。习惯上,你可以用 0 去填充,如果p是填充的数量,在这个案例中, p = 1,因为我们在周围都填充了一个像素点,输出也就变
成了(n + 2p − f + 1) × (n + 2p − f + 1),所以就变成了(6 + 2 × 1 − 3 + 1) × (6 + 2 × 1 −3 + 1) = 6 × 6,和输入的图像一样大。这个涂绿的像素点(左边矩阵)影响了输出中的这些格子(右边矩阵)。这样一来,丢失信息或者更准确来说角落或图像边缘的信息发挥的作用较小的这一缺点就被削弱了。
刚才我已经展示过用一个像素点来填充边缘,如果你想的话,也可以填充两个像素点,也就是说在这里填充一层。实际上你还可以填充更多像素。上图里画的这种情况,填充后p =2。
至于选择填充多少像素,通常有两个选择,分别叫做 Valid 卷积和 Same 卷积。

卷积 特点
Valid卷积 意味着不填充
same卷积 意味你填充后,你的输出大小和输入大小是一样的
  • Valid 卷积:如果你有一个n × n的图像,用一个f × f的过滤器卷积,它将会给你一个(n − f + 1) × (n − f + 1)维的输出。这类似于我们在前面的视频中展示的例子,有一个 6×6 的图像,通过一个 3×3 的过滤器,得到一个 4×4 的输出。
  • same 卷积:根据这个公式n − f + 1,当你填充p个像素点, n就变成了n + 2p,最后公式变为n + 2p − f + 1。因此如果你有一个n × n的图像,用p个像素填充边缘,输出的大小就是这样的(n + 2p − f + 1) × (n + 2p − f + 1) 。如果你想让n + 2p − f + 1 = n的话,使得输出和输入大小相等,如果你用这个等式求解p,那么p = (f − 1)/2。(只和f有关,因此f通常为奇数)所以当f是一个奇数的时候,只要选择相应的填充尺寸,你就能确保得到和输入相同尺寸的输出。
    因此f通常是奇数,原因:
    1)如果f是偶数,只能使用不对称填充,只有f是奇数的情况下,same卷积才会有自然的填充,而不是左边填充多一点,右边填充少一点,这样不对称的填充。
    2)当你有一个奇数维过滤器,他就有一个中心点。有时在CV里,有一个中心像素点更方便,便于指出过滤器的位置。(没明白why

4.卷积步长(Strided convolutions)

之前默认步长为1,如果步长不为1,那么卷积之后的维度不再只由f决定。
假设步长为2,则卷积之后得到下图:
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第18张图片
输入和输出的维度是由下面的公式决定的。如果你用一个f × f的过滤器卷积一个n × n的图像,你的 padding 为p,步幅为s,在这个例子中s = 2,你会得到一个输出,因为现在你不是一次移动一个步子,而是一次移动s个步子,输出于是变
为( n+2pfs n + 2 p − f s +1)×( n+2pfs n + 2 p − f s +1)
如果商不是一个整数怎么办?在这种情况下,我们向下取整(也叫做对z进行地板除floor),这意味着z向下取整到最近的整数。这个原则实现的方式是,你只在蓝框完全包括在图像或者填充完的图像内部时,才对它进行运算。如果移动到了外面,那你就不要进行相乘操作,这是一个惯例。因此正确的计算输出维度的方法是向下取整,以免 n+2pfs n + 2 p − f s 不是整数。
注意:数学里面的卷积操作包括镜像翻转,而深度学习里面,翻转并不重要,而且也简化了编程。

5.三维卷积(Convolutions over volumes)

三维立体卷积—RGB彩色图像6×6×3,可以想象成6×6图像的堆叠。同时,过滤器也是三维的,3×3×3,对应红绿蓝三个通道。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第19张图片
给这些命个名字(原图像),这里的第一个 6 代表图像高度,第二个 6 代表宽度,这个3 代表通道的数目。同样你的过滤器也有一个高,宽和通道数,并且图像的通道数必须和过滤器的通道数匹配,所以这两个数(紫色方框标记的两个数)必须相等。下个幻灯片里,我们就会知道这个卷积操作是如何进行的了,这个的输出会是一个 4×4 的图像,注意是 4×4×1,最后一个数不是 3 了。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第20张图片
为了计算这个卷积操作的输出,你要做的就是把这个 3×3×3 的过滤器先放到最左上角的位置,这个 3×3×3 的过滤器有 27 个数, 27 个参数就是 3 的立方。依次取这 27 个数,然后乘以相应的红绿蓝通道中的数字。先取红色通道的前 9 个数字,然后是绿色通道,然后再是蓝色通道,乘以左边黄色立方体覆盖的对应的 27 个数,然后把这些数都加起来,就得到了输出的第一个数字。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第21张图片
如果要计算下一个输出,你把这个立方体滑动一个单位,再与这 27 个数相乘,把它们都加起来,就得到了下一个输出,以此类推。
那么,这个能干什么呢?举个例子,这个过滤器是 3×3×3 的, 如果你想检测图像红色通道的边缘,那么你可以将第一个过滤器设为 111000111 [ 1 0 − 1 1 0 − 1 1 0 − 1 ] ,和之前一样,而绿色通道全为 000000000 [ 0 0 0 0 0 0 0 0 0 ] ,蓝色也全为 000000000 [ 0 0 0 0 0 0 0 0 0 ] 。如果你把这三个堆叠在一起形成一个 3×3×3 的过滤器,那么这就是一个检测垂直边界的过滤器,但只对红色通道有用。
或者如果你不关心垂直边界在哪个颜色通道里,
那么你可以用一个这样的过滤器 111000111 [ 1 0 − 1 1 0 − 1 1 0 − 1 ] 111000111 [ 1 0 − 1 1 0 − 1 1 0 − 1 ] 111000111 [ 1 0 − 1 1 0 − 1 1 0 − 1 ] ,所有三个通道都是这样。所以通过设置第二个过滤器参数,你就有了一个边界检测器, 3×3×3 的边界检测器,用来检测任意颜色通道里的边界。参数的选择不同,你就可以得到不同的特征检测器,所有的都是 3×3×3 的过滤器。
按照计算机视觉的惯例,当你的输入有特定的高宽和通道数时,你的过滤器可以有不同的高,不同的宽,但是必须一样的通道数。理论上,我们的过滤器只关注红色通道,或者只关注绿色或者蓝色通道也是可行的。
再注意一下这个卷积立方体,一个 6×6×6 的输入图像卷积上一个 3×3×3 的过滤器,得到一个 4×4 的二维输出。
现在你已经了解了如何对立方体卷积,还有最后一个概念,对建立卷积神经网络至关重要。就是,如果我们不仅仅想要检测垂直边缘怎么办?如果我们同时检测垂直边缘和水平边缘,还有 45°倾斜的边缘,还有 70°倾斜的边缘怎么做?换句话说,如果你想同时用多个过滤器怎么办?
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第22张图片
第一个黄色的可能是一个垂直边界检测器或者是学习检测其他的特征。第二个橘色的过滤器,它可以是一个水平边缘检测器。
所以和第一个过滤器卷积,可以得到第一个 4×4 的输出,然后卷积第二个过滤器,得到一个不同的 4×4 的输出。我们做完卷积,然后把这两个 4×4 的输出,取第一个把它放到前面,然后取第二个过滤器输出,把它画在这,放到后面。所以把这两个输出堆叠在一起,这样你就都得到了一个 4×4×2 的输出立方体,你可以把这个立方体当成,重新画在这,就是一个这样的盒子,所以这就是一个 4×4×2 的输出立方体。它用 6×6×3 的图像,然后卷积上这两个不同的 3×3 的过滤器,得到两个 4×4 的输出,它们堆叠在一起,形成一个 4×4×2 的立方体,这里的 2 的来源于我们用了两个不同的过滤器。

总结一下维度:
如果你有一个n × n × nc n c (通道数)的输入图像,在这个例子中就是 6×6×3,这里的 nc n c 就是通道数目,然后卷积上一个f × f × nc n c ,按照惯例,这个(前一个 nc n c )和这个(后一个 nc n c )必须数值相同。然后你就得到了(n − f + 1)×(n − f + 1)× nc n c ′ ,这里的 nc n c ′ 其实就是下一层的通道数,它就是你用的过滤器的个数。默认步长为1,如果不为1,也会相应的变化。
这个对立方体卷积的概念真的很有用,你现在可以用它的一小部分直接在三个通道的RGB 图像上进行操作。更重要的是,你可以检测两个特征,比如垂直和水平边缘或者 10 个或者 128 个或者几百个不同的特征,并且输出的通道数会等于你要检测的特征数。
对于这里的符号,我一直用通道数( nc n c )来表示最后一个维度,在文献里大家也把它叫做 3 维立方体的深度。这两个术语,即通道或者深度,经常被用在文献中。但我觉得深度容易让人混淆,因为你通常也会说神经网络的深度。所以,在这些视频里我会用通道这个术语来表示过滤器的第三个维度的大小。

6.单层卷积网络(One Layer of a Convolutional Network)

Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第23张图片
形成一个卷积神经网络层,然后增加偏差,它是一个实数,通过 Python 的广播机制给这 16 个元素都加上同一偏差。然后应用非线性激活函数 ReLU,输出结果是一个 4×4 矩阵。
对于第二个 4×4 矩阵,我们加上不同的偏差,它也是一个实数, 16 个数字都加上同一个实数,然后应用非线性函数,也就是一个非线性激活函数 ReLU,最终得到另一个 4×4 矩阵。然后重复我们之前的步骤,把这两个矩阵堆叠起来,最终得到一个 4×4×2 的矩阵。我们通过计算,从 6×6×3 的输入推导出一个 4×4×2 矩阵,它是卷积神经网络的一层,把它映射到标准神经网络中四个卷积层中的某一层或者一个非卷积神经网络中。即下图的过程。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第24张图片
注意前向传播中一个操作就是 z[1] z [ 1 ] = W[1] W [ 1 ] a[0] a [ 0 ] + b[1] b [ 1 ] ,其中 a[0]=x a [ 0 ] = x ,执行非线性函数得到 a[1] a [ 1 ] ,即 a[1] a [ 1 ] = g( z[1] z [ 1 ] )。这里的输入是 a[0] a [ 0 ] ,也就是x,这些过滤器用变量 W[1] W [ 1 ] 表示。在卷积过程中,我们对这 27 个数进行操作,其实是 27×2,因为我们用了两个过滤器,我们取这些数做乘法。实际执行了一个线性函数,得到一个 4×4 的矩阵。卷积操作的输出结果是一个4×4 的矩阵,它的作用类似于 W[1] W [ 1 ] a[0] a [ 0 ] ,也就是这两个 4×4 矩阵的输出结果,然后加上偏差。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第25张图片
这一部分(图中蓝色边框标记的部分)就是应用激活函数 ReLU 之前的值,它的作用类似于 z[1] z [ 1 ] ,最后应用非线性函数,得到的这个 4×4×2 矩阵,成为神经网络的下一层,也就是激活层。
这就是 a[0] a [ 0 ] a[1] a [ 1 ] 的演变过程,首先执行线性函数,然后所有元素相乘做卷积,具体做法是运用线性函数再加上偏差,然后应用激活函数 ReLU。这样就通过神经网络的一层把一个6×6×3 的维度 a[0] a [ 0 ] 演化为一个 4×4×2 维度的 a[1] a [ 1 ] ,这就是卷积神经网络的一层。
示例中我们有两个过滤器,也就是有两个特征,因此我们才最终得到一个 4×4×2 的输出。但如果我们用了 10 个过滤器,而不是 2 个,我们最后会得到一个 4×4×10 维度的输出图像,因为我们选取了其中 10 个特征映射,而不仅仅是 2 个,将它们堆叠在一起,形成一个4×4×10 的输出图像,也就是 a[1] a [ 1 ]
为了加深理解,我们来做一个练习。假设你有 10 个过滤器,而不是 2 个,神经网络的一层是 3×3×3,那么,这一层有多少个参数呢?我们来计算一下,每一层都是一个 3×3×3 的矩阵,因此每个过滤器有 27 个参数,也就是 27 个数。然后加上一个偏差,用参数b表示,现在参数增加到 28 个。有 10 个过滤器,加在一起是 28×10,也就是 280 个参数。
请注意一点,不论输入图片有多大, 1000×1000 也好,5000×5000 也好,参数始终都是280 个。用这 10 个过滤器来提取特征,如垂直边缘,水平边缘和其它特征。即使这些图片很大, 参数却很少, 这就是卷积神经网络的一个特征, 叫作“避免过拟合”。 你已经知道到如何提取 10 个特征,可以应用到大图片中,而参数数量固定不变,此例中只有 28 个,相对较少。

总结一下用于描述卷积神经网络中的一层(以l层为例),也就是卷积层的各种标记:
这一层是卷积层,用 f[l] f [ l ] 表示过滤器大小,我们说过过滤器大小为f × f,上标[l]表示l层中过滤器大小为f × f。用 p[l] p [ l ] 来标记 padding 的数量,padding 数量也可指定为一个 valid 卷积,即无 padding。或是 same 卷积,即选定 padding,如此一来,输出和输入图片的高度和宽度就相同了。用 s[l] s [ l ] 标记步幅。
这一层的输入会是某个维度的数据,表示为n × n × n[c] n [ c ] n[c] n [ c ] 某层上的颜色通道数。
我们要稍作修改,增加上标[l − 1],因为它是上一层的激活值,图片的高度和宽度有可能不同,所以分别用上下标H和W来标记,即 n[l1]H n H [ l − 1 ] × n[l1]W n W [ l − 1 ] × n[l1]c n c [ l − 1 ] 。那么在第l层,图片大小为 n[l1]H n H [ l − 1 ] × n[l1]W n W [ l − 1 ] × n[l1]c n c [ l − 1 ] , l层的输入就是上一层的输出,因此上标要用[l − 1]。神经网络这一层中会有输出,它本身会输出图像。其大小为 n[l]H n H [ l ] × n[l]W n W [ l ] × n[l]c n c [ l ] ,这就是输出图像的大小。
前面我们提到过,这个公式给出了输出图片的大小,至少给出了高度和宽度, ⌊ n+2pfs n + 2 p − f s +1⌋( n+2pfs n + 2 p − f s +1,直接用这个运算结果,也可以向下取整)。在这个新表达式中, l层输出图像
的高度,即 n[l]H n H [ l ] = ⌊ n[l1]H+2p[l]f[l]s[l] n H [ l − 1 ] + 2 p [ l ] − f [ l ] s [ l ] +1⌋,同样我们可以计算出图像的宽度,用W替换参数H,
n[l]W n W [ l ] = ⌊ n[l1]W+2p[l]f[l]s[l] n W [ l − 1 ] + 2 p [ l ] − f [ l ] s [ l ] +1⌋,公式一样,只要变化高度和宽度的参数我们便能计算输出图像的高度或宽度。这就是由 n[l1]H n H [ l − 1 ] 推导 n[l]H n H [ l ] 以及 n[l1]W n W [ l − 1 ] 推导 n[l]W n W [ l ] 的过程。
输出图像中的通道数量就是神经网络中这一层所使用的过滤器的数量。如何确定过滤器的大小呢?我们知道卷积一个 6×6×3 的图片需要一个 3×3×3 的过滤器,因此过滤器中通道的数量必须与输入中通道的数量一致。因此,输出通道数量就是输入通道数量,所以过滤器维度等于 f[l] f [ l ] × f[l] f [ l ] × n[l1]c n c [ l − 1 ]

7.简单卷积网络实例

用一个例子来熟悉一下之前学过的标记。

问题描述:图片分类
定义一张图片输入定义为x,然后辨别图片中有没有猫,用0或1表示,这是一个人类问题,我们来构建适用于这项任务的卷积神经网络。大小为39×39×3。即 n[0]H n H [ 0 ] = n[0]W n W [ 0 ] = 39, n[0]c n c [ 0 ] = 3。

假设第一层我们用3×3的过滤器来提取特征,那么 f[1] f [ 1 ] = 3, s[1] s [ 1 ] = 1, p[1] p [ 1 ] = 0,所以高度和宽度使用same卷积。如果有10个过滤器,神经网络的下一层激活值为37×37×10,写10是因为我们用了10个过滤器,37是公式 n+2pfs n + 2 p − f s +1的计算结果,也就是 39+031 39 + 0 − 3 1 +1 = 37,所以输出是37×37,它是一个valid卷积,这是输出结果的大小。第一层标记为 n[1]H n H [ 1 ] = n[w]H n H [ w ] =37, n[1]c n c [ 1 ] =10, n[1]c n c [ 1 ] 等于第一层中过滤器的个数,这是第一层激活值的维度(37×37×10)。

假设还有另外一个卷积层,这次我们采用的过滤器是5×5的矩阵,在标记法中,神经网络下一层的f = 5,,即 f[2] f [ 2 ] = 5,步幅为2,即 s[2] s [ 2 ] = 2。padding为0,即 p[2] p [ 2 ] =0,且有20个过滤器,所以其输出结果会是一张新图像,这次的输出结果为 17×17×20,因为步幅是 2,维度缩小得很快,大小从 37×37 减小到 17×17,减小了一半还多,过滤器是 20 个,所以通道数也是20,17×17×20即激活值 a[2] a [ 2 ] 的维度。因此 n[2]H n H [ 2 ] = n[2]W n W [ 2 ] = 17, n[2]c n c [ 2 ] = 20。

我们来构建最后一个卷积层,假设过滤器还是5×5,步幅为2,即 f[2] f [ 2 ] =5, s[3] s [ 3 ] =2,计算过程我跳过了,最后输出为7×7×40,假设用了40个过滤器。padding为0,40个过滤器,最后结果为7×7×40。

到此,这张39×39×3的输入图像就处理完毕了,为图片提取了7×7×40个特征,计算出来就是1960个特征。然后对该卷积进行处理。平滑处理后可以输出一个向量,其填充内容是 logistic 回归单元还是 softmax 回归单元,完全取决于我们是想识图片上有没有猫,还是想识别K种不同对象中的一种,用 y^ y ^ 表示最终神经网络的预测输出。明确一点,最后这一步是处理所有数字,即全部的 1960 个数字,把它们展开成一个很长的向量。为了预测最终的输出结果,我们把这个长向量填充到 softmax 回归函数中。
这是卷积神经网络的一个典型范例,设计卷积神经网络时,确定这些超参数比较费工夫。要决定过滤器的大小、步幅、 padding 以及使用多少个过滤器。
需要掌握的一点是,随着神经网络计算深度不断加深,通常开始时的图像也要更大一些,初始值为 39×39,高度和宽度会在一段时间内保持一致,然后随着网络深度的加深而逐渐减小,从 39 到 37,再到 17,最后到 7。而通道数量在增加,从 3 到 10,再到 20,最后到 40。
一个典型的卷积神经网络通常有三层,一个是卷积层,我们常常用 Conv 来标注。上一个例子,我用的就是 CONV。还有两种常见类型的层,一个是池化层,我们称之为 POOL。最后一个是全连接层,用 FC 表示。虽然仅用卷积层也有可能构建出很好的神经网络,但大部分神经网络架构师依然会添加池化层和全连接层。幸运的是,池化层和全连接层比卷积层更容易设计。网络中最常用的这几种层,你就可以利用它们构建更强大的网络了。

8.池化层

除了卷积层,卷积网络也经常使用池化层来缩减模型的大小,提高计算速度,同时提高所提取特征的鲁棒性。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第26张图片
先举个栗子:
假如输入是4×4的矩阵,用到的池化层类型是最大池化(max pooling)。执行最大池化的树池是一个2×2矩阵。
执行过程:把4×4的输入拆分成不同的区域(把区域用不同的颜色来标记)。
输出: 2×2,输出的每个元素都是其对应颜色区域中的最大元素值。
这就像是应用了一个规模为 2 的过滤器,因为我们选用的是 2×2 区域,步幅是 2,这些就是最大池化的超参数。

因为我们使用的过滤器为 2×2,最后输出是 9。然后向右移动 2 个步幅,计算出最大值2。然后是第二行,向下移动 2 步得到最大值 6。最后向右移动 3 步,得到最大值 3。这是一个 2×2 矩阵,即f = 2,步幅是 2,即s = 2。

直观理解最大池化功能,可以把4×4输入看作是某些特征的集合,也许不是。你可以把这个4×4区域看作是某些特征的集合,也就是神经网络中某一层的非激活值集合。数字大意味着可能探测到了某些特定的特征,左上象限具有的特征可能是一个垂直边缘,一只眼睛。(这个特征可能就是一只猫眼探测器)然而,右上象限并不存在这个特征。最大化操作的功能就是只要在任何一个象限内提取到某个特征,会保留在最大化的池化输出里。

Max Pooling的直观理解:
所以最大化运算的实际作用就是,如果在过滤器中提取到某个特征,那么保留其最大值。如果没有提取到这个特征,可能象限中不存在这个特征,那么其中的最大值也还是很小。

有一个有意思的特点就是,他有一组超参数,并没有参数需要学习。实际上,梯度下降,一旦确定了f和s,就是一个固定运算,梯度下降无需改变任何值。
我们来看一个有若干个超级参数的示例,输入是一个5×5的矩阵。我们采用最大池化法,它的过滤器参数为3×3,即f=3,步幅为1,s=1,输出矩阵是3×3。之前将的计算卷积层输大小的公式同样适用于最大池化,即 n+2pfs n + 2 p − f s +1,这个公式也可以计算最大池化的输出大小。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第27张图片
此例是计算3×3输出的每个元素,f = 3,s = 1。如果输入是三维的,那么输出也是三维的。计算最大池化的方法就是分别对每个通道执行上图所示的过程。一般来说,输入是5×5× nc n c ,输出是3×3× nc n c nc n c 个通道每个通道都单独执行最大池化计算。
平均池化:选取的不是最大值,而是平均数。
目前来说,最大池化比平均池化更常用。但也有例外,就是深度很深的神经网络,你可以用平均池化来分解规模为7×7×1000的网络的表示层,在整个空间内求平均值,得到1×1×1000。

总结一下:
池化的超级参数包括过滤器大小f和步幅,常用的参数值为f=2,s=2,应用频率非常高,其效果相当于高度和宽度缩减一半。也有使用f = 3,s = 2,p=0的情况。至于其它超级参数就要看你用的最大池化还是平均池化了。Max Pooling的时候往往很少用到padding,当然也有例外的情况。
最大池化de 输入就是 nH n H × nW n W × nc n c ,假设没有padding,则输出⌊ nHfs n H − f s +1⌋×⌊ nWfs n W − f s +1⌋× nc n c ,输入通道和输出通道个数相同,因为我们对每个通道都做了池化。

注意:池化过程中没有需要学习的参数,是一个静态属性。执行反向传播时,没有参数适用于最大池化。只有这些设置过的超参数,可能是手动设置的,也可能是通过交叉验证设置的。

10.卷积神经网络示例

问题描述:
一张大小为32×32×3的RGB模式的输入图片,做手写体数字识别。比如7,你想识别它是0~9中哪一个。

Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第28张图片
我用的这个网络模型和经典网络 LeNet-5 非常相似,灵感也来源于此。 LeNet-5 是多年前 Yann LeCun 创建的,我所采用的模型并不是 LeNet-5,但是受它启发,许多参数选择都与LeNet-5 相似。输入是 32×32×3 的矩阵,假设第一层使用过滤器大小为 5×5,步幅是 1, padding是 0,过滤器个数为 6,那么输出为 28×28×6。将这层标记为 CONV1,它用了 6 个过滤器,增加了偏差,应用了非线性函数,可能是 ReLU 非线性函数,最后输出 CONV1 的结果。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第29张图片
然后构建一个池化层,这里我选择用最大池化,参数f=2,s = 2,因为padding 为0。开始构建池化层,最大池化使用的过滤器是2×2,步幅为2,表示层的高度和宽度会减少一般。因此,28×28变成了14×14,通道数量保持不变,所以最终输出为 14×14×6,将该输出标记为 POOL1。

在卷积神经网络文献中,卷积有两种分类,这与所谓层的划分存在一致性。一类卷积是一个卷积层和一个池化层一起作为一层,这就是神经网络的 Layer1。另一类卷积是把卷积层作为一层,而池化层单独作为一层。
人们在计算神经网络有多少层时,通常只统计具有权重和参数的层。因为池化层没有权重和参数,只有一些超参数。这里,我们把 CONV1和 POOL1 共同作为一个卷积,并标记为 Layer1。
一般我在统计网络层数时,只计算具有权重的层,也就是把 CONV1 和 POOL1 作为 Layer1。这里我们用 CONV1和 POOL1 来标记,两者都是神经网络 Layer1 的一部分,POOL1 也被划分在 Layer1 中,因为它没有权重,得到的输出是 14×14×6。

Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第30张图片
我们再为它构建一个卷积层,过滤器大小为5×5,步幅为1,这次我们用10个过滤器,最后输出一个10×10×10的矩阵,标记为CONV2。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第31张图片
然后做最大池化,超参数f=2,s=2。结果中高度和宽度会减半,最后输出5×5×10,标记为POOL2,这就是神经网络的第二个卷积层,即Layer2。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第32张图片
5×5×16 矩阵包含 400 个元素,现在将 POOL2 平整化为一个大小为 400 的一维向量。我们可以把平整化结果想象成这样的一个神经元集合,然后利用这 400 个单元构建下一层。下一层含有 120 个单元,这就是我们第一个全连接层,标记为 FC3。这 400 个单元与 120 个单元紧密相连, 这就是全连接层。它很像我们在第一和第二门课中讲过的单神经网络层,这是一个标准的神经网络。它的权重矩阵为 W[3] W [ 3 ] , 维度为 120×40。 这就是所谓的“全连接”, 因为这 400 个单元与这 120 个单元的每一项连接,还有一个偏差参数。最后输出 120 个维度,因为有 120 个输出。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第33张图片
然后我们对这个 120 个单元再添加一个全连接层,这层更小,假设它含有 84 个单元,标记为 FC4。
最后用着84个单元填充一个softmax单元。如果我们想通过手写数字识别来识别手写0~9这10个数字,这个softmax就会有10个输出。
此例中的卷积神经网络很典型,看上去它有很多超参数,关于如何选定这些参数,后面提供更多建议。常规做法是,尽量不要自己设置超参数,而是查看文献中别人采用了哪些超参数,选一个在别人任务中效果很好的架构,那么它也有可能适用于你自己的应用程序。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第34张图片
现在,我想指出的是,随着神经网络深度的加深,高度 nH n H 和宽度 nW n W 通常都会减少,前面提到过,从 32×32 到 28×28,到 14×14,到 10×10,再到 5×5。所以随着层数增加,高度和宽度都会减小,而通道数量会增加,从 3 到 6 到 16 不断增加,然后得到一个全连接层。
在神经网络中,另一种常见模式就是一个或多个卷积后面跟随一个池化层,然后一个或多个卷积层后面再跟一个池化层,然后是几个全连接层,最后是一个 softmax。这是神经网络的另一种常见模式。
接下来讲讲神经网络的激活值形状,激活值大小和参数数量。输入为 32×32×3,这些数做乘法,结果为 3072,所以激活值 a[0] a [ 0 ] 有 3072 维,激活值矩阵为 32×32×3,输入层没有参数。计算其他层的时候,试着自己计算出激活值,这些都是网络中不同层的激活值形状和激活值大小。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第35张图片
有几点要注意:
第一,池化层和最大池化层没有参数;
第二,卷积层的参数相对较少,之前提到过,其实许多参数都存在于神经网络的全连接层。观察可发现,随着神经网络的加深,激活值尺寸会逐渐变小,如果激活值尺寸下降太快,也会影响神经网络性能。示例中,激活值尺寸在第一层为 6000,然后减少到 1600,慢慢减少到 84,最后输出 softmax结果。我们发现,许多卷积网络都具有这些属性,模式上也相似。

一个卷积神经网络包括卷积层、池化层和全连接层。许多计算机视觉研究正在探索如何把这些基本模块整合起来,构建高效的神经网络,整合这些基本模块确实需要深入的理解。根据我的经验,找到整合基本构造模块最好方法就是大量阅读别人的案例。

10.为什么使用卷积

和只用全连接层相比,卷积层的两个主要优势在于参数共享和稀疏连接。举例说明一下。
假设有一张 32×32×3 维度的图片,假设用了 6 个大小为 5×5 的过滤器,输出维度为 28×28×6。 2×32×3=3072, 28×28×6=4704。我们构建一个神经网络,其中一层含有 3072 个单元, 下一层含有 4074 个单元, 两层中的每个神经元彼此相连, 然后计算权重矩阵, 它等于 4074×3072≈1400 万, 所以要训练的参数很多。
虽然以现在的技术, 我们可以用 1400 多万个参数来训练网络,因为这张 32×32×3 的图片非常小,训练这么多参数没有问题。如果这是一张 1000×1000 的图片,权重矩阵会变得非常大。我们看看这个卷积层的参数数量,每个过滤器都是 5×5,一个过滤器有 25 个参数,再加上偏差参数,那么每个过滤器就有 26 个参数,一共有 6 个过滤器,所以参数共计 156 个,参数数量还是很少。
卷积网络映射这么少参数有两个原因:
一是参数共享。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第36张图片
观察发现,特征检测如垂直边缘检测如果适用于图片的某个区域,那么它也可能适用于图片的其他区域。也就是说,如果你用一个 3×3 的过滤器检测垂直边缘,那么图片的左上角区域,以及旁边的各个区域(左边矩阵中蓝色方框标记的部分)都可以使用这个 3×3 的过滤器。每个特征检测器以及输出都可以在输入图片的不同区域中使用同样的参数,以便提取垂直边缘或其它特征。它不仅适用于边缘特征这样的低阶特征,同样适用于高阶特征,例如提取脸上的眼睛,猫或者其他特征对象。即使减少参数个数,这 9 个参数同样能计算出 16 个输出。直观感觉是,一个特征检测器,如垂直边缘检测器用于检测图片左上角区域的特征,这个特征很可能也适用于图片的右下角区域。因此在计算图片左上角和右下角区域时,你不需要添加其它特征检测器。假如有一个这样的数据集,其左上角和右下角可能有不同分布,也有可能稍有不同,但很相似,整张图片共享特征检测器,提取效果也很好。

二是使用稀疏连接
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第37张图片
解释一下,这个 0 是通过 3×3 的卷积计算得到的,它只依赖于这个 3×3 的输入的单元格,右边这个输出单元(元素 0)仅与 36 个输入特征中 9 个相连接。而且其它像素值都不会对输出产生任影响,这就是稀疏连接的概念。
再举一个例子,这个输出(右边矩阵中红色标记的元素 30)仅仅依赖于这 9 个特征(左边矩阵红色方框标记的区域),看上去只有这 9 个输入特征与输出相连接,其它像素对输出没有任何影响。
神经网络可以通过这两种机制减少参数,以便我们用更小的训练集来训练它,从而预防过度拟合。你们也可能听过,卷积神经网络善于捕捉平移不变。通过观察可以发现,向右移动两个像素,图片中的猫依然清晰可见,因为神经网络的卷积结构使得即使移动几个像素,这张图片依然具有非常相似的特征,应该属于同样的输出标记。实际上,我们用同一个过滤器生成各层中,图片的所有像素值,希望网络通过自动学习变得更加健壮,以便更好地取得所期望的平移不变属性。
这就是卷积或卷积网络在计算机视觉任务中表现良好的原因。
Convolutional Neural Networks---Foundations of Convolutional Neural Networks_第38张图片
最后,我们把这些层整合起来,看看如何训练这些网络。比如我们要构建一个猫咪检测器,我们有下面这个标记训练集, x表示一张图片, y^ y ^ 是二进制标记或某个重要标记。我们选定了一个卷积神经网络,输入图片,增加卷积层和池化层,然后添加全连接层,最后输出一个 softmax,即 y^ y ^ 。卷积层和全连接层有不同的参数w和偏差b,我们可以用任何参数集合来定义代价函数。一个类似于我们之前讲过的那种代价函数,并随机初始化其参数wb,代价 函 数 J 等 于 神 经 网 络 对 整 个 训 练 集 的 预 测 的 损 失 总 和 再 除 以m ( 即 Cost J = 1m 1 m mi=1 ∑ i = 1 m L( y^(i) y ^ ( i ) , y(i) y ( i ) )) 。
所以训练神经网络,你要做的就是使用梯度下降法,或其它算法,例如 Momentum 梯度下降法,含 RMSProp 或其它因子的梯度下降来优化神经网络中所有参数,以减少代价函数J的值。通过上述操作你可以构建一个高效的猫咪检测器或其它检测器。

你可能感兴趣的:(tensorflow实战,深度学习+神经网络)