python卷积神经网络_神经网络-卷积神经网络(python3)

前言

这篇对于卷积神经网络的介绍翻译自斯坦福大学的cs231n课程笔记,这是十分著名的一个系列课程,网上也有很多翻译版。我们秉承着“纸上得来终觉浅,绝知此事要躬行”的态度,自己动手进行了翻译。我们选择这篇文章进行翻译是因为其讲解确实很透彻,可以说是不厌其烦地对卷积神经网络的来龙去脉进行了系统的介绍。通篇理解下来,可以说是醍醐灌顶、茅塞顿开,会对卷积神经网络有一个明确的认识和理解。

卷积神经网络

卷积神经网络(convolutional neural network,CNN)与之前所讨论的常规神经网络十分相似,它们都由可以对权重和偏置进行学习的神经元构成。每个神经元接收一些输入数据,然后执行点积操作,再紧接一个任意的非线性激活函数。整个网络仍然表示为一个可微分的评估函数,从其一端输入原始图像像素,另一端输出类别的概率。其最后一层(全连接层)同样有损失函数,并且我们学习常规神经网络的方法和技巧在这里仍然奏效。

那么卷积神经网络有什么不同之处?首先卷积网络很明确地假设所有输入都为图像,基于此假设,我们在结构中添加了一些特有的性质。这些特有的性质使得前向函数的实现更加高效,并且极大的减少了网络中参数的数量。

结构概述

回顾:正如我们所熟知的,常规神经网络接收一个输入(一维向量),并通过一系列的隐藏层对其进行转换。每个隐藏层由一组神经元构成,其中每个神经元都与前一层的全部神经元相连接,并且同一层的各个神经元都是独立工作的,它们的连接并不共享。位于最后一层的全连接层称为输出层,在分类模型中,它将会得出类别的概率。

标准神经网络对于大尺寸图像的应用效果不佳:在CIFAR-10(一个开源在线的图像数据集)中,图像的尺寸仅为32×32×3(宽度32,高度32,3个通道),因此一个常规神经网络的第一层隐藏层中的单个全连接的神经元将会有32×32×3=3072个权重(全连接网络中,输入向量有多少维,每个神经元就需要有多少个权重,这样才能做点积)。这个数量看起来还好,但是显然这种全连接的结构并不能扩展到更大尺寸的图像。例如:一个200×200×3的大尺寸图像,将会使神经元有200×200×3=120000个权重。并且我们几乎肯定会有许多这样的神经元,因此参数的数量将会急剧增加。显然,这种全连接的结构效率低下,并且大量的参数将会很快导致过拟合。

三维神经元:卷积神经网络充分利用了其输入是由图像组成的这一事实,并以更加合理的方式对结构进行了约束。特别是,与常规网络不同,卷积网络各层的神经元具有三个维度,即宽度、高度、深度。例如:将CIFAR-10中的图像作为输入,我们将其称之为输入数据,并且该数据的尺寸为32×32×3(分别为宽度,高度,深度)。正如我们随后将看到的,每一层的神经元仅与前一层的局部相连,而不是采用全连接的方式。此外,CIFAR-10的最终输出层的尺寸为1×1×10,因为在卷积网络结构的最后我们将会把完整的图像缩减为关于类别概率的一维向量,且该一维向量沿着深度维度排列。如下图所示:

左图:常规三层神经网络。右图:由三维神经元构成的卷积网络(宽度,高度,深度)。卷积网络的每一层将三维输入数据转换为经过神经元激活的三维输出数据。在这个图例中,红色的输入层代表图像,因此它的宽度和高度就是图像的宽度和高度,而它的深度为3(红,绿,蓝三个通道)。

卷积网络的各层

正如上文所描述的,一个简单的卷积网络由一系列的层所构成,并且卷积网络的每一层通过一个可微函数将一批数据转换成另一批数据。我们主要用三类层来构造卷积网络:卷积层、池化层以及全连接层。我们将通过堆叠这些层来形成一个完整的卷积网络结构。

示例:接下来我们将讨论更多细节问题,一个用于对CIFAT-10进行分类的简单的卷积网络的结构是(输入层-卷积层-ReLu函数层-池化层-全连接层),详细来说:输入层(32×32×3)将保存图像的原始像素值,在本例中一个图像具有宽度32,高度32,以及三个颜色通道R,G,B。

卷积层负责计算与输入层局部连接的神经元的输出,即分别计算每个神经元的权重与它们所连接的输入数据的局部之间的点积。如果我们打算使用12个滤波器,那么将会得到尺寸为32×32×12的数据。

ReLu层将会对每一个元素应用一个激活函数,例如以0为阈值的

,该操作并不会改变数据的尺寸,故其尺寸仍为32×32×12。

池化层将会在二维面上(宽度,高度)执行降采样的操作,即得到尺寸为16×16×12的数据。

全连接层将会计算类别的概率,得到尺寸为1×1×10的数据,其中10个数值分别对应每个类别的概率。全连接层,顾名思义该层和普通的神经网络一样,每一个神经元都将与前面数据的全部数据点相连接。

