Inception系列学习笔记
InceptionV1
又叫做GooleNet,他的创新点主要有:
1、提出Inception模块。
2、使用辅助Loss。
3、全连接层用简单的平均池化代替。
网络太大就不放了。下面介绍一下Inception模块:
a图是基本的inception模块,b图是添加1x1卷积的inception模块,这样极大的降低了计算量。Inception模块中的卷积步长都是1,另外为了保持特征图大小一致,都设置了Padding方式为Same。每个卷积层后面都接了ReLU激活函数。在输出前有一个Concat层代表把4组不同类型但大小相同的特征响应图堆叠在一起,获得输出特征图。Inception模块一共使用了4种不同大小的卷积核对输入特征图进行了特征提取。并且在原始的Inception模块基础上,为了降低计算量使用1x1卷积来降维。
GoogleNet将最后的全连接层全部替换为了全局平均池化层,这可以显著减少网络的参数量。AlexNet最后的三个全连接层的参数量占了总参数量的差不多90%,GoogLeNet移除了全连接层使用全局平均池化层进行代替并证明了这种方式实现的精度更好,并且推理速度也明显加快。
代码:
def Conv2d_BN(x, nb_filter,kernel_size, padding='same',strides=(1,1),name=None):
if name is not None:
bn_name = name + '_bn'
conv_name = name + '_conv'
else:
bn_name = None
conv_name = None
x = Conv2D(nb_filter,kernel_size,padding=padding,strides=strides,activation='relu',name=conv_name)(x)
x = BatchNormalization(axis=3,name=bn_name)(x)
return x
def Inception(x,nb_filter):
branch1x1 = Conv2d_BN(x,nb_filter,(1,1), padding='same',strides=(1,1),name=None)
branch3x3 = Conv2d_BN(x,nb_filter,(1,1), padding='same',strides=(1,1),name=None)
branch3x3 = Conv2d_BN(branch3x3,nb_filter,(3,3), padding='same',strides=(1,1),name=None)
branch5x5 = Conv2d_BN(x,nb_filter,(1,1), padding='same',strides=(1,1),name=None)
branch5x5 = Conv2d_BN(branch5x5,nb_filter,(1,1), padding='same',strides=(1,1),name=None)
branchpool = MaxPooling2D(pool_size=(3,3),strides=(1,1),padding='same')(x)
branchpool = Conv2d_BN(branchpool,nb_filter,(1,1),padding='same',strides=(1,1),name=None)
x = concatenate([branch1x1,branch3x3,branch5x5,branchpool],axis=3)
return x
def GoogLeNet():
inpt = Input(shape=(224,224,3))
#padding = 'same',填充为(步长-1)/2,还可以用ZeroPadding2D((3,3))
x = Conv2d_BN(inpt,64,(7,7),strides=(2,2),padding='same')
x = MaxPooling2D(pool_size=(3,3),strides=(2,2),padding='same')(x)
x = Conv2d_BN(x,192,(3,3),strides=(1,1),padding='same')
x = MaxPooling2D(pool_size=(3,3),strides=(2,2),padding='same')(x)
x = Inception(x,64)#256
x = Inception(x,120)#480
x = MaxPooling2D(pool_size=(3,3),strides=(2,2),padding='same')(x)
x = Inception(x,128)#512
x = Inception(x,128)
x = Inception(x,128)
x = Inception(x,132)#528
x = Inception(x,208)#832
x = MaxPooling2D(pool_size=(3,3),strides=(2,2),padding='same')(x)
x = Inception(x,208)
x = Inception(x,256)#1024
x = AveragePooling2D(pool_size=(7,7),strides=(7,7),padding='same')(x)
x = Dropout(0.4)(x)
x = Dense(1000,activation='relu')(x)
x = Dense(1000,activation='softmax')(x)
model = Model(inpt,x,name='inception')
return model
Inception V2
Inception V2即在InceptionV1的基础上加上了BN层并且将卷积5x5用两个3x3卷积代替。
创新点
1、提出了BN层,每次先对输入特征图进行归一化,再送入下一层神经网络输入层。加快了网络的收敛速度。
2、Conv+BN+Scale+ReLU。Inception V2中每个卷积层后面都有BN层,并且一般BN层还会配合Scale层一起用。
3、和VGGNet的思想一致,用多个小的卷积核代替大的卷积核,并获得一致的感受野。
4、进一步加深了网络的深度,使得网络的特征提取能力进一步加强。
5、增强了模型的非线性表达能力,因为每个卷积后面都加了一个ReLU。卷积层变多,非线性激活函数自然更多,模型的非线性表达能力变得更强。
网络结构
具体关于BN层的反向传播的知识另开一篇博客介绍。
InceptionV3
在InceptionV2的基础上做了微小的改变就获得了Inception V3,Inception V3模块的结构为:
可以看得出来进一步减少了计算量,但是仅在网络中段使用效果会比较好。
InceptionV4
InceptionV4就是在前面的基础上添加了resnet模块。
Inception系列网络的一些Trick:
1、辅助分类器。介绍Inception V1(Google Net)的时候我已经介绍过了,这种损失现在已经被称为多任务损失了,典型的如目标检测中的分类和回归损失。
2、标签平滑。在比赛中经常用到,以前构造标签的时候实际是哪一类就置1,其他类的都置为0,不够平滑,学习时就会很难,容易过拟合。所以标签平滑就是给真实标签最大值,也按照概率给其他类一些值,如给一些根号值。
3、使用合适的方法下采样,具体如下图所示。
其中Figure9(a)表示先直接下采样再增加通道数,直接下采样很容易丢掉一些表征信息,这些信息学不到模型可能就会有瓶颈。而Figure9(b)表示先增加通道数再直接下采样,先增加通道数时参数会增大了很多倍,太复杂,耗内存,计算量大。Figure10(a)用了两层3x3的卷积,步长变大,图像也可以缩小,即代替Pooling来下采样。Figure10(d)是最好的方案,即把特征图拆成2部分,一部分直接采样(pooling),一个做卷积(下采样),再把两种信息连到一起,这样通过分开的方式相对于以前的方法挖掘到不同的信息更多,因为卷积和pooling都是在原始特征图上做的。
总结
inceptionv1是通过增加网络的宽度来提高网络性能,在每个inception模块中,使用了不同大小的卷积核,可以理解成不同的感受野,然后将其concentrate起来,丰富了每层的信息。
之后inceptionv2,使用了BN算法(BN使用在conv之后,relu之前),来加速网络的收敛速度。
在V3版本中,还使用了卷积因子分解的思想,将大卷积核分解成小卷积,节省了参数,降低了模型大小。
在V4版本中,使用了更加统一的inception模块,并结合了resnet的残差思想,能将网络做得更深。