论文地址:
[v1] Going Deeper with Convolutions
[v2] Batch Normalization:Accelerating Deep Network Training by Reducing Internal Covariate Shift
[v3] Rethinking theInception Architecture for Computer Vision
[v4] Inception-v4,Inception-ResNet and the Impact of Residual Connections on Learning
参考博客:
深度学习-GoogLeNet
GoogLeNet
深度学习:详细说明GoogleNet网络结构
GoogLeNet是2014年的ILSVRC的冠军模型,GoogLeNet做了更大胆的网络上的尝试,而不是像VGG继承了LeNet以及Alexnet的一切框架。GoogLeNet虽然有22层,但是参数量只有AlexNet的1/12。
GoogLeNet论文指出获得高质量模型最保险的做法就是增加模型的深度,或者是它的宽度,但是一般情况下,更深和更宽的网络会出现以下问题:
总之更大的网络容易产生过拟合,并且增加了计算量。
GoogLeNet给出的解决方案:
将全连接层甚至一般的卷积都转化为稀疏连接 -> 提出了名为Inception
的结构来实现此目的。
这是一种网中网结构(Network in Network)。就是原来的节点也是一个网络,使用了Inception
,这个网络结构的宽度和深度都可以扩大。从而带来性能的提升。
对上图做以下说明:
1 . 采用不同大小的卷积核意味着不同大小的感受野,最后拼接意味着不同尺度特征的融合;
2 . 之所以卷积核大小采用1、3和5,主要是为了方便对齐。设定卷积步长stride=1之后,只要分别设定pad=0、1、2,那么卷积之后便可以得到相同维度的特征,然后这些特征就可以直接拼接在一起了;
4 . 网络越到后面,特征越抽象,而且每个特征所涉及的感受野也更大了,因此随着层数的增加,3x3和5x5卷积的比例也要增加。
使用5x5的卷积核仍然会带来巨大的计算量。为此,文章借鉴NIN,采用1x1卷积核来进行降维。
(1)作用1:在相同尺寸的感受野中叠加更多的卷积,能提取到更丰富的特征。
上图左侧是是传统的卷积层结构(线性卷积),在一个尺度上只有一次卷积;右图是Network in Network结构(NIN结构),先进行一次普通的卷积(比如3x3),紧跟再进行一次1x1的卷积,对于某个像素点来说1x1卷积等效于该像素点在所有特征上进行一次全连接的计算,所以右侧图的1x1卷积画成了全连接层的形式,需要注意的是NIN结构中无论是第一个3x3卷积还是新增的1x1卷积,后面都紧跟着激活函数(比如ReLu)。
将两个卷积串联,就能组合出更多的非线性特征。
举个例子,假设第1个3x3卷积+激活函数近似于f1(x)=ax2+bx+c,第二个1x1卷积+激活函数近似于f2(x)=mx2+nx+q,那f1(x)和f2(f1(x))比哪个非线性更强,更能模拟非线性的特征?答案是显而易见的。NIN的结构和传统的神经网络中多层的结构有些类似,后者的多层是跨越了不同尺寸的感受野(通过层与层中间加pool层),从而在更高尺度上提取出特征;NIN结构是在同一个尺度上的多层(中间没有pool层),从而在相同的感受野范围能提取更强的非线性。
(2)作用2:使用1x1卷积进行降维,降低了计算复杂度。
同样是对一个深度为512的特征矩阵使用65个大小为5x5的卷积核进行卷积,不使用1x1卷积核进行降维话一共需要819200个参数,如果使用1x1卷积核进行降维一共需要50688个参数,明显少了很多。
提出两个问题:
1、如果使用1x1进行特征压缩,是否会影响最终结果?
回答:不会,作者的解释是,如果你想要把特征厚度从128变成256,你可以直接用3x3进行特征提取。如果你先用1x1进行压缩到64,然后再用3x3把64channel的特征扩展成256,其实对后续的精度没有影响,而且减少了运算次数。
2、为什么inception是多个尺度上进行卷积再聚合?
回答:直观上,多个尺度上同时卷积可以提取到不同尺度的特征。而这也意味着最后分类判断更加准确。
具体改进后的Inception
:
对上图做如下说明:
注:上表中的“#3x3 reduce”,“#5x5 reduce”表示在3x3,5x5卷积操作之前使用了1x1卷积的数量。
原始输入图像为224x224x3,且都进行了零均值化的预处理操作(图像每个像素减去均值)。
使用7x7的卷积核(滑动步长2,padding为3),64通道,输出为112x112x64,卷积后进行ReLU操作;
经过3x3的max pooling(步长为2),输出为((112 - 3+1)/2)+1=56,输出为56x56x64,再进行ReLU操作;
然后过一个LRN局部响应归一化;
使用3x3的卷积核(滑动步长为1,padding为1),192通道,输出为56x56x192,卷积后进行ReLU操作;
经过3x3的max pooling(步长为2),输出为((56 - 3+1)/2)+1=28,输出为28x28x192,再进行ReLU操作;
然后过一个LRN局部响应归一化;
分为四个分支,采用不同尺度的卷积核来进行处理,输入为28x28x192:
(1)64个1x1的卷积核,然后RuLU,输出28x28x64;
(2)96个1x1的卷积核,作为3x3卷积核之前的降维,变成28x28x96,然后进行ReLU计算,再进行128个3x3的卷积(padding为1),输出28x28x128;
(3)16个1x1的卷积核,作为5x5卷积核之前的降维,变成28x28x16,进行ReLU计算后,再进行32个5x5的卷积(padding为2),输出28x28x32;
(4)pool层,使用3x3的核(padding为1),输出28x28x192,然后进行32个1x1的卷积,输出28x28x32;
将四个结果进行连接,对这四部分输出结果的第三维并联,即64+128+32+32=256,最终输出28x28x256。
分为四个分支,采用不同尺度的卷积核来进行处理,输入为28x28x256:
(1)128个1x1的卷积核,然后RuLU,输出28x28x128;
(2)128个1x1的卷积核,作为3x3卷积核之前的降维,变成28x28x128,进行ReLU,再进行192个3x3的卷积(padding为1),输出28x28x192;
(3)32个1x1的卷积核,作为5x5卷积核之前的降维,变成28x28x32,进行ReLU计算后,再进行96个5x5的卷积(padding为2),输出28x28x96;
(4)pool层,使用3x3的核(padding为1),输出28x28x256,然后进行64个1x1的卷积,输出28x28x64;
将四个结果进行连接,对这四部分输出结果的第三维并联,即128+192+96+64=480,最终输出输出为28x28x480。
第四层(4a,4b,4c,4d,4e)、第五层(5a,5b)……,与3a、3b类似,在此就不再重复。
GoogLeNet的结构就是3+3+3总共9个inception模块组成的,每个Inception有两层,加上开头的3个卷积层和输出前的FC层,总共22层!然后每3层的inception之后都会有一个输出结果,这个网络一共有三个输出结果。
GoogLeNet用到了辅助分类器。因为除了最后一层的输出结果,中间节点的分类效果也可能是很好的,所以GoogleNet将中间的某一层作为输出,并以一个较小的权重(0.3)加入到最终分类结果中。其实就是一种变相的模型融合,同时给网络增加了反向传播的梯度信号,也起到了一定的正则化的作用。
结构分析:
Inception-v1将多尺度的卷积层、池化层提取的特征图拼接输入下一层,提升模型多尺度特征提取能力。
Inception-v1参考看NiN的网络设计,利用1*1Conv来降维输入通道,减少模型参数量,并引入更多的非线性,提升模型泛化能力。
V2版本所做的主要改进:
1.引入batch normalization。
2.借鉴VGG,使用几个小滤波器(3 x 3)卷积层的组合代替一个大滤波器(5 x 5或7 x 7)卷积层。
3.进一步改进,考虑了nx1的卷积核,用1xn与nx1取代3x3卷积(可分离卷积)。
下面的准则来源于大量的实验,因此包含一定的推测,但实际证明基本都是有效的。
上述的这些并不能直接用来提高网络质量,而仅用来在大环境下作指导。
参考:深度学习中的BN,LN,IN,GN总结
(1)问题提出
深度网络参数训练时内部存在协方差偏移(Internal Covariate Shift)现象:深度网络内部数据分布在训练过程中发生变化的现象。
(2)为什么会带来不好影响
训练深度网络时,神经网络隐层参数更新会导致网络输出层输出数据的分布发生变化,而且随着层数的增加,根据链式规则,这种偏移现象会逐渐被放大。这对于网络参数学习来说是个问题:因为神经网络本质学习的就是数据分布(representation learning),如果数据分布变化了,神经网络又不得不学习新的分布。为保证网络参数训练的稳定性和收敛性,往往需要选择比较小的学习速率(learning rate),同时参数初始化的好坏也明显影响训练出的模型精度,特别是在训练具有饱和非线性(死区特性)的网络,比如采用S或双S激活函数网络,比如LSTM,GRU。
(3)解决办法
引入BN,作为深度网络模型的一个层,每次先对input数据进行归一化,再送入神经网络输入层。
(4)BN为什么有效
神经网络的训练过程中,更新了某一层的权重参数,后续每一层网络的输出都可能发生变化,最终引起loss值的变化。所以当没有BN层时,loss的收敛就需要我们精心设计权重的初始化方法和超参数的调节方法以及等待漫长的训练时间;但当我们在各层之间加入了BN层后,某层的输出仅由两个参数γ和β决定,使用梯度下降法优化参数时,优化方法只需要调节两个参数的值来控制各层的输出,而不需要调节各层的全部参数。这样极大地提高了收敛速度,避免了小心翼翼的参数初始化和超参数调节过程。
Batch normalization 也可以被看做一个层面。 在一层层的添加神经网络的时候,我们先有数据 X, 再添加全连接层,全连接层的计算结果会经过激励函数成为下一层的输入,接着重复之前的操作。 BN就被添加在每一个全连接和激励函数之间。
经过BN之后,大部分输入数据能够分布在激活函数所对应的中间区域,而不是两边(梯度为±1)的区域,这样的数据更加有效。
我们引入一些 batch normalization 的公式。这三步就是我们在刚刚一直说的 normalization 工序, 但是公式的后面还有一个反向操作,将 normalize 后的数据再扩展和平移。原来这是为了让神经网络自己去学着使用和修改这个扩展参数 gamma, 和平移参数 β,这样神经网络就能自己慢慢琢磨出前面的 normalization 操作到底有没有起到优化的作用, 如果没有起到作用, 我就使用 gamma 和 belt 来抵消一些 normalization 的操作。
最后我们来看看一张神经网络训练到最后,代表了每层输出值的结果的分布图。这样我们就能一眼看出Batch normalization 的功效啦。让每一层的值在有效的范围内传递下去。
在深度神经网络中中,如果每层的数据分布都不一样的话,将会导致网络非常难收敛和训练,而如果把每层的数据都在转换在均值为0,方差为1的状态下,这样每层数据的分布都是一样的训练会比较容易收敛。
在网络的训练中,BN的使用使得一个batch中所有样本都被关联在了一起,因此网络不会从某一个训练样本中生成确定的结果,即同样一个样本的输出不再仅仅取决于样本的本身,也取决于跟这个样本同属一个batch的其他样本,而每次网络都是随机取batch,这样就会使得整个网络不会朝这一个方向使劲学习,一定程度上避免了过拟合。
1.高度依赖于mini-batch的大小,实际使用中会对mini-Batch大小进行约束,不适合类似在线学习(mini-batch为1)。
2.不适用于RNN网络中normalize操作:BN实际使用时需要计算并且保存某一层神经网络mini-batch的均值和方差等统计信息,对于对一个固定深度的前向神经网络(DNN,CNN)使用BN,很方便;但对于RNN来说,sequence的长度是不一致的,换句话说RNN的深度不是固定的,不同的time-step需要保存不同的statics特征,可能存在一个特殊sequence比其的sequence长很多,这样training时,计算很麻烦。
Batch Normalization 的处理对象是对一批样本,是对这批样本的同一维度特征做归一化;
Layer Normalization 的处理对象是单个样本,是对这单个样本的所有维度特征做归一化。
大尺寸的卷积核可以带来更大的感受野,也意味着更多的参数,比如5x5卷积核参数是3x3卷积核的25/9=2.78倍。为此,作者借鉴VGG-Net,用2个连续的3x3卷积层(stride=1)组成的小网络来代替单个的5x5卷积层,这便是Inception-V2结构,保持感受野范围的同时又减少了参数量,如下图:
提出两个问题:
1 . 这种2个连续的3x3卷积层(stride=1)组成的小网络来代替单个的5x5卷积层会造成表达能力的下降吗?
后面有大量实验可以表明不会造成表达缺失;
2 . 3x3卷积之后还要再加激活吗?
作者也做了对比试验,表明添加非线性激活会提高性能。
从上面来看,大卷积核完全可以由一系列的3x3卷积核来替代,那能不能分解的更小一点呢。文章考虑了 nx1 卷积核。最重要的改进就是分解Factorization,把7x7分解成两个一维的卷积(1x7和7x1),3x3的也是一样,这样的好处是,既可以加速运算,又可以将一个卷积拆成两个卷积,这样使得网络的深度进一步加深,并且增加了网络的非线性。(每增加一层都要用ReLU),此时网络的输入也从224x224变成299x299。
作者发现在网络的前期使用这种分解效果并不好,还有在中度大小的feature map上使用效果才会更好。(对于mxm大小的feature map,建议m在12到20之间)。这样的非对称卷积不要用在靠近输入的层,会影响精度,要用在较高的层。
可分离卷积(Separable convolution)详解
深入浅出可分离卷积
可分离卷积包括:
假设feature的size为[channel,height,width],空间也就是指:[height, width]这两维度组成的,深度也就是指channel这一维度。
具有如下特点:
空间可分离卷积就是在空间维度将标准卷积运算拆分成多个小卷积核。例如我们可以将卷积核拆分成两个(或多个)向量的外积。可分离卷积的第一个版本主要处理图像和内核的空间尺寸-高度和宽度。 它将一个内核分为两个较小的内核,其中最常见的是将一个3x3内核分为一个3x1和1x3内核。 因此,代替进行一次具有9个乘法的卷积,而是执行两次分别具有3个乘法两个卷积组合起来共需要6次乘法,以实现相同的效果。
一般的,空间可分离卷积就是将nxn的卷积分成1xn和nx1两步计算,普通的3x3卷积在一个5x5的feature map上的计算方式如下图,每个位置需要9次乘法,一共9个位置,整个操作要81次做乘法:
同样的状况在空间可分离卷积中的计算方式如下图,第一步先使用3x1的filter,所需计算量为:15x3=45;第二步使用1x3的filter,所需计算量为:9x3=27;总共需要72次乘法就可以得到最终结果,要小于普通卷积的81次乘法:
它的核心思想是将一个完整的卷积运算分解为两步进行,分别为逐深度卷积(Depthwise Convolution)与逐点卷积(Pointwise Convolution)。
假设输入层为一个大小为64×64像素、3通道彩色图片。经过一个包含4个Filter的卷积层,最终输出4个Feature Map,且尺寸与输入层相同。整个过程可以用下图来概括:
此时,卷积层共4个Filter,每个Filter包含了3个Kernel,每个Kernel的大小为3×3。因此卷积层的参数数量可以用如下公式来计算:N_std = 4 × 3 × 3 × 3 = 108
同样是上述例子,一个大小为64×64像素、三通道彩色图片首先经过第一次卷积运算,不同之处在于此次的卷积完全是在二维平面内进行,且Filter的数量与上一层的Depth相同。所以一个三通道的图像经过运算后生成了3个Feature map,如下图所示。
其中一个Filter只包含一个大小为3×3的Kernel,卷积部分的参数个数计算如下:N_depthwise = 3 × 3 × 3 = 27
Depthwise Convolution完成后的Feature map数量与输入层的depth相同,但是这种运算对输入层的每个channel独立进行卷积运算后就结束了,没有有效的利用不同map在相同空间位置上的信息。因此需要增加另外一步操作来将这些map进行组合生成新的Feature map,即接下来的Pointwise Convolution。
Pointwise Convolution的运算与常规卷积运算非常相似,不同之处在于卷积核的尺寸为 1×1×M,M为上一层的depth。所以这里的卷积运算会将上一步的map在深度方向上进行加权组合,生成新的Feature map。有几个Filter就有几个Feature map。如下图所示。
由于采用的是1×1卷积的方式,此步中卷积涉及到的参数个数可以计算为:N_pointwise = 1 × 1 × 3 × 4 = 12
参考<<卷积参数量计算(标准卷积,分组卷积,深度可分离开)>>
(1)常规卷积:
(2)深度可分离卷积:
Separable Convolution的参数个数是常规卷积的约1/3。因此,在参数量相同的前提下,采用Separable Convolution的神经网络层数可以做的更深。
Inception v3整体上采用了Inception v2的网络结构,并在优化算法、正则化等方面做了改进,具体如下:
参考:深度学习中的标签平滑正则化
在进行多分类时,很多时候采用one-hot标签进行计算交叉熵损失,而单纯的交叉熵损失时,只考虑到了正确标签的位置的损失,而忽略了错误标签位置的损失。这样导致模型可能会在训练集上拟合的非常好,但由于其错误标签位置的损失没有计算,导致预测的时候,预测错误的概率比较大,也就是常说的过拟合。标签平滑可以在一定程度上防止过拟合。
有上面实例可以看出,带有标签平滑的损失要比传统交叉熵损失要更大。换言之,带有标签平滑的损失要想下降到传统交叉熵损失的程度,就要学习的更好,迫使模型往正确分类的方向走。
只要用到的是交叉熵损失(cross loss),都可以采取标签平滑处理。
Inception V4研究了Inception模块与残差连接的结合。ResNet结构大大地加深了网络深度,还极大地提升了训练速度,同时性能也有提升。
本文详细呈现了三种新的网络结构:
GoogLeNet复现(Pytorch实现)