关于CNN(卷积神经网络)的理解

关于CNN(卷积神经网络)的理解

对于从事计算机相关工作的人来说,机器学习、深度学习等词汇一定不会陌生而且。这也是属于AI(人工智能)这个大范畴的,现在的科技公司,不与AI沾点边好像都不好意思叫科技公司。之前有人说21世纪是生物的世纪,现在看来,21世纪早已被AI占领了。

AI的迅速火爆与CNN(卷积神经网络)的提出有很大关系。我最早在杂志上面看到一篇关于神经网络的科普文,当时还没有从事这方面的研究,认为可以用计算机模拟人的神经了,太牛逼了。现在看来还远远达不到生物的神经水平,而神经网络仅仅是参照生物神经激活的一种高维非线性表达方式。

与CNN有关的文章实在太多了,也有讲得很详细的,所以我不希望记录一些重复的工作。本文希望从一些方面来诠释CNN,并且包括一些比较新的研究成果以及自己的思考,作为自己学习的一个总结。如有错误或者疏漏,欢迎提出。在阅读这篇文章之前,希望你已经对深度学习以及CNN有一定的了解。当然本文涉及的内容也是相对简单的一些知识,可能会比较杂乱,都是我觉得值得记录的东西。

从CNN的组成出发

CNN虽然很早就提出来了,但是真正让CNN火起来的是其在图像分类上面取得的巨大成功,而这个成功自然离不开Hinton在2012年的[1],直接在ILSVRC-2012比赛中图像分类正确率超过了第二名26.2%,可谓效果相当惊人。[1]中给出的一种网络结构AlexNet也可谓非常经典。

来自[2]的AlexNet图片,较[1]原文中的图更加简洁。

从AlexNet中我们可以看出早期的CNN结构主要由卷积层(图中Conv)、激活层(图中并没有画出)、池化层(图中未画出)、全连接层(图中FC)以及Dropout层(图中未画出)组成。除了以上提到的几个层之外,本文也将讨论一个在2015年提出的非常重要的层——Batch Normalization层[3]

卷积层

卷积核的意义

毫无疑问卷积层是CNN中最重要的一个层。而卷积层实际的操作也就是卷积核在图像上的操作。卷积核我更喜欢称为滤波器(filter),因为filter更加能够体现卷积的性质。实际上filter做的事情更加像是一种匹配,这种匹配是二维空间上的。更加通用一点来说,卷积是一种二维空间上的模式匹配(pattern recognition),卷积核可以看作“模式”,也就是需要匹配的模板。如下图所示。

最右侧矩阵为filter的值,该filter是希望匹配一个弧形的图像。而最左侧图像的像素值矩阵(中间)与该filter的矩阵值分布类似,所以最后计算结果数值很大(即成功匹配了)。

这就类似于字符串匹配,如果我们只考虑最简单的遍历字符串的$O(n*m)$算法,那么将需要匹配的模板(模式,比如正则表达式)在输入串上面“游走”一边,看能不能匹配到。而卷积就是filter作为模式在输入上面“游走”一遍。不同的是,filter游走的结果不是匹配到一个特定的东西就结束, 而是对于每一个位置的匹配给出一个“打分”,这个“打分”暗示了该区域与filter的匹配程度,也影响到是否被激活。还有一点不同的是,字符串是一维的,所以匹配只需要逐字试就可以了。但是卷积的输入是二维的,所以我们要“游走”图片上所有可能的位置,也就有了卷积这种操作。其实卷积之后的各层跟之前层在空间上是对应的。

缩放/旋转不变性

从上面的解释可以看出,卷积核的这种匹配,这种空间上element-wise相乘来看是否相似的匹配是有局限性的。很容易想到的就是如果图片旋转90度,结果就会很不理想。由于filter并不会自动旋转,所以在空间上element-wise的匹配是死板的,这也使得卷积基本没有旋转不变性[4](Max pooling具有一定的旋转不变性,在后面会说)。例如上图中的例子,如果将图片的像素矩阵顺时针旋转90度之后与filter做element-wise的乘法,结果为3000,是原结果的一半不到。

