本系列为 斯坦福CS231n 《深度学习与计算机视觉(Deep Learning for Computer Vision)》的全套学习笔记,对应的课程视频可以在 这里 查看。更多资料获取方式见文末。
上篇 深度学习与CV教程(4) | 神经网络与反向传播 提到的神经网络是线性分类器的堆叠,只不过在中间加入非线性函数,对中间层产生的模板加权后得到最终的得分。计算机视觉中用到更多的神经网络结构是卷积神经网络(Convolutional Neural Networks) ,它与前面提到的前馈神经网络的构想是一致的,只是包含卷积层等特殊构建的神经网络层次结构。本篇ShowMeAI给大家详细展开介绍卷积神经网络。
关于卷积神经网络的详细知识也可以参考ShowMeAI的深度学习教程 | 吴恩达专项课程 · 全套笔记解读中的文章卷积神经网络解读
1957年,Frank Rosenblatt 发明了第一代感知器,第一次实现感知器算法。感知器算法和神经网络很相似,都有 w w w、 x x x、 b b b 等参数,也有参数更新规则。但是感知器只能输出 0 0 0、 1 1 1 两个数,参数更新规则也不是反向传播。
f ( x ) = { 0 i f w ⋅ z + b < 0 1 o t h e r w i s e f(x)= \begin{cases} 0 & if \space\space w\cdot z+b<0 \\ 1 & otherwise \end{cases} f(x)={01if w⋅z+b<0otherwise
更新规则:
w i ( t + 1 ) = w i ( t ) + α ( d j − y j ( t ) ) x j , i w_i(t+1)=w_i(t)+\alpha(d_j-y_j(t))x_{j,i} wi(t+1)=wi(t)+α(dj−yj(t))xj,i
1960年,Widrow 和 Hoff 的 Adaline/Madaline,首次尝试把线性层叠加,整合成多层感知器网络,与现代神经网络层的结构比较类似,但是仍然没有反向传播或其他训练方法。
1986年 Rumelhart 才首次提出反向传播算法,然后我们熟悉的链式法则、更新规则等才逐渐出现。至此有了神经网络核心的训练方法,但是仍然无法训练大型的神经网络。
2006年,Hinton 和 Salakhutdinov 的论文表明神经网络不仅可以训练并且可以高效的训练,但是需要谨慎的初始化,才能反向传播。他们先预先训练得到隐层的参数,再训练整个网络。
直到2012年,深度神经网络才得到大规模的应用。首先是 Geoffrey Hinton 等将 CNN 用于语音识别,然后其同实验室的 Alex Acero 等发表了里程碑式的论文,将 CNN 用于 Image net 大赛极大提高识别率,成为图像分类的标杆方法。
从1959年开始 ,Hubel & Wiesel 做了一些列实验,试图弄明白神经元如何在视觉皮层上工作。他们把电极放进猫的脑袋中,然后给猫不同的视觉刺激,比如不同的边缘方向、不同的形状等,然后测量神经元的应激响应。
他们得出一些重要的结论:一是大脑皮层上的细胞与视觉中的区域相关联,有映射关系。二是神经元间存在分层关系。初级层次的细胞对光的方向产生反应,复杂一点的会对光的移动有反应,超复杂的可以反应端点,识别形状。
1980年,Fukushima 的感知神经器首次将这种简单细胞与复杂细胞的概念形成实例,一种简单细胞与复杂细胞交替层结构。简单细胞会有一些可调参数,复杂细胞对简单细胞执行池化操作。
1998年,LeCun, Bottou, Bengio, Haffner等人首次展示一个实例,应用反向传播和基于梯度的学习方法来训练卷积神经网络,用于邮政编码识别,效果显著。但是有局限性,不能用到更复杂的数据中。
2012年,Alex 等人提出一种现代化的卷积神经网络,称为 AlexNet。与 LeCun 的很相似,只是更大更深,可以充分利用大量图片数据比如 Image net 和 GPU 并行计算能力。
今天,CNN已经被广泛应用到图像分类、目标检测、图像分割等。这些技术被广泛用于自动驾驶领域,使用GPU驱动,将高性能的 GPU 置于嵌入式系统。应用到其他领域,比如人脸识别、视频分类、姿势识别、医学影像分析、星系分类、路标识别,也应用到游戏中,比如 AlfaGo。除了分类识别等任务,还可用于图像描述、艺术创作(Deep Dream,神经图像风格迁移)。
卷积神经网络(CNN / ConvNet) 和常规神经网络非常相似:
卷积神经网络的结构基于输入数据是图像,向结构中添加了一些特有的性质,使得前向传播函数实现起来更高效,并且大幅度降低了网络中参数的数量。
常规神经网络的输入是一个向量,比如把一张 32 × 32 × 3 32 \times 32 \times 3 32×32×3 的图片延展成 3072 × 1 3072 \times 1 3072×1 的列向量 x x x,然后在一系列的隐层中对它做变换。
每个隐层都是由若干的神经元组成,每个神经元都与前一层中的所有神经元连接(这就是全连接的概念)。 但是在一个隐层中,神经元相互独立不进行任何连接。
最后的全连接层被称为「输出层」,在分类问题中,它输出的值被看做是不同类别的评分值。比如线性分类 W x Wx Wx , W W W 是 10 × 3072 10 \times 3072 10×3072 的权重矩阵,即 W W W 有 10 个行向量,最终输出是一个 10 × 1 10 \times 1 10×1 的得分向量,其中的每一个值是 W W W 的某一个行向量和 x x x 的点积结果,也就是一个神经元的输出。
最终会有 10 10 10 个神经元输出 10 10 10 个值( W 0 x , W 1 x , ⋯ , W 9 x W_0x, W_1x, \cdots, W_9x W0x,W1x,⋯,W9x), x x x 和每一个神经元相连,因此是全连接的。
但是全连接神经网络在处理大的图片数据时参数会急速增加,同时效果也不尽如人意。
全连接方式效率不高,且参数量大,可能会导致网络过拟合。
关于卷积层的动图讲解也可以参考ShowMeAI的的深度学习教程 | 吴恩达专项课程 · 全套笔记解读中的文章卷积神经网络解读
与常规神经网络不同,卷积神经网络的各层中的神经元都是 3 维的:宽度、高度和深度(这里的深度指的是激活数据体的第三个维度,而不是整个网络的深度,整个网络的深度指的是网络的层数)。
对于用来分类 CIFAR-10 中图像的卷积网络,其最后的输出层的维度是 1 × 1 × 10 1 \times 1 \times 10 1×1×10,因为在卷积神经网络结构的最后部分将会把全尺寸的图像压缩为包含分类评分的一个向量,向量是在深度方向排列的。
上图左边是常规神经网络,每个神经元和上层的神经元都是全连接的;右图是卷积神经网络,每个神经元都有三个维度,网络每一层都将 3D 的输入数据变化为神经元 3D 的激活数据并输出。
在这个例子中,红色的输入层装的是图像,所以它的宽度和高度就是图像的宽度和高度,它的深度是3(代表了R/红、G/绿、B/蓝3个颜色通道)。
蓝色的部分是第一层卷积层的输出,这里的深度显然不为1,表明有多种滤波器。如果我们有 6 6 6 个 5 × 5 5 \times 5 5×5 的滤波器,每个卷积核代表从输入捕捉某些信息的滤波器,那它们依次滑过整张图片,得到第一个卷积层的输出结果是 28 × 28 × 6 28 \times 28 \times 6 28×28×6 的。如下图所示:
一个简单的卷积神经网络是由各种层按照顺序排列组成,卷积神经网络主要由三种类型的层构成:卷积层,池化(Pooling)层和全连接层(全连接层和常规神经网络中的一样)。通过将这些层叠加起来,就可以构建一个完整的卷积神经网络。
一个用于 CIFAR-10 图像数据分类的卷积神经网络的结构可以是「输入层-卷积层-ReLU层-池化层-全连接层」,这四个层也是目前卷积神经网络比较常用的层。
卷积神经网络一层一层地将图像从原始像素值变换成最终的分类评分值。
实际应用的时候,卷积网络是由多个卷积层依次堆叠组成的序列,然后使用激活函数(比如ReLU函数)对其进行逐一处理。然后这些卷积层、激活层、池化层会依次堆叠,上一层的输出作为下一层的输入。每一层都会使用多个卷积核,每个卷积核对用一个激活映射。
卷积网络这些卷积层的所有卷积核完成训练后,会发现:
这些卷积核是从简单到复杂的特征序列。这实际上和 Hubel & Wiesel 的实验结果比较相似,即使在我们并没有明确的让网络去学习这些从简单到复杂的特征,但是给它这种层次结构并经过反向传播训练后,这些类型的卷积核最终也能学到。
我们有 32 个已经在卷积网络中训练好的 5 × 5 5 \times 5 5×5 卷积核,每一个卷积核滑过原始图像得到一张激活映射,将它们可视化,我们可以看出卷积核在原图像匹配和寻找什么。
比如下图上方红框中的第一个卷积核对应得到红框的激活映射,卷积核看起来像是一个定向边缘的模板,所以当其滑过图像,在那些有定向边缘的地方会得到较高的值。
之所以称作卷积,只是计算形式上就是卷积,滤波器和信号(图像)的元素相乘后求和。
左边的输入层存有原始图像,右边的输出层得到各类别评分。
图像经过一系列卷积层、RELU层、池化层,最后经过全连接层得到针对不同类别的分类得分,这里只显示了得分最高的 5 个评分值和对应的类别。
整个网络包括输入层、输出层共有 17 层,架构是 [conv-relu-conv-relu-pool] x3-fc-softmax,共有7000个参数,使用 3 × 3 3 \times 3 3×3 卷积和 2 × 2 2 \times 2 2×2 池化区域。斯坦福大学 课程主页 上展示的就是这个 CNN 网络。
下面详细介绍卷积层、池化层等层次及其工作原理。
卷积层是构建卷积神经网络的核心层,网络中大部分的计算量都由它产生。
关于卷积层的动图讲解也可以参考ShowMeAI的的深度学习教程 | 吴恩达专项课程 · 全套笔记解读中的文章卷积神经网络解读
卷积层的参数是由一些可学习的滤波器(filter) 集合构成的。每个滤波器在宽度和高度上都比较小,但是深度和输入数据一致。
比如卷积神经网络第一层的一个典型的滤波器的尺寸可以是 5 × 5 × 3 5 \times 5 \times 3 5×5×3(宽高都是 5 5 5 像素,深度是 3 3 3 是因为图像应为颜色通道,所以有3的深度)。
在前向传播的时候,让每个滤波器都在输入数据的宽度和高度上滑动(更精确地说是做卷积),然后计算这个滤波器和输入数据对应每一个区域的内积,最终会生成一个 2 维的激活映射(也叫激活图)(activation map),激活图给出了在每个空间位置处滤波器的反应。
直观地来说,网络会让滤波器学习,结果是当它看到某些类型的视觉特征时就激活,具体的视觉特征可能是某些方位上的边界,或者在第一层上某些颜色的斑点,甚至可以是网络更高层上的蜂巢状或者车轮状图案。
在每个卷积层上,一般有多个滤波器组成集合(比如12个),每个都会生成一个不同的二维激活映射。将这些激活映射在深度方向上层叠起来就生成了这个卷积层的输出3D数据。
这个3D数据的每一个激活图,都是由一些参数相同的神经元在原图像的不同位置做内积得到的输出数据组成的。每张激活图对应的所有神经元参数都相同(因为实际上就是同一个滤波器在图像上不同位置滑动的结果,每到一个位置就是一个神经元),称为参数共享。
卷积层每个神经元和原图像只在一个小区域进行全连接,称为 局部连接。因为在处理图像这样的高维度输入时,让每个神经元都与前一层中的所有神经元进行全连接是不现实的。
局部连接的空间大小叫做神经元的感受野(receptive field) ,它的尺寸(其实就是滤波器的空间尺寸)是一个超参数。在深度方向上,这个连接的大小总是和输入量的深度相等。即连接在空间(宽高)上是局部的,但是在深度上总是和输入数据的深度一致。
重复一下之前的例子,一张 32 × 32 × 3 32 \times 32 \times 3 32×32×3 的图片,滤波器大小为 5 × 5 × 3 5 \times 5 \times 3 5×5×3。此时感受野尺寸是 5 × 5 5 \times 5 5×5,滤波器的深度需要和原图像深度一致,为 3 3 3。那么神经元的权重个数为 5 × 5 × 3 = 75 5 \times 5 \times 3=75 5×5×3=75 个,再加一个偏置项,共 76 76 76 个。神经元和原图像一个同样大小的区域是全连接的,共有 75 75 75 个连接,但是与整个图像是局部连接的(只在 5 × 5 5 \times 5 5×5 的空间上连接),如果是全连接则需要有 3072 3072 3072 个连接。
卷积层的所有神经元与原始图像卷积后,输出数据体的尺寸由三个超参数控制:深度(depth),步长(stride) 和零填充(zero-padding) 。
① 深度 :卷积层中使用的滤波器往往有多个,深度就是滤波器的数量。
② 步长:步长就是滤波器每次移动跨越的像素数量。
③ 零填充:在图像的边界外填充零像素点。
比如有一个 7 × 7 7 \times 7 7×7 的原始图片,滤波器的尺寸是 3 × 3 3 \times 3 3×3,步长为 1 1 1 时的输出是 5 × 5 5 \times 5 5×5;步长为 2 2 2 时输出是 3 × 3 3 \times 3 3×3,但步长是 3 3 3 的时候尺寸不再适合。
假设图片的尺寸是 N × N N \times N N×N,滤波器尺寸是 F × F F \times F F×F,步长为 S S S,则输出数据的尺寸为: ( N − F ) / S + 1 (N-F)/S +1 (N−F)/S+1。所以当 N = 7 N=7 N=7, F = 3 F=3 F=3:
所以步长的设置不合理会导致网络的异常,引入零填充可一定程度解决这个问题。
下面考虑加入零填充的情形。在 7 × 7 7 \times 7 7×7 的图像外面加入一圈零像素,滤波器尺寸仍为 3 × 3 3 \times 3 3×3,步长为 1,此时的输出尺寸应该是多少?答案是 7 × 7 7 \times 7 7×7,因为此时的原图像相当于变成 9 × 9 9 \times 9 9×9。此时的输出数据空间尺寸和输入的相同。
综上,可得输出数据尺寸的计算公式:
假如输入数据体尺寸 W × W W \times W W×W,卷积层中神经元的感受野尺寸 F × F F \times F F×F,步长 S S S 和零填充的数量 P P P,则输出数据体的空间尺寸为 ( W + 2 P − F ) / S + 1 (W+2P-F)/S+1 (W+2P−F)/S+1 。
一般来说,当步长 S = 1 S=1 S=1 时,为保证输入尺寸和输出尺寸相同,零填充的数量为: P = ( F − 1 ) / 2 P=(F-1)/2 P=(F−1)/2 。
那么这个卷积层有多少个参数呢?
那么这个卷积层一共有多少个神经元呢?
但是,既然有 32 × 32 × 10 32 \times 32 \times 10 32×32×10 个神经元,每个神经元的参数为 76,那为什么只有 760 个参数呢?大家可以在后面的参数共享部分可以找到答案。
AlexNet 神经网络架构,赢得了2012年的 ImageNet 挑战,它的结构中:
在卷积层中使用参数共享是用来控制参数的数量。
就用上面的真实案例,在第一个卷积层就有 55 × 55 × 96 = 290 , 400 55 \times 55 \times 96=290,400 55×55×96=290,400 个神经元(假设神经元都是独立的)
作一个合理的假设:如果一个特征在计算某个空间位置 ( x , y ) (x,y) (x,y)的时候有用,那么它在计算另一个不同位置 ( x 2 , y 2 ) (x_2,y_2) (x2,y2)的时候也有用。
基于这个假设,可以显著地减少参数数量。也是基于这个假设,滤波器可以在原图片上滑动。
如果我们将深度维度上一个单独的 2 维切片看做深度切片(depth slice),比如这个尺寸为 [ 55 × 55 × 96 ] [55 \times 55 \times 96] [55×55×96] 的输出数据体就有 96 个深度切片,每个尺寸为 [ 55 × 55 ] [55 \times 55] [55×55] 。在每个深度切片上的神经元都使用同样的权重和偏置项。
在这样的参数共享下,例子中的第一个卷积层就只有 96 个不同的参数集了,一个参数集对应一个深度切片,共有 96 × ( 11 × 11 × 3 + 1 ) = 34 , 944 96 \times (11 \times 11 \times 3+1)=34,944 96×(11×11×3+1)=34,944 个不同的参数(包括偏置项)。
在每个深度切片中的 55 × 55 55 \times 55 55×55 个权重使用的都是同样的参数。
在反向传播的时候,需要计算每个神经元对它的权重的梯度,所以需要把同一个深度切片上的所有神经元对权重的梯度进行累加,这样就得到了对这个共享权重的梯度。这样,每个切片只更新一个权重集。
补充解释:正是因为参数共享,卷积层的前向传播在每个深度切片中可以看做是在计算神经元权重和输入数据体的卷积(这就是「卷积层」名字由来)。这也是为什么总是将这些权重集合称为滤波器(filter) (或卷积核(kernel) ),因为它们和输入进行了卷积。
有时候参数共享假设可能没有意义,特别是当卷积神经网络的输入图像是一些明确的中心结构时候。这时候我们就应该期望在图片的不同位置学习到完全不同的特征。一个具体的例子就是输入图像是人脸,人脸一般都处于图片中心。你可能期望不同的特征,比如眼睛特征或者头发特征可能(也应该)会在图片的不同位置被学习。在这个例子中,通常就放松参数共享的限制,将层称为局部连接层(Locally-Connected Layer)。
下面是一个卷积层的运行演示。因为 3D 数据难以可视化,所以所有的数据(输入数据体是蓝色,权重数据体是红色,输出数据体是绿色)都进行深度切片然后排成一列来展现。
注意输入数据体使用了零填充 P = 1 P=1 P=1,所以输入数据体外边缘一圈都是 0 0 0。下面的例子在绿色的输出激活图上循环演示,展示了其中每个元素都是蓝色的输入数据和红色的滤波器逐元素相乘,然后求其总和,最后加上偏置项得来。高清版展示,建议访问 课程官网。
卷积运算本质上就是在滤波器和输入数据的局部区域做点积。卷积层的常用实现方式就是利用这一点,将卷积层的前向传播变成一个巨大的矩阵乘法:
输入图像的局部区域被 im2col
操作拉伸为列。比如,如果输入是 [ 227 × 227 × 3 ] [227 \times 227 \times 3] [227×227×3] ,要与尺寸为 11 × 11 × 3 11 \times 11 \times 3 11×11×3 的滤波器以步长为 4 4 4 进行卷积,就取输入中的 [ 11 × 11 × 3 ] [11 \times 11 \times 3] [11×11×3] 数据块,然后将其拉伸为长度为 11 × 11 × 3 = 363 11 \times 11 \times 3=363 11×11×3=363 的列向量。重复进行这一过程,因为步长为 4 4 4,所以输出的宽高为 ( 227 − 11 ) / 4 + 1 = 55 (227-11)/4+1=55 (227−11)/4+1=55,即需要 55 \times 55=3025 个这样的列向量与滤波器做点积。所以输入数据 X X X 经过im2col操作后的输出矩阵 X_col
的尺寸是 [ 363 × 3025 ] [363 \times 3025] [363×3025] ,其中每列是 X X X 上拉伸的感受野,共有 55 × 55 = 3 , 025 55 \times 55=3,025 55×55=3,025 个。注意因为感受野之间有重叠,所以输入数据体中的数字在不同的列中可能有重复。
卷积层的权重也同样被拉伸成行。举例,如果有 96 个尺寸为 [ 11 × 11 × 3 ] [11 \times 11 \times 3] [11×11×3] 的滤波器,就生成一个矩阵 W_row
,尺寸为 [ 96 × 363 ] [96 \times 363] [96×363] 。
现在卷积的结果和进行一个大矩阵乘法 np.dot(W_row, X_col)
是等价的了,能得到每个滤波器和每个感受野间的点积。在这个例子中,这个操作的输出是 [ 96 × 3025 ] [96 \times 3025] [96×3025] ,给出了每个滤波器在每个位置的点积输出。
结果最后必须被重新变为合理的输出尺寸 [ 55 × 55 × 96 ] [55 \times 55 \times 96] [55×55×96] 。
这个方法的缺点就是占用内存太多,因为在输入数据体中的某些值在 X_col
中被复制了多次。但是,其优点是有非常多高效的矩阵乘法实现方式供我们可以使用,比如常用的 BLAS API。同样,im2col
思路可以用在汇聚操作中。
反向传播:卷积操作的反向传播(同时对于数据和权重)还是一个卷积(但是是在空间上翻转的滤波器)。使用一个1维的例子比较容易演示(这里不再展开)。
一些网络结构中会使用 1 × 1 1 \times 1 1×1 的卷积,这个方法最早是在论文 Network in Network 中出现。在后来的很多模型结构中,使用它主要是起到升降维的作用。
大家也会看到扩张卷积(空洞卷积)这样的特殊结构。我们之前看过的卷积层滤波器是连续的,但让滤波器中元素之间有间隙也是合理的设计,这就叫做扩张。这种特殊的卷积可以帮助 CNN 有效扩大感受野。
如下图为普通卷积和空洞卷积的动图对比:
通常,在连续的卷积层之间会周期性地插入一个池化层。它的作用是逐渐降低数据体的空间(宽、高)尺寸,这样的话就能减少网络中参数的数量,使得计算资源耗费变少,也能有效控制过拟合。
池化层最常用的是 MAX 操作,对输入数据体的每一个深度切片独立进行操作,改变它的空间尺寸。最常见的形式是使用尺寸 2 × 2 2 \times 2 2×2 的滤波器,以步长为 2 2 2 来对每个深度切片进行降采样,将其中B 75 % 75\% 75% 的激活信息都丢掉。每个 MAX 操作是从 4 4 4 个数字中取最大值(也就是在深度切片中某个 2 × 2 2 \times 2 2×2 的区域)。深度方向保持不变,不进行降采样。
池化层也不用零填充,并且池化滤波器间一般没有重叠,步长等于滤波器尺寸。
除了最大池化,池化单元还可以使用其他的函数,比如平均池化(average pooling)或 L2 范式池化(L2-norm pooling)。平均池化历史上比较常用,但是现在已经很少使用了。
池化层在输入数据体的每个深度切片上,独立地对其进行空间上(高度、宽度)的降采样。
反向传播
一些争议
在卷积神经网络的结构中,提出了一些归一化层的概念,想法是为了实现在生物大脑中观测到的抑制机制。但是这些层渐渐都不再流行,因为实践证明它们的效果即使存在,也是极其有限的。
对于不同类型的归一化层,可以看看nAlex Krizhevskyn的关于 cuda-convnet library API 的讨论。
全连接层,顾名思义,神经元对于前一层中的所有激活数据是全连接的,这个和常规神经网络中一样,通常会把前一层数组拉成一个向量,与 W W W 的每个行向量进行点积,得到每一类的分数。
最后一个池化层输出的结果是数据经过整个网络累计得到的,前几个卷积层可能检测一些比较简单的特征比如边缘,得到边缘图后输入到下一个卷积层,然后进行更复杂的检测,这样层层下来,最后一层的结果可以看成是一组符合模板的激活情况,比较大的值表明之前的所有检测结果都比较大,激活程度高,这样就汇聚了大量的信息。
虽然输出的数据比较简单,但却是非常复杂的滤波器(或特征)激活后的情况,特征在卷积核中体现。
全连接层和卷积层之间唯一的不同就是卷积层中的神经元只与输入数据中的一个局部区域连接,并且在同一个深度切片上的神经元共享参数。然而在两类层中,神经元都是计算点积,所以它们的函数形式是一样的。因此,将此两者相互转化是可能的:
① 对于任一个卷积层,都存在一个能实现和它一样的前向传播函数的全连接层。
② 反过来,任何全连接层都可以被转化为卷积层。
两种转换的示意图如下图所示:
上述两种转换中,全连接层转化为卷积层在实际运用中更加有用。
假设一个卷积神经网络的输入是 224 × 224 × 3 224 \times 224 \times 3 224×224×3 的图像,一系列的卷积层和池化层将图像数据变为尺寸为 7 × 7 × 512 7 \times 7 \times 512 7×7×512 的激活数据体(在 AlexNet 中就是这样,通过使用5个池化层来对输入数据进行空间上的降采样,每次尺寸下降一半,所以最终空间尺寸为 224/2/2/2/2/2=7)。
全连接层中,AlexNet 先使用了两个尺寸为 4096 4096 4096 的全连接层,然后又使用了一个有1000 个神经元的全连接层用于计算分类评分。
我们可以将这 3 个全连接层中的任意一个转化为卷积层:
我们注意到,每次类似的变换,都需要把全连接层的权重 W W W 重塑成卷积层中和输入数据尺寸相同的滤波器。这个转化最大的意义是让一些计算更高效:
我们来看看这个例子:
将 224 × 224 × 3 224 \times 224 \times 3 224×224×3 的图片经过卷积网络(不包括最后三个全连接层)后得到 7 × 7 × 512 7 \times 7 \times 512 7×7×512 的激活数据体(降采样5次,除32)。然后经过第一个全连接层,该全连接层的神经元需要 7 × 7 × 512 7 \times 7 \times 512 7×7×512 个参数。
如果换成一张 384 × 384 384 \times 384 384×384 的大图片经过同样的网络(不包括最后三个全连接层)等效输出尺寸为 12 × 12 × 512 12 \times 12 \times 512 12×12×512( 384 / 32 = 12 384/32 = 12 384/32=12),如果直接用来通过全连接层,由于尺寸不同,会无法通过。
卷积神经网络通常是由三种层构成:卷积层,池化层和全连接层(简称FC)。ReLU 激活函数也应该算是一层,它逐元素地进行激活函数操作。
卷积神经网络最常见的形式就是将一些卷积层和 ReLU 层放在一起,其后紧跟池化层,然后重复如此直到图像在空间上被缩小到一个足够小的尺寸,在某个地方过渡成成全连接层也较为常见。最后的全连接层得到输出,比如分类评分等。
换句话说,最常见的卷积神经网络结构如下:
INPUT → [[CONV → RELU]*N → POOL?]*M → [FC → RELU]*K → FC
其中 *
指的是重复次数,POOL?
指的是一个可选的池化层。其中 N > = 0 N >=0 N>=0(通常 N < = 3 N<=3 N<=3), M > = 0 M>=0 M>=0, K > = 0 K>=0 K>=0(通常 K < 3 K<3 K<3)。
例如,下面是一些常见的网络结构规律:
INPUT → FC,实现一个线性分类器,此处 N = M = K = 0 N = M = K = 0 N=M=K=0;
INPUT → CONV → RELU → FC;
INPUT → [CONV → RELU → POOL]*2 → FC → RELU → FC,此时在每个池化层前只有一个卷积层;
INPUT → [CONV → RELU → CONV → RELU → POOL]*3 → [FC → RELU]*2 → FC,此时每个池化层前有两个卷积层,这个思路适用于更大更深的网络,因为在执行具有破坏性的池化操作前,多重的卷积层可以从输入数据中学习到更多的复杂特征。
经验:几个小滤波器卷积层的组合比一个大滤波器卷积层好。
假设你一层一层地重叠了 3 3 3 个 3 × 3 3 \times 3 3×3 的卷积层(层与层之间有非线性激活函数)。
下图是第1层和第2层卷积层的堆叠感受野示意图
假设不采用这3个 3 × 3 3 \times 3 3×3 的卷积层,而是使用一个单独的有 7 × 7 7 \times 7 7×7 的感受野的卷积层,那么所有神经元的感受野也是 7 × 7 7 \times 7 7×7,但是就有一些缺点:
直观说来,最好选择带有小滤波器的卷积层组合,而不是用一个带有大的滤波器的卷积层。前者可以表达出输入数据中更多个强力特征,使用的参数也更少。
唯一的不足是,在进行反向传播时,中间的卷积层可能会导致占用更多的内存。
原始输入图像,经常设置为 2 N 2^N 2N 形式。常用数字包括32(比如CIFAR-10),64,96(比如STL-10)或224(比如ImageNet卷积神经网络)、384和512。
在某些案例(尤其是早期的卷积神经网络结构)中,基于前面的各种规则,内存的使用量迅速飙升。
因为GPU通常因为内存导致性能瓶颈,所以做出一些妥协是必须的。在实践中,人们倾向于在网络的第一个卷积层做出妥协。
这些网络的详细结构会在后续再展开介绍。
关于详细的下述网络结构讲解也可以阅读ShowMeAI的的深度学习教程 | 吴恩达专项课程 · 全套笔记解读中的文章经典CNN网络实例详解
第一个成功的卷积神经网络应用,是Yann LeCun在上世纪90年代实现的。当然,最著名还是被应用在识别数字和邮政编码等的 LeNet 结构。
AlexNet 卷积神经网络由Alex Krizhevsky,Ilya Sutskever 和 Geoff Hinton 实现。AlexNet 在2012年的 ImageNet ILSVRC 竞赛 中夺冠,性能远远超出第二名(16%的 top5 错误率,第二名是 26% 的 top5 错误率)。这个网络的结构和 LeNet 非常类似,但是更深更大,并且使用了层叠的卷积层来获取特征。
Matthew Zeiler 和 Rob Fergus 发明的网络在2013年 ILSVRC 比赛中夺冠,它被称为 ZFNet(Zeiler & Fergus Net 的简称)。它通过修改结构中的超参数来实现对 AlexNet 的改良,具体说来就是增加了中间卷积层的尺寸,让第一层的步长和滤波器尺寸更小。
2014年 ILSVRC 的胜利者是谷歌的 Szeged等 实现的卷积神经网络。它主要的贡献就是实现了一个奠基模块,它能够显著地减少网络中参数的数量(AlexNet中有60M,该网络中只有4M)。以及,GoogLeNet 没有在卷积神经网络的最后使用全连接层,而是使用了一个平均池化,把大量不是很重要的参数都去除掉了。GooLeNet 还有几种改进的版本,最新的一个是 Inception-v4。
VGGNet 是Karen Simonyan和 Andrew Zisserman实现的卷积神经网络,在2014年 ILSVRC 取得第二名的成绩。它主要的贡献是展示出网络的深度是算法优良性能的关键部分。他们最好的网络包含了 16 个卷积/全连接层。网络的结构非常一致,从头到尾全部使用的是 3 × 3 3 \times 3 3×3 的卷积和 2 × 2 2 \times 2 2×2 的池化。
残差网络(Residual Network)是2015年ILSVRC的胜利者,由何恺明等实现。它使用了特殊的跳跃链接,大量使用了 批量归一化(batch normalization)。这个结构同样在最后没有使用全连接层。
在构建卷积神经网络结构时,最大的瓶颈是内存瓶颈。大部分现代GPU的内存都不太大。要注意三种内存占用来源:
卷积神经网络中的每一层中都有激活数据体的原始数值,以及损失函数对它们的梯度(和激活数据体尺寸一致)。通常,大部分激活数据都是在网络中靠前的层中(比如第一个卷积层)。
一旦对于所有这些数值的数量有了一个大略估计(包含激活数据,梯度和各种杂项),把这个值乘以4,得到原始的字节数(因为每个浮点数占用4个字节,如果是双精度浮点数那就是占用8个字节),然后多次除以 1024 分别得到占用内存的 KB、MB,最后是GB计量。如果你的网络有内存问题,一个常用的方法是降低批尺寸(batch size),因为绝大多数的内存都是被激活数据消耗掉了。
ConvNetJS CIFAR-10 demo 可以在服务器上实时地调试卷积神经网络的结构,观察计算结果。
可以点击 B站 查看视频的【双语字幕】版本
【字幕+资料下载】斯坦福CS231n | 面向视觉识别的卷积神经网络 (2017·全16讲)