翻译自:http://cs231n.github.io/convolutional-networks/
卷积神经网络(CNN / ConvNets)
卷积神经网络与上一章的普通神经网络非常相似:它们由具有可学习的权重和偏差的神经元组成。每个神经元接收一些输入,执行一个点积,并且可以选择非线性跟随它。整个网络仍然表现出单一的可微分分数函数:从一端的原始图像像素到另一端的分数分数。而且他们在最后一个(完全连接)层仍然有损失函数(例如SVM / Softmax),并且我们为学习常规神经网络开发的所有技巧/技巧仍然适用。
那么变化是什么?ConvNet体系结构明确地假设输入是图像,这允许我们将某些属性编码到体系结构中。这些使得转发功能更有效地实施并极大地减少了网络中的参数数量。
架构概述
回想一下:规则的神经网络。正如我们在前一章中看到的那样,神经网络接收到一个输入(单个矢量),并通过一系列隐藏层进行转换。每个隐藏层由一组神经元组成,其中每个神经元完全连接到前一层的所有神经元,并且单层神经元完全独立运行,不共享任何连接。最后一个完全连接的图层称为“输出图层”,在分类设置中,它表示班级分数。
规则的神经网络不能很好地扩展到完整的图像。在CIFAR-10中,图像只有32x32x3(32宽,32高,3色通道),因此在常规神经网络的第一个隐藏层中的单个完全连接的神经元将具有32 * 32 * 3 = 3072的权重。这个数量似乎仍然可以管理,但显然这种完全连接的结构并不能扩展到更大的图像。例如,比较可观的大小的图像,例如200x200x3,将导致具有200 * 200 * 3 = 120,000重量的神经元。而且,我们几乎肯定会想要有几个这样的神经元,所以参数会快速加起来!显然,这种完整的连接是浪费的,大量的参数很快就会导致过度配置。
3D卷的神经元。卷积神经网络充分利用了输入由图像组成的事实,并以更合理的方式约束了体系结构。特别是,与常规的神经网络不同,ConvNet的层次具有三维排列的神经元:宽度,高度,深度。(请注意,字深度这里指的是激活体积的第三维,而不是整个神经网络的深度,它可以指网络中的层数)。例如,CIFAR-10中的输入图像是输入体积为激活,体积尺寸为32x32x3(分别为宽度,高度,深度)。正如我们将很快看到的那样,层中的神经元只会连接到它之前层的一个小区域,而不是以完全连接的方式连接到所有神经元。此外,CIFAR-10的最终输出层的尺寸为1x1x10,因为在ConvNet体系结构的末尾,我们会将整个图像缩减为沿深度维度排列的单个分数向量。这是一个可视化:
ConvNet由图层组成。每个图层都有一个简单的API:它将输入的3D音量转换为具有可能有或没有参数的可微函数的输出3D音量。
用于构建ConvNets的层
正如我们上面所描述的,一个简单的ConvNet是一系列图层,ConvNet的每一层通过可微函数将一个激活体积转换为另一个激活体积。我们使用三种主要类型的层来构建ConvNet体系结构:卷积层,池化层和完全连接层(正如在常规神经网络中所见)。我们将堆叠这些图层以形成完整的ConvNet 架构。
示例架构:概述。我们将在下面介绍更多细节,但用于CIFAR-10分类的简单ConvNet可以具有体系结构[INPUT - CONV - RELU - POOL - FC]。更详细地说:
- INPUT [32x32x3]将保存图像的原始像素值,在这种情况下,图像的宽度为32,高度为32,并具有三个颜色通道R,G,B。
- CONV层将计算连接到输入中局部区域的神经元的输出,每个计算它们的权重与它们在输入体积中连接的一个小区域之间的点积。如果我们决定使用12个滤镜,这可能导致音量如[32x32x12]。
- RELU层将应用元素激活函数,如[ 数学处理错误]米一个X(0,X)阈值为零。这会使卷的大小不变([32x32x12])。
- POOL层将沿着空间维度(宽度,高度)执行下采样操作,从而产生诸如[16x16x12]的音量。
- FC(即完全连接)层将计算类别分数,从而产生大小为[1×1×10]的数量,其中每个数字对应于一个类别分数,例如10个类别的CIFAR-10。和普通的神经网络一样,顾名思义,这个层中的每个神经元都将连接到前一卷中的所有数字。
通过这种方式,ConvNets将原始图像逐层从原始像素值转换为最终的类别分数。请注意,某些图层包含参数,其他图层则不包含。具体而言,CONV / FC层执行转换,这些转换不仅是输入体积中的激活,而且也是参数(神经元的权重和偏差)的函数。另一方面,RELU / POOL层将实现一个固定的功能。CONV / FC图层中的参数将使用梯度下降进行训练,以便ConvNet计算的类别分数与每个图像的训练集中的标签一致。
综上所述:
- ConvNet体系结构最简单的情况就是将图像体积转换为输出体积的图层列表(例如保存班级分数)
- 有几种不同类型的层(例如CONV / FC / RELU / POOL是迄今最流行的)
- 每层接受一个输入3D音量并通过可微分功能将其转换为输出3D音量
- 每层可能有也可能没有参数(例如,CONV / FC do,RELU / POOL不)
- 每一层可能有也可能没有额外的超参数(例如,CONV / FC / POOL,RELU不)
我们现在描述各个层次及其超参数及其连接的细节。
卷积层
Conv层是卷积网络的核心组成部分,它完成大部分计算繁重的工作。
概述和直觉,没有大脑的东西。让我们首先讨论CONV层在没有大脑/神经元类比的情况下计算什么。CONV层的参数由一组可学习的过滤器组成。每个滤波器在空间上都很小(沿着宽度和高度),但是会延伸到输入音量的整个深度。例如,ConvNet的第一层上的典型过滤器可能具有5x5x3的尺寸(即,5像素的宽度和高度,3是因为图像具有深度3,颜色通道)。在正向传递期间,我们沿着输入体积的宽度和高度滑动(更精确地说,卷积)每个滤波器,并计算滤波器输入和任意位置输入之间的点积。当我们在输入体积的宽度和高度上滑动滤波器时,我们将生成一个二维激活图,给出该滤波器在每个空间位置的响应。直观地说,网络将学习当他们看到某种类型的视觉特征时激活的过滤器,例如第一层上的某种方向的边缘或某种颜色的斑点,或最终在网络的更高层上的整个蜂窝或轮状图案。现在,我们将在每个CONV图层中有一整套滤镜(例如12个滤镜),并且它们中的每一个都将生成单独的二维激活图。我们将沿着深度维度堆叠这些激活图并产生输出量。并且它们中的每一个将产生单独的二维激活图。我们将沿着深度维度堆叠这些激活图并产生输出量。并且它们中的每一个将产生单独的二维激活图。我们将沿着深度维度堆叠这些激活图并产生输出量。
大脑观点。如果你是大脑/神经元类比的粉丝,3D输出体积中的每个条目也可以被解释为神经元的输出,该输出只查看输入中的一个小区域,并与所有神经元共享参数,在空间上是正确的(因为这些数字全都来自应用相同的过滤器)。我们现在讨论神经元连接的细节,它们在空间中的排列以及它们的参数共享方案。
本地连接。当处理像图像这样的高维输入时,正如我们上面看到的,将神经元连接到前一个体积中的所有神经元是不切实际的。相反,我们将每个神经元连接到输入音量的局部区域。这种连接的空间范围是一个超参数,称为神经元的接受场(相当于过滤器的大小)。沿着深度轴的连通程度总是等于输入音量的深度。在我们如何处理空间尺寸(宽度和高度)和深度尺寸时,再次强调这种不对称是非常重要的:连接在空间上(沿着宽度和高度)是局部的,但始终沿着输入体积的整个深度。
例1。例如,假设输入音量大小为[32x32x3](例如RGB CIFAR-10图像)。如果接受域(或过滤器大小)是5x5,那么Conv层中的每个神经元将对输入体积中的[5x5x3]区域具有权重,总共5 * 5 * 3 = 75个权重(以及+1偏置参数)。请注意,沿深度轴的连接范围必须为3,因为这是输入音量的深度。
例2。假设一个输入量大小为[16x16x20]。然后使用3x3的示例感受野大小,Conv层中的每个神经元现在将总共具有3 * 3 * 20 = 180个连接到输入音量。请注意,再次,连接在空间上是局部的(例如3x3),但是沿着输入深度(20)是全部的。
空间安排。我们已经解释了Conv层中每个神经元与输入体积的连通性,但我们尚未讨论输出体积中有多少神经元或它们如何排列。三个超参数控制输出音量的大小:深度,步幅和零填充。我们接下来讨论这些:
- 首先,输出音量的深度是一个超参数:它对应于我们想要使用的滤波器的数量,每个滤波器学习在输入中寻找不同的东西。例如,如果第一个卷积层将原始图像作为输入,则沿着深度维度的不同神经元可以在各种定向边缘或颜色斑点的存在下激活。我们将参考一组神经元,它们都将输入的相同区域看作深度列(有些人更喜欢术语“ 光纤”)。
- 其次,我们必须指定我们滑动过滤器的步幅。当步幅为1时,我们一次将滤镜移动一个像素。当步幅为2(或者罕见的3或更多,尽管这在实践中很少见),那么当我们滑动它们时,滤波器一次跳跃2个像素。这将在空间上产生较小的输出量。
- 正如我们将很快看到的,有时候将输入音量填充到边界周围将会很方便。这个零填充的大小是一个超参数。零填充的优点在于,它可以让我们控制输出体积的空间大小(最常见的是,我们很快就会看到,我们将使用它来精确地保留输入体积的空间大小,以便输入和输出宽度和高度是相同的)。
我们可以计算输出音量的空间大小,作为输入音量大小的函数([ 数学处理误差]w ^),Conv层神经元的感受野大小([ Math Processing Error ]F),它们应用的步幅([ 数学处理错误]小号)和零填充量([ 数学处理错误]P) 在边界。您可以说服自己,计算多少神经元“适合”的正确公式由[ 数学处理错误]给出(w ^- F+2P)/小号+1。例如,对于7x7输入和3x3滤波器,步长为1,pad 0,我们将得到一个5x5输出。随着步幅2,我们会得到一个3x3输出。让我们再看一个图形化的例子:
使用零填充。在左边的例子中,请注意输入维数是5,输出维度是相等的:也是5.结果如此,因为我们的接受性字段是3,我们使用零填充1.如果没有使用零填充,那么输出体积的空间维数仅为3,因为它是多少神经元在整个原始输入中“拟合”的。通常,将零填充设置为[ 数学处理错误]P=(F- 1)/2当步幅是[ 数学处理错误]小号=1确保输入音量和输出音量在空间上具有相同的大小。以这种方式使用零填充是非常常见的,我们将在讨论更多关于ConvNet体系结构的全部理由时讨论。
限制步伐。再次注意,空间排列超参数具有相互约束。例如,当输入的大小为[ 数学处理错误]w ^=10,不使用零填充[ 数学处理错误]P=0,并且过滤器大小为[ 数学处理错误]F=3,那么将无法使用步幅[ 数学处理错误]小号=2,因为[ 数学处理错误](w ^- F+2P)/小号+1=(10- 3+0)/2+1=4.5,即不是整数,表明神经元在整个输入中不“整齐”地对称。因此,超参数的这种设置被认为是无效的,并且ConvNet库可以抛出异常或将其余的零填充以使其合适,或裁剪输入以使其适合或者其他。正如我们将在ConvNet体系结构部分中看到的那样,适当调整ConvNets的大小以使所有维度“解决”可能是一个真正令人头痛的问题,使用零填充和一些设计准则将显着减轻。
真实世界的例子。所述Krizhevsky等。赢得2012年ImageNet挑战的架构接受了大小[227x227x3]的图像。在第一卷积层上,它使用感受野大小的神经元[ Math Processing Error ]F=11,步幅[ 数学处理错误]小号=4并且没有零填充[ 数学处理错误]P=0。由于(227-11)/ 4 + 1 = 55,并且由于Conv层具有[ 数学处理误差]的深度,ķ=96,Conv层输出音量大小[55x55x96]。本卷中的每个55 * 55 * 96神经元都连接到输入音量大小为[11x11x3]的区域。而且,每个深度列中的所有96个神经元都连接到输入的相同[11x11x3]区域,但当然具有不同的权重。除此之外,如果你阅读实际的纸张,它声称输入图像是224×224,这肯定是不正确的,因为(224 - 11)/ 4 + 1很明显不是一个整数。这使得ConvNets的历史中很多人感到困惑,对发生的事情知之甚少。我自己最好的猜测是Alex使用了他在本文中没有提到的3个额外像素的零填充。
参数共享。卷积层中使用参数共享方案来控制参数的数量。使用上面的实际例子,我们看到第一个Conv层有55 * 55 * 96 = 290,400个神经元,每个神经元有11 * 11 * 3 = 363个权重和1个偏差。总之,仅在ConvNet的第一层上增加了290400 * 364 = 105,705,600个参数。显然,这个数字非常高。
事实证明,通过作出一个合理的假设,我们可以大大减少参数的数量:如果一个特征对于在某个空间位置(x,y)进行计算是有用的,那么在另一个位置(x2 ,y2)上。换句话说,将单个2维深度切片表示为深度切片(例如,大小为[55x55x96]的卷有96个深度切片,每个大小为[55x55]),我们将限制每个深度切片中的神经元使用相同的权重和偏差。使用这个参数共享方案,我们例子中的第一个Conv层现在只有96个独特权重集合(每个深度切片一个权重集合),共96 * 11 * 11 * 3 = 34,848个唯一权重或34,944个参数( +96偏见)。或者,每个深度切片中的所有55 * 55神经元现在将使用相同的参数。在反向传播实践中,体积中的每个神经元都会计算其权重的梯度,但是这些梯度将叠加在每个深度切片上,并且仅更新每个切片的一组权重。
注意,如果在一个单一的深度切片所有神经元都使用相同的权重向量,则CONV层的直传可以在每个深度切片被计算为一个卷积神经元的与输入量(因此,名称权重:卷积层)。这就是为什么通常将权重集合称为过滤器(或内核),与输入进行卷积的原因。
请注意,有时参数共享假设可能没有意义。当ConvNet的输入图像具有特定的中心结构时,尤其如此,例如,我们应该期望在图像的一侧应该学习完全不同的特征。一个实际的例子是当输入是在图像中居中的面。你可能会期望在不同的空间位置可以(而且应该)学习不同的眼睛特定或头发特定的特征。在这种情况下,通常放宽参数共享方案,而只需将图层称为本地连接层。
Numpy的例子。为了让上面的讨论更加具体,让我们用代码和特定的例子来表达相同的想法。假设输入量是一个numpy数组X
。然后:
- 位置处的深度列(或光纤)
(x,y)
将是激活X[x,y,:]
。 - 一个深度切片或者等效的深度激活图
d
将是激活X[:,:,d]
。
Conv层示例。假设输入音量X
已经形成X.shape: (11,11,4)
。进一步假设我们不使用零填充([ Math Processing Error ]P=0),过滤器大小是[ 数学处理错误]F=五,并且步幅是[ 数学处理错误]小号=2。输出音量因此将具有空间大小(11-5)/ 2 + 1 = 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中,*
上面的操作表示数组之间的元素相乘。还要注意,权重矢量W0
是该神经元的权重矢量,并且b0
是偏差。在这里,由于滤波器大小为5,输入音量的深度为4 ,W0
因此假定其形状为“形状” W0.shape: (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
(或两者)
我们发现我们正在索引到第二个深度维度V
(在索引1处),因为我们正在计算第二个激活图,并且W1
现在使用了一组不同的参数()。在上面的例子中,我们为了简洁起见省略了Conv层执行的一些其他操作来填充输出数组的其他部分V
。此外,回想一下,这些激活图经常通过诸如ReLU之类的激活函数按照元素进行,但是这里没有示出。
总结。总而言之,Conv层:
- 接受大小的数量[ 数学处理错误]w ^1×H1×d1
- 需要四个超参数:
- 过滤器数量[ 数学处理错误]ķ,
- 其空间范围[ 数学处理错误]F,
- 大步[ 数学处理错误]小号,
- 零填充量[ 数学处理错误]P。
- 产生大小的数量[ 数学处理错误]w ^2×H2×d2 哪里:
- [ 数学处理错误]w ^2=(w ^1- F+2P)/小号+1
- [ 数学处理错误]H2=(H1- F+2P)/小号+1 (即宽度和高度均匀对称计算)
- [ 数学处理错误]d2=ķ
- 通过参数共享,它引入了[ 数学处理错误]F⋅F⋅d1每个过滤器的权重,总共[ 数学处理错误](F⋅F⋅d1)⋅ķ权重和[ 数学处理错误]ķ 偏见。
- 在输出音量中,[ 数学处理错误]d- 深度切片(大小[ 数学处理错误]w ^2×H2)是执行[ 数学处理错误]的有效卷积的结果,d用[ 数学处理错误]的步幅过滤输入音量,小号,然后偏移[ 数学处理错误]d偏向。
超参数的常见设置是[ 数学处理错误]F=3,小号=1,P=1。然而,激励这些超参数的常用惯例和经验法则。请参阅下面的ConvNet体系结构部分。
卷积演示。以下是一个CONV层的演示。由于三维体积难以可视化,所有体积(输入体积(蓝色),体重体积(红色),输出体积(绿色))都可视化,每个深度切片堆叠成行。输入量大小[ 数学处理错误]w ^1=五,H1=五,d1=3,并且CONV层参数是[数学处理错误]ķ=2,F=3,小号=2,P=1。也就是说,我们有两个大小的过滤器[ 数学处理错误]3×3,并且它们以2的步幅施加。因此,输出体积大小具有空间尺寸(5-3 + 2)/ 2 + 1 = 3。此外,请注意,[ 数学处理误差]P=1应用于输入音量,使输入音量的外边界为零。下面的可视化对输出激活(绿色)进行迭代,并显示每个元素的计算方法是将高亮显示的输入(蓝色)与滤镜(红色)进行元素相乘,然后对其进行求和,然后通过偏差对结果进行偏移。
作为矩阵乘法实现。请注意,卷积运算本质上是在滤波器和输入的局部区域之间执行点积。CONV层的常见实现模式是利用这一事实并将卷积层的正向通过制定为如下的一个大矩阵乘法:
- 输入图像中的局部区域在通常称为im2col的操作中被拉伸成列。例如,如果输入是[227x227x3],并且它将在步幅4与11x11x3滤波器卷积,则我们将在输入中采用[11x11x3]个像素块,并将每个块拉伸到大小为11 * 11 * 3 = 363.在步长4的输入中迭代该过程沿着宽度和高度给出(227-11)/ 4 + 1 = 55个位置,导致尺寸为[363×3025]
X_col
的im2col的输出矩阵,其中每列是一个伸出的感受野,总共有55 * 55 = 3025个。请注意,由于接受域重叠,输入体积中的每个数字可能会复制到多个不同的列中。 - CONV层的权重类似地伸展成行。例如,如果有大小为[11x11x3]的96个滤镜,则会给出
W_row
大小为[96 x 363] 的矩阵。 - 卷积的结果现在相当于执行一个大矩阵乘法
np.dot(W_row, X_col)
,它可以评估每个滤波器与每个接收场的位置之间的点积。在我们的例子中,这个操作的输出是[96 x 3025],给出每个位置上每个过滤器的点积的输出。 - 结果必须重新调整为适当的输出尺寸[55x55x96]。
这种方法的缺点是可以使用大量内存,因为输入卷中的某些值会被多次复制X_col
。但是,好处是有很多非常有效的Matrix Multiplication实现可以利用(例如,在常用的BLAS API中)。此外,我们可以重复使用相同的im2col想法来执行池操作,我们将在下面讨论这个操作。
反向传播。卷积操作的后向传递(对于数据和权重)也是卷积(但是具有空间翻转的滤波器)。这很容易用一个玩具例子(现在不扩展)在一维情况下推导出来。
1x1卷积。另外,一些论文使用1x1卷积,首先由Network in Network进行调查。有些人首先感到困惑的是看到1x1卷积,特别是当它们来自信号处理背景时。通常情况下,信号是二维的,所以1x1卷积是没有意义的(它只是逐点缩放)。然而,在ConvNets中,情况并非如此,因为我们必须记住,我们运行的是三维体积,并且过滤器始终贯穿输入体积的整个深度。例如,如果输入为[32x32x3],则执行1x1卷积将有效地执行三维点积(因为输入深度为3个通道)。
扩大卷积。最近的一个发展(例如参见Fisher Yu和Vladlen Koltun的论文)将在CONV层中引入一个称为扩张的超参数。到目前为止,我们只讨论了连续的CONV滤波器。但是,可以在每个单元格之间放置具有空格的过滤器,称为扩展。作为一个例子,在一个维度中,一个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。在某些设置中,这可以非常有用地与0扩散滤波器结合使用,因为它允许您使用更少的图层更加积极地合并空间信息。例如,如果您将两个3x3 CONV图层叠在一起,那么您可以说服自己,第二层上的神经元是输入的5x5补丁的函数(我们可以说这些神经元的有效感受域是5×5)。如果我们使用扩张的卷积,那么这个有效的接受场会变得更快。
池层
定期在ConvNet体系结构中的连续Conv层之间插入Pooling层是很常见的。其功能是逐步减少表示的空间大小,以减少网络中的参数和计算量,从而控制过拟合。池层在输入的每个深度切片上独立运行,并使用MAX操作在空间上调整其大小。最常见的形式是具有2x2大小过滤器的池化层,在输入的每个深度切片上沿着宽度和高度两次施加2个下采样的步幅,放弃75%的激活。在这种情况下,每个MAX操作最多需要超过4个数字(某个深度切片中的小2×2区域)。深度维度保持不变。更一般地说,池化层:
- 接受大小的数量[ 数学处理错误]w ^1×H1×d1
- 需要两个超参数:
- 其空间范围[ 数学处理错误]F,
- 大步[ 数学处理错误]小号,
- 产生大小的数量[ 数学处理错误]w ^2×H2×d2 哪里:
- [ 数学处理错误]w ^2=(w ^1- F)/小号+1
- [ 数学处理错误]H2=(H1- F)/小号+1
- [ 数学处理错误]d2=d1
- 由于它计算输入的固定功能,因此引入零参数
- 请注意,对Pooling图层使用零填充并不常见
值得注意的是,在实践中发现的最大池层只有两种常见的变体:具有[ 数学处理错误]的池层,F=3,小号=2(也称为重叠池),更常见的是[ 数学处理错误]F=2,小号=2。与更大的接受领域合并大小太破坏性。
一般池。除了最大池化之外,池化单元还可以执行其他功能,例如平均池化或甚至L2规范池化。平均汇集通常用于历史上,但最近已经失宠,与最大汇集操作相比,已被证明在实践中效果更好。
反向传播。回顾反向传播章节,max(x,y)操作的后向传递具有简单的解释,因为只将渐变路由到正向传递中具有最高值的输入。因此,在汇聚层的正向传递期间,通常跟踪最大激活的索引(有时也称为开关),以便在反向传播期间梯度路由是有效的。
摆脱池塘。许多人不喜欢这种集合操作,并认为没有它就可以逃脱。例如,争取简单性:所有卷积网都建议放弃池层,转而采用仅由重复的CONV层组成的体系结构。为了减小表示的大小,他们建议在一段时间内在CONV层中采用更大的步幅。在训练良好的生成模型(例如变分自动编码器(VAEs)或生成对抗网络(GAN))中,丢弃池化层也是重要的。未来的体系结构似乎很可能只有很少到没有共享层。
标准化层
已经提出许多类型的归一化层用于ConvNet体系结构,有时意图实施在生物脑中观察到的抑制方案。然而,这些层次已经失宠,因为实际上他们的贡献已经被证明是最小的,如果有的话。对于各种类型的规范化,请参阅Alex Krizhevsky的cuda-convnet库API中的讨论。
完全连接的层
正如在常规神经网络中看到的,完全连接层中的神经元与前一层中的所有激活都有完全连接。因此,它们的激活可以通过矩阵乘法和偏移偏移来计算。有关更多信息,请参阅笔记的“ 神经网络”部分。
将FC图层转换为CONV图层
值得注意的是,FC和CONV层之间的唯一区别在于,CONV层中的神经元仅连接到输入中的局部区域,并且CONV中的许多神经元共享参数。然而,两层神经元仍然计算点积,所以它们的功能形式是相同的。因此,事实证明可以在FC和CONV层之间进行转换:
- 对于任何CONV层,都有一个实现相同前向功能的FC层。权重矩阵可能是一个大矩阵,除了某些块(由于局部连通性),其中大部分块的权重相等(由于参数共享),其大部分为零。
- 相反,任何FC层都可以转换为CONV层。例如,具有[ 数学处理错误]的FC层ķ=4096那就是看一些尺寸的输入量[ 数学处理错误]7×7×512可以等效地表示为具有[ 数学处理错误]的CONV层F=7,P=0,小号=1,ķ=4096。换句话说,我们将滤波器大小设置为输入音量的大小,因此输出将仅为[ 数学处理错误]1×1×4096 因为只有一个深度列“适合”输入音量,与初始FC层相同。
FC-> CONV转换。在这两种转换中,将FC层转换为CONV层的能力在实践中特别有用。考虑采用224x224x3图像的ConvNet体系结构,然后使用一系列CONV图层和POOL图层将图像缩小为7x7x512大小的激活卷(在我们稍后会看到的AlexNet体系结构中,这是通过使用5个汇聚层,每次对输入进行空间下采样,使得最终空间尺寸为224/2/2/2/2/2 = 7)。从那里,AlexNet使用两个尺寸为4096的FC层,最后使用1000个神经元计算类分数的最后一个FC层。如上所述,我们可以将这三个FC层中的每一个转换为CONV层:
- 将看起来[7x7x512]卷的第一个FC层替换为使用过滤器大小的CONV层[ 数学处理错误]F=7,输出音量[1x1x4096]。
- 将第二个FC层替换为使用过滤器大小的CONV层[ 数学处理错误]F=1,输出音量[1x1x4096]
- 用[ 数学处理错误]类似地替换上一个FC层,F=1,给出最终输出[1x1x1000]
这些转换中的每一个实际上都可能涉及操纵(例如重塑)权重矩阵[ 数学处理错误]w ^在每个FC层到CONV层过滤器。事实证明,这种转换使我们能够在单个正向通道中以更大的图像在许多空间位置上非常有效地“滑动”原始ConvNet。
例如,如果224x224图像给出了大小[7x7x512]的大小 - 即减少32,则通过转换的体系结构转发尺寸为384x384的图像会得到自[384/32] = 12的等效体积[12x12x512]。接下来我们刚刚从FC层转换而来的接下来的3个CONV层现在会给出最终的大小[6x6x1000],因为(12-7)/ 1 + 1 = 6。注意,不是一个单独的向量类分数大小为[1x1x1000],我们现在可以在整个384x384图片上获得整个6x6的班级分数数组。
以32像素的步幅在384x384图像的224x224作物上独立评估原始ConvNet(使用FC图层)可以获得与转发转换的ConvNet一次相同的结果。
自然地,转发转换的ConvNet一次比在所有这36个位置迭代原始ConvNet效率更高,因为36个评估共享计算。这个技巧通常用于实践中以获得更好的性能,例如,调整图像的大小以使其更大,使用转换后的ConvNet评估许多空间位置的类别分数,然后对班级分数进行平均是很常见的。
最后,如果我们想要在图像上有效地应用原始的ConvNet,但是步幅小于32像素,该怎么办?我们可以通过多次前锋传球达成。例如,请注意,如果我们想要使用16像素的步幅,我们可以通过组合通过转发转换的ConvNet两次收到的体积来实现:首先在原始图像上方,然后在图像上方,但图像的空间位移由16个像素沿着宽度和高度。
- Net Surgery上的IPython Notebook 显示了如何在代码中使用Caffe在实践中执行转换,
ConvNet架构
我们已经看到,卷积网络通常仅由三种类型的层构成:CONV,POOL(除非另有说明,我们假设最大池)和FC(全连接的短路)。我们还将显式地将RELU激活函数编写为一个层,它应用了元素非线性。在本节中,我们讨论如何将这些通常堆叠在一起形成整个ConvNets。
图层模式
ConvNet体系结构最常见的形式是叠加一些CONV-RELU层,随后使用POOL层,并重复此模式,直到图像空间合并为小尺寸。在某些情况下,过渡到完全连接的层是很常见的。最后的完全连接图层保存输出,如班级分数。换句话说,最常见的ConvNet架构遵循以下模式:
INPUT -> [[CONV -> RELU]*N -> POOL?]*M -> [FC -> RELU]*K -> FC
其中*
表示重复,并且POOL?
表示可选的池化层。此外,N >= 0
(通常N <= 3
)M >= 0
,K >= 0
(通常K < 3
))。例如,下面是一些常见的ConvNet架构,您可能会看到遵循以下模式:
INPUT -> FC
,实现了一个线性分类器。这里N = M = K = 0
。INPUT -> CONV -> RELU -> FC
INPUT -> [CONV -> RELU -> POOL]*2 -> FC -> RELU -> FC
。这里我们看到每个POOL层之间都有一个CONV层。INPUT -> [CONV -> RELU -> CONV -> RELU -> POOL]*3 -> [FC -> RELU]*2 -> FC
这里我们看到在每个POOL层之前堆叠了两个CONV层。对于更大更深的网络来说,这通常是一个好主意,因为在破坏性池化操作之前,多个堆叠CONV层可以开发更复杂的输入体积特征。
将一个小型过滤器CONV叠放到一个大型感受野CONV层上。假设您将三个3x3 CONV层层叠在一起(当然,非线性之间)。在这种布置中,第一CONV层上的每个神经元都具有输入音量的3x3视图。第二CONV层上的神经元具有第一CONV层的3x3视图,并且因此扩展了输入体积的5x5视图。类似地,第三CONV层上的神经元具有第二CONV层的3×3视图,并因此具有输入体积的7×7视图。假设代替这三层3x3 CONV,我们只想使用一个带有7x7感受域的CONV层。这些神经元的空间范围(7x7)具有相同的输入体积的感受野大小,但有几个缺点。首先,神经元将在输入上计算线性函数,而三组CONV层包含非线性特征,使其特征更具表现力。其次,如果我们假设所有的卷都有[数学处理错误]C通道,那么可以看出单个7x7 CONV层将包含[ 数学处理错误]C×(7×7×C)=49C2参数,而三个3x3 CONV层将只包含[ 数学处理错误]3×(C×(3×3×C))=27C2参数。直观地说,使用小型过滤器来堆叠CONV层,而不是使用一个带有大型过滤器的CONV层,这使得我们可以表达更强大的输入功能,并且参数更少。作为一个实际的缺点,如果我们打算做反向传播,我们可能需要更多的内存来保存所有的中间CONV层结果。
最近的离开。应该指出的是,在谷歌的初始体系结构以及微软亚洲研究院的当前(最先进的)剩余网络中,线性列表层的传统范例最近受到了挑战。这两者(请参阅案例研究部分的详细信息)具有更复杂和不同的连接结构。
在实践中:使用ImageNet上最好的工具。如果您在思考架构决策时感到有些疲劳,那么您会很高兴知道,在90%或更多的应用程序中,您不必担心这些问题。我喜欢将这一点总结为“ 不要成为英雄 ”:不要为了某个问题而将自己的体系结构卷起来,而应该考虑ImageNet上当前效果最好的任何体系结构,下载预训练模型并对数据进行微调。你几乎不需要从头开始训练ConvNet或从零开始设计一个ConvNet。我还在深度学习学院做了这一点。
图层大小调整模式
到目前为止,我们已经忽略了在ConvNet中每个层中使用的常用超参数的提及。我们将首先阐述确定架构大小的常用经验规则,然后遵循规则并讨论符号:
该输入层(包含图像)应该是由2分多次整除。常用数字包括32(例如CIFAR-10),64,96(例如STL-10)或224(例如常见的ImageNet ConvNets),384和512。
所述CONV层应该使用小的过滤器(3×3例如或至多5×5),使用的步幅[ 数学处理错误]小号=1,并且关键的是,用零填充输入音量,使得conv层不会改变输入的空间维度。即,当[ 数学处理错误]F=3,然后使用[ 数学处理错误]P=1将保留输入的原始大小。当[ 数学处理错误]F=五,[ 数学处理错误]P=2。对于一般[ 数学处理错误]F,可以看出[ 数学处理错误]P=(F- 1)/2保留输入大小。如果您必须使用更大的过滤器尺寸(例如7x7左右),则通常在查看输入图像的第一个conv层上看到这一点。
该池层是负责下采样输入的空间尺寸的。最常见的设置是使用2x2接受字段的最大池(即[ 数学处理错误]F=2),并跨度为2(即[ 数学处理错误]小号=2)。请注意,这会丢弃输入音量中激活的75%(由于宽度和高度下采样为2)。另一个稍微不太常见的设置是使用3x3感受野,步幅为2,但是这样做。对于大于3的最大池接收的接受字段大小是非常罕见的,因为汇集过于有损和积极。这通常会导致性能下降。
减少大小头痛。上面介绍的方案令人满意,因为所有CONV层都保留了输入的空间大小,而POOL层本身负责空间下的体积下采样。在另一个我们使用大于1的步幅的替代方案中,或者不要在CONV层中零填充输入时,我们必须非常仔细地跟踪整个CNN体系结构中的输入音量,并确保所有步幅和滤波器“工作正常out“,并且ConvNet架构很好且对称布线。
为什么在CONV中使用1的步幅?实践中更小的步伐更好地工作。此外,如前所述,步幅1允许我们将所有空间下采样保留到POOL层,而CONV层仅在深度方向上转换输入体积。
为什么使用填充?除了在CONV之后保持空间大小恒定的前述益处之外,这样做实际上提高了性能。如果CONV层没有对输入进行零填充并且只执行有效的卷积,那么在每个CONV之后卷的大小会减少一小部分,并且边界处的信息将被“冲走”得太快。
基于内存限制的妥协。在某些情况下(特别是ConvNet架构的早期阶段),使用上面介绍的经验法则可以快速建立内存容量。例如,使用三个3x3 CONV层(每个64个滤镜和填充1)过滤224x224x3图像会创建三个尺寸为[224x224x64]的激活卷。这相当于总共大约1000万次激活,或72MB内存(每个图像的激活和渐变)。由于GPU经常受到内存的瓶颈,因此可能需要妥协。实际上,人们更喜欢在网络的第一个CONV层做出妥协。例如,一个折衷方案可能是使用第一个CONV层,其滤波器大小为7x7,步幅为2(如ZF网所示)。又例如,AlexNet使用11x11的筛选器大小和4的步幅。
实例探究
在卷积网络领域有几个有名字的体系结构。最常见的是:
- LeNet。卷积网络的第一个成功应用是由Yann LeCun在20世纪90年代开发的。其中最着名的是用于阅读邮政编码,数字等的LeNet架构。
- AlexNet。该推广卷积网络计算机视觉中的第一部作品是AlexNet,由Alex Krizhevsky,伊利亚Sutskever和Geoff韩丁发展。AlexNet 于2012 年提交给ImageNet ILSVRC挑战赛,并且明显超越季军(与26%的亚军相比,16%的前5名错误)。该网络与LeNet具有非常相似的架构,但是更深,更大,并且卷积层相互堆叠(先前通常只有一个CONV层总是紧跟着POOL层)。
- 采埃孚网络。2013年ILSVRC冠军是来自Matthew Zeiler和Rob Fergus的卷积网络。它被称为ZFNet(Zeiler&Fergus Net的简称)。这是对AlexNet的改进,通过调整体系结构超参数,特别是通过扩大中间卷积层的大小并使第一层上的步幅和过滤器尺寸更小。
- GoogLeNet。ILSVRC 2014获奖者是Szegedy等人的卷积网络。来自Google。其主要贡献是开发了一个先启模块,该模块显着减少了网络中的参数数量(4M,与60M的AlexNet相比)。另外,本文在ConvNet的顶部使用平均池(Average Pooling)而不是完全连接层(Fully Connected layers),从而消除了大量似乎并不重要的参数。GoogLeNet还有几个后续版本,最近的Inception-v4。
- VGGNet。2014年ILSVRC亚军是来自Karen Simonyan和Andrew Zisserman的网络,后者被称为VGGNet。它的主要贡献在于表明网络的深度是良好表现的关键组成部分。他们最终的最佳网络包含16个CONV / FC层,并且极具吸引力,具有非常均匀的架构,从开始到结束只执行3x3卷积和2x2池化。他们的预训模型可用于Caffe的即插即用。VGGNet的缺点是评估和使用更多的内存和参数(140M)更为昂贵。这些参数中的大部分都位于第一个完全连接的层中,因为发现这些FC层可以在不降低性能的情况下被移除,从而大大减少了必要参数的数量。
- ResNet。残余网络由Kaiming He等开发。是ILSVRC 2015的获胜者。它具有特殊的跳过连接和批量标准化的大量使用。该体系结构还缺少网络末端的完全连接层。读者还可以参考凯明的演示文稿(视频,幻灯片)以及最近在火炬中重现这些网络的实验。ResNets目前是迄今为止最先进的卷积神经网络模型,并且是实践中使用ConvNets的默认选择(截至2016年5月10日)。特别是,还可以看到最近的开发,调整了原来的架构何凯明等人。深度残留网络中的身份映射(2016年3月发布)。
VGGNet详细。作为案例研究,让我们更详细地分解VGGNet。整个VGGNet由CONV层组成,其执行3x3卷积步骤1和垫1,POOL层执行2x2最大池步骤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
与卷积网络常见的一样,请注意大部分内存(以及计算时间)都用于早期的CONV层,而大部分参数都位于最后一个FC层。在这种情况下,第一个FC层包含100M权重,总共140M。
计算考虑
构建ConvNet体系结构时要注意的最大瓶颈是内存瓶颈。许多现代GPU具有3/4 / 6GB内存的限制,最好的GPU具有大约12GB的内存。有三个主要的记忆来源来记录:
- 从中间体积大小:这些是ConvNet每层激活的原始数量,以及它们的梯度(大小相同)。通常,大部分激活都在ConvNet的早期层次上(即第一个Conv层)。由于它们是反向传播所必需的,但它们只是在测试时间运行ConvNet的一个聪明的实现原则上可以大大减少这种情况,只需将任意层的当前激活存储起来,并丢弃以前激活的层。
- 从参数大小:这些是保存网络参数的数字,它们在反向传播期间的梯度,并且如果优化使用动量,Adagrad或RMSProp,则通常也是步高速缓存。因此,单独存储参数矢量的存储器通常必须乘以至少3的因子。
- 每个ConvNet实现都必须维护各种各样的内存,例如图像数据批次,可能是其扩充版本等。
一旦粗略估计了总值(激活,渐变和杂项),数字应该转换为GB的大小。取数值,乘以4得到原始字节数(因为每个浮点数是4个字节,或者对于双精度可能是8个),然后除以1024多次以获得以KB为单位的内存量, MB,最后是GB。如果你的网络不适合,“适合”的通用启发式就是减少批量,因为大部分内存通常被激活所消耗。
其他资源
与实施有关的额外资源:
- Soumith CONV性能基准
- ConvNetJS CIFAR-10演示允许您使用ConvNet体系结构,并在浏览器中实时查看结果和计算结果。
- Caffe是流行的ConvNet库之一。
- 最先进的ResNets Torch7