针对这个问题,一种方法是Data augmentation,也就是在数据预处理的时候生成一些旋转之后的样本用于训练。这种方法实际上并没有弥补filter对于旋转之后图片感知力的不足,我认为CNN本身在这个问题上泛化能力是不足的。当然也有人从网络结构上解决这个事情,例如[5]提出的Spacial Transformer Networks,但是这类网路也只是在层间(对feature map)进行一个空间上的变换,无法克服卷积本质上对于仿射变换支持不足的弱点。

Spacial Transformer Networks

卷积核的大小

在目前主流网络中,如ResNet[6]、 DenseNet[7]以及MobileNet[8]都大量使用$3 \times 3$或者$1 \times 1$的卷积核。为什么会用这样大小的卷积核呢?

首先卷积核的边长应该是奇数的。奇数的边长使得卷积核能有一个中心像素,这个中心像素对应输入中的像素点来在原输入上滑动是非常方便的。对于padding来说,奇数边长的卷积核使得两边的padding是对称的。

为什么会使用$3 \times 3$的卷积核呢?根据卷积核在原输入上滑动的性质,如果我希望匹配一个猫的耳朵的形状,那么卷积核大小难道不应该跟猫耳的区域大小差不多吗?$3 \times 3$的像素能匹配到什么东西呢?首先我们要知道仅用$3 \times 3$的卷积核感受野(输出中一个像素对应输入的区域大小)只有$3 \times 3$,也就是输出一个像素所感知的区域在输入中只有很小的区域。但是神经网络是多层的,如果第$i+1$层对第$i$层的感受野为$3 \times 3$,那么在下一层继续使用一个$3 \times 3$的卷积核,则第$i+2$层对第$i$层的感受野是$5 \times 5$。这样多层下来是可以感知很宽广的区域的。但是为什么不直接用$5 \times 5$的卷积核呢?答案是节约参数。同样的感受野的情况下使用两个$3 \times 3$的卷积核(假如通道数为1,不考虑偏置)参数为$2 \times 3 \times 3=18$,而$5 \times 5$的卷积核参数为$5 \times 5=25$。很显然多个小卷积核参数个数小于一个大卷积核,这种情况在3个$3 \times 3$和1个$7 \times 7$下差距更加明显。

多个$3 \times 3$的卷积核与$5 \times 5$以及$7 \times 7$的感受野相同,图源自[9]

而$1 \times 1$的卷积核有什么作用呢?$1 \times 1$的卷积核可以进行通道间交互,将在下一节通道里讨论。

通道

卷积的通道(channel)到底有什么意思?这个在很多关于CNN的教程中都没有提到,只说了怎么计算下一层。首先,我们知道的是,每一层的卷积核的通道数对应输入的通道数,而卷积核的个数对应输出的通道数。例如我们用$K^i_j$来表示第$i$个卷积核的第$j$个通道,那么有多少个$i$就对应多少个输出通道,而有多少个$j$就对应多少个输入通道(输入图片的通道数)。对于第$i$个卷积核,$K^i_j$中不同的$j$在输入对应的通道上做卷积,然后求和。如果把不同的$j$对应的卷积核看作不同的权重,那么$K^i$在输入上做的就是对不同的通道的卷积的加权求和。加权求和是不是很熟悉?其实这跟全连接层做的事情是一样的。也就是说卷积核关于通道的操作就是对不同的通道进行全连接,进行加权求和,如下图。

卷积与全连接的类比

这样我们也就不难理解$1 \times 1$卷积核的作用了。就是用来做通道间的交互的。其实,就是通道之间的加权求和,跟全连接层作用一样。在[8]中提出的MobileNets中,为了节省参数(从名字就可以看出是为了移动设备,要减少计算量),直接提出了只在通道内部做卷积$3 \times 3$的卷积,然后用$1 \times 1$的卷积做通道之间的交互。什么意思呢,就是对于输入,一个通道对应一个卷积核,卷积核只作用于这一个通道,输出的也只是一个通道的二维矩阵,这个过程中只在每个通道自己内部做卷积,而没有通道间的交互,这个过程被称为depthwise convolution。而为了通道间的交互,再使用$1 \times 1$的卷积来做通道间的全连接,这个过程称为pointwise convolution。将普通的卷积层分为depthwise convolution和pointwise convolution两层,可以大大减少参数的数目。

