本文是笔者对卷积神经网络的一个学习,主要参考了网上的一些资料与李宏毅老师的视频。本文仅代表了笔者对于CNN的浅薄认识,如有错误,欢迎指出,共同进步。
CNN是一款非常经典的神经网络,现存有一些比较著名的CNN如LeNet-5,AlexNet,VGG16等。这些网络虽然结构不同,但都包含了基本的模块,如卷积层(Convolution),池化层(Pooling)与全连接层(Fully Connection)等。本文将从为什么使用CNN,CNN常用的模块以及几种经典的CNN模型进行进行讲解。
CNN常常用在计算机视觉领域(Computer Version),常常用来处理数字图片。而数字图片在计算机中大多都是以矩阵的形式来保存,如灰度图像的二维矩阵与RGB图像的三维矩阵(数字图像以矩阵的形式保存会更方便计算机计算与存储),并且矩阵中某个具体的点为图像的像素点(Pixel)。数字图像上的图案常常有三个特点:
CNN能够在CV领域性能突出,离不开上述三个特点。当然这也与CNN的结构组成脱不了关系(结构决定功能)。
CNN里面最重要的模块就是卷积层了。卷积层一般用来提取图像中的某些特征,例如梯度或边界。而卷积层中最重要的模块就是卷积核了(Kernel\Filter),卷积运算的通用公式如下:
G [ m , n ] = ( f ∗ k ) [ m , n ] = ∑ i ∑ j k [ i , j ] f [ m − i , n − j ] (1) G[m, n] = (f * k)[m, n] = \sum_i{\sum_j{k[i, j]f[m-i, n-j]}} \tag{1} G[m,n]=(f∗k)[m,n]=i∑j∑k[i,j]f[m−i,n−j](1)其中 f f f表示输入图片, k k k表示该卷积核, G G G表示输出矩阵,也被叫做feature map, i , j {i, j} i,j表示卷积核的索引, m , n {m, n} m,n表示输出矩阵索引。通俗来讲,卷积运算就是卷积核在图像上滑动的过程中执行矩阵点乘运算并求和。
常见的卷积操作主要包含以下几个超参数:
针对不同的情况,可能需要不同的卷积运算。常用的卷积运算有5种类型,分别为一般卷积,扩张卷积,转置卷积,可分离卷积与空间卷积。
一般卷积就是普通卷积也是最常用的卷积。(下图为卷积核大小 3 × 3 {3 \times 3} 3×3,步长 s t r i d e = 2 {stride = 2} stride=2和填充 p = 1 {p = 1} p=1的2D卷积)
扩张卷积(Dialted Convolution)也被称为空洞卷积或者膨胀卷积,是在标准的卷积核中加入空洞,以此来增加模型的感受野。所以与一般卷积相比,还需要多设置一个扩展率(dialtion rate)的参数,扩张率是指卷积核之间值的间隔。比如下图为扩张率等于2的 3 × 3 {3 \times 3} 3×3卷积核的卷积操作。
扩张卷积的主要作用是在不丢失分辨率的情况下扩大模型的感受野,这对于提取占据面积较大的特征有比较好的效果,但是对于一些很小的物体,则不太友好。
转置卷积也被称为分数步长卷积(Fractionally-strided convolution)和反卷积(Deconvolution),其主要用于实现上采样(up-sampling)的功能。与基于插值的方法不同,转置卷积的参数是可以学习获得的。
转置卷积并不是简单地把卷积核进行转置或者将输入矩阵进行转置,转置卷积实际上是卷积的逆向操作。
让我们从矩阵运算的角度来观察卷积运算。假设输入图像的大小为 4 × 4 {4 \times 4} 4×4的矩阵,如:
在卷积运算中,可以把卷积操作写作一个矩阵。如下图中卷积核大小为 3 × 3 {3 \times 3} 3×3的卷积核。
若其卷积步长为1,将卷积核进行重新排序,得到一个 4 × 16 {4 \times 16} 4×16的“卷积矩阵”:
为什么是 4 × 16 {4 \times 16} 4×16呢,4其实就是输出矩阵的元素数量,16是输入矩阵的元素数量。所以还需要将输入矩阵转化为 16 × 1 {16 \times 1} 16×1的列向量:
这样就可以用矩阵乘法实现卷积运算了:
用公式可以写成:
M × I = O (2) M \times I = O \tag {2} M×I=O(2)其中 M M M表示卷积矩阵, I I I表示输入向量, O O O表示输出向量。所以通过输入卷积矩阵与输出向量可以求得输入向量为:
I ‘ = O × M T (3) I^{‘} = O \times M^T \tag{3} I‘=O×MT(3)这里的输出 I ′ {I^{'}} I′并不等于输入 I {I} I,因为从信息论的角度看,卷积并不是可逆的,所以转置卷积也并不是通过输出矩阵与卷积核计算出原始的输入矩阵,而是计算出一个与输入形状相同的矩阵。所以转置卷积主要是用来实现上采样的功能。
可分离卷积主要分为空间可分离卷积和深度可分离卷积两种。
空间可分离卷积其实就是把卷积核分解成一个列向量与一个行向量的乘积。以Sobel内核为例:
那么x filter可以写成:
[ − 1 0 1 − 2 0 2 − 1 0 1 ] = [ 1 2 1 ] × [ − 1 0 1 ] \begin{bmatrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \end{bmatrix} = \begin{bmatrix} 1 \\ 2 \\ 1 \end{bmatrix} \times \begin{bmatrix} -1 & 0 & 1 \end{bmatrix} ⎣⎡−1−2−1000121⎦⎤=⎣⎡121⎦⎤×[−101]y filter可以写成:
[ 1 2 1 0 0 0 − 1 − 2 − 1 ] = [ 1 0 − 1 ] × [ 1 2 1 ] \begin{bmatrix} 1 & 2 & 1 \\ 0 & 0 & 0 \\ -1 & -2 & -1 \end{bmatrix} = \begin{bmatrix} 1 \\ 0 \\ -1 \end{bmatrix} \times \begin{bmatrix} 1 & 2 & 1 \end{bmatrix} ⎣⎡10−120−210−1⎦⎤=⎣⎡10−1⎦⎤×[121]这种方式可以把卷积核中的9个参数用6个参数来表示,这有利于提升训练效率。当然并非所有的卷积核都可以分解成为两个向量的乘积,所以使用空间卷积训练实际上是缩减了模型的参数空间。
深度可分离卷积与后面讲到的空间卷积相似,只不过深度可分离卷积把卷积分成了两步进行。现以输入图像为 12 × 12 × 3 {12 \times 12 \times 3} 12×12×3的RGB图像为例。
空间卷积是十分重要的一个卷积方式,因为它常常用于处理多通道的彩色图片。空间卷积实际上就是把多通道的彩色图片看作是一个整体,把卷积核也看作是一个立体的矩阵,然后进行卷积运算。假设输入为 6 × 6 × 3 {6 \times 6 \times 3} 6×6×3的图片,卷积核的大小为 3 × 3 × 3 {3 \times 3 \times 3} 3×3×3,其中最后的一个3表示卷积核的输入通道数,卷积核的输入通道数必须与通过它的图像的通道数相等。
想了好久,才决定把卷积层的反向传播也写下来,毕竟这部分对于手撕CNN是必不可少的一部分。完成正向传播还没算完成算法的一半,而反向传播才是算法的开始。所谓反向传播,是指从输出端的损失函数往输入端方向按照链式求导法则来求得损失函数对于各层的导数。假设卷积层 i i i的输入为 A i {A^i} Ai,输出为 A i + 1 {A^{i + 1}} Ai+1,该层使用的卷积核为 K i {K^i} Ki,即有:
A i ∗ K i = A i + 1 (4) A^i * K^i = A^{i + 1} \tag{4} Ai∗Ki=Ai+1(4)
那么若已知损失函数对于 A i + 1 {A^{i + 1}} Ai+1的导数为 d A i + 1 {dA^{i + 1}} dAi+1,那么损失函数对于 A i {A^i} Ai的导数为:
d A i = d A i + 1 ∗ R ( K i ) (5) dA^i = dA^{i + 1} * R(K^i) \tag{5} dAi=dAi+1∗R(Ki)(5)
这里要注意的是,需要先判断 d A i + 1 {dA^{i + 1}} dAi+1是否需要填充。另外 R ( K i ) R(K^i) R(Ki)表示对 K i {K^i} Ki求反,即:
R ( [ k 11 k 12 k 21 k 22 ] ) = [ k 22 k 21 k 12 k 11 ] (6) R (\begin{bmatrix} k_{11} & k_{12} \\ k_{21} & k_{22} \end{bmatrix}) = \begin{bmatrix} k_{22} & k_{21} \\ k_{12} & k_{11} \end{bmatrix} \tag{6} R([k11k21k12k22])=[k22k12k21k11](6)反向传播的动图如下:
前面所说的是卷积层从输出到输入的反向求导,而从输出到卷积核的方向求导如下:
d K [ a , b ] i = s u m ( d A i + 1 . ∗ ( A [ a : a + w ] [ b : b + w ] i ) ) (7) dK^i_{[a, b]} = sum(dA^{i + 1} .* (A^{i}_{[a: a + w][b: b + w]})) \tag{7} dK[a,b]i=sum(dAi+1.∗(A[a:a+w][b:b+w]i))(7)这里 a , b {a, b} a,b表示 K i K^i Ki的元素下标, w w w表示 K i K^i Ki的大小, . ∗ {.*} .∗表示点乘符号。
除了卷积层,CNN还会用到池化层。池化层主要作用是减少张量,和加速计算。池化层的操作比较简单,就是把输入划分不同的区域,然后对每个区域执行一些操作。池化层主要有两种,一种是最大池化,就是对每个区域选择最大值;另一种是平均池化,就是对每个区域选择平均值。下图为最大池化层的前向实现:
最大池化的反向传播需要记录前向实现时每个最大值的位置,然后再把输出的导数赋予该位置,如:
最大池化与平均池化的差异在于,最大池化能够保留输入的纹理特征,而平均池化则保留整体的数据特征。不仅如此,最大池化还被认为有Dropout的作用。
全连接层中,该层的每个神经元都与上一层的输入相连,如:
全连接层再加上激活函数就可以构成一个神经网络,如BP神经网络,但是一般不会使用全连接神经网络处理图像,主要是因为全连接神经网络对于局部信息的处理太差了。
全连接层的误差反向传播比较简单,现假设第 i i i层的输入为 A i {A^i} Ai,输出为 A i + 1 {A^{i + 1}} Ai+1,权重矩阵为 W i W^i Wi,那么前向传递可以写成:
W i × A i = A i + 1 (8) W^i \times A^i = A^{i + 1} \tag{8} Wi×Ai=Ai+1(8)若已知损失函数对于 A i + 1 {A^{i + 1}} Ai+1的导数为 d A i + 1 {dA^{i + 1}} dAi+1,那么损失函数对于 A i {A^i} Ai的导数为:
d A a i = ∑ b ( W b a i ⋅ d A b i + 1 ) (9) dA^i_a = \sum_b{(W_{ba}^i \cdot dA_b^{i+1})} \tag{9} dAai=b∑(Wbai⋅dAbi+1)(9)上式中 a {a} a表示 A i {A^i} Ai元素的下标, b {b} b表示 A i + 1 {A^{i + 1}} Ai+1元素的下标。那么损失函数对于权重矩阵 W i W^i Wi的导数为:
d W i = d A b i + 1 × ( A i ) T (10) dW^i = dA_b^{i + 1} \times (A^i)^T \tag{10} dWi=dAbi+1×(Ai)T(10)以上公式是未考虑激活函数的,若需要考虑激活函数,那么仅需要计算激活函数处的导数,再与该层的导数进行点乘即可。
通过下图可以明显看出全连接层与卷积层之间的差别:
由此可以看出卷积层的输入与输出之间并不是全部连接在一起的,这表明每个输出元素都有自己的局部感受野,卷积层的这种特点也被称为稀疏连接(Sparse Connection);另外,在一次卷积运算的时候,卷积核都是相等的,这意味着卷积层能够捕获图像中所有具备相同特征的信息,这种特点被称为权重共享(Weight Sharing)。
而全连接层中相邻两层的神经元之间都有连接,并且每个连接的权重都不一样,这就意味着全连接层采集到的信息糅合度太高,难以有效析有效的局部信息。
如果把卷积层当作前锋,专门负责进攻,那么全连接层就像是六边形战士,实现无差别攻击。
但这样并不代表卷积层一定就比全连接层好,由上述分析可以看出,卷积层出色在于处理局部信息,并且并不适用于实现分类的功能;而全连接层则能顾全大局,擅长处理整体信息,并且也常常在分类器中使用。正是因为卷积层与全连接层的这种差异,二者常常结合在一起使用。常常使用卷积层来提取局部特征信息,然后把局部信息整合后再经过全连接层进行全局处理。这样的方式实现了局部与整体的分工协同,提高了模型的性能。
经过卷积层的输出一般还需要通过激活函数,并且一般使用ReLu作为激活函数,因为图像处理过程中的值一般不会存在负值,并且ReLu的导数只有0与1,这在一定程度上能够避免梯度消失或梯度爆炸等问题。下图为ReLu的函数图形。
为了把卷积层,池化层或激活函数层等与全连接层连接,还需要对数据进行空间变换。而Flatten Layer就是实现把高维数据转为1维向量的形式:
本文的主要讲述了CNN的组成结构,包括卷积层,池化层和全连接层等的工作原理。如有错误,欢迎指出。
Y. Lecun, L. Bottou, Y. Bengio and P. Haffner, “Gradient-based learning applied to document recognition,” in Proceedings of the IEEE, vol. 86, no. 11, pp. 2278-2324, Nov. 1998, doi: 10.1109/5.726791.
Krizhevsky, A. , I. Sutskever , and G. Hinton . “ImageNet Classification with Deep Convolutional Neural Networks.” Advances in neural information processing systems 25.2(2012).
Simonyan K , Zisserman A . Very Deep Convolutional Networks for Large-Scale Image Recognition[J]. Computer Science, 2014.
He K , Zhang X , Ren S , et al. Deep Residual Learning for Image Recognition[J]. 2016 IEEE Conference on Computer Vision and Pattern Recognition (CVPR), 2016.
Szegedy C , Liu W , Jia Y , et al. Going Deeper with Convolutions[J]. IEEE Computer Society, 2014.
轻松理解转置卷积(transposed convolution)或反卷积(deconvolution)
A guide to convolution arithmetic for deep learning
卷积神经网络(CNN)的理解与可视化
CNN中常用的四种卷积详解
卷积神经网络数学原理解析
卷积神经网络(CNN)的理解与可视化
CNN中常用的四种卷积详解
卷积神经网络数学原理解析
本文图片来自于网络,转载请注明出处