卷积网络(convolutional network)(LeCun, 1989),也叫做 卷积神经网络(convolutional neural network, CNN),是一种专门用来处理具有类似网格结构的数据的神经网络。例如时间序列数据(可以认为是在时间轴上有规律地采样形成的一维网格)和图像数据(可以看作是二维的像素网格)。卷积网络在诸多应用领域都表现优异。“卷积神经网络’’ 一词表明该网络使用了 卷积(convolution)这种数学运算。卷积是一种特殊的线性运算。卷积网络是指那些至少在网络的一层中使用卷积运算来替代一般的矩阵乘法运算的神经网络。
卷积网络为什么会出现?得先看看更早时期提出的 全连接网络(Fully Connected Neural Network,FC)在处理类似图片数据时会出现的问题:
针对上述问题,图像的主要特点:
CNN 正是针对图像的特点来解决 FC 的缺点的。卷积神经网络通常由一个或多个卷积层和顶端的全连通层(对应经典的神经网络)组成,同时也包括 关联权重 和 池化层(Pooling Layer)等。下图就是一个卷积神经网络架构。
与其他深度学习结构相比,卷积神经网络在图像和语音识别方面能够给出更好的结果。这一模型也可以使用反向传播算法进行训练。相比其他深度、前馈神经网络,卷积神经网络可以用更少的参数,却获得更高的性能。卷积神经网络的一般结构包括卷积神经网络的常用层, 如卷积层、池化层、全连接层和输出层;有些还包括其他层,如正则化层、 高级层等。
针对FC神经网络处理图片数据的两个缺点,CNN提出的解决方案是 权值共享 和 卷积操作。首先要先理解一个概念:感受野,感受野表示当前特征图的 每个像素 表示 原始图像 的哪部分,看图说话:
输入图像 X \boldsymbol{X} X,维度为 5 × 5 \boldsymbol{5×5} 5×5,Layer2 的输出特征维度是 3 × 3 \boldsymbol{3×3} 3×3,则其中的任一像素表征着 X \boldsymbol{X} X 的 9 个像素即 Layer1 中的绿色部分,则 Layer2 的感受野为 3,Layer3 的输出特征维度是 1 × 1 \boldsymbol{1×1} 1×1,只有一个像素,表征着 Layer2 整张特征图,对应到 X \boldsymbol{X} X 也是表征 X \boldsymbol{X} X 的整幅特征图,因此 Layer3 的感受野是 5。总结成一个规律就是,特征图越小,其感受野越大。
由我们上面介绍的感受野的概念,网络层的每个输出节点(输出像素)仅与感受野区域内 k × k \boldsymbol{k × k} k×k 个输入节点相连接,假如输出节点数为 J \boldsymbol{J} J,则当前层的参数量为 k × k × J \boldsymbol{k × k×J} k×k×J,相对于全连接层的 I × J \boldsymbol{I×J} I×J, k \boldsymbol{k} k 一般取值较小,如 1、 3、5 等, k × k \boldsymbol{k×k} k×k 远小于 I \boldsymbol{I} I,因此成功地将参数量减少了很多。注: 上述假设以及在后面的示例中只有一层卷积层,这是为了用感受野容易表示卷积图像位置,如果是多层卷积,则不能随便使用感受野这个名词。
通过权值共享的思想,对于每个输出节点 o j \boldsymbol{o_j} oj,均使用相同的权值矩阵 W \boldsymbol{W} W,那么无论输出节点的数量 J \boldsymbol{J} J 是多少,网络层的参数量总是 k × k \boldsymbol{k × k} k×k。如下图所示,在计算左上角位置的输出像素时,使用权值矩阵 W \boldsymbol{W} W:
[ w 00 w 01 w 02 w 10 w 11 w 12 w 020 w 21 w 22 ] \begin{bmatrix} w_{00} & w_{01} & w_{02} \\ w_{10} & w_{11} & w_{12}\\ w_{020} & w_{21} & w_{22} \end{bmatrix} ⎣⎡w00w10w020w01w11w21w02w12w22⎦⎤
与对应感受野内部的像素相乘累加,作为左上角像素的输出值;在计算右下方感受野区域时,共享权值参数 W \boldsymbol{W} W,即使用相同的权值参数 W \boldsymbol{W} W相乘累加,得到右下角像素的输出值,此时网络层的参数量只有 3 × 3 = 9 \boldsymbol{3 × 3 = 9} 3×3=9 个,且与输入、输出节点数无关。
通过运用局部相关性和权值共享的思想,我们成功把全连接网络的参数量从 I × J \boldsymbol{I×J} I×J 减少到 × \boldsymbol{ × } k×k (准确地说,是在单输入通道、单卷积核的条件下)。这种共享权值的“局部连接层”网络其实就是卷积神经网络。
卷积层是卷积神经网络的核心层,而卷积(Convolution)又是卷积层的核心。对卷积直观的理解,就是两个函数的一种运算,这种运算就称为卷积运算。下图就是一个简单的二维空间卷积运算示例,虽然简单,但却包含了卷积的核心内容。
上图中,输入和卷积核都是张量,卷积运算就是用卷积分别乘以输入张量中的每个元素,然后输出一个代表每个输入信息的张量。其中卷积核 (kernel)又称权重过滤器,简称为过滤器(filter)。我们可以将输入、卷积 核推广到更高维空间上,输入由 2 × 2 \boldsymbol{2×2} 2×2 矩阵,拓展为 5 × 5 \boldsymbol{5×5} 5×5 矩阵,卷积核由一个标量拓展为一个 3 × 3 \boldsymbol{3×3} 3×3 矩阵,卷积结果如下:
用卷积核中每个元素,乘以对应输入矩阵中的对应元素,这点还是一 样,但输入张量为 5 × 5 \boldsymbol{5×5} 5×5 矩阵,而卷积核为 3 × 3 \boldsymbol{3×3} 3×3 矩阵,所以这里首先就要解决 一个如何对应的问题,这个问题解决了,这个推广也就完成了。把卷积核作为在输入矩阵上的一个移动窗口,对应关系就迎刃而解了。了解上述的卷积方式之后,下面开始介绍的卷积是单通道输入、单卷积核的情况,然后推广至多通道输入、单卷积核,最后讨论最常用,也是最复杂的多通道输入、多个卷积核的卷积层实现。动图如下:
从数学上来讲,深度学习里面所谓的卷积运算,其实它被称为 互相关(cross-correlation)运算:将图像矩阵中,从左到右,由上到下,取与滤波器同等大小的一部分,每一部分中的值与滤波器中的值对应相乘后求和,最后的结果组成一个矩阵,其中没有对核进行翻转。
首先讨论单通道输入 C i n = 1 \boldsymbol{C_{in} = 1} Cin=1,如灰度图片只有灰度值一个通道,单个卷积核 C o u t = 1 \boldsymbol{C_{out} = 1} Cout=1 的情况(卷积核的个数决定卷积层的输出通道数)。以输入 X \boldsymbol{X} X 为 5 × 5 \boldsymbol{5×5} 5×5 的矩阵,卷积核为 3 × 3 \boldsymbol{3×3} 3×3 的矩阵为例,如下图:
计算过程如下:与卷积核同大小的感受野(输入 X \boldsymbol{X} X 上方的绿色方框)首先移动至输入 X \boldsymbol{X} X 最左上方,选中输入 X \boldsymbol{X} X 上 3 × 3 \boldsymbol{3×3} 3×3 的感受野元素,与卷积核(图片中间 3 × 3 \boldsymbol{3×3} 3×3 方框)对应元素相乘:
[ 1 − 1 0 − 1 − 2 2 1 2 − 2 ] ⨀ [ − 1 1 2 1 − 1 3 0 − 1 − 2 ] = [ − 1 − 1 0 − 1 2 6 0 − 2 4 ] \begin{bmatrix} 1 & -1 & 0\\ -1 & -2 & 2\\ 1 & 2 & -2 \\ \end{bmatrix}⨀ \begin{bmatrix} -1 & 1 & 2\\ 1 & -1 & 3\\ 0 & -1 & -2 \\ \end{bmatrix}= \begin{bmatrix} -1 & -1 & 0\\ -1 & 2 & 6\\ 0 & -2 & 4 \\ \end{bmatrix} ⎣⎡1−11−1−2202−2⎦⎤⨀⎣⎡−1101−1−123−2⎦⎤=⎣⎡−1−10−12−2064⎦⎤
⨀ 符号表示哈达马积(Hadamard Product),即矩阵的对应元素相乘。运算后得到 3 × 3 \boldsymbol{3×3} 3×3 的矩阵,这 9 个数值全部相加:
− 1 − 1 + 0 − 1 + 2 + 6 + 0 − 2 + 4 = 7 − 1−1 + 0−1 + 2 +6 + 0− 2 + 4=7 −1−1+0−1+2+6+0−2+4=7
得到标量 7,写入输出矩阵第一行、第一列的位置。完成第一个感受野区域的特征提取后,感受野窗口向右移动一个步长单位(Strides,记 为,默认为 1),选中下图中绿色方框中的 9 个感受野元素,按照同样的计算方法,与卷积核对应元素相乘累加,得到输出 10,写入第一行、第二列位置。
感受野窗口再次向右移动一个步长单位,选中下图中绿色方框中的元素,并与卷积核相乘累加,得到输出 3,并写入输出的第一行、第三列位置。
此时感受野已经移动至输入 X \boldsymbol{X} X 的有效像素的最右边,无法向右边继续移动(在不填充无效元素的情况下),因此感受野窗口向下移动一个步长单位( = 1),并回到当前行的行首位置,继续选中新的感受野元素区域,与卷积核运算得到输出-1。此时的感受野由于经过向下移动一个步长单位,因此输出值 -1 写入第二行、第一列位置。
最终输出我们得到一个 3 × 3 \boldsymbol{3×3} 3×3 的矩阵,比输入 5 × 5 \boldsymbol{5×5} 5×5 略小,这是因为感受野不能超出元素边界的缘故,由此我们也能知道,在没有扩展输入图像的情况下卷积,输出图像的维度一定会变小,我们将这种卷积方式称作 Vaild卷积。可以观察到,卷积运算的输出矩阵大小由卷积核的大小 k \boldsymbol{k} k ,输入 X \boldsymbol{X} X 的高宽,移动步长 s \boldsymbol{s} s,是否填充等因素共同决定。
多通道输入的卷积层更为常见,比如彩色的图片包含了 R/G/B 三个通道,每个通道上
面的像素值表示 R/G/B 色彩的强度。下面我们以 3 通道输入、单个卷积核为例,将单通道输入的卷积运算方法推广到多通道的情况。在多通道输入的情况下,卷积核的通道数需要和输入 X \boldsymbol{X} X 的通道数量相匹配,卷积核的第个通道和 X \boldsymbol{X} X 的第 i \boldsymbol{i} i 个通道运算,得到第 i \boldsymbol{i} i 个中间矩阵,此时可以视为单通道输入与单卷积核的情况,所有通道的中间矩阵对应元素再次相加,作为最终输出。
上图中:每行的最左边 5 × 5 \boldsymbol{5×5} 5×5 的矩阵表示输入 X \boldsymbol{X} X 的 1~3 通道,第 2 列的 3 × 3 \boldsymbol{3×3} 3×3 矩阵分别表示卷积核的 1~3 通道,第 3 列的矩阵表示当前通道上运算结果的中间矩阵,最右边一个矩阵表示卷积层运算的最终输出。在初始状态,每个通道上面的感受野窗口同步落在对应通道上面的最左边、最上方位置,每个通道上感受野区域元素与卷积核对应通道上面的矩阵相乘累加,分别得到三个通道上面的输出 7、-11、-1 的中间变量,这些中间
变量相加得到输出-5,写入对应位置。
随后,感受野窗口同步在 X \boldsymbol{X} X 的每个通道上向右移动 s = 1 \boldsymbol{s = 1} s=1 个步长单位,此时感受野区域元素如下图所示,每个通道上面的感受野与卷积核对应通道上面的矩阵相乘累加,得到中间变量 10、20、20,全部相加得到输出 50,写入第一行、第二列元素位置。
以此方式同步移动感受野窗口,直至最右边、最下方位置,此时全部完成输入和卷积核的卷积运算,得到 3 × 3 \boldsymbol{3×3} 3×3 的输出矩阵。
输入的每个通道处的感受野均与卷积核的对应通道相乘累加,得到与通道数量相等的中间变量,这些中间变量全部相加即得到当前位置的输出值。输入通道的通道数量决定了卷积核的通道数。一个卷积核只能得到一个输出矩阵,无论输入 X \boldsymbol{X} X 的通道数量。
一般来说,一个卷积核只能完成某种逻辑的特征提取,当需要同时提取多种逻辑特征时,可以通过增加多个卷积核来得到多种特征,提高神经网络的表达能力,这就是多通道输入、多卷积核的情况。
多通道输入、多卷积核是卷积神经网络中最为常见的形式,前面已经介绍了单卷积核的运算过程,每个卷积核和输入 X \boldsymbol{X} X 做卷积运算,得到一个输出矩阵。当出现多卷积核时,第 i \boldsymbol{i} i ( ∈ \boldsymbol{ ∈ } i∈n,为卷积核个数)个卷积核与输入 X \boldsymbol{X} X 运算得到第个输出矩阵(也称为输出张量 O \boldsymbol{O} O 的通道 i \boldsymbol{i} i),最后全部的输出矩阵在通道维度上进行拼接(Stack 操作,创建输出通道数的新维度),产生输出张量 O \boldsymbol{O} O , O \boldsymbol{O} O 包含了 n \boldsymbol{n} n 个通道数。
以 3 通道输入、2 个卷积核的卷积层为例。第一个卷积核与输入 X \boldsymbol{X} X 运算得到输出 O \boldsymbol{O} O 的第一个通道,第二个卷积核与输入运算得到输出的第二个通道,输出的两个通道拼接在一起形成了最终输出 O \boldsymbol{O} O 。每个卷积核的大小 k \boldsymbol{k} k 、步长 s \boldsymbol{s} s 、填充设定等都是统一设置,这样才能保证输出的每个通道大小一致,从而满足拼接的条件。
在CNN中,通常我们会使用大小为奇数的卷积核,因为进行卷积操作时一般会以卷积核模块的一个位置为基准进行滑动,这个基准通常就是卷积核模块的中心。若卷积核为奇数,卷积锚点很好找,自然就是卷积模块中心,但如果卷积核是偶数,这时候就没有办法确定了,让谁是锚点似乎都不怎么好。
步长就是卷积核或过滤器在左边窗口中每次移动的格数 (无论是自左向右移动,或自上向下移动),对于 2D 输入来说,分为沿 x \boldsymbol{x} x (向右)方向和 y \boldsymbol{y} y (向下)方向的移动长度。下图中,绿色实线代表的卷积核的位置是当前位置,绿色虚线代表是上一次卷积核所在位置,从上一次位置移动到当前位置的移动长度即是步长的定义。下图中感受野沿 x \boldsymbol{x} x 方向的步长为 2,表达为步长 s = 2 \boldsymbol{s = 2} s=2。
当感受野移动至输入 X \boldsymbol{X} X 右边的边界时,感受野向下移动一个步长 s = 2 \boldsymbol{s = 2} s=2,并回到行首。如下图,感受野向下移动 2 个单位,并回到行首位置,进行相乘累加运算。
循环往复移动,直至达到最下方、最右边边缘位置。然后得到 2 × 2 \boldsymbol{2×2} 2×2 的矩阵。
可以看到,通过设定步长,可以有效地控制信息密度的提取。当步长设计的较小时,卷积核以较小幅度移动窗口,有利于提取到更多的特征信息,输出张量的尺寸也更大;当步长设计的较大时,卷积核以较大幅度移动窗口,有利于减少计算代价,过滤冗余信息,输出张量的尺寸也更小。
同时,在卷积核移动过程中,其值始终是不变的,都是卷积核的值。也可以说,卷积核的值在整个过程中都是共享的,所以又把卷积核的值称为共享变 量。卷积神经网络采用参数共享的方法大大降低了参数的数量。在下图中,卷积核如果继续往右移动2格,卷积核窗口部分将在输入矩 阵之外,这种情况该如何处理?具体处理方法就涉及下面的内容——填充(Padding)。
在前面我们提过,如果不对图片进行拓展的话,经过卷积运算后的输出 O \boldsymbol{O} O 的高宽会小于输入 X \boldsymbol{X} X 的高宽;且当卷积核的步长过大时,卷积核可能会超过图片边界。在实际的网络模型设计时,我们通常希望输出 O \boldsymbol{O} O 的高宽能够与输入 X \boldsymbol{X} X 的高宽相同,从而方便网络参数的设计、残差连接等。为了让输出 O \boldsymbol{O} O 的高宽能够与输入 X \boldsymbol{X} X 的相等,一般通过在原输入 X \boldsymbol{X} X 的高和宽维度上面进行填充(padding)若干无效元素操作,得到增大的输入 X ′ \boldsymbol{X'} X′ 。通过精心设计填充单元的数量,在 X ′ \boldsymbol{X'} X′ 上面进行卷积运算得到输出 O \boldsymbol{O} O 的高宽可以和原输入 X \boldsymbol{X} X 相等。这种输入与输出的特征图维度一样的卷积方式,我们称作 Same卷积,不填充称作 Vaild卷积。
如下图,在高/行方向的上(Top)、下(Bottom)方向,宽/列方向的左(Left)、 右(Right)均可以进行不定数量的填充操作,填充的数值一般默认为 0,也可以填充自定义的数据。上、下方向各填充 1 行,左、右方向各填充 2 列,得到新的输入 X ′ \boldsymbol{X'} X′。
那么添加填充后的卷积层运算同样,仅仅是把参与运算的输入从 X \boldsymbol{X} X 换成了填充后得到的新张量 X ′ \boldsymbol{X'} X′ 。如下图,感受野的初始位置在填充后的 X ′ \boldsymbol{X'} X′ 的左上方,完成相乘累加运算,得到输出 1,写入输出张量的对应位置。
循环往复,最终得到 5 × 5 \boldsymbol{5 × 5} 5×5 的输出张量。
经过上述对输入图像、卷积核、步长、填充、输出图像的分析,使用张量将它们表示如下:
如果已知 n 、 f 、 s \boldsymbol{n、f、s} n、f、s,则 p = f − 1 2 \boldsymbol{p = \frac{f - 1}{2}} p=2f−1, o = ⌊ n + 2 p − f s + 1 ⌋ \boldsymbol{o = \lfloor \frac{n + 2p - f}{s} + 1\rfloor} o=⌊sn+2p−f+1⌋。最后再来分析以下卷积核在 2.5 多通道输入和多卷积核 的末尾我分析过在实际中卷积核的大小 f \boldsymbol{f} f 常常使用奇数是为了找到一个好锚点。实际上选择奇数的卷积核也更容易(padding)。当我们使用 Same卷积 时,这时候我们就需要用到 padding。但是如果 f \boldsymbol{f} f 是偶数的话, p = f − 1 2 \boldsymbol{p = \frac{f - 1}{2}} p=2f−1就不是整数了。这意味着我们只需要在输入图像的一边或者两边进行填充。
(这里可选看)在 PyTorch 中,假设 Input 维度为 ( N , C i n , H i n , W i n ) \boldsymbol{(N,C_{in},H_{in}, W_{in})} (N,Cin,Hin,Win),Output 维度为 ( N , C o u t , H o u t , W o u t ) \boldsymbol{(N,C_{out},H_{out}, W_{out})} (N,Cout,Hout,Wout),两维度关系如下:
在本篇博客中,我跟大家分享了卷积神经网络中的基础结构——卷积层,并依次介绍了权值共享、卷积操作、卷积核,填充等内容。卷积神经网络的基础知识有很多,本篇博客介绍不完,剩下的我放到下一篇博客。期待您的访问!感恩!
下一篇:卷积神经网络之池化层、BN 层