在介绍卷积神经网络之前,先提出三个观点,正是这三个观点使得卷积神经网络能够真正起作用。
1. 局部性
对于一张图片而言,需要检测图片中的特征来决定图片的类别,通常情况下这些特征都不是由整张图片决定的,而是由一些局部的区域决定的。
比如图4.1中的鸟喙,该特征只存在于图片的局部中。
2. 相同性
对于不同的图片,如果它们具有同样的特征,这些特征会出现在图片不同的位置也就是说可以用同样的检测模式去检测不同图片的相同特征,只不过这些特征处于图片中不同的位置,但是特征检测所做的操作几乎一样。
图4.2中两张图片的鸟喙处于不同的位置,但是可以用相同的检测模式去检测。
3. 不变性
对于一张大图片,如果我们进行下采样,那么图片的性质基本保持不变。
图4.3经过下采样还是能够看出来是一张鸟的图片。
上面的三个性质分别对应着卷积神经网络中的三种思想,接下来介绍网络的层结构。
卷积神经网络和一般的全连接神经网络是相似的,也是由一些神经元构成的,如图4.4所示。这些神经元中有着需要学习的参数,通过网络输入,最后输出结果,通过损失函数来优化网络中的参数。卷积神经网络与其不同之处在于网络的层结构是不同的。图4.4是全连接神经网络,由一系列隐藏层构成,每个隐藏层由若干个神经元构成,其中每个神经元都和前一层的所有神经元相关联,但是每一层中的神经元是相互独立的。
这样的神经网络在处理图片上存在什么问题呢?比如在MNIST数据集上,图片大小是 28x28,那么第一个隐藏层的单个神经元的权重数目就是28x28=784,这似乎还不是特别大,但这只是一张小图片,且是灰度图。对于一张较大的图片而言,比如200x200x3,就会导致权重数目是200x200x3=120000,如果设置几个隐藏层中的神经元数目,就会导致参数增加特别快。其实这样的图片在现实中并不算大图片,所以全连接神经网络对于处理图像并不是一个好的选择。
图4.5所示的是卷积神经网络的处理过程,不同于一般的全连接神经网络,卷积神经网络是一个3D容量的神经元,也就是说神经元是以三个维度来排列的:宽度、高度和深度。比如输入的图片是32x32x3,那么这张图片的宽度就是32,高度也是32,深度是3。后面会详细地介绍卷积神经网络是如何计算的,以及为什么它被这样设计并取得如此好的效果。
卷积神经网络中的主要层结构有三个:卷积层、池化层和全连接层,通过堆叠这些层结构形成了一个完整的卷积神经网络结构。卷积神经网络将原始图片转化成最后的类别得分,其中一些层包含参数,一些层没有包含参数,比如卷积层和全连接层拥有参数,而激活层和池化层不含参数。这些参数通过梯度下降法来更新,最后使得模型尽可能正确地识别出图片类别。
接下来具体介绍每一种层的连接方式和它们的超参数。
卷积层
卷积层是卷积神经网络的核心,大多数计算都是在卷积层中进行的。
1. 概述
首先介绍卷积神经网络的参数。这些参数是由一些可学习的滤波器集合构成的,每个滤波器在空间上(宽度和高度)都比较小,但是深度和输入数据的深度保持一致。举例来说,卷积神经网络的第一层卷积一个典型的滤波器的尺寸可以是5x5x3(宽和高都是5),或者是3x3x3(宽和高都是3),这里的宽度和高度可以任意定义,但是深度必须是3,因为深度要和输入一致,而输入的图片是3通道的。在前向传播的时候,让每个滤波器都在输入数据的宽度和高度上滑动(卷积),然后计算整个滤波器和输入数据任意一处的内积。
当滤波器沿着输入数据的宽度和高度滑动时,会生成一个二维的激活图,激活图上的每个空间位置表示了原图片对于该滤波器的反应。直观来看,网络会让滤波器学习到当它看到某些类型的视觉特征的时候就激活,具体的视觉特征可以是边界、颜色轮廓、甚至可以是网络更高层上的蜂巢状或者车轮状图案。
在每个卷积层上,会有一整个集合的滤波器,比如20个,这样就会形成20张二维的、不同的激活图,将这些激活图在深度方向上层叠起来就形成了卷积层的输出。
如果用大脑和生物神经元做比喻,那么输出的3D数据中的每个数据都可以看成是神经元的一个输出,而该神经元只是观察输入数据中的一种特征,并且和空间上左右两边的所有神经元共享参数(因为这些输出都是使用同一个滤波器得到的结果)。下面介绍卷积神经网络中的神经元连接,它们在空间中的排列,以及它们参数共享的模式。
2. 局部连接
在处理图像这样高维度输入的时候,让每个神经元都与它那一层中的所有神经元进行全连接是不现实的。相反,让每个神经元只与输入数据的一个局部区域连接是可行的,为什么可以这样做呢?其实这是因为图片特征的局部性,所以只需要通过局部就能提取出相应的特征。
与神经元连接的空间大小叫做神经元的感受野(receptivefeld),它的大小是一个人为设置的超参数,这其实就是滤波器的宽和高。在深度方向上,其大小总是和输入的深度相等。最后强调一下,对待空间维度(宽和高)和深度维度是不同的,连接在空间上是局部的,但是在深度上总是和输人的数据深度保持一致。
图4.6形象地展示了感受野在空间和深度上的大小,左边表示输入的数据,中间是感受野,右边每个小圆点表示一个神经元。下面举一个具体的例子来说明一下。比如输入的数据尺寸为32x32x3,如果感受野(滤波器尺寸)是5x5,卷积层中每个神经元会有输入数据中5x5x3区域的权重,一共5x5x3=75个权重。这里再次强调感受野深度的大小必须是3,和输入数据保持一致。比如输入数据体尺寸是16x16x20感受野是3x3,卷积层中每个神经元和输入数据体之间就有3x3x20=180个连接这里的深度必须是20,和输入数据一致。
3. 空间排列
前面介绍了每个神经元只需要与输入数据的局部区域相连接,但是没有介绍卷积层中神经元的数量和它们的排列方式、输出深度、滑动步长,以及边界填充控制着卷积层的空间排布。
首先,卷积层的输出深度是一个超参数,它与使用的滤波器数量一致,每种滤波器所做的就是在输入数据中寻找一种特征。比如说输入一张原始图片,卷积层输出的深度是20,这说明有20个滤波器对数据进行处理,每种滤波器寻找一种特征进行激活。
其次,在滑动滤波器的时候,必须指定步长。比如步长为1,说明滤波器每次移动1个像素点。当步长为2的时候,滤波器会滑动2个像素点。滑动的操作会使得输出的数据在空间上变得更小。
最后介绍边界填充,可以将输入数据用0在边界进行填充,这里将0填充的尺寸作为一个超参数,有一个好处就是,可以控制输出数据在空间上的尺寸,最常用来保证输入和输出在空间上尺寸一致。
输出的尺寸到底是多少呢?其实可以用一个公式来计算,就是,其中W表示输入的数据大小,F表示卷积层中神经元的感受野尺寸,S表示步长,P表示边界填充0的数量。比如输入是7x7、滤波器是3x3,步长是1,填充的数量是0。那么根据公式,就能得到,即输出的空间大小是5x5,如果步长是2,那么 ,输出的空间大小就是3x3。可以用图 4.7所示的这个一维的例子来具体说明。
右上角表示神经网络的权重,其中输入数据的大小为5,感受野的大小为3;左边表示滑动步长为1,且填充也为1;右边表示滑动步长为2,填充为1。
4. 零填充的使用
从上面的例子中,我们看到输入的维度是5,输出的维度也是5。之所以如此,是因为感受野是3,并且使用了1的零填充。如果不使用零填充,那么输出数据的维度也就只有3,因为。一般来说,当步长S=1时,零填充的值为,这样就能够保证输入的数据和输出的数据具有相同的空间尺寸。
5. 步长的限制
通过上面的公式我们知道步长的选择是有所限制的,举例来说,当输入尺寸 W=10 的时候,如果不使用零填充,即 P=0,滤波器尺寸 F=3,这样步长 S=2 就行不通,因为,结果不是一个整数,这就说明神经元不能整齐对称地滑过输入数据体,这样的超参数设置是无效的,使用 PyTorch 的时候就会报错,可以使用零填充让设置变得合理。在后面卷积神经网络的结构设计中,需要合理地设计网络的尺寸,使得所有维度都能够正常工作,这件事并没有看上去那么容易。
6. 参数共享
在卷积层使用参数共享可以有效地减少参数的个数,这样之所以能够行得通,是因为之前介绍的特征的相同性,也就是说相同的滤波器能够检测出不同位置的相同特征。比如说一个卷积层的输出是20x20x32,那么其中神经元的个数就是 20x20x32=12800,如果窗口大小是3x3、而输入的数据体深度是10,那么每个神经元就有3x3x10=900个参数,这样合起来就有12800x900=11520000个参数,单单一层卷积就有这么多参数,这样运算速度显然是特别慢的。
根据之前介绍的,一个滤波器检测出一个空间位置处的特征,那么也能够有效检测出位置的特征,所以就可以用相同的滤波器来检测相同的特征,基于这个假设,我们就能够有效减少参数个数。比如上面这个例子,一共有32个滤波器这使得输出体的厚度是32、每个滤波器的参数为3x3x10=900,总共的参数就有32x900=28800个,极大减少了参数的个数。
由参数共享我们知道输出体数据在深度切片上所有的权重都使用同一个权重向量,那么卷积层在向前传播的过程中,每个深度切片都可以看成是神经元的权重对输入数据体做卷积,这也就是为什么要把这些3D的权重集合称为滤波器,或者卷积核。
需要注意的是,参数共享之所以能够有效,是因为一个特征在不同位置的表现是相同的,比如一个滤波器检测到了水平边界这个特征,那么这个特征具有平移不变性所以在其他位置也能够检测出来。但是有时候这样的假设可能是没有意义的,特别是当卷积神经网络的输入图像呈现的是一些明确的中心结构的时候,希望在图片的不同位置学习到不同的特征。一个具体的例子就是人脸识别,人脸一般位于图片的中心,我们希望不同的特征能够在不同的位置被学习到,比如眼睛特征或者头发特征,正是由于这些特征在不同的地方,才能够对人脸进行识别。
7. 总结
最后总结一下卷积层的一些性质。
- 输入数据体的尺寸是
- 4个超参数:滤波器数量K,滤波器空间尺寸F,滑动步长S,零填充的数量P
- 输出数据体的尺寸为,其中
- 由于参数共享,每个滤波器包含的权重数目为,卷积层一共有个权重和K个偏置
- 在输出体数据中,第d个深度切片(空间尺寸是),用第d个滤波器和输入数据进行有效卷积运算的结果,再加上第d个偏置
对于卷积神经网络的一些超参数,常见的设置是F=3,S=1,P=1,同时这些超参数也有一些约定俗成的惯例和经验,在之后的章节会介绍。
池化层
上一部分介绍完卷积神经网络中最核心的内容——卷积层,下面来介绍一下第二种层结构——池化层。
通常会在卷积层之间周期性插入一个池化层,其作用是逐渐降低数据体的空间尺寸,这样就能够减少网络中参数的数量,减少计算资源耗费,同时也能够有效地控制过拟合。
下面先来介绍到底什么是池化层。池化层和卷积层一样也有一个空间窗口,通常采用的是取这些窗口中的最大值作为输出结果,然后不断滑动窗口,对输入数据体每个深度切片单独处理,减少它的空间尺寸,如图4.8所示。
从图4.8能够看出池化层能够有效降低数据体空间的大小,图4.9形象地说明了窗口大小是2,滑动步长是2的最大值池化是如何计算的:每次都从2x2的窗口中选择最大的数值,同时每次滑动2个步长进入新的窗口。
池化层之所以有效,是因为之前介绍的图片特征具有不变性,也就是通过下采样不会丢失图片拥有的特征,由于这种特性,我们可以将图片缩小再进行卷积处理,这样能够大大降低卷积运算的时间。
最常用的池化层形式是尺寸为2x2的窗口,滑动步长为2,对图像进行下采样将其中75%的激活信息都丢掉,选择其中最大的保留下来,这其实是因为我们希望能够更加激活里面的数值大的特征,去除一些噪声信息。
池化层有一些和卷积层类似的性质。
- 输入数据体的尺寸是
- 有两个需要设置的超参数,空间大小F和滑动步长S
- 输出数据体的尺寸是,其中,,
- 对输入进行固定函数的计算,没有参数引入
- 池化层中很少引入零填充
在实际中,有两种方式:一种是F=3,S=2,这种池化有重叠;另外更常用的一种是F=2,S=2,一般来说应该谨慎使用比较大的池化窗口,以免对网络有破坏性。
除了最大值池化之外,还有一些其他的池化函数,比如平均池化,或者L2范数池化。在实际中证明,在卷积层之间引入最大池化的效果是最好的,而平均池化一般放在卷积神经网络的最后一层。
全连接层
全连接层和之前介绍的一般的神经网络的结构是一样的,每个神经元与前一层所有的神经元全部连接,而卷积神经网络只和输入数据中的一个局部区域连接,并且输出的神经元每个深度切片共享参数。
一般经过了一系列的卷积层和池化层之后,提取出图片的特征图,比如说特征图的大小是3x3x512,这个时候,将特征图中的所有神经元变成全连接层的样子,直观上也就是将一个3D的立方体重新排列,变成一个全连接层,里面有3x3x512=4608个神经元,再经过几个隐藏层,最后输出结果。
在这个过程中为了防止过拟合会引入Dropout。最近的研究表明,在进入全连接层之前,使用全局平均池化能够有效地降低过拟合。
卷积神经网络的基本形式
卷积神经网络中通常是由上面介绍的三种层结构所构成,上一章还介绍过引入激活函数增加模型的非线性,所以卷积神经网络最常见的形式就是将一些卷积层和ReLU层放在一起,有可能在ReLU层前面加上批标准化层,随后紧跟着池化层,再不断重复,直到图像在空间上被缩小到一个足够小的尺寸,然后将特征图展开,连接几层全连接层,最后输出结果,比如分类评分等。
图4.10就是一种卷积神经网络的基本形式。
1. 小滤波器的有效性
一般而言,几个小滤波器卷积层的组合比一个大滤波器卷积层要好,比如层层堆叠了3个3x3的卷积层,中间含有非线性激活层,在这种排列下面,第一个卷积层中每个神经元对输入数据的感受野是3x3,第二层卷积层对第一层卷积层的感受野也是3x3,这样对于输入数据的感受野就是5x5,同样,第三层卷积层上对第二层卷积层的感受野是3x3,这样第三层卷积层对于第一层输入数据的感受野就是7x7。
假设这里不使用3个3x3的感受野,直接单独使用一个7x7大小的卷积层,那么所有神经元的感受野也是7x7,但是这样会有一些缺点。多个卷积层首先与非线性激活层交替的结构,比单一卷积层的结构更能提取出深层的特征;其次,假设输入数据体的深度是C,输出体的深度也是C,那么单独的7x7的卷积层会有的参数个数,而使用3个3x3的卷积层的组合,仅仅含有的参数。直观来说,选择小滤波器的卷积组合能够对输入数据表达出更有力的特征,同时使用参数也更少。唯一的不足是反向传播更新参数的时候,中间的卷积层可能会占用更多的内存。
2. 网络的尺寸
对于卷积神经网络的尺寸设计,没有严格的数学证明,这是根据经验制定出来的规则。
- 输入层:一般而言,输入层的大小应该能够被2整除很多次,常用的数字包括32,64,96 和 224。
- 卷积层:卷积层应该尽可能使用小尺寸的滤波器,比如3x3或者5x5,滑动步长取1。还有一点就是需要对输入数据体进行零填充,这样可以有效地保证卷积层不会改变输入数据体的空间尺寸。如果必须要使用更大的滤波器尺寸,比如7x7,通常用在第一个面对原始图像的卷积层上。
- 池化层:池化层负责对输入的数据空间维度进行下采样,常用的设置使用2x2的感受野做最大值池化,滑动步长取2。另外一个不常用的设置是使用3x3的感受野步长设置为2。一般而言池化层的感受野大小很少超过3,因为这样会使得池化过程过于激烈,造成信息的丢失,这通常会造成算法的性能变差。
- 零填充:零填充的使用可以让卷积层的输入和输出在空间上的维度保持一致除此之外,如果不使用零填充,那么数据体的尺寸就会略微减少,在不断进行卷积的过程中,图像的边缘信息会过快地损失掉。
上面介绍了卷积神经网络中最重要的三种层结构:卷积层、池化层和全连接层,下面会介绍每一种层结构在PyTorch中是如何实现的。