通过这种方式,卷积网络将原始图像逐层地从原始像素值转换为最终的类别概率。注意,有些层包含一些参数,而有些层则不包含参数。尤其是卷积层和全连接层,其不仅有激活函数,也有参数(神经元的权重和偏置),二者共同对输入数据执行变换操作。另一方面,ReLu层和池化层将执行一个具有固定功能的函数。卷积层和全连接层中的参数将使用梯度下降进行训练,以使卷积网络计算的类别概率与训练集中每个图像的标签一致。

综上所述:一个卷积网络结构最简单的情况就是顺序排列各个层,以达到将图像数据转换为输出数据的目的。

共有几种不同类型的层(例如最流行的:卷积层,全连接层,ReLu层,池化层)。

每一层接收一个三维数据作为输入,并且通过可微函数将其转换为另一个三维数据作为输出。

每一层都可能包含或者不包含参数(例如:卷积层和全连接层包含参数,ReLu层和池化层则不包含参数)。

每一层都可能包含或者不包含超参数(例如:卷积层、全连接层、池化层包含超参数,ReLu层则不包含超参数)。

现在,让我们来对每一层,及其超参数的细节以及其连接方式进行具体的描述。

卷积层

卷积层是一个卷积神经网络的核心组成部分,它负责完成大部分计算繁重的工作。

概述以及直观认识:我们先来讨论卷积层是如何进行计算的,并且是从更加直观的角度来进行讨论,而不是将其类比为脑神经。首先,卷积层的参数由一组可以进行学习的滤波器组成。每一个滤波器都是一个小的二维面区域(沿宽度和高度),但却延伸到输入数据的全部深度。例如:卷积网络第一层上的一个典型滤波器的尺寸可能为5×5×3(即,5个像素的宽度和高度,而3是由于图像的深度为3)。在正向传播期间,我们沿着输入数据的宽度和高度方向滑动(更确切地说是卷积)每个滤波器,并计算滤波器的端口与滤波器处于每个位置上的输入的点积。当我们将滤波器沿着输入数据的高度和宽度滑过之后,将会得到一个二维的激活映射图,该图给出了滤波器在滑动过的每个位置上得到的结果。直观地说,网络将让滤波器进行学习,使得当他们看到某种类型的视觉特征时就会激活,例如第一层上某种方向的条棱或某种颜色的斑点,或者最终在网络的更高层上形成的整个蜂窝或轮状图案。举例来说:假设如下图所示,有一个5×5×1的输入数据,而滤波器的尺寸为3×3×1,该滤波器共有3×3×1=9个端口,其值分别为(-1,0,1,-1,0,1,-1,0,1)。滤波器从输入数据最左上角的3×3的二维区域位置开始,一次移动一个小格,最终移动到最右下角的位置,滤波器每移动到一个位置,就计算该区域内的输入值与滤波器端口的点积(在本图中,计算1×-1 + 0×0 + 2×1 + 5×-1 + 4×0 + 2×1 + 3×-1 + 4×0 + 5×1 = 0),并将得到的结果放在二维的激活映射图的相应位置上(在本图中,将点积得到的结果0放在激活映射图的第一行第二列上)。实际上,这里还需要加上一个偏置。再将最终结果放到二维激活映射图中。

接下来,我们将在每个卷积层上使用一整组的滤波器(即12个滤波器),其中每一个滤波器都将产生一个二维的激活映射图。我们将这些激活映射图沿着深度堆叠起来,得到一个输出数据。

从脑神经角度理解:如果您喜欢把它与脑神经进行类比的话,那么三维的输出数据的每个数据点也可以解释为神经元的输出值,该神经元只关注于输入的一小部分区域,并且与左右相邻的神经元共享参数(因为这些神经元的输出值都是来自同一个滤波器的结果)。接下来我们将讨论这些神经元的连接细节,它们在空间中的排列方式,以及它们的参数共享方案。

局部连接:当处理例如图像这种高维输入时,正如我们上面看到的,将所有神经元进行全连接是不现实的。因此,我们将每个神经元只与输入数据的部分相连接。这种连接在二维面(即宽度和高度)上的范围是一个超参数,称之为神经元的感受野(相当于是过滤器的大小),而沿着深度方向的连接范围却总是和输入数据的深度相等。必须再次强调我们在处理二维面(宽度和高度)和深度上的不对称性。在二维面上是局部连接(沿着宽度和高度的),而沿着输入数据的整个深度方向进行的却是全连接。例1:例如,假设输入数据的尺寸是32×32×3。如果感受野(或者说滤波器的尺寸)是5×5,那么卷积层中的每个神经元将会有对应于输入数据中5×5×3区域的权重,即每个神经元总共有5×5×3=75个权重(加上1个偏置参数)。值得注意的是,沿着深度方向的连接范围必须为3,因为这是输入数据的深度。

例2:假设一个输入数据的尺寸为16×16×20,感受野的尺寸假设为3×3,卷积层中的每一个神经元与输入数据体之间将会有3×3×20=180个连接。再次强调,连接在二维面上是局部的(即3×3),但是在输入的深度方向上却是全连接的(20)。

左图:浅红色所表示的是输入数据(即32×32×3),而深红色表示第一层卷积层上的神经元所连接的局部数据的示例。卷积层上的每个神经元只与输入数据的局部相连接,但是在深度上却是全连接的。注意,这里沿着深度方向有多个神经元(在本例中是5个),它们都注视着输入数据的同一区域(参见后文提到的深度列)。右图:仍然计算神经元的权重和输入的点积,再紧接一个非线性激活函数,只是它们的连接现在被限制在局部区域内。

