08-模型加速之轻量化模型(一)压缩再扩展:SqueezeNet

当物体检测应用到实际工业场景时,模型的参数量是一个十分重要的指标,较小的模型可以高效地进行分布式训练,减小模型更新开销,降低平台体积功耗存储和计算能力的限制,方便在FPGA等边缘平台上部署。
  基于以上几点,Han等人提出了轻量化模型SqueezeNet,其性能与AlexNet相近,而模型参数仅有AlexNet的1/50。在本节将首先介绍SqueezeNet的模型结构,然后对该模型进行总结与分析。

SqueezeNet网络结构
  随着网络结构的逐渐加深,模型的性能有了大幅度提升,但这也增加了网络参数与前向计算的时间。SqueezeNet从网络结构优化的角度出发,使用了如下3点策略来减少网络参数,提升网络性能:
  1.)使用1×1卷积来替代部分的3×3卷积,这也是之前介绍过的常用的策略,可以将参数减少为原来的1/9。
  2.)减少输入通道的数量,这一点也是通过1×1卷积来实现,通道数量的减少可以使后续卷积核的数量也相应地减少。
  3.)在减少通道数之后,使用多个尺寸的卷积核进行计算,以保留更多的信息,提升分类的准确率。
  基于以上3点,SqueezeNet提出了如图7.3所示的基础模块,称之为Fire Module。图中输入特征尺寸为H×W,通道数为M,依次经过一个Squeeze层与Expand层,然后进行融合处理.

 

 每一个模块的具体意义如下:

·SqueezeNet层:首先使用1×1卷积进行降维,特征图的尺寸不变,这里的S1小于M,达到了压缩的目的。
Expand层:并行地使用1×1卷积与3×3卷积获得不同感受野的特征图,有点类似Inception模块,达到扩展的目的。
·Concat:对得到的两个特征图进行通道拼接,作为最终输出。
·模块中的S1、e1与e2都是可调的超参,Fire Module默认 e1=e2=4×S1。激活函数使用了ReLU函数。
v>
下面使用PyTorch来搭建一个单独的SqueezeNet的Fire模块,新建一个squeezenet_fire.py文件:
import torch
from torch import nn

class Fire(nn.Module):
    
    def __init__(self, inplanes, squeeze_planes, expand_planes):
        super(Fire, self).__init__()
        # squeeze_planes为1
        self.conv1 = nn.Conv2d(inplanes, squeeze_planes, kernel_size=1, stride=1)
        self.bn1 = nn.BatchNorm2d(squeeze_planes)
        self.relu1 = nn.ReLU(inplace=True)
        
        # expand_planes为e1和e2
        self.conv2 = nn.Conv2d(squeeze_planes, expand_planes, kernel_size=1, stride=1)
        self.bn2 = nn.BatchNorm2d(expand_planes)
        
        self.conv3 = nn.Conv2d(squeeze_planes, expand_planes, kernel_size=3, stride=1, padding=1)
        self.bn3 = nn.BatchNorm2d(expand_planes)
        self.relu2 = nn.ReLU(inplace=True)
        
    def forward(self, x):
        
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.relu1(x)
        
        out1 = self.conv2(x)
        out1 = self.bn2(out1)
         
        out2 = self.conv3(x)
        out2 = self.bn3(out2)
        
        # 对两个分支的输出进行Concat处理
        out = torch.cat([out1, out2], 1)        
        out = self.relu2(out)
        
        return out
View Code

test.py

import torch
from SqueezeNet import Fire

fire_block = Fire(512, 128, 512).cuda()
print(fire_block)

input = torch.randn(10, 512, 28, 28).cuda()
output = fire_block(input)

print(output.shape)
View Code

Fire(
  (conv1): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1))
  (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (relu1): ReLU(inplace=True)
  (conv2): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1))
  (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (conv3): Conv2d(128, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (relu2): ReLU(inplace=True)
)
torch.Size([10, 1024, 28, 28])

  基于Fire Module,SqueezeNet的网络结构如图7.4所示。输入图像首先送入Conv1,得到通道数为96的特征图,然后依次使用8个Fire Module,通道数也逐渐增加。图7.4中横线上的值代表了通道数。最后一个卷积为Conv 10,输入通道数为N的特征图,N代表需要物体的类别数。

  SqueezeNet一共使用了3个Pool层,前两个是Max Pooling层,步长为2,最后一个为全局平均池化,利用该层可以取代全连接层,减少了计算量。

SqueezeNet总结
SqueezeNet是一个精心设计的轻量化网络,使用常见的模型压缩技术,如SVD、剪枝和量化等,可以进一步压缩该模型的大小。例如,使用Deep Compresion技术对其进行压缩时,在几乎不损失性能的前提
下,模型大小可以压缩到0.5MB。
基于其轻量化的特性,SqueezeNet可以广泛地应用到移动端,促进了物体检测技术在移动端的部署与应用。

 

 

posted @ 2022-11-14 16:01  赵家小伙儿  阅读(154)  评论(0编辑  收藏  举报