除此之外,通道还可以看作特征。对于原始的输入图像,一般是RGB三个颜色通道,而不同的颜色就是它的特征。延续刚刚与全连接层的类比,卷积层通过特征(通道)间的全连接(加权求和)来提取更高维、更抽象的特征。例如在很多问题中,都使用最后一个全连接层之前的输出作为特征向量使用。而这个特征向量的每一个元素就对应一个通道,就是各通道内部的二维矩阵通过池化压缩为一个元素而已。所以通道和特征是对应的。

激活层

非线性

激活层其实大家应该已经很熟悉ReLU、Sigmoid以及tanh等激活函数。这些激活函数形式很也很简单。激活层顾名思义是用来激活的,由于神经网络本身的线性性,我们使用激活层来表达高维非线性函数。假设没有激活层的话,那么神经网络的层可以线性表示为$f_i(\vec{x}) = W^i\vec{x}+\vec{b^i}$,其中$i$表示第$i$层。那么最终结果也可以线性表示:
$$f(\vec{x}) = f_N(f_{N-1}(…f_1(\vec{x}))) \\
= W^N(W^{N-1}(…W^1(\vec{x})+\vec{b}^1)+\vec{b}^{N-1})+\vec{b}^N \\
= W^NW^{N-1}…W^1\vec{x} + W^NW^{N-1}…W^2\vec{b}^1 + … + W^N\vec{b}^{N-1}+\vec{b}^N$$

而如果有一个非线性函数加在每个卷积层之后就不一样了,整个函数都会是非线性的。正是激活层向神经网络加入了非线性性质,才使得神经网络能够拟合复杂的多维非线性函数。但是CNN仍然具有一些线性性,这导致对于某些对抗样本无法正确的分类。如[10]所说的,即使是一个很小的噪声加在图片上,人根本看不出区别来,但是CNN会犯很严重的错误。如Goodfellow说的,这不是因为过拟合,而是很小的噪声一层一层的线性累积造成的,所以CNN还是有线性缺点。

梯度消失

梯度消失问题在batch normalization[3]提出之后就基本上已经解决这个问题了,在现在的网络结构中,基本都能够很好的训练。但是在之前,人们可是被这个问题困扰了很久,这个问题也是反向传播算法的一个短板。在反向传播的过程中,传播回某一层梯度的时候,由于链式法则,我们需要乘上激活函数的导数。如$f(\vec{x})=g(W^\vec{x} + \vec{b})$,其中$g$为激活函数。则该层反向传播时对输入的梯度为$\frac{\partial f}{\partial \vec{x}} = \frac{\partial f}{\partial g} \frac{\partial g}{\partial \vec{x}}$其中$\frac{\partial f}{\partial g}$则是激活函数$g$的求导。而Sigmoid的导数为$g’(x) = \frac{e^{-x}}{(1+e^{-x})^2}$的函数图像为下图:

Sigmoid导数的函数图像

可以看出,最大也就才0.25,想一想每层梯度都乘$\frac{1}{4}$,那么最终传回来的将是很小的值。梯度的值在回传的过程中是成指数级下降的。tanh也类似,虽然其导数可以取到1,但是只是在$x=0$的时候,很显然同样也会有梯度消失的问题。

这个时候ReLU被提出来使用了,还是在经典的[1]中,$ReLU(x) = max(0, x)$,这样的形式很简洁,计算也足够快,但是最关键的是它的导数。当$x<0$时,导数为0,而$x>0$时,导数为1。简洁的导数为1可以减轻梯度消失问题。而真正可以说是基本解决了梯度消失问题的还是batch normalization,之后会讨论。

Dying ReLU

对于一个激活函数来说,能够有区分性激活就是它最大的作用,对于某些值(一般来说是高的值)激活,而一些值不激活。然而ReLU这样一个特殊的激活函数在$x<0$的情况下对所有值都是平等的对待了,也就是说不能激活了,因为输出全部是0。而且当$x<0$的话,ReLU的导数也是0,那么根本就更新不了权值。这个时候就会有一个疑惑,既然梯度为0,产生不了回传的梯度,那不是相当于始终更新不了吗?那也就没法学习了?而且初始化使得$x$有一半的概率都会为0。但实际上这个问题并不是特别明显,因为对于一个卷积核来说,不太可能对各种输入都恒输出为负数(从而导致ReLU产生0的结果)。所以当我们在使用mini-batch SGD的时候,一个batch中总有使得该卷积核的结果激活的样本,所以该卷积核仍然能够得到训练。