空间排列:我们已经阐明了卷积层中的每个神经元与输入数据之间的连接,但是我们还没有讨论神经元的个数以及它们如何进行排列的。三个超参数控制着输出数据的尺寸:分别是深度、步长以及零填充,接下来我们将对其进行讨论:首先,输出数据的深度是一个超参数:它对应于我们使用的滤波器的个数,每个滤波器都能够进行学习以从输入中寻找一些不同的东西。例如,第一个卷积层将原始图像作为输入,那么沿着深度方向的不同神经元可以在各种不同的定向条棱或颜色斑点存在时激活。我们称注视着输入的同一区域的一组神经元为深度列(有些人也喜欢叫纤维条)。

其次,我们必须指定我们滑动滤波器的步长。当步长为1时,我们将滤波器每次移动一个像素。当步长为2(或者3或者更多,虽然实际中并不常见)时,我们将滤波器一次跳跃2个像素来进行滑动。这样将产生二维面(宽度和高度)尺寸较小的输出数据。

正如我们即将看到的,有时在输入数据的边界四周使用0填充将会很方便。零填充的大小也是一个超参数。零填充的优点在于,它可以让我们控制输出数据的二维面的尺寸(正如我们马上就要看到的,最常见的是,我们将使用它来精确地保留输入数据的二维面的尺寸,以使输入和输出的宽度和高度是相同的)。

我们可以根据输入数据的尺寸

,卷积层神经元的感受野的尺寸

,它们所应用的步长

,以及边界上使用的零填充的尺寸

,来计算输出数据的尺寸。你可以自己证明一下,计算有多少个神经元合适的公式为

。例如有一个7×7的输入,步长为1的3×3的滤波器,没有零填充即

,于是我们会得到5×5的输出。如果是2步长我们将会得到3×3的输出。让我们再来看一个图形化的例子:

如图所示:在这个例子中,只有一个空间维度(X轴),神经元的感受野F=3,输入大小为W=5,而零填充P=1。左边:神经元以1的步长滑过输入,给出的输出尺寸为(5 - 3 + 2)/ 1 + 1 = 5。右边:神经元的步长为S=2,给出的输出尺寸为(5 - 3 + 2)/ 2 + 1 = 3。而本例中的神经元的权重为1,0,-1(最右边的三个绿色方格所示),而偏置为0。显然,所有的黄色的神经元之间共享这些权重参数(参见下面的参数共享)。

零填充的使用:在上面的例子中,左图中的输入尺寸是5,输出尺寸也是5。这是因为我们的感受野是3并且我们使用的零填充的尺寸为1。如果没有使用零填充,那么输出数据的尺寸将是3。通常,在步长S = 1时,将零填充设置为P = (F - 1)/2 可以确保输入数据与输出数据具有相同大小的二维面(宽度和高度)。以这种方式使用零填充是非常常见的,我们将在讨论更多卷积网络的结构时对其充分原因进行探讨。

步长的限制:需要再次注意,决定神经元空间排列方式的超参数是相互约束的。例如,当输入尺寸

,不使用零填充即

,滤波器的大小为

,那么步长就不可能为2,因为

,即结果为非整数,这显然不行。因此,这样设置超参数是无效的,神经网络库可能会抛出一个异常,或是对其余部分进行零填充,或是对输入进行剪裁,等等。正如我们将在神经网络结构部分看到的,适当调整神经网络的尺寸以使所有维度都得到合理的解决可能是一件非常头疼的事情,因此使用零填充和某些设计准则将显著缓解这种压力。

真实世界的例子:Krizhevsky等人赢得2012年ImageNet挑战赛的架构能够接受大小为227×227×3的图片输入。在第一层卷积层,使用的神经元的感受野尺寸为

,步长

,零填充

。因为

,并且由于卷积层深度

,因此卷积层的输出大小为55×55×96。55×55×96个神经元中的每一个都与输入数据中大小为11×11×3的区域连接。此外,每一个深度列(纤维条)上的神经元都与同一个11×11×3的区域相连接,但每个神经元必然都有着不同的权重。

参数共享:参数共享方案在卷积层中用于控制参数的数量。我们使用上述真实世界的例子,在第一层卷积层中共有55×55×96=290400个神经元,并且每一个神经元都有11×11×3=363个权重和一个偏置。将这些加在一起,那么仅在卷积网络的第一层上就有290400×364=105705600个参数。显然,这个数量非常大。事实证明,我们可以通过一个合理的假设来大大减少参数的数量:即一个数据点如果在一些位置上

可用于计算,那么在另一个位置上

也可用于计算。换句话说,将一个2维面切片表示为深度切片(例如:尺寸为55×55×96的数据具有96个深度切片,每个深度切片尺寸为55×55)。我们将限制每个深度切片中的神经元具有相同的权重和偏置。有了这种参数共享方案,我们例子中的第一层卷积层中将只有96组不同的权重(每一组对应一个深度切片),总共有96×11×11×3=34848个权重,或者说是34944个参数(加上96个偏置)。或者说,每个深度切片中的55×55个神经元现在将使用相同的参数。在实际的反向传播过程中,数据中的每个神经元都会计算其权重的梯度,但是该梯度将叠加在每个深度切片上,并且仅更新每个切片的一组权重。

