查看原文
其他

《Computer vision》笔记-SqueezeNet(6)

石文化 机器学习算法工程师 2021-12-31

       

作者: 石文华          

编辑: 田   旭          




01

概述


具有相同精度的CNN模型,较小的CNN架构至少有以下三个优点: 


  1. 在分布式训练期间,较小的CNN需要较少的服务器通信。 

  2. 较小的CNN可以减少从云端下载模型的带宽。 

  3. 较小的CNN更适合部署在FPGA和内存有限的硬件上。Squeezeet是一种小型化的CNN架构,具备上述提到的几点优势,SqueezeNet在ImageNet上实现了AlexNet级精度,参数却减少了50倍,是AlexNet的1/510。 此外,通过模型压缩技术,我们能够将SqueezeNet压缩到小于0.5MB(比AlexNet小510倍)。


02

设计此网络采用的策略 


  1. 用1x1卷积核替换3x3卷积核,通道数相同的情况下,1x1的卷积核参数要比3x3的卷积核减少9倍。

  2. 减少输入特征图的通道数,因为普通卷积的卷积核是:长x宽x通道,使用瓶颈层减少通道数的话参数就自然少了很多。 

  3. 延迟下采样,以使卷积层具有较大的激活的特征图,更大的激活图保留了更多的信息,可以提供更高的分类准确率。



03

网络的核心模块(Fire模块) 


首先是squeeze 卷积层组成(只有1x1过滤器),接着是由1x1和3x3两种卷积都有的expand层,如下图所示:


上图中,s1x1 = 3,e1x1 = 4,e3x3 = 4,s1x1表示的是squeeze层中1x1卷积的数量,e1x1表示的是expand层中1x1卷积的数量,e3x3表示的是expand层中3x3卷积的数量。它们三个是超参数,当我们使用Fire模块时,我们将s1x1设置为小于(e1x1 + e3x3),使得squeeze层有助于限制3x3过滤器的输入通道数量,也就是expand层的输入特征图的通道数。



04

网络结构  


我们现在描述SqueezeNet CNN架构。 如下图可知(中图和右图使用了ResNet网络中的shortcut作为提升策略),SqueezeNet 从一个独立的卷积层(conv1)开始,然后是8个Fire模块(fire2-9), 最后一个卷积层(conv10)。 从网络的开始到结束,逐渐增加每个Fire模块的过滤器数量 。根据策略3,需要延迟下采样,所以SqueezeNet分别在图层conv1,fire4,fire8和conv10以步幅2执行最大池化,尽可能使卷积层具有较大的特征图;


 

有关SqueezeNet的详细信息和设计选择:


  1. 1x1和3x3卷积核的输出激活具有相同的高度和宽度,因此需要对3x3卷积前的特征图进行填充,使输出特征图跟输入特征图大小相同。 

  2. Fire模块里面的squeeze层和expand层采用Relu函数进行激

  3. 在Fire9模块之后应用Dropout,比例为50%, 

  4. 没有全连接层,而是采用全局平均池化。 

  5. 在训练SqueezeNet时,学习率从0.04开始,并且在整个训练中线性降低学习率。 




05

超参数  


在SqueezeNet中,每一个Fire module有3个维度的超参数,即s1x1 、 e1x1 和 e3x3。SqueezeNet一共有8个Fire modules,即一共24个超参数。下面两个是需要注意的比例关系: 


  1. SR:压缩比,即the squeeze ratio ,为squeeze层中filter个数除以Fire module中filter总个数得到的一个比例。 

  2. pct3x3:在expand层有1x1和3x3两种卷积,这里定义的参数是3x3卷积个占卷积总个数的比例。 


分别测试SR与模型准确率以及模型大小的关系、pct3x3与模型准确率以及模型大小的关系。如下图可知,左图给出了压缩比(SR)的影响。压缩比小于0.25时,正确率开始显著下降。右图给出了3∗3卷积比例的影响,在比例小于25%时,正确率开始显著下降,此时模型大小约为原先的44%。超过50%后,模型大小显著增加,但是正确率不再上升。




06

代码如下  



