本专栏将从论文的角度解读一下CV方向的一些经典神经网络模型及其贡献与意义,以期加深自己的印象,后续可以随时翻看并且学习其中好的tricks。上一期介绍了基于InceptionV1提出的GoogLeNet,这一期介绍Inception的改进之路——InceptionV2到V4.
一、InceptionV2 & V3
相关的论文:
1、《Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift》(论文链接),作者及相关信息如下:
2、《Rethinking the Inception Architecture for Computer Vision》(论文链接),作者及相关信息如下:
做出的改进(tricks):
1、Batch Normalization
机器学习中有个很重要的假设:独立同分布假设。就是假设训练数据和测试数据是满足相同分布的,这是通过训练数据获得的模型能够在测试集获得差不多的效果的一个基本保障。
神经网络学习过程其实也是在学习数据分布,那么,细化到神经网络的每一层间,第N层的输入是由第N-1层的输入与第N-1层的参数得到的,但是第N-1层的参数是会变的,这就引起了第N层的输入分布一直在变化,并且实际上每一batch的输入数据分布也存在差异;那每轮训练时分布都不一致,网络每次都需要去适应不同的数据分布,那么相对的训练效果就得不到保障,导致模型收敛的速度大大降低。Google将这种现象称为Internal Covariate Shift。
那么如何解决这个问题呢?机器学习中有一种常用的规范化数据分布的方法,即白化(Whitening)。白化(比如PCA白化)对数据分布进行变换,使得输入分布具有相同的均值与方差,这样来固定每一层的输入分布,但它会导致每一层的表达能力受限,并且计算量大。
因此Google提出了Batch Normalization来解决ICS问题。有关BN的详细介绍与公式推导可以看大佬博客这里和这里。
可是具有相同的均值和方差的分布并不一定就是同一个分布,因此BN并没有从根本上解决ICS问题,它更多的还是防止梯度消失来加速网络收敛。至于为什么能防止梯度消失、加速收敛,可以看这里。
并且在论文中也比较了BN层是应该放在线性层(即全连接或卷积层)前面好还是放在线性层后面好。作者们认为放在前面还是会引起数据分布改变,没有解决ICS问题,因此还是放后面,即conv层+BN层。(那非线性激活层放在哪呢,在这篇论文中,是conv+BN+ReLU,但较多实践中表明conv+ReLU+BN效果更好,可以看这里)
BN的提出我只能用牛逼来形容,太强了。
2、用多个小卷积核代替大卷积核
这一点也是借鉴了VGG,之前VGGNet综述也讲过,不再赘述。
原来的InceptionV1:
改进后的Inception:
但是作者们也提出了相应的问题:
这样设置是否会使得网络表达能力受限?如果我们的主要目标是对计算的线性部分进行分解,是不是建议在第一层保持线性激活(即在两个3×3卷积层之间使用线性激活函数而不是ReLU激活函数,这样使得其与一个5×5卷积层是等价的)?
作者们通过实验证明,ReLU牛逼。
3、非对称卷积
刚才将5×5卷积核用两个3×3卷积核进行替换,但是作者们还不满意,还想更小一点,再节省一点计算量,那用2×2卷积核?效果不够顶,于是提出了非对称卷积,即将n×n卷积核分解成1×n和n×1的卷积核!!!我直接,看懂掌声。
因此任意nxn的卷积都可以通过1xn卷积后接nx1卷积来替代,原来是 n×n 次乘法,分解之后,变成了 2×n 次乘法了,降低了计算量。但作者们发现在网络的前期使用这种分解效果并不好,这样的非对称卷积不要用在靠近输入的层,会影响精度,要用在中度大小的特征图(feature map)上使用效果才会更好(特征图大小建议在12到20之间)。
4、
在降低特征图大小时,是先池化呢还是先Inception卷积呢?
论文对这一点也进行了讨论:方法一(左图)先池化会导致特征缺失(因为在卷积层提取信息之前就减少了特征图尺寸),方法二(右图)是正常的缩小方法,但计算量很大。因此作者们使用了并行的结构:
这里可能有人会有和我一样的疑问,InceptionV1中本来不就有pool分支,那么区别在哪呢?可以仔细观察一下基于InceptionV1提交的GoogLeNet模型:
发现关键所在了吗?步长S不同!这里减少特征图大小的方法显然是方法一,先通过一个步长为2的MaxPool减小了特征图大小,然后再Inception卷积,Inception中MaxPool分支的步长为1,不改变特征图大小。作者们发现了这样做的弊端,即特征缺失,因此想改用方法二,但是不想接受计算量的提升,所以提出了并行的想法。
因此,最终的InceptionV2 & V3网络结构图如下:
二、InceptionV4
论文相关信息(论文链接):
做出的改进(tricks):
一言以蔽之:先是基于InceptionV3设计了一个更为简洁的InceptionV4;并且发现ResNet牛逼,于是将Inception和残差连接相结合,实验表明结合ResNet可以加速训练,同时提高性能。论文中的图占了相当一部分,也没有什么好多讲的,直接通过图来看结构吧:
InceptionV4:
其中Stem:
(符号V默认padding=VALID)
Inception-A:
Inception-B:
Inception-C:
Reduction-A:
Reduction-B:
Inception-ResNet-V1:
其中stem:
Inception-ResNet-A:
Inception-ResNet-B:
Inception-ResNet-C:
Reduction-A:与InceptionV4一样
Reduction-B:
Inception-ResNet-V2:
其中Stem:与InceptionV4一样
Inception-ResNet-A:
Inception-ResNet-B:
Inception-ResNet-C:
Reduction-A:与InceptionV4一样
Reduction-B:
值得一提的是,作者研究发现残差连接并不会明显提升模型精度,而是会加快训练收敛,并且在原文中写到:如果滤波器数量超过1000,残差网络开始出现不稳定,同时网络会在训练过程早期便会出现“死亡”,即经过成千上万次迭代,在平均池化(average pooling) 之前的层开始只生成0。通过降低学习率,或增加额外的BN层都无法避免这种状况。同时,发现在将残差模块添加到激活层之前,对其进行放缩能够稳定训练,通常来说将残差放缩因子定在0.1-0.3,即使缩放并不是完全必须的,它似乎并不会影响最终准确率,但是放缩能有益于训练的稳定性。
总结
Google不愧是商业模式比较成熟的公司,时刻没有忘记其想把模型移植到移动端的初心,所以可以看见很多围绕减小计算量而设计的tricks。从基于InceptionV1提出的GoogLeNet,到这一期介绍的InceptionV2、V3、V4,以及结合了ResNet的Inception-ResNet-V1、V2,可以看到Google团队对模型的不断改进之路,他们吸收了很多其他论文中的先进经验与想法,但并不是直接拿来用,也是进行了一些对比实验来确定效果的,毕竟深度学习目前还是一门实践领先理论的学科。Inception结构还是比较经典的,更别提还有BN这一基石性的发明,贡献拉满了~