此图为Krizhebsky等人学习到的示例滤波器,此处显示的96个滤波器中每个滤波器的尺寸为11×11×3,并且每个滤波器由一个深度切片中的55×55个神经元共享。注意,参数共享假设是相对比较合理的:即如果在图片中的某个位置检测到水平条棱很重要,那么由于图片的平移不变性,它也将在图片的其他位置起到重要作用,这是很直观的。因此不需要重新进行学习来检测卷积层输出数据中每个55×55不同位置上的水平条棱。

请注意,有时参数共享假设可能没有意义。当输入到卷积网络中的图像具有特定的中心结构时,尤其如此,例如,我们期望在图像的一侧学习到完全不同的特征而不是另一侧。一个实际的例子是,当输入的是在图像中居中的人脸图像时,你可能(而且应该)希望在不同的空间位置学习到眼部或头发的特定特征。在这种情况下,通常会放宽参数共享方案,而只将该层称之为局部连接层。

Numpy实际举例:为了使以上的讨论更加具体,我们将用具体例子的代码来阐明上述思想。假设输入数据是一个numpy arrayX,于是:一个在(x,y)位置上的深度列(或者说是纤维条)为X[x,y,:]。

一个深度切片,或者等效于一个在深度d位置上的激活映射图为X[:,:,d]。

假设输入数据X的尺寸为X.shape:(11,11,4)。此外,假设我们不使用零填充(即

),滤波器的尺寸为

,并且步长为

。因此输出数据的尺寸将会是

,即给定一个宽度和高度都为4的数据。输出特征体中的激活映射图(称之为V)如下所示(在该例中只对一部分元素进行计算)。V[0,0,0] = np.sum(X[:5,:5,:] * W0) + b0

V[1,0,0] = np.sum(X[2:7,:5,:] * W0) + b0

V[2,0,0] = np.sum(X[4:9,:5,:] * W0) + b0

V[3,0,0] = np.sum(X[6:11,:5,:] * W0) + b0

您应该还记得在numpy中*操作表示array之间的每个元素相乘。同时向量W0是神经元的权重向量,b0是神经元的偏置。这里假设W0的尺寸为W0.shape:(5,5,4),因为滤波器的尺寸为5×5,输入数据的深度为4。注意,在每个点上,我们都是像之前普通神经网络中那样进行点积,此外,正如我们看到的,我们使用相同的权重和偏置(由于参数共享),并且沿着宽度维度以2为单位递增(即步长)。要构建输出数据中的第二个激活映射图,我们可以:V[0,0,1] = np.sum(X[:5,:5,:] * W1) + b1

V[1,0,1] = np.sum(X[2:7,:5,:] * W1) + b1

V[2,0,1] = np.sum(X[4:9,:5,:] * W1) + b1

V[3,0,1] = np.sum(X[6:11,:5,:] * W1) + b1

V[0,1,1] = np.sum(X[:5,2:7,:] * W1) + b1(沿y滑动位置的例子)

V[2,3,1] = np.sum(X[4:9,6:11,:] * W1) + b1(既沿x又沿y滑动的例子)

正如我们看到的,因为我们正在计算第二个激活映射图,故我们索引到V的第二层深度,并且我们使用了一组不同的参数W1。在上述例子中,我们为了简洁起见,只计算输出数据 arrayV的一部分。此外,这些激活映射图中的每个元素通常都会执行一个诸如ReLu函数之类的激活函数,但是这里并没有提及。

总结:对卷积层进行一下总结。接收一个尺寸为

的输入数据

需要四个超参数滤波器的数量

滤波器的尺寸

步长

零填充数量

产生一个尺寸为

的数据,并且

通过参数共享,它将为每个滤波器引入

个权重,总共有

个权重和

个偏置

在输出数据中,第

个深度切片(大小为

)是将第

个滤波器在输入数据上以步长

进行有效卷积,然后与偏置相加减得到的结果。

一种比较常见的超参数的设置为

矩阵乘法的实现:注意,卷积运算本质上是将滤波器和输入特征体的局部区域进行点积。而卷积层的常见实现模式是利用这一事实并将卷积层的正向传播制定为如下的一个大矩阵乘法:输入图像的局部区域在一个通常被称为im2col的操作中被拉伸成列。例如,如果输入数据的尺寸为227×227×3并且由尺寸为11×11×3的滤波器以步长为4进行卷积,那么我们将在输入数据中拿出包含11×11×3个像素的区块,并将每个区块拉伸为尺寸为11×11×3=363的列向量。在输入数据上以4为步长沿着宽度或者高度滑动都有(227-11)/4+1=55个位置,故在输入数据上迭代执行拉伸过程,将得到一个大小为363×3025的im2col输出矩阵X_col,其中每列都是一个被拉伸的感受野,因此总共有55×55=3025列。

卷积层的权重类似的拉伸成行。例如,如果有96个大小为11×11×3的滤波器,将会得到一个大小为96×363的矩阵W_row。