import keras
from keras.models import Model
from keras.layers import Input,Dense,Activation,Dropout,Flatten,GlobalAveragePooling2D
from keras.layers import Conv2D,MaxPool2D,Concatenate
def SqueezeNet(img_w,img_h,n_channels):
   #输入
   input_shape=(img_w,img_h,n_channels)
   #输入层
   img_input=Input(shape=input_shape,name='img_input')
   #第一个卷积层
   conv1=Conv2D(filters=96,kernel_size=(7,7),strides=(2,2),padding='same',activation='relu',name='conv1')(img_input)
   maxpool1=MaxPool2D(pool_size=(3,3),strides=(2,2),name='maxpool1')(conv1)
   #第一组fire
   fire1_squee=Conv2D(filters=16,kernel_size=(1,1),strides=(1,1),padding='same',activation='relu',name='fire1_squee')(maxpool1)
   fire1_expand1=Conv2D(filters=64,kernel_size=(1,1),strides=(1,1),padding='same',activation='relu',name='fire1_expand1')(fire1_squee)
   fire1_expand3=Conv2D(filters=64,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu',name='fire1_expand3')(fire1_squee)
   fire1=Concatenate(axis=-1)([fire1_expand1,fire1_expand3]) #合并
   #第二组fire
   fire2_squee=Conv2D(filters=16,kernel_size=(1,1),strides=(1,1),padding='same',activation='relu',name='fire2_squee')(fire1)
   fire2_expand1=Conv2D(filters=64,kernel_size=(1,1),strides=(1,1),padding='same',activation='relu',name='fire2_expand1')(fire2_squee)
   fire2_expand3=Conv2D(filters=64,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu',name='fire2_expand3')(fire2_squee)
   fire2=Concatenate(axis=-1)([fire2_expand1,fire2_expand3]) #合并
   #第三组fire
   fire3_squee=Conv2D(filters=32,kernel_size=(1,1),strides=(1,1),padding='same',activation='relu',name='fire3_squee')(fire2)
   fire3_expand1=Conv2D(filters=128,kernel_size=(1,1),strides=(1,1),padding='same',activation='relu',name='fire3_expand1')(fire3_squee)
   fire3_expand3=Conv2D(filters=128,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu',name='fire3_expand3')(fire3_squee)
   fire3=Concatenate(axis=-1)([fire3_expand1,fire3_expand3]) #合并
   #下采样
   maxpool2=MaxPool2D(pool_size=(3,3),strides=(2,2),name='maxpool2')(fire3)
   #第四组fire
   fire4_squee=Conv2D(filters=32,kernel_size=(1,1),strides=(1,1),padding='same',activation='relu',name='fire4_squee')(maxpool2)
   fire4_expand1=Conv2D(filters=128,kernel_size=(1,1),strides=(1,1),padding='same',activation='relu',name='fire4_expand1')(fire4_squee)
   fire4_expand3=Conv2D(filters=128,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu',name='fire4_expand3')(fire4_squee)
   fire4=Concatenate(axis=-1)([fire4_expand1,fire4_expand3]) #合并
   #第五组fire
   fire5_squee=Conv2D(filters=48,kernel_size=(1,1),strides=(1,1),padding='same',activation='relu',name='fire5_squee')(fire4)
   fire5_expand1=Conv2D(filters=192,kernel_size=(1,1),strides=(1,1),padding='same',activation='relu',name='fire5_expand1')(fire5_squee)
   fire5_expand3=Conv2D(filters=192,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu',name='fire5_expand3')(fire5_squee)
   fire5=Concatenate(axis=-1)([fire5_expand1,fire5_expand3]) #合并
   #第六组fire
   fire6_squee=Conv2D(filters=48,kernel_size=(1,1),strides=(1,1),padding='same',activation='relu',name='fire6_squee')(fire5)
   fire6_expand1=Conv2D(filters=192,kernel_size=(1,1),strides=(1,1),padding='same',activation='relu',name='fire6_expand1')(fire6_squee)
   fire6_expand3=Conv2D(filters=192,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu',name='fire6_expand3')(fire6_squee)
   fire6=Concatenate(axis=-1)([fire6_expand1,fire6_expand3]) #合并
   #第七组fire
   fire7_squee=Conv2D(filters=64,kernel_size=(1,1),strides=(1,1),padding='same',activation='relu',name='fire7_squee')(fire6)
   fire7_expand1=Conv2D(filters=256,kernel_size=(1,1),strides=(1,1),padding='same',activation='relu',name='fire7_expand1')(fire7_squee)
   fire7_expand3=Conv2D(filters=256,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu',name='fire7_expand3')(fire7_squee)
   fire7=Concatenate(axis=-1)([fire7_expand1,fire7_expand3]) #合并
   #下采样
   maxpool3=MaxPool2D(pool_size=(3,3),strides=(2,2),name='maxpool3')(fire7)
   #第八组fire
   fire8_squee=Conv2D(filters=64,kernel_size=(1,1),strides=(1,1),padding='same',activation='relu',name='fire8_squee')(maxpool3)
   fire8_expand1=Conv2D(filters=256,kernel_size=(1,1),strides=(1,1),padding='same',activation='relu',name='fire8_expand1')(fire8_squee)
   fire8_expand3=Conv2D(filters=256,kernel_size=(3,3),strides=(1,1),padding='same',activation='relu',name='fire8_expand3')(fire8_squee)
   fire8=Concatenate(axis=-1)([fire8_expand1,fire8_expand3]) #合并
   conv2=Conv2D(filters=2,kernel_size=(1,1),strides=(1,1),padding='same',activation='relu',name='conv2')(fire8)
   Gap=GlobalAveragePooling2D()(conv2)
   model=Model(img_input,Gap)
   return model
model=SqueezeNet(224,224,3)
model.summary()



输出结果如下:




参考

https://blog.csdn.net/csdnldp/article/details/78648543 
https://arxiv.org/pdf/1602.07360.pdf



 

END




往期回顾之作者石文华

【1】《Computer vision》笔记-VGGNet(2)

【2】《Computer vision》笔记-AlexNet(1)

【3】 干货|(DL~3)deep learning中一些层的介绍

【4】 干货|(DL~2)一看就懂的卷积神经网络

【5】 基础|认识机器学习中的逻辑回归、决策树、神经网络算法

【6】 (Keras/监督学习)15分钟搞定最新深度学习车牌OCR









机器学习算法工程师


                            一个用心的公众号

长按,识别,加关注

进群,学习,得帮助

你的关注,我们的热度,

我们一定给你学习最大的帮助




\

你点的每个赞,我都认真当成了喜欢


: . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存