只有当一个卷积核对于几乎所有样本都输出为负数的时候,才会导致ReLU“死掉”(Dying ReLU),导致该卷积核的参数得不到训练。这个有可能是因为有一个很大的负bias造成的。解决这个问题的一个办法是使用Leaky ReLU[11],公式为$LReLU(x)= \begin{cases} x, x > 0 \\ 0.01x, x \leq 0 \end{cases}$。可以看到在$x<0$的时候并不是直接等于0,而是赋予$x$一个很小的权重,这样$x<0$的时候相当于没激活,因为值很小,但是不会“死去”,因为不为0。

LeakyReLU函数图像

除此之外,还有Parametric ReLU[12],就是将上式LReLU中的0.01替换为一个可训练的参数。虽然看似改动很小,但是会有一些有意思的事情,我们之后讨论。

池化层

GAP

一般来说,为了在网络最后使用特征图来分类,网络最后会使用全连接层,将特征图连接为一个向量用于分类。而将二维的特征图上的像素点全部使用全连接层连接出一个向量的时候,人们发现,全连接层上的参数实在太多了。一次全连接就相当于所有输入的像素和所有输出的向量元素之间都有一个连线,都有一个权重。这导致一个网络中大多数参数都全连接层里,而且和其他层的参数数目不是一个数量级的。

VGG16网络各层的参数个数

可以看到fc1的参数个数达到了102760448,超出其他层太多。为了节约,[13]中提出了使用Global Average Pooling。包括ResNet也使用了这种思想,直接把最后的feature map在每个通道取平均值,最后每个通道只剩下一个元素值,然后再用全连接层,这样节约了太多参数了。而且这种方法比直接用全连接层更加有效,得到的结果更好。

Global Average Pooling

Max Pooling

如果说池化是为了降维,将高分辨的图降低分辨率,那么average pooling取平均值似乎更加合理,这样能够体现该区域的一个平均状况。但是max pooling似乎更加符合神经网络“激活”的特点。正如卷积那一部分说的,我们做的是对特征或者模式的匹配,那么该区域只要有一块匹配到了,被激活了,那么整个区域都应该被视为匹配到了,都应该视为激活的。如果使用average pooling,那么激活的区域很可能就被周围未激活的区域拖了后腿,从而整块大区域未激活。所以使用max pooling是符合神经网络的特点的。

同时max pooling也使得CNN具有一定的旋转不变性。在旋转角度很小的情况下(比如$5^{\circ}$),这么小的角度,使得max pooling作用的区域大小里面最大的值还是那个值,为CNN提供了一定的旋转不变性。但是这种贡献太小了,根本不能因此而说CNN有旋转不变性。

全连接层

很多时候,全连接层都是用来作为分类器的。其分类的本质可以理解为对特征进行加权。比如在ResNet中,最后一个全连接层之前是GAP将特征图$2048 \times 7 \times 7$变为2048维的特征向量。这个向量我们称为特征向量,它的2048维可以类比为2048个感知到的特征,比如动物的耳朵、颜色等。有了这些特征,我们要得到对应的类别,那么可以根据一定的权重来把这些特征求和。比如兔子,可能它对耳朵长度、牙齿长度特征的权重会大一些,而对爪长这个特征权重会很小(甚至为负),因为更长的耳朵和牙齿、短的爪长才是兔子,当这些特征是对应的期望的数值时,最终加权求和的结果就会很大,那么预测兔子的可能性就更大。而这就是全连接层用于分类做的事情。