卷积的结果现在相当于执行一个大矩阵乘法np.dot(W_row,X_col),它算出每个滤波器和其在每个位置上的感受野内的输入执行点积的结果值,在我们的例子中,该操作的输出矩阵大小为96×3025。

结果必须重新调整为适当的大小,即55×55×96。

这种方法的缺点是浪费内存,因为输入数据中的一些值在X_col中被复制了多次。然而,其好处是有很多非常有效的矩阵乘法的实现方式可以利用。此外,我们可以重复使用和im2col相同的思想来执行池化操作,我们将在下面的内容中来讨论该操作。

反向传播:卷积操作(对于数据和权重)的反向传播也是卷积(但是,却是具有空间反转的滤波器)。这很容易用一个玩具例子在1维情况下推导出来(在这里先不进行扩展)。

1×1卷积:一些论文开始会使用1×1卷积作为网络的研究工作。有些人一开始看到1×1卷积会感到有些困惑,尤其是当他们具有信号处理研究背景时。通常情况下,信号是2维的,所以1×1卷积是没有意义的(它只是逐点缩放)。然而,在卷积网络中情况并非如此,因为我们一定要记住,我们是在3维数据上进行操作,并且滤波器始终是贯穿输入数据的整个深度。例如,如果输入数据是32×32×3,于是执行1×1卷积将会高效地执行3维点积(因为输入数据的深度是3)。

扩张卷积:一项最近的研究进展打算向卷积层中再引入一个超参数(参见Fisher Yu 和 Vladlen Koltun的论文),称之为扩张度。到目前为止,我们只讨论了连续的卷积滤波器。然而,我们也可以设置一个在每个单元格之间都有空格的滤波器,称之为扩张。举例来说,假设在1维空间上一个大小为3的滤波器W对输入X进行计算可得:w[0]*x[0] + w[1]*x[1] + w[2]*x[2],即扩张度为0。若扩张度为1,我们将会计算:w[0]*x[0] + w[1]*x[2] + w[2]*x[4]。换句话说,滤波器的应用具有大小为1的间隔。在某些设置中,将其与0扩张滤波器结合使用,将会非常有用。因为它允许你使用更少的图层迅速地将输入的空间信息进行整合。例如:如果您将两个3x3 的卷积层叠在一起,那么第二层上的神经元将对输入数据有着的5x5的感受野(我们可以说第二层上神经元的有效感受野是5×5)。 如果我们使用扩张卷积,那么这个有效的感受野会增长得更快。

池化层

在卷积网络结构中,在连续的卷积层之间周期性的插入池化层是很常见的。其功能是逐步减少表示的空间尺寸,以减少网络中的参数数量以及降低计算量,且因此也可以控制过拟合。池化层在输入数据的每个深度切片上独立运行,并使用MAX操作调整其二维面的尺寸。最常见的池化层的形式具有尺寸为2×2的滤波器,在输入数据的每个深度切片上分别沿着宽度和高度执行以2为步长的降采样操作,以丢弃75%的数据。在这种情况下,每个MAX操作将会从4个数值中(在某个深度切片的一个小的2×2的区域)选择最大的一个数值。而深度方向仍保持不变,更一般地来说,池化层:接收一个尺寸为

的数据

需要两个超参数感受野的尺寸

步长

产生一个尺寸为

的数据,且:

由于它对输入执行一个固定的函数计算,因此不包含参数。

注意,一般并不对池化层使用零填充。

值得注意的是,在实际中,只建立两种常见形式的最大池化层:具有

的池化层(也叫做交叉池化),以及更常见的

。而以更大的感受野进行池化则太具有破坏性。

常见池化:除了最大池化之外,池化单元还可以执行其他功能,例如平均池化甚至是L2-正则池化。过去人们经常使用平均池化,但最近,其地位逐渐被已经在实践中有着更良好表现的最大池化所替代。

池化层在输入数据的每个深度切片上独立地执行二维面上的降采样操作。左图:在该例中,尺寸为224×224×64的输入数据由尺寸为2×2的滤波器以2为步长池化为一个尺寸为112×112×64的的输出数据。注意到,特征体的深度保持不变。右图:最常见的降采样操作是取最大值,即最大池化,图中所示的是以2为步长进行的最大池化。也就是说每个最大值都是从四个数值中选择的(小的2×2的区域)。

反向传播:回顾一下反向传播章节,

操作的反向传播非常简单,因为只需要找到前向传播中输入的最大值的梯度。因此,在池化层的前向传播期间,通常对其数据的最大值的索引进行跟踪(通常称之为switch),以使反向传播期间能更加高效地寻找到其梯度。

避免池化:许多人并不喜欢这种池化操作,并认为我们可以完全摆脱掉它。例如:为了达到简单性的目的,人们建议所有卷积网络都放弃池化层转而采用仅由重复的卷积层组成的结构。为了减少表征的大小,他们建议偶尔在卷积层中使用更大的步长。在训练良好的生成模型中,丢弃池化层也是很重要的,例如变分自动编码器(VAEs)或生成对抗网络(GAN)。 未来的网络结构很可能很少有或者几乎没有池化层。

归一化层

