《简记SqueezeNet》
对移动端算力有限的情况下对深度学习推理的场景越来越多,模型压缩技术应运而生,同为Deep Compression团队推出的SqueezeNet一经问世就广为流传,奉为经典,到目前为止,这篇论文的影响还是巨大的,在众多深度学习分支目标检测、分割以及分类等任务的模型压缩加速中,依然是重要轻量级backbone选择,如目标检测的SqueezeNet-ssd,甚至基于关键点的CornerNet目标检测算法在其加速版本CornerNet-lite中也是参考了SqueezeNet,并设计了轻量级版本CornerNet-Squeeze。本文旨在全面记录SqueezeNet核心的内容和思想。
Key Words:SqueezeNet1.0、Fire Module、模型压缩、AlexNet
Beijing, 2020
作者:Berkeley、Stanford
Code:https://github.com/forresti/SqueezeNet
Paper链接:https://arxiv.org/abs/1602.07360
模型介绍(模型大小,适用场景,主要成就)
SqueezeNet 发表于ICLR-2017,实现了与AlexNet相同的精度,但只用了1/50的参数量4.8M。且模型的参数量利用Deep Compression最少可以压缩到0.5M,是AlexNet的1/510的参数量。适用于移动端模型部署,下表是两个模型的performance对比。
Architecture | model size | top-1 Accuracy | top-5 Accuracy |
---|---|---|---|
AlexNet | 240MB | 57.2% | 80.3% |
SqueezeNet | 4.8MB | 57.5% | 80.3% |
核心模块
核心模块称为 Fire module,由两部分组成:
-
squeeze module 由 1x1 卷积组成,用于限制输入到3x3卷积的input channel数,类似Bottleneck
-
expand moudule 由 1x1 和 3x3 两部分组成,1x1代替部分3x3,减少9倍运算量
-
squeeze部分的1x1卷积的通道数记为 s 1 x 1 s_{1x1} s1x1,Expand部分1x1卷积和3x3卷积的通道数分布记为 e 1 x 1 e_{1x1} e1x1和 e 3 x 3 e_{3x3} e3x3,在Fire模块中作者建议 s 1 x 1 < e 1 x 1 + e 3 x 3 s_{1x1} < e_{1x1} + e_{3x3} s1x1<e1x1+e3x3,这么做相当于在两个 3x3 卷积的中间加入了瓶颈层,作者的实验中的一个策略是 s 1 x 1 = e 1 x 1 4 = e 3 x 3 4 s_{1x1} = \frac{e_{1x1}}{4}=\frac{e_{3x3}}{4} s1x1=4e1x1=4e3x3
-
思想类似于inceptio,每层都是用ReLU作为激活函数
![](https://i-blog.csdnimg.cn/blog_migrate/c9fdb0d87ffffe5db1ba4509ae9ebaed.jpeg)
核心模块实现方式,基于Pytorch:
class Fire(nn.Module):
def __init__(self, inplanes, squeeze_planes,
expand1x1_planes, expand3x3_planes):
super(Fire, self).__init__()
self.inplanes = inplanes
# squeeze by 1x1
self.squeeze = nn.Conv2d(inplanes, squeeze_planes, kernel_size=1)
self.squeeze_activation = nn.ReLU(inplace=True)
# expand 1x1
self.expand1x1 = nn.Conv2d(squeeze_planes, expand1x1_planes, kernel_size=1)
self.expand1x1_activation = nn.ReLU(inplace=True)
# expand 3x3
self.expand3x3 = nn.Conv2d(squeeze_planes, expand3x3_planes, kernel_size=3, padding=1)
self.expand3x3_activation = nn.ReLU(inplace=True)
def forward(self, x):
# B C H W
x = self.squeeze_activation(self.squeeze(x))
return torch.cat([
self.expand1x1_activation(self.expand1x1(x)),
self.expand3x3_activation(self.expand3x3(x))], 1)
网络架构
整个网络包含10层,利用global_avg_pooling代替了全连接层,也是其大幅度减少参数量的原因之一。
训练过程中,初始学习率设为为0.04,在训练过程中线性降低学习率。
-
第1层为卷积层,缩小输入图像,提取96维特征
-
第2到9层为fire模块,每个模块内部先减少通道数(squeeze)再增加通道数(expand),每两个模块之后,通道数会增加
-
在1、4、8层之后加入降采样的max pooling,缩小尺寸为原来的一半
-
第10层是 1x1 卷积,将特征维度与类别match上
-
最后用一个global average pooling得到这张图的1000类得分,使用softmax函数归一化为概率
论文对比了以下三种不同的实现方式:
![](https://i-blog.csdnimg.cn/blog_migrate/31dc2b691c9e2b3365ce1bb23004499b.jpeg)
三种不同的实现方式的准确率如下:
![](https://i-blog.csdnimg.cn/blog_migrate/7257ccc47c842e53ecb4ce5880b7a42f.jpeg)
结论是中间的只加Simple Bypass的效果最好,和ResNet一样的思想而且不增加参数量
核心思想
论文的核心思想是 Design strategies for CNN architectures with few parameters 即通过设计网络结构使模型具有很少的参数量,从而满足移动端的需要。
提高运算速度有几个可以调整的方向:
- 减少可学习参数的数量;
- 减少整个网络的计算量;
- 模型量化、压缩剪枝等;
其中,减少模型训练和测试时候的计算量,单个step的速度更快;减小模型文件的大小,更利于模型的保存和传输;可学习参数更少,则网络占用的显存也更小。
论文中强调SqueezeNet模型压缩使用了3个策略:
-
将 3x3 卷积替换成 1x1 卷积:通过这一步,一个卷积操作的参数数量减少了9倍;
-
减少 3x3 卷积的通道数:一个 3x3 卷积的计算量是 3x3xMxN (其中 M,N分别是输入Feature Map和输出Feature Map的通道数),作者认为这样一个计算量过于庞大,因此希望将M,N减小以减少参数数量;
-
将下采样后置:作者认为较大的Feature Map含有更多的信息,因此将降采样往分类层移动。注意这样的操作虽然会提升网络的精度,但是它有一个非常严重的缺点:即会增加网络的计算量。
优缺点分析
-
优点:
- 在不大幅降低模型精度的前提下,最大程度的提高运算速度
- SqueezeNet是一个高密小网络,高密小网络的好处,使用更少的参数
- 灵活的FPGA与嵌入式部署
- 无特殊层,可以更方便在框架间迁移
-
缺点:
-
由于参数过少,导致对于复杂问题的表达能力较弱,可以考虑使用模型蒸馏的方式对其优化
-
虽然比AlexNet减少了50倍的参数,但是AlexNet本身全连接节点过于庞大,50倍参数的减少和SqueezeNet的设计并没有太大关系,去掉全连接之后3倍参数的减少更为合适,全连接层的参数多,对性能提升帮助不大,现在往往被pooling代替
-
SqueezeNet得到的模型是5MB左右,0.5MB的模型还要得益于Deep Compression。虽然Deep Compression也是这个团队的文章,但是将0.5这个数列在文章的题目中显然不是很合适
-
总结&思考
-
SqueezeNet与AlexNet的效果相同,但是模型小了50倍,通过Deep Compression压缩会小510倍
-
SqueezeNet的Fire Module由两部分组成即squeeze和expand区别于SE-Net,思想类似于inception,由于caffe不支持单层卷积多种卷积核,所以分别进行1x1 expand和3x3 expand再把结果concat
-
SqueezeNet 延迟下采样,即下采样滞后,论文认为较大的activation map更有利于提高模型的精度。
通常卷积网络的下采样是通过池化或者卷积层中stride>1来实现,下采样是卷积网络中必不可少的,而下采样通常在前面几层,如果网络在前几层就有很大的下采样,则后续大多数层的activation maps都会很小。如果延迟下采样到后面的层,则网络结构中大多数层都会获得较大的activation maps。
-
Fire Module的SR(squeeze ratio)是squeeze层的滤波器个数和expand层的滤波器个数的比值,这个比值越大,说明模型越大,即参数量越多,当然效果更好一些,但论文实验中0.5和1.0的准确率相差很小,vanilla SqueezeNet的SR=0.125,即1:4+4的关系。
-
SqueezeNet一共10层,没有全连接层,而是用global_avg_pool代替了
-
SqueezeNet的各种实现中,加入simple by-pass的效果最好
Q1:为什么这种方式就是延迟下采样,什么样不是延迟下采样?
A1:既然SqueezeNet对标的是AlexNet,那么AlexNet网络的结构如下,可以发现AlexNet在模型的前两层就进行了8倍下采样,然后第5层16倍下采样之后进入全连接层
Q2:减少运算量的一个方式是大卷积核前的Bottleneck(使用1x1的网络结构将高维空间映射到低纬空间的设计有的时候我们也称之为Bottleneck layer),但是bottleneck后维度降低了,加入ReLU函数是不是会丢失信息,如果把squeeze模块后面的激活函数换掉是不是更好呢?
![](https://i-blog.csdnimg.cn/blog_migrate/e1186c361e6a7831a0f409c4dc8d5e2c.jpeg)
A2: 这里需要注意的是,不是维度低经过ReLU一定是不好的,而是Depthwise卷积之后加ReLU是会有信息损失的,如上图Xception论文中已经实验证明了Depthwise卷积后再加ReLU效果会变差,而SqueezeNet中并没有涉及到Depthwise卷积操作。
Q3:SqueezeNet1_1和SqueezeNet1_0的区别是什么?
A3:SqueezeNet1.1相对于1.0把下采样前置了,使其运算量上比1.0少2.4倍,而且准确率没有损失。
参考
https://arxiv.org/abs/1602.07360
https://zhuanlan.zhihu.com/p/49465950
https://www.jianshu.com/p/fdd7d7353c55
https://blog.csdn.net/weixin_44538273/article/details/88852217