如果我们用矩阵$W$来代表全连接层,那么$W\vec{x}$代表分类的结果。$W$的行数就是类别的个数,而$W$的第$i$行向量就是学到的第$i$个类别的代表,它的数值是这个类的代表。通过它与输入特征点积,得到对应这个类别的得分,得分越高,是这个类的可能性越高。沿用兔子的例子,如果第$i$类为兔子,而特征中第$j$个为耳朵长短,那么学出来的$W_{i,j}$的值应该是高的,因为它“期望”一个较高的值与它相乘。所以真正学习到的类别信息是在最后作为分类的全连接层里,之前的层更多的是为了学习一个高维、抽象的特征表示。值得一提的是,最后的全连接层作为分类器是线性的,所以我们理想情况下希望之前的层学习到的特征表示是线性可分的。

BN层

Batch Normalization的思想与Hinton在训练深度信念网络(Deep Belief Networks[14])时用的方法是有一定的联系的。在Deep Belief Networks的训练中,先逐层训练,即每次只训练一个层,这样可以避免一次训练很多个层的时候从后面层传回来的梯度逐渐消失的情况。 而Batch Normalization则是把每一层的输入给归一化,类似于前面Hinton的把层间的联系区分开,假设层间数据分布不变,来解决梯度消失问题。

如果不进行归一化,那么训练的时候可能出现什么情况呢?假设第一层输出的数据分布在[a, b],那么第一次训练的时候,第二层接收的是[a, b]的数据,根据这个数据分布来训练。然而在经过一次梯度下降更新权重之后,第一层由于权重变了,结果对于同样的输入,第一层输出分布变为了[c, d]。这时对第二层是不利的,第二层最开始是假设输入为[a, b]进行训练的,然而这下变为了[c, d],第二层就有点不知所措了。所以Batch Normalization的思想就是把层间数据归一化,使得每层输入的数据分布在每次训练中都是相同的。

网络的结构

ResNet

Identity Mapping

ResNet的提出是令人兴奋的,因为它直接解决了深层网络难以训练的问题。它的形式很优美$G(x) = F(x) + x$。

Residual Block

很多有关ResNet的博文或者解释中都提到了ResNet解决了梯度消失的问题,因为梯度可以沿那个额外加上的$x$传递回前面的层。但是很显然梯度消失并不是ResNet真正要解决的问题。[6]中也说到梯度消失已经被Batch Normalization解决了,而ResNet面临的问题作者也没有具体说明是什么,但是他举了一个很有意思的例子。假如有一个浅层的网络和一个深层的网络,深层网络的浅层部分和浅层网络一样。那么我们只要假设深层网络剩余的部分是恒等变换(identity mapping,$f(x) = x$),也就是剩下的部分不改变输入的值,那么深层网络至少应该和浅层网络一样,如下图。

[6]提出的假设

深层网络至少应该能做到和浅层网络一样的效果,然而实际实验中得到的结果是深层网络往往比浅层结果差。这其中主要的原因就是恒等变换的$f(x) = x$在CNN中是不成立的,无论参数为多少,都不能做到。所以ResNet提出$f(x)+x$的真正原因是,CNN能够做到$f(x)=0$(卷积核参数全为0),那么$f(x)+x$就等于$x$了,就做到了identity mapping。但实际上这种跳层的连接从深层网络等效为浅层的角度来说,ResNet做到了自动调节网络深度,能够自动学习跳过其中的一些层,这也是关键的一点。

对于identity mapping来说,我自己也有一些思考。单就要使CNN做到$f(x)=x$来说,最大的问题在于激活函数。卷积层如果不是bottleneck的结构,即通道的数目是在逐层增大的话,那么卷积层是可以做到identity mapping的。例如$W^i_j$代表输出通道为第$j$个,在输入第$i$个通道上作用的卷积核,那么我们令当$i=j$时,卷积核最中心那个点的参数为1,其余参数都为0(包括非中心点或$i\neq j$的情况)。如果输入有$a$个通道,那么得到的输出通道前$a$层是与输入恒等的。所以问题主要出在激活函数上,ReLU不能做到$f(x)=x$在$x$任意取值都相等。这个时候可以联想到我们之前提过一个PReLU[12]对吧,参数化的ReLU,$PReLU(x)= \begin{cases} x, x > 0 \\ \alpha x, x \leq 0 \end{cases}$。而这个$\alpha$是可学习的。那么当它学到$\alpha = 1$的时候,这不就是$f(x)=x$了吗?有意思的是Parameter ReLU这篇文章也是ResNet的作者He Kaiming提出的,这就让人浮想联翩了,他是否最开始也是希望通过这种方式解决identity mapping呢?