人们已经提出了许多类型的归一化层来用于卷积网络结构,有些时候意图采取在生物脑中观察到的抑制方案。然而,这些层都已经失宠,因为实际上即使它们对卷积网络结构有着一些贡献的话,其贡献也已经被证明是极其有限的。对于各种类型的归一化,请参阅Alex Krizhevsky的cuda-convnet库API中的讨论。

全连接层

正如在常规神经网络中看到的,全连接层中的神经元与前一层数据的全部数据点完全连接。因此其输出数据可以通过矩阵乘法和偏置来进行计算。

全连接层到卷积层的转换

值得注意的是,全连接层和卷积层之间的唯一区别在于,卷积层中的神经元仅与输入中的局部区域相连,并且卷积层中的许多神经元共享参数。然而,全连接层和卷积层的神经元仍然都进行点积运算,所以它们的函数形式是相同的。因此,事实证明可以在全连接层和卷积层之间进行转换:对于任意一个卷积层,都有一个能实现相同前向传播函数的全连接层与之对应。其权重矩阵将会是一个许多区块内的元素都相等的(由于参数共享)大矩阵。且其大部分都是零,除了一小部分区块外(由于局部连接性)。

反之,任何全连接层都可以转换为卷积层。例如,一个有4096个神经元的全连接层,注视着尺寸为7×7×512的输入数据,可以等价于一个

的卷积层。换句话说,我们将滤波器的尺寸设置为与输入数据的大小相同,因此输出则为1×1×4096,这是因为只有一个深度列与整个输入数据进行卷积,其结果与最初的全连接层相一致。

全连接层->卷积层:在这两种转换中,将全连接层转换为卷积层的能力在实践中非常有用。想象一下,采用尺寸为224×224×3的图像作为输入的卷积网络结构,使用一系列的卷积层和池化层来将图像压缩为尺寸为7×7×512的数据(稍后我们会看到,在AlexNet结构中,这是通过使用5个池化层对输入的二维面执行

的降采样操作,使得最终的二维面尺寸为224/2/2/2/2/2=7)。紧接着,AlexNet使用两个有4096个神经元的全连接层,并且最终使用有1000个神经元的全连接层作为最后一层,用于计算类别的概率。如上所述,我们可以将这三个全连接层每个都转换为卷积层:将注视着尺寸为7×7×512的数据的全连接层替换为滤波器尺寸为

的卷积层,从而得到输出数据的大小为1×1×4096。

将第二层全连接层替换为滤波器尺寸

的卷积层,从而得到输出数据的尺寸为1×1×4096。

最后一层全连接层同样如此,替换为滤波器尺寸为

的卷积层,得到输出数据的大小为1×1×1000。

实际上,每一个转换都涉及将全连接层中的权重矩阵

重塑为卷积层的滤波器。事实证明,在一次前向传播中,这种转换使我们即使面对更大的图像,也能在其许多区域位置上非常有效地“滑动”原始卷积网络。

例如,如果尺寸为224×224的图像输出得到7×7×512的数据,即二维面上缩小了32倍。那么由于384/32=12,故一个尺寸为384×384的图像,将通过转换后的网络结构得到一个尺寸为12×12×512的数据。接下来,我们刚才从三个全连接层转换而来的三个卷积层将会输出最终数据,其尺寸为6×6×1000,因为(12-7)/1+1=6。注意,我们现在得到的是关于该尺寸为384×384的图像的整个6×6的概率矩阵。而不是1×1×1000的一维向量。

在一次前向传播中,转换后的卷积网络自然比在全部的36个位置上迭代原始卷积网络更加高效,其原因就是因为这36个计算共享计算资源。这种技巧在实际中也被用于提升模型的性能表现。例如,人们通常改变一张图像的尺寸,使其更大,然后使用转换后的卷积网络在其二维面的多个位置上计算类别概率,然后再取类别概率的平均值。

卷积网络的架构

我们已经了解到,卷积网络通常仅由三种类型的层所构成:卷积层,池化层(通常假设是最大池化层,除非另有说明)以及全连接层。同时,我们将ReLu激活函数明确地表示为一个层,其功能是对每个元素执行一次非线性操作。

各层之间的排列模式

卷积网络最常见的形式是叠加一些卷积-ReLu层,随后是池化层,然后重复此模式,直到图像被整合到一个较小的尺寸。在某些情况下,常常使用全连接层进行过渡。最后的全连接层将会得到输出,例如类别的概率。换句话说,常见的卷积网络结构如下:

INPUT -> [[CONV -> RELU]*N -> POOL?]*M -> [FC -> RELU]*K -> FC

其中*表示重复,POOL?表示可选的池化层。此外,N>=0(且通常N<=3),M>=0,K>=0(且通常K<3)。例如,这里有一些常见的卷积网络结构,它们都遵循这样的模式:INPUT -> FC,即执行一个线性分类器,其中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的感受野,因此相当于对输入数据有着5×5的感受野。同理,第三层卷积层的每个神经元对第二层卷积层也有着3×3的感受野,故相当于其对输入数据有着7×7的接收域。假设我们不使用这三个感受野为3x3卷积层,而是只使用一个感受野为7×7的卷积层,那么其神经元同样将对输入数据有着7×7的感受野,但是却有如下几个缺点:首先,三个包含非线性激活函数的卷积层堆叠在一起,比单一卷积层的结构更能提取出深层的更好的特征。其次,如果我们假设所有的数据点都有

