寒假希望自己能够有所提升吧,不要再当一个简单地代码搬运工,所以希望自己能够坚持下来每天阅读一些文章,然后进行总结,冲冲冲
论文全称: SQUEEZENET: ALEXNET-LEVEL ACCURACY WITH 50X FEWER PARAMETERS AND <0.5MB MODEL SIZE
这里提供几个链接,大家可以自己下载下来学习
百度网盘
链接:论文原文
提取码:huzs
官网链接
论文链接:论文链接
代码链接:代码链接
其实这篇文章相较于后续的其他轻量化网络,其实可以学习借鉴的东西并不多,但是由于这篇属于轻量化网络的开篇之作,最早公开于2016年2月,所以我想借用这次机会,从头学习一下轻量化网络的演变路程,希望可以收获一些感悟
近年来,深度卷积神经网络(CNNs)的研究主要集中在提高精度上。对于给定的精度级别,通常可以识别多个达到该精度级别的CNN架构。在同等精度的情况下,较小的CNN体系结构至少有三个优点:
1)较小的CNN在分布式训练期间需要较少的跨服务器通信。
2) 较小的cnn需要较少的带宽才能将新车型从云端导出到自动驾驶汽车。
3) 更小的CNN更适合部署在FP-GAs和其他内存有限的硬件上。
为了提供所有这些优势,我们提出了一个称为挤压网的小型CNN架构。SqueezeNet在ImageNet上实现AlexNet级精度,参数减少50倍。此外,通过模型压缩技术,我们可以将squezenet压缩到小于0.5MB(比AlexNet小510倍)。
可在此处下载SqueezeNet架构:https://github.com/DeepScale/SqueezeNet
其实文章的重点在大多数网络都在往深而精确的网络中改进,但是现实生活中由于计算平台的限制,比如嵌入式系统,比如车载系统中,都没法提供足够的算力来计算大型的CNN网络,而目的方法都是对网络进行剪枝,作者想要提供一种简洁的小型网络,来满足
1)更有效的分布式训练
2)可以将新模型导出到客户端时开销更小
3)可行的FPGA和嵌入式部署
所以提出了squeezeNet模块
squeezenet模型主要使用了三个策略
fire模块由以下两部分组成:
在fire模块中有三组超参数:
s
1
×
1
s_{1\times1}
s1×1、
e
1
×
1
e_{1\times1}
e1×1 、
e
3
×
3
e_{3\times3}
e3×3。squeeze部分的
1
×
1
1\times1
1×1卷积的通道数记作
s
1
×
1
s_{1\times1}
s1×1。而expand部分
1
×
1\times
1×卷积和
3
×
3
3\times3
3×3卷积的通道数分别记作
e
1
×
1
e_{1\times1}
e1×1 、
e
3
×
3
e_{3\times3}
e3×3。作者建议使用Fire模块时,
s
1
×
1
<
e
1
×
1
+
e
3
×
3
s_{1\times1}
s1×1
3
×
3
3\times3
3×3卷积之中加入瓶颈层,有助于限制3x3滤波器的输入通道数量。
下面代码片段是Keras实现的Fire模块,注意拼接Feature Map的时候使用的是Cancatnate操作,这样不必要求
e
1
×
1
=
e
3
×
3
e_{1\times1}=e_{3\times3}
e1×1=e3×3。
def Fire_Model(x, s_1, e_1, e_3, fire_name):
# squeeze部分
squeeze_x = Conv2D(kernel_size=(1,1),filters=s_1x1,padding='same',activation='relu',name=fire_name+'_s1')(x)
# expand部分
expand_x_1 = Conv2D(kernel_size=(1,1),filters=e_1x1,padding='same',activation='relu',name=fire_name+'_e1')(squeeze_x)
expand_x_3 = Conv2D(kernel_size=(3,3),filters=e_3x3,padding='same',activation='relu',name=fire_name+'_e3')(squeeze_x)
expand = merge([expand_x_1, expand_x_3], mode='concat', concat_axis=3)
return expand
图3是SqueezeNet的几个实现,左侧是不加short-cut的SqueezeNet,中间是加了short-cut的,右侧是short-cut跨有不同Feature Map个数的卷积的。作者在后续还补充了一些其他细节:
代码实现
def squeezeNet(x):
conv1 = Conv2D(input_shape = (224,224,3), strides = 2, filters=96, kernel_size=(7,7), padding='same', activation='relu')(x)
poo1 = MaxPool2D((2,2))(conv1)
fire2 = Fire_Model(poo1, 16, 64, 64,'fire2')
fire3 = Fire_Model(fire2, 16, 64, 64,'fire3')
fire4 = Fire_Model(fire3, 32, 128, 128,'fire4')
pool2 = MaxPool2D((2,2))(fire4)
fire5 = Fire_Model(pool2, 32, 128, 128,'fire5')
fire6 = Fire_Model(fire5, 48, 192, 192,'fire6')
fire7 = Fire_Model(fire6, 48, 192, 192,'fire7')
fire8 = Fire_Model(fire7, 64, 256, 256,'fire8')
pool3 = MaxPool2D((2,2))(fire8)
fire9 = Fire_Model(pool3, 64, 256, 256,'fire9')
dropout1 = Dropout(0.5)(fire9)
conv10 = Conv2D(kernel_size=(1,1), filters=1000, padding='same', activation='relu')(dropout1)
gap = GlobalAveragePooling2D()(conv10)
return gap
因为squeezenet其实并不想后面的其他轻量化网络效果那么好,所以作者只是与alexnet进行了对比,使用ImageNet(Deng等人,2009)(ILSVRC 2012)数据集对图像进行分类,使用AlexNet5和相关的模型压缩结果作为比较的基础来评估squeezenet。
详细的实验对比这里也不过多赘述,主要就是与alexnet不同压缩情况进行对比,有兴趣的朋友下来可以看下原文(原文其实实验对比也不是像mobilenet那样还对比了目标检测的任务,可以看看)
SqueezeNet主要的方法是
3
×
3
3\times3
3×3卷积替换成为
1
×
1
1\times1
1×1卷积,和减少
3
×
3
3\times3
3×3卷积的通道数这两种方法来降低参数量,然后通过下采样后置来提供精度,降低卷积被替换而损失的精度。从参数量来说,SqueezeNet的目的已经达到了。但是从效果上来说,其实SqueezeNet的效果其实并不像后面那几篇一样,有这很惊艳的方法。但是由于他算是真正意义上的第一篇轻量化网络,所以大家对此也算比较包容