当然,identity mapping使得深层网络能够跳层或者与浅层网络等效,那么这样训练出来的深层网络究竟是不是我们想要的深层网络呢?继续深的网络到底还有没有意义呢?这些都还需要进一步研究。但就目前来说,更多的网络开始关注的是网络的宽度了。

各层的连接顺序

关于ResNet的连接顺序,作者He Kaiming专门重新发表了一篇文章讨论[15],提出了修改版的ResNet。

[15]中修改版的ResNet

直观上来看,左侧的大箭头代表网络identity map的走向。可以看到,左边原始的ResNet在$F(x)+x$之后有一个ReLU层,这样identity map只存在相邻的residual block中。但是如果把ReLU放在相加之前。那么可以看到,整个网络的identity map都是连通的,也就是说任意两层之间都存在$f(x)=x$。这篇文章中也说到了这样做确实会使得性能有所提升。

Inception

Google的Inception也是非常流行的网络结构,它进行了对网络宽度的探索。但是我始终觉得没有ResNet那样漂亮简洁。最初的Inception[16]中提出了在同一层分别使用$1 \times 1$、$3 \times 3$、$5 \times 5$的卷积核进行卷积,另外还有一个max pooling,然后结果堆叠在一起。这样有什么好处呢,我们之前说到卷积核的大小其实代表了这一层的感受野,能够感知上一层多大的区域,那么Inception结构就是希望在不确定应该感知多大的区域的时候,干脆就全都感知了,把这些特征一起拿来用。

初版Inception结构

后来的Inception融合了一些比如用多个小卷积核替代大卷积核的思想,又经过了几次改版。由于我对Inception的网络结构理解不深,就不在这里继续讨论了。

参考文献


  1. 1.A. Krizhevsky, I. Sutskever, and G. E. Hinton. ImageNet Classification with Deep Convolutional Neural Networks. NIPS 2012.
  2. 2.X. Han, Y. Zhong, L. Cao, and L. Zhang. Pre-Trained AlexNet Architecture with Pyramid Pooling and Supervision for High Spatial Resolution Remote Sensing Image Scene Classification. MDPI 2017.
  3. 3.S. Ioffe and C.Szegedy. Batch Normalization. ICML 2015.
  4. 4.I. Goodfellow, Y. Bengio and A. Courville. Deep Learning.
  5. 5.M. Jaderberg, K. Simonyan, A. Zisserman and K. Kavukcuoglu. Spatial Transformer Networks. NIPS 2015.
  6. 6.K. He, X. Zhang, S. Ren and J. Sun. Deep Residual Learning for Image Recognition. CVPR 2015.
  7. 7.G. Huang, Z. Liu and L.Maaten. Densely Connected Convolutional Networks. CVPR 2017.
  8. 8.A. G. Howard, M. Zhu, B. Chen and D.Kalenichenko. MobileNets: Efficient convolutional neural networks for mobile vision applications. arXiv preprint arXiv:1704.04861.
  9. 9.知乎 留德华叫兽 的回答。https://www.zhihu.com/question/38098038
  10. 10.G. Ian, S. Jonathon and S. Christian. Explaining and Harnessing Adversarial Examples. arXiv preprint arXiv:1412.6572.
  11. 11.A. L. Mass, A. Y. Hannun and A. Y. Ng. Rectifier Nonlinearities Improve Neural Network Acoustic Models. ICML 2013.
  12. 12.K. He, X. Zhang, S. Ren and J. Sun. Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification. IEEE international conference on computer vision 2015.
  13. 13.L. Min, C. Qiang and Y. Shuicheng. Network in network. arXiv preprint arXiv:1312.4400.
  14. 14.G. E. Hinton. Deep Belief Networks. Scholarpedia 2009.
  15. 15.K. He, X. Zhang, S. Ren and J. Sun. Identity Mappings in Deep Residual Networks. ECCV 2016.
  16. 16.C. Szegedy, W. Liu, Y. Jia, P. Sermanet, S. Reed, D. Anguelov, D. Erhan, V. Vanhoucke and A. Rabinovich. Going deeper with convolutions. CVPR 2015.
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×