个通道,那么一个感受野为7×7的卷积层将包含

个参数,然而三个感受野为3×3的卷积层将只包含

个参数。直观地说,将具有小感受野的卷积层堆叠,与用一个具有较大感受野的卷积层相比而言,更能够强有力地表达出输入数据中的特征,并且使用的参数也更少。唯一不足的是,在进行反向传播时,中间的卷积层可能会导致占用更多的内存。

最新进展:应当指出的是,逐层排列各个层的传统范例已经受到了挑战,挑战来自Google的Inception 架构,以及微软亚洲研究院当前的(最先进的)Residual 网络。这两者具有更复杂且不同的连接结构(详细信息请参阅案例研究部分)。

实践中使用ImageNet上最好用的模式:您可能在考虑该使用哪种架构时感到有些力不从心,不过值得庆幸的是,在90%或更多的应用程序中,您不必担心这些问题。我喜欢将这一点总结为“不要逞英雄”:与其自己费劲心思搞一套架构,不如看看目前在ImageNet上都有哪些比较好的架构,下载一个预训练模型并在你自己的数据集上对其进行微调。所以,你几乎不需要从头开始训练或是设计一个卷积网络。

各个层的尺寸设置

到目前为止,我们还并没有提及卷积网络中每一层中常用的超参数。那么接下来,就让我们先对确定结构尺寸的通用规则进行阐述,然后再对其需要注意的地方进行探讨。

输入层应该能被2整除多次,其常用数字包括32(例如CIFAR-10),64,96(例如STL-10)或224(例如,常见的 ImageNet 卷积网络),384和512。

卷积层应该使用小尺寸的滤波器(例如3×3或者最多是5×5),使用步长

,还有最为关键的一点就是使用零填充对输入数据进行填充,以使卷积层的输出保持和输入数据相等的二维面大小。亦即,当

时,使用零填充

,则会保留输入数据最初的尺寸。而当

时,

。显而易见,对于任意一个

,若

,则输出数据将会保留输入数据的尺寸。如果您不得不使用更大尺寸的滤波器(例如7×7左右),这种做法在第一层卷积层上将会十分常见。

池化层负责在输入的二维面上进行降采样,其最常见的设置是采用具有2×2接收域(即

)的最大池化,并且步长为2(即

)。值得注意的是,这会丢弃输入数据中75%的数据点(由于降采样在宽度和高度上均降低2倍)。另一种不算是特别常见的设置是,使用3×3的感受野,步长为2。对于最大池化来说,感受野的尺寸大于3是极其罕见的,因为进行池化操作会造成很大的损耗和破坏,若感受野尺寸太大,将会降低网络的性能表现。

摆脱尺寸困扰:上面介绍的方案都十分令人满意,所有的卷积层都保留了输入的尺寸,池化层负责执行数据二维面上的降采样操作。然而,如果步长大于1,或者不进行零填充时,我们就必须非常谨慎地对通过整个卷积网络结构的输入数据进行跟踪,以确保所有的步长和滤波器能够“正常工作”,并且我们要尽可能地使卷积网络具有优美而对称的结构布局。

为什么在卷积层中使用1步长?在实践中,步长越小,其效果越好。此外,如之前所述,步长为1可以让二维面上的降采样全部由池化层负责,而卷积层只负责对输入数据的深度进行变换。

为什么使用零填充?如之前所述,除了保证数据通过卷积层之后二维面尺寸不变的好处之外,这样做实际上也起到了提升性能的作用。如果卷积层没有对输入进行零填充且只执行有效的卷积,那么在执行每个卷积之后数据的尺寸都会减少一小部分,即图片边缘上的信息很快将会被“冲掉”。

基于内存限制所做出的妥协:在某些情况下(尤其是早期的卷积网络架构),使用上面介绍的规则可以快速建立内存容量。 例如,三个3x3 的卷积层,其中每个卷积层有64个滤波器,零填充为

,用其对大小为224x224x3的图像进行过卷积将会创建三个大小为224x224x64的数据。这相当于总共大约1000万个数据点,或72MB内存。 由于GPU经常受到内存瓶颈的限制,因此我们可能需要对此做出妥协。实际上,人们更喜欢在网络的第一个卷积层上做出妥协。例如,一个折中的方案可以是使用一个滤波器尺寸为7×7,步长为2的卷积层作为第一层。又例如,一个Alex网络使用尺寸为11×11的滤波器且以4作为步长。

案例学习

在卷积网络领域有若干个有名有姓的架构,其中最常见的是:LeNet:卷积网络的第一个成功应用是由Yann LeCun在20世纪90年代开发的。 其中最着名的是LeNet架构,用于阅读邮政编码,以及数字等。

Alex net:最早在计算机视觉中推广卷积网络的是由Alex Krizhevsky,Ilya Sutskever和Geoff Hinton开发的AlexNet。AlexNet于2012年被提交到ImageNet ILSVRC挑战赛上,并且其表现明显超越季军(与top5错误率为26%的亚军相比,其仅有16%的top5错误率)。该网络与LeNet具有非常相似的架构,但是更深,更大,并且具有堆叠在一起的卷积层(先前通常是一个卷积层后面紧接着一个池化层)。

