卷积神经网络类似于一般的神经网络,由可学习的权重和误差组成,每一个神经元接受一些输入,完成一些非线性的操作。整个神经网络完成了一个可微的打分函数,从图像点到分类得分。在全连接或者最后一层他们也有一个损失函数。
而卷积神经网络中有明确的假设那就是输入时图像,这代表了网络机构具有特殊的性质。
概览
神经网络接受一个单个的输入并且沿着一系列的隐含层转换。每个隐含层由一系列的神经元构成,在单层的神经元中相互独立而且没有什么联系,最后一层叫做输出层,在分类问题中代表着类的分数。
普通的神经网络对于图像数据表现并不好,因为权重的参数过多,没办法很快的训练。3d容量的神经元,cnn每层的神经元都有三个维度,长宽高。在每一层神经元都会连接到一个小的区域而不是全部链接。
用来建立卷积神经网络的层
一个简单的卷积神经网络是一层,每一层都通过一个可微的函数转化成另一个网络层。我们用三种结构来建立卷积神经网络,convolutional,pooling以及fully connected 层。
INPUT-CONV-RELU-POOL-FC
- 输入[32x32x3]存有图像的原始像素值,本例中图像宽高均为32,有3个颜色通道。
- 卷积层中,神经元与输入层中的一个局部区域相连,每个神经元都计算自己与输入层相连的小区域与自己权重的内积。卷积层会计算所有神经元的输出。如果我们使用12个滤波器(也叫作核),得到的输出数据体的维度就是[32x32x12]。
-
ReLU层将会逐个元素地进行激活函数操作,比如使用以0为阈值的
作为激活函数。该层对数据尺寸没有改变,还是[32x32x12]。
- 汇聚层在在空间维度(宽度和高度)上进行降采样(downsampling)操作,数据尺寸变为[16x16x12]。
- 全连接层将会计算分类评分,数据尺寸变为[1x1x10],其中10个数字对应的就是CIFAR-10中10个类别的分类评分值。正如其名,全连接层与常规神经网络一样,其中每个神经元都与前一层中所有神经元相连接。
卷积层
卷积层是建立cnn的主要步骤。大意是说,首先由很多个深度一样但是大小比较小的过滤器,然后这个过滤器在整个面积上进行移动,在移动的过程中产生一个单独的2维的激活层,然后我们把每一个激活层叠加在一起就产生了一个结果输出。
换个说法,每一个3维的输出都可以被解释成一个仅仅对应一个小部分的神经元,与其他的空间上的神经元共享参数,应用同样的筛选器,现在我们来讨论神经元链接情况的细节,包括空间的分布等等。
本地的连接,当我们处理高维的输入比如图像的时候,把神经元与过去所有的神经元链接是不实际的,换句话说,我们可以把神经元在局部连接在一起,但是在空间上扩展这种连接的参数。连接的程度总是等于输入的深度,强调这种对称性很重要在我们处理这三个维度上:因为这种连接在长和宽上是局部的,但是在深度上是完全的。
空间管理:我们已经解释了每个卷积层对于输入容量的连接,但是我们还没有讨论到底有多少个神经元或者他们是怎么分布的。参数控制:depth,stride和padding就是控制输出的重要参数。
depth:首先,输出量的深度是一个超级参数:它对应于我们想要使用的过滤器的数量,每个学习在输入中寻找不同的东西。例如,如果第一卷积层作为原始图像的输入,则沿着深度维度的不同神经元可以在存在各种定向边缘或颜色的斑点的情况下激活。我们将参考一组神经元,它们都是与输入的相同区域作为深度列(有些人也喜欢术语-纤维)。
其次,我们必须指定我们滑动过滤器的步幅。当步幅为1时,我们一次移动一个像素的滤镜。当步幅为2(或不常见的3或更多,虽然这在实践中是罕见的),然后当我们滑动它们时,过滤器一次跳过2像素。这将在空间上产生较小的产量。
此零填充的大小是超参数。零填充的一个很好的特点是,它将允许我们控制输出量的空间大小(最常见的是我们将会看到,我们将很快使用它来精确保留输入容积的空间大小,从而输入和输出宽度高度相同)。
输出数据体在空间上的尺寸可以通过输入数据体尺寸(W),卷积层中神经元的感受野尺寸(F),步长(S)和零填充的数量(P)的函数来计算。(译者注:这里假设输入数组的空间形状是正方形,即高度和宽度相等)输出数据体的空间尺寸为(W-F +2P)/S+1。比如输入是7x7,滤波器是3x3,步长为1,填充为0,那么就能得到一个5x5的输出。如果步长为2,输出就是3x3。下面是例子:
使用零填充:在上面左边例子中,注意输入维度是5,输出维度也是5。之所以如此,是因为感受野是3并且使用了1的零填充。如果不使用零填充,则输出数据体的空间维度就只有3,因为这就是滤波器整齐滑过并覆盖原始数据需要的数目。一般说来,当步长
步长的限制:注意这些空间排列的超参数之间是相互限制的。举例说来,当输入尺寸
真实案例:Krizhevsky*
"); background-size: cover; background-position: 0px 2px;">*构架赢得了2012年的ImageNet挑战,其输入图像的尺寸是[227x227x3]。在第一个卷积层,神经元使用的感受野尺寸
参数共享:在卷积层中使用参数共享是用来控制参数的数量。就用上面的例子,在第一个卷积层就有55x55x96=290,400个神经元,每个有11x11x3=364个参数和1个偏差。将这些合起来就是290400x364=105,705,600个参数。单单第一层就有这么多参数,显然这个数目是非常大的。
作一个合理的假设:如果一个特征在计算某个空间位置(x,y)的时候有用,那么它在计算另一个不同位置(x2,y2)的时候也有用。基于这个假设,可以显著地减少参数数量。换言之,就是将深度维度上一个单独的2维切片看做深度切片(depth slice),比如一个数据体尺寸为[55x55x96]的就有96个深度切片,每个尺寸为[55x55]。在每个深度切片上的神经元都使用同样的权重和偏差。在这样的参数共享下,例子中的第一个卷积层就只有96个不同的权重集了,一个权重集对应一个深度切片,共有96x11x11x3=34,848个不同的权重,或34,944个参数(+96个偏差)。在每个深度切片中的55x55个权重使用的都是同样的参数。在反向传播的时候,都要计算每个神经元对它的权重的梯度,但是需要把同一个深度切片上的所有神经元对权重的梯度累加,这样就得到了对共享权重的梯度。这样,每个切片只更新一个权重集。
注意,如果在一个深度切片中的所有权重都使用同一个权重向量,那么卷积层的前向传播在每个深度切片中可以看做是在计算神经元权重和输入数据体的卷积(这就是“卷积层”名字由来)。这也是为什么总是将这些权重集合称为滤波器(filter)(或卷积核(kernel)),因为它们和输入进行了卷积。
注意有时候参数共享假设可能没有意义,特别是当卷积神经网络的输入图像是一些明确的中心结构时候。这时候我们就应该期望在图片的不同位置学习到完全不同的特征。一个具体的例子就是输入图像是人脸,人脸一般都处于图片中心。你可能期望不同的特征,比如眼睛特征或者头发特征可能(也应该)会在图片的不同位置被学习。在这个例子中,通常就放松参数共享的限制,将层称为局部连接层(Locally-Connected Layer)。
Numpy例子:为了让讨论更加的具体,我们用代码来展示上述思路。假设输入数据体是numpy数组X。那么:
一个位于(x,y)的深度列(或纤维)将会是X[x,y,:]。
在深度为d处的深度切片,或激活图应该是X[:,:,d]。
卷积层例子:假设输入数据体X的尺寸X.shape:(11,11,4),不使用零填充(
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中,*操作是进行数组间的逐元素相乘。权重向量W0是该神经元的权重,b0是其偏差。在这里,W0被假设尺寸是W0.shape: (5,5,4),因为滤波器的宽高是5,输入数据量的深度是4。注意在每一个点,计算点积的方式和之前的常规神经网络是一样的。同时,计算内积的时候使用的是同一个权重和偏差(因为参数共享),在宽度方向的数字每次上升2(因为步长为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 (或两个方向上同时)
我们访问的是V的深度维度上的第二层(即index1),因为是在计算第二个激活图,所以这次试用的参数集就是W1了。在上面的例子中,为了简洁略去了卷积层对于输出数组V中其他部分的操作。还有,要记得这些卷积操作通常后面接的是ReLU层,对激活图中的每个元素做激活函数运算,这里没有显示。
小结: 我们总结一下卷积层的性质:
输入数据体的尺寸为
4个超参数:滤波器的数量
滤波器的空间尺寸
步长
零填充数量
,其中:
由于参数共享,每个滤波器包含
在输出数据体中,第
对这些超参数,常见的设置是
卷积层演示:下面是一个卷积层的运行演示。因为3D数据难以可视化,所以所有的数据(输入数据体是蓝色,权重数据体是红色,输出数据体是绿色)都采取将深度切片按照列的方式排列展现。输入数据体的尺寸是
"); background-size: cover; background-position: 0px 2px;">*查看此演示。
输入图像的局部区域被im2col操作拉伸为列。比如,如果输入是[227x227x3],要与尺寸为11x11x3的滤波器以步长为4进行卷积,就取输入中的[11x11x3]数据块,然后将其拉伸为长度为11x11x3=363的列向量。重复进行这一过程,因为步长为4,所以输出的宽高为(227-11)/4+1=55,所以得到im2col操作的输出矩阵X_col的尺寸是[363x3025],其中每列是拉伸的感受野,共有55x55=3,025个。注意因为感受野之间有重叠,所以输入数据体中的数字在不同的列中可能有重复。
卷积层的权重也同样被拉伸成行。举例,如果有96个尺寸为[11x11x3]的滤波器,就生成一个矩阵W_row,尺寸为[96x363]。
现在卷积的结果和进行一个大矩阵乘np.dot(W_row, X_col)是等价的了,能得到每个滤波器和每个感受野间的点积。在我们的例子中,这个操作的输出是[96x3025],给出了每个滤波器在每个位置的点积输出。
结果最后必须被重新变为合理的输出尺寸[55x55x96]。
这个方法的缺点就是占用内存太多,因为在输入数据体中的某些值在X_col中被复制了多次。但是,其优点是矩阵乘法有非常多的高效实现方式,我们都可以使用(比如常用的BLAS*
"); background-size: cover; background-position: 0px 2px;">*API)。还有,同样的im2col思路可以用在汇聚操作中。
反向传播:卷积操作的反向传播(同时对于数据和权重)还是一个卷积(但是是和空间上翻转的滤波器)。使用一个1维的例子比较容易演示。
1x1卷积:一些论文中使用了1x1的卷积,这个方法最早是在论文Network in Network*
"); background-size: cover; background-position: 0px 2px;">*中出现。人们刚开始看见这个1x1卷积的时候比较困惑,尤其是那些具有信号处理专业背景的人。因为信号是2维的,所以1x1卷积就没有意义。但是,在卷积神经网络中不是这样,因为这里是对3个维度进行操作,滤波器和输入数据体的深度是一样的。比如,如果输入是[32x32x3],那么1x1卷积就是在高效地进行3维点积(因为输入深度是3个通道)。
扩张卷积:最近一个研究(Fisher Yu和Vladlen Koltun的论文*
"); background-size: cover; background-position: 0px 2px;">*)给卷积层引入了一个新的叫扩张(dilation)的超参数。到目前为止,我们只讨论了卷积层滤波器是连续的情况。但是,让滤波器中元素之间有间隙也是可以的,这就叫做扩张。举例,在某个维度上滤波器w的尺寸是3,那么计算输入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的间隙。在某些设置中,扩张卷积与正常卷积结合起来非常有用,因为在很少的层数内更快地汇集输入图片的大尺度特征。比如,如果上下重叠2个3x3的卷积层,那么第二个卷积层的神经元的感受野是输入数据体中5x5的区域(可以成这些神经元的有效感受野是5x5)。如果我们对卷积进行扩张,那么这个有效感受野就会迅速增长。
汇聚层
通常,在连续的卷积层之间会周期性地插入一个汇聚层。它的作用是逐渐降低数据体的空间尺寸,这样的话就能减少网络中参数的数量,使得计算资源耗费变少,也能有效控制过拟合。汇聚层使用MAX操作,对输入数据体的每一个深度切片独立进行操作,改变它的空间尺寸。最常见的形式是汇聚层使用尺寸2x2的滤波器,以步长为2来对每个深度切片进行降采样,将其中75%的激活信息都丢掉。每个MAX操作是从4个数字中取最大值(也就是在深度切片中某个2x2的区域)。深度保持不变。汇聚层的一些公式:
输入数据体尺寸
有两个超参数:
空间大小
步长
,其中
在汇聚层中很少使用零填充
在实践中,最大汇聚层通常只有两种形式:一种是
普通汇聚(General Pooling):除了最大汇聚,汇聚单元还可以使用其他的函数,比如平均汇聚(average pooling)或L-2范式汇聚(L2-norm pooling)。平均汇聚历史上比较常用,但是现在已经很少使用了。因为实践证明,最大汇聚的效果比平均汇聚要好。
不使用汇聚层:很多人不喜欢汇聚操作,认为可以不使用它。比如在Striving for Simplicity: The All Convolutional Net*
"); background-size: cover; background-position: 0px 2px;">*一文中,提出使用一种只有重复的卷积层组成的结构,抛弃汇聚层。通过在卷积层中使用更大的步长来降低数据体的尺寸。有发现认为,在训练一个良好的生成模型时,弃用汇聚层也是很重要的。比如变化自编码器(VAEs:variational autoencoders)和生成性对抗网络(GANs:generative adversarial networks)。现在看起来,未来的卷积网络结构中,无汇聚层的结构不太可能扮演重要的角色。
归一化层
在卷积神经网络的结构中,提出了很多不同类型的归一化层,有时候是为了实现在生物大脑中观测到的抑制机制。但是这些层渐渐都不再流行,因为实践证明它们的效果即使存在,也是极其有限的。对于不同类型的归一化层,可以看看Alex Krizhevsky的关于cuda-convnet library API*
"); background-size: cover; background-position: 0px 2px;">*的讨论。
全连接层
在全连接层中,神经元对于前一层中的所有激活数据是全部连接的,这个常规神经网络中一样。它们的激活可以先用矩阵乘法,再加上偏差。更多细节请查看神经网络章节。
把全连接层转化成卷积层
全连接层和卷积层之间唯一的不同就是卷积层中的神经元只与输入数据中的一个局部区域连接,并且在卷积列中的神经元共享参数。然而在两类层中,神经元都是计算点积,所以它们的函数形式是一样的。因此,将此两者相互转化是可能的:
对于任一个卷积层,都存在一个能实现和它一样的前向传播函数的全连接层。权重矩阵是一个巨大的矩阵,除了某些特定块(这是因为有局部连接),其余部分都是零。而在其中大部分块中,元素都是相等的(因为参数共享)。
相反,任何全连接层都可以被转化为卷积层。比如,一个
全连接层转化为卷积层:在两种变换中,将全连接层转化为卷积层在实际运用中更加有用。假设一个卷积神经网络的输入是224x224x3的图像,一系列的卷积层和汇聚层将图像数据变为尺寸为7x7x512的激活数据体(在AlexNet中就是这样,通过使用5个汇聚层来对输入数据进行空间上的降采样,每次尺寸下降一半,所以最终空间尺寸为224/2/2/2/2/2=7)。从这里可以看到,AlexNet使用了两个尺寸为4096的全连接层,最后一个有1000个神经元的全连接层用于计算分类评分。我们可以将这3个全连接层中的任意一个转化为卷积层:针对第一个连接区域是[7x7x512]的全连接层,令其滤波器尺寸为
针对第二个全连接层,令其滤波器尺寸为
对最后一个全连接层也做类似的,令其
实际操作中,每次这样的变换都需要把全连接层的权重W重塑成卷积层的滤波器。那么这样的转化有什么作用呢?它在下面的情况下可以更高效:让卷积网络在一张更大的输入图片上滑动(译者注:即把一张更大的图片的不同区域都分别带入到卷积网络,得到每个区域的得分),得到多个输出,这样的转化可以让我们在单个向前传播的过程中完成上述的操作。
举个例子,如果我们想让224x224尺寸的浮窗,以步长为32在384x384的图片上滑动,把每个经停的位置都带入卷积网络,最后得到6x6个位置的类别得分。上述的把全连接层转换成卷积层的做法会更简便。如果224x224的输入图片经过卷积层和汇聚层之后得到了[7x7x512]的数组,那么,384x384的大图片直接经过同样的卷积层和汇聚层之后会得到[12x12x512]的数组(因为途径5个汇聚层,尺寸变为384/2/2/2/2/2 = 12)。然后再经过上面由3个全连接层转化得到的3个卷积层,最终得到[6x6x1000]的输出(因为(12 - 7)/1 + 1 = 6)。这个结果正是浮窗在原图经停的6x6个位置的得分!(译者注:这一段的翻译与原文不同,经过了译者较多的修改,使更容易理解)
面对384x384的图像,让(含全连接层)的初始卷积神经网络以32像素的步长独立对图像中的224x224块进行多次评价,其效果和使用把全连接层变换为卷积层后的卷积神经网络进行一次前向传播是一样的。
自然,相较于使用被转化前的原始卷积神经网络对所有36个位置进行迭代计算,使用转化后的卷积神经网络进行一次前向传播计算要高效得多,因为36次计算都在共享计算资源。这一技巧在实践中经常使用,一次来获得更好的结果。比如,通常将一张图像尺寸变得更大,然后使用变换后的卷积神经网络来对空间上很多不同位置进行评价得到分类评分,然后在求这些分值的平均值。
最后,如果我们想用步长小于32的浮窗怎么办?用多次的向前传播就可以解决。比如我们想用步长为16的浮窗。那么先使用原图在转化后的卷积网络执行向前传播,然后分别沿宽度,沿高度,最后同时沿宽度和高度,把原始图片分别平移16个像素,然后把这些平移之后的图分别带入卷积网络。(译者注:这一段的翻译与原文不同,经过了译者较多的修改,使更容易理解)
Net Surgery*
"); background-size: cover; background-position: 0px 2px;">*上一个使用Caffe演示如何在进行变换的IPython Note教程。
卷积神经网络的结构
卷积神经网络通常是由三种层构成:卷积层,汇聚层(除非特别说明,一般就是最大值汇聚)和全连接层(简称FC)。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个3x3的卷积层(层与层之间有非线性激活函数)。在这个排列下,第一个卷积层中的每个神经元都对输入数据体有一个3x3的视野。第二个卷积层上的神经元对第一个卷积层有一个3x3的视野,也就是对输入数据体有5x5的视野。同样,在第三个卷积层上的神经元对第二个卷积层有3x3的视野,也就是对输入数据体有7x7的视野。假设不采用这3个3x3的卷积层,二是使用一个单独的有7x7的感受野的卷积层,那么所有神经元的感受野也是7x7,但是就有一些缺点。首先,多个卷积层与非线性的激活层交替的结构,比单一卷积层的结构更能提取出深层的更好的特征。其次,假设所有的数据有
最新进展:传统的将层按照线性进行排列的方法已经受到了挑战,挑战来自谷歌的Inception结构和微软亚洲研究院的残差网络(Residual Net)结构。这两个网络(下文案例学习小节中有细节)的特征更加复杂,连接结构也不同。
层的尺寸设置规律
到现在为止,我们都没有提及卷积神经网络中每层的超参数的使用。现在先介绍设置结构尺寸的一般性规则,然后根据这些规则进行讨论:
输入层(包含图像的)应该能被2整除很多次。常用数字包括32(比如CIFAR-10),64,96(比如STL-10)或224(比如ImageNet卷积神经网络),384和512。
卷积层应该使用小尺寸滤波器(比如3x3或最多5x5),使用步长
汇聚层负责对输入数据的空间维度进行降采样。最常用的设置是用用2x2感受野(即
减少尺寸设置的问题:上文中展示的两种设置是很好的,因为所有的卷积层都能保持其输入数据的空间尺寸,汇聚层只负责对数据体从空间维度进行降采样。如果使用的步长大于1并且不对卷积层的输入数据使用零填充,那么就必须非常仔细地监督输入数据体通过整个卷积神经网络结构的过程,确认所有的步长和滤波器都尺寸互相吻合,卷积神经网络的结构美妙对称地联系在一起。
为什么在卷积层使用1的步长?在实际应用中,更小的步长效果更好。上文也已经提过,步长为1可以让空间维度的降采样全部由汇聚层负责,卷积层只负责对输入数据体的深度进行变换。
为何使用零填充?使用零填充除了前面提到的可以让卷积层的输出数据保持和输入数据在空间维度的不变,还可以提高算法性能。如果卷积层值进行卷积而不进行零填充,那么数据体的尺寸就会略微减小,那么图像边缘的信息就会过快地损失掉。
因为内存限制所做的妥协:在某些案例(尤其是早期的卷积神经网络结构)中,基于前面的各种规则,内存的使用量迅速飙升。例如,使用64个尺寸为3x3的滤波器对224x224x3的图像进行卷积,零填充为1,得到的激活数据体尺寸是[224x224x64]。这个数量就是一千万的激活数据,或者就是72MB的内存(每张图就是这么多,激活函数和梯度都是)。因为GPU通常因为内存导致性能瓶颈,所以做出一些妥协是必须的。在实践中,人们倾向于在网络的第一个卷积层做出妥协。例如,可以妥协可能是在第一个卷积层使用步长为2,尺寸为7x7的滤波器(比如在ZFnet中)。在AlexNet中,滤波器的尺寸的11x11,步长为4。
案例学习
下面是卷积神经网络领域中比较有名的几种结构:
LeNet: 第一个成功的卷积神经网络应用,是Yann LeCun在上世纪90年代实现的。当然,最著名还是被应用在识别数字和邮政编码等的LeNet*
"); background-size: cover; background-position: 0px 2px;">*结构。
AlexNet:AlexNet*
"); background-size: cover; background-position: 0px 2px;">*卷积神经网络在计算机视觉领域中受到欢迎,它由Alex Krizhevsky,Ilya Sutskever和Geoff Hinton实现。AlexNet在2012年的ImageNet ILSVRC 竞赛*
"); background-size: cover; background-position: 0px 2px;">*中夺冠,性能远远超出第二名(16%的top5错误率,第二名是26%的top5错误率)。这个网络的结构和LeNet非常类似,但是更深更大,并且使用了层叠的卷积层来获取特征(之前通常是只用一个卷积层并且在其后马上跟着一个汇聚层)。
ZF Net:Matthew Zeiler和Rob Fergus发明的网络在ILSVRC 2013比赛中夺冠,它被称为 ZFNet*
"); background-size: cover; background-position: 0px 2px;">*(Zeiler & Fergus Net的简称)。它通过修改结构中的超参数来实现对AlexNet的改良,具体说来就是增加了中间卷积层的尺寸,让第一层的步长和滤波器尺寸更小。
GoogLeNet:ILSVRC 2014的胜利者是谷歌的Szeged等*
"); background-size: cover; background-position: 0px 2px;">*实现的卷积神经网络。它主要的贡献就是实现了一个奠基模块,它能够显著地减少网络中参数的数量(AlexNet中有60M,该网络中只有4M)。还有,这个论文中没有使用卷积神经网络顶部使用全连接层,而是使用了一个平均汇聚,把大量不是很重要的参数都去除掉了。GooLeNet还有几种改进的版本,最新的一个是Inception-v4*
"); background-size: cover; background-position: 0px 2px;">*。
VGGNet:ILSVRC 2014的第二名是Karen Simonyan和 Andrew Zisserman实现的卷积神经网络,现在称其为VGGNet*
"); background-size: cover; background-position: 0px 2px;">*。它主要的贡献是展示出网络的深度是算法优良性能的关键部分。他们最好的网络包含了16个卷积/全连接层。网络的结构非常一致,从头到尾全部使用的是3x3的卷积和2x2的汇聚。他们的预训练模型*
"); background-size: cover; background-position: 0px 2px;">*是可以在网络上获得并在Caffe中使用的。VGGNet不好的一点是它耗费更多计算资源,并且使用了更多的参数,导致更多的内存占用(140M)。其中绝大多数的参数都是来自于第一个全连接层。后来发现这些全连接层即使被去除,对于性能也没有什么影响,这样就显著降低了参数数量。
ResNet:残差网络*
"); background-size: cover; background-position: 0px 2px;">*(Residual Network)是ILSVRC2015的胜利者,由何恺明等实现。它使用了特殊的跳跃链接,大量使用了批量归一化*
"); background-size: cover; background-position: 0px 2px;">*(batch normalization)。这个结构同样在最后没有使用全连接层。读者可以查看何恺明的的演讲(视频*
"); background-size: cover; background-position: 0px 2px;">*,PPT*
"); background-size: cover; background-position: 0px 2px;">*),以及一些使用Torch重现网络的实验*
"); background-size: cover; background-position: 0px 2px;">*。ResNet当前最好的卷积神经网络模型(2016年五月)。何开明等最近的工作是对原始结构做一些优化,可以看论文Identity Mappings in Deep Residual Networks*
"); background-size: cover; background-position: 0px 2px;">*,2016年3月发表。
VGGNet的细节:我们进一步对VGGNet*
"); background-size: cover; background-position: 0px 2px;">*的细节进行分析学习。整个VGGNet中的卷积层都是以步长为1进行3x3的卷积,使用了1的零填充,汇聚层都是以步长为2进行了2x2的最大值汇聚。可以写出处理过程中每一步数据体尺寸的变化,然后对数据尺寸和整体权重的数量进行查看:
INPUT: [224x224x3] memory: 2242243=150K weights: 0CONV3-64: [224x224x64] memory: 22422464=3.2M weights: (333)64 = 1,728CONV3-64: [224x224x64] memory: 22422464=3.2M weights: (3364)64 = 36,864POOL2: [112x112x64] memory: 11211264=800K weights: 0CONV3-128: [112x112x128] memory: 112112128=1.6M weights: (3364)128 = 73,728CONV3-128: [112x112x128] memory: 112112128=1.6M weights: (33128)128 = 147,456POOL2: [56x56x128] memory: 5656128=400K weights: 0CONV3-256: [56x56x256] memory: 5656256=800K weights: (33128)256 = 294,912CONV3-256: [56x56x256] memory: 5656256=800K weights: (33256)256 = 589,824CONV3-256: [56x56x256] memory: 5656256=800K weights: (33256)256 = 589,824POOL2: [28x28x256] memory: 2828256=200K weights: 0CONV3-512: [28x28x512] memory: 2828512=400K weights: (33256)512 = 1,179,648CONV3-512: [28x28x512] memory: 2828512=400K weights: (33512)512 = 2,359,296CONV3-512: [28x28x512] memory: 2828512=400K weights: (33512)512 = 2,359,296POOL2: [14x14x512] memory: 1414512=100K weights: 0CONV3-512: [14x14x512] memory: 1414512=100K weights: (33512)512 = 2,359,296CONV3-512: [14x14x512] memory: 1414512=100K weights: (33512)512 = 2,359,296CONV3-512: [14x14x512] memory: 1414512=100K weights: (33512)512 = 2,359,296POOL2: [7x7x512] memory: 77512=25K weights: 0FC: [1x1x4096] memory: 4096 weights: 775124096 = 102,760,448FC: [1x1x4096] memory: 4096 weights: 40964096 = 16,777,216FC: [1x1x1000] memory: 1000 weights: 40961000 = 4,096,000TOTAL memory: 24M * 4 bytes ~= 93MB / image (only forward! ~*2 for bwd)TOTAL params: 138M parameters
注意,大部分的内存和计算时间都被前面的卷积层占用,大部分的参数都用在后面的全连接层,这在卷积神经网络中是比较常见的。在这个例子中,全部参数有140M,但第一个全连接层就包含了100M的参数。
计算上的考量
在构建卷积神经网络结构时,最大的瓶颈是内存瓶颈。大部分现代GPU的内存是3/4/6GB,最好的GPU大约有12GB的内存。要注意三种内存占用来源:
来自中间数据体尺寸:卷积神经网络中的每一层中都有激活数据体的原始数值,以及损失函数对它们的梯度(和激活数据体尺寸一致)。通常,大部分激活数据都是在网络中靠前的层中(比如第一个卷积层)。在训练时,这些数据需要放在内存中,因为反向传播的时候还会用到。但是在测试时可以聪明点:让网络在测试运行时候每层都只存储当前的激活数据,然后丢弃前面层的激活数据,这样就能减少巨大的激活数据量。
来自参数尺寸:即整个网络的参数的数量,在反向传播时它们的梯度值,以及使用momentum、Adagrad或RMSProp等方法进行最优化时的每一步计算缓存。因此,存储参数向量的内存通常需要在参数向量的容量基础上乘以3或者更多。
卷积神经网络实现还有各种零散的内存占用,比如成批的训练数据,扩充的数据等等。
一旦对于所有这些数值的数量有了一个大略估计(包含激活数据,梯度和各种杂项),数量应该转化为以GB为计量单位。把这个值乘以4,得到原始的字节数(因为每个浮点数占用4个字节,如果是双精度浮点数那就是占用8个字节),然后多次除以1024分别得到占用内存的KB,MB,最后是GB计量。如果你的网络工作得不好,一个常用的方法是降低批尺寸(batch size),因为绝大多数的内存都是被激活数据消耗掉了。