ZF Net: 2013年ILSVRC冠军是来自Matthew Zeiler和Rob Fergus的卷积网络。 它被称为ZFNet(Zeiler 与 Fergus Net 的简称)。该网络通过调整网络架构的超参数对AlexNet进行了改进,特别是扩大了中间卷积层的尺寸并减小第一层上的步长和过滤器的尺寸。

GoogLeNet: 2014年ILSVRC的冠军是来自Google的 Szegedy 等人的卷积网络。 其主要贡献是开发了一个Inception模块,该模块显着减少了网络中的参数数量(与Alex net的60M相比,该网络的参数数量只有4M)。此外,该文章在卷积网络顶层使用的是平均池化层而不是全连接层(Fully Connected layers),从而消除了大量似乎并不重要的参数。此外,GoogLeNet还有几个后续版本,如最近的Inception-v4。

VGGNet: 2014年ILSVRC的亚军是出自Karen Simonyan和Andrew Zisserman的网络,即后来人么所熟知的VGGNet。它的主要贡献在于表明网络的深度是其良好表现的关键组成部分。该网络的最终改良版包括16个卷积/全连接层,并且最具吸引力的是,该网络从开始到结束只执行3x3卷积和2x2池化,结构上十分匀称。他们的预训练模型适用于即插即用的Caffe,VGGNet的缺点是需要更多的内存和参数(140M)。其中大部分参数都在第一层全连接层,后来发现即使去掉这些参数,也不会导致性能的下降,这就使得参数的数量可以显著减少。

ResNet: Resdual 网络由何凯明等人开发。是2015年ILSVRC的获胜者。它使用了特殊的跳跃连接,并且大量使用批量标准化。该网络结构同样没有在最后使用全连接层,读者还可以参考何凯明的演讲(或者视频和幻灯片),以及最近一些使用Torch重现这些网络的试验。ResNet是迄今为止最为先进的卷积神经网络模型,并且当人们想在实践中使用神经网络时,ResNet是默认的首选(截至2016年5月10日)。何凯明等人最近对其原始结构做了一些改进,可以参看论文Identity Mappings in Deep Residual Networks(2016年3月发表)。

VGGNet的细节:我们将VGGNet作为例子分解开来,对其进行详细的研究。整个VGG网络由卷积层和池化层组成,其中卷积层执行3×3,步长为1,零填充为1的卷积操作,池化层执行2×2,步长为2的最大池化操作(没有零填充)。我们可以写出过程中每一步数据尺寸的变化,从而对数据的尺寸和权重的数量进行跟踪:

INPUT: [224x224x3] memory: 224*224*3=150K weights: 0

CONV3-64: [224x224x64] memory: 224*224*64=3.2M weights: (3*3*3)*64 = 1,728

CONV3-64: [224x224x64] memory: 224*224*64=3.2M weights: (3*3*64)*64 = 36,864

POOL2: [112x112x64] memory: 112*112*64=800K weights: 0

CONV3-128: [112x112x128] memory: 112*112*128=1.6M weights: (3*3*64)*128 = 73,728

CONV3-128: [112x112x128] memory: 112*112*128=1.6M weights: (3*3*128)*128 = 147,456

POOL2: [56x56x128] memory: 56*56*128=400K weights: 0

CONV3-256: [56x56x256] memory: 56*56*256=800K weights: (3*3*128)*256 = 294,912

CONV3-256: [56x56x256] memory: 56*56*256=800K weights: (3*3*256)*256 = 589,824

CONV3-256: [56x56x256] memory: 56*56*256=800K weights: (3*3*256)*256 = 589,824

POOL2: [28x28x256] memory: 28*28*256=200K weights: 0

CONV3-512: [28x28x512] memory: 28*28*512=400K weights: (3*3*256)*512 = 1,179,648

CONV3-512: [28x28x512] memory: 28*28*512=400K weights: (3*3*512)*512 = 2,359,296

CONV3-512: [28x28x512] memory: 28*28*512=400K weights: (3*3*512)*512 = 2,359,296

POOL2: [14x14x512] memory: 14*14*512=100K weights: 0

CONV3-512: [14x14x512] memory: 14*14*512=100K weights: (3*3*512)*512 = 2,359,296

CONV3-512: [14x14x512] memory: 14*14*512=100K weights: (3*3*512)*512 = 2,359,296

CONV3-512: [14x14x512] memory: 14*14*512=100K weights: (3*3*512)*512 = 2,359,296

POOL2: [7x7x512] memory: 7*7*512=25K weights: 0

FC: [1x1x4096] memory: 4096 weights: 7*7*512*4096 = 102,760,448

FC: [1x1x4096] memory: 4096 weights: 4096*4096 = 16,777,216

FC: [1x1x1000] memory: 1000 weights: 4096*1000 = 4,096,000

TOTAL memory: 24M * 4 bytes ~= 93MB / image (only forward! ~*2 for bwd)

TOTAL params: 138M parameters

注意,与常见的卷积网络一样,大部分的内存(以及计算时间)都被前面的卷积层所消耗,且绝大多数参数都位于后面的全连接层上。在本例中,第一个全连接层包含的权重数量为100M,而权重的总量也不过是140M。

计算上的考量

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值