[ 轻量级网络 ] 经典网络模型1——SqueezeNet 详解与复现


🤵 AuthorHorizon John

编程技巧篇各种操作小结

🎇 机器视觉篇会变魔术 OpenCV

💥 深度学习篇简单入门 PyTorch

🏆 神经网络篇经典网络模型

💻 算法篇再忙也别忘了 LeetCode


🚀 SqueezeNet

SqueezeNet 在 ImageNet 上实现与 AlexNet 同等级别的精度,但 参数少了50倍

通过模型压缩技术,实现了 SqueezeNet 模型压缩到小于0.5MB,相比 AlexNet 模型小了510倍


🔗 论文地址:SqueezeNet: AlexNet-level accuracy with 50x fewer parameters and <0.5MB model size


SqueezeNet architectural dimensions

在这里插入图片描述


🚀 SqueezeNet 详解

🎨 SqueezeNet 网络结构

🚩 模型轻量化优势

近年来,深度卷积神经网络(CNNs)的研究主要集中在 提高准确性 方面 ;
对于 同等精度级别 ,通常存在着多种 CNN 网络结构 ;
但是在同样的精度下,更小的 CNN 至少有三方面的 优势

(1)模型训练:更小的 CNN 在分布式训练中需要更少的跨服务器通信 ;
(2)模型导出:更小的 CNN 需要更少的带宽来将新模型从云导出到自动驾驶汽车 ;
(3)模型部署:较小的 CNN 更适合部署在FPGA等内存有限的硬件上 ;


🚩 模型压缩方法

(1)奇异值分解(singular value decomposition (SVD));
(2)网络剪枝(Network Pruning);
(3)深度压缩(Deep Compression);


🚩 Fire Module

设计目标:在保证同等级别准确率的同时,实现用更少参数的 CNN结构 ;

使用的策略:

(1)使用 1 x 1 卷积滤波器代替 3 x 3 卷积 (参数量少9倍);
(2)使用3x3个滤波器减少输入通道的数量,利用 squeeze layers 实现 ;
(3)在网络后期进行下采样操作,可以使卷积层有更大的激活特征图 ;

策略(1)(2)用于减少CNN参数量,策略(3)用于在有限的参数量下最大化CNN准确率;


Fire Module 卷积滤波器结构

在这里插入图片描述


Fire Module 组成: 主要包括 挤压层(squeeze) 和 拓展层(expand) ;
squeeze :只有 1 x 1 卷积滤波器 ;
expand :混合有 1 x 1 和 3 x 3 卷积滤波器 ;

并引入了三个调节维度的 超参数
S1x1 :squeeze 中 1 x 1 卷积滤波器个数 ;
e1x1 :expand 中 1 x 1 卷积滤波器个数 ;
e3x3 :expand 中 3 x 3 卷积滤波器个数 ;

上图中, S1x1 = 3 ,e1x1 = 4 ,e3x3 = 4 ;

S1x1 < ( e1x1 + e3x3 )时,squeeze 可以将输入通道的数量限制到 3 x 3 卷积滤波器 ;


其他细节:

(1)为使 1 x 1 和 3 x 3 卷积滤波器的输出激活具有相同的高度和宽度,在 3 x 3 卷积滤波器操作中添加一个1像素的零填充边界 ;
(2)使用 ReLU 函数作为挤压层(squeeze) 和 拓展层(expand)的激活函数 ;
(3)在 fire9 模块后应用了 50%的 Dropout ;
(4)在 SqueezeNet 中没有 全连接层 ,设计灵感来源于 NiN 网络 ;
(5)训练 SqueezeNet 时,学习率设置为 0.04 开始,整个训练过程使用线性降低学习率 ;


🚩 SqueezeNet 结构框图

左图:SqueezeNet ;
中图:带简单旁路的 SqueezeNet ;
右图:带复杂旁路的 SqueezeNet ;


在这里插入图片描述


🎨 SqueezeNet 结构探索

结构探索主要分为两个部分:

🚩 微观结构探索

微观结构探索( 每个模块层的维度和配置 ):

使用了以下超参数进行实验分析:

Squeeze Ratio(挤压比,SR): S1x1 = SR * ( e1x1 + e3x3 );

Percentage of 3x3 filters :从 “mostly 1x1” 到 “mostly 3x3” 进行测试 ;

在这里插入图片描述


🚩 宏观结构探索

宏观结构探索( 模块与其他层之间的高层次端到端结构 ):

作者通过前面所说到的三个结构对 SqueezeNet 的宏观结构进行了实验探索 ;
( SqueezeNet - 带简单旁路的 SqueezeNet - 带复杂旁路的 SqueezeNet )

作者使用了三种宏观架构对 SqueezeNet 进行了训练,并对它们的准确率和模型大小进行了对比 ;

有趣的是,简单旁路比复杂旁路具有更高的精度提高 ;

在这里插入图片描述


🚀 SqueezeNet 复现

# Here is the code :

import torch
import torch.nn as nn
from torchinfo import summary


class Fire(nn.Module):
    def __init__(self, in_channels, squeeze_channels, expand1x1_channels, expand3x3_channels):
        super(Fire, self).__init__()
        self.in_channels = in_channels
        self.squeeze = nn.Conv2d(in_channels, squeeze_channels, kernel_size=1)
        self.squeeze_activation = nn.ReLU(inplace=True)
        self.expand1x1 = nn.Conv2d(squeeze_channels, expand1x1_channels,
                                   kernel_size=1)
        self.expand1x1_activation = nn.ReLU(inplace=True)
        self.expand3x3 = nn.Conv2d(squeeze_channels, expand3x3_channels,
                                   kernel_size=3, padding=1)
        self.expand3x3_activation = nn.ReLU(inplace=True)

    def forward(self, x):
        x = self.squeeze_activation(self.squeeze(x))
        e1 = self.expand1x1_activation(self.expand1x1(x))
        e2 = self.expand3x3_activation(self.expand3x3(x))
        out = torch.cat([e1, e2], 1)
        return out


class SqueezeNet(nn.Module):
    def __init__(self, version='1_0', num_classes=1000):
        super(SqueezeNet, self).__init__()
        self.num_classes = num_classes
        if version == '1_0':
            self.features = nn.Sequential(
                nn.Conv2d(3, 96, kernel_size=7, stride=2),
                nn.ReLU(inplace=True),
                nn.MaxPool2d(kernel_size=3, stride=2, ceil_mode=True),
                Fire(96, 16, 64, 64),
                Fire(128, 16, 64, 64),
                Fire(128, 32, 128, 128),
                nn.MaxPool2d(kernel_size=3, stride=2, ceil_mode=True),
                Fire(256, 32, 128, 128),
                Fire(256, 48, 192, 192),
                Fire(384, 48, 192, 192),
                Fire(384, 64, 256, 256),
                nn.MaxPool2d(kernel_size=3, stride=2, ceil_mode=True),
                Fire(512, 64, 256, 256),
            )

        elif version == '1_1':
            self.features = nn.Sequential(
                nn.Conv2d(3, 64, kernel_size=3, stride=2),
                nn.ReLU(inplace=True),
                nn.MaxPool2d(kernel_size=3, stride=2, ceil_mode=True),
                Fire(64, 16, 64, 64),
                Fire(128, 16, 64, 64),
                nn.MaxPool2d(kernel_size=3, stride=2, ceil_mode=True),
                Fire(128, 32, 128, 128),
                Fire(256, 32, 128, 128),
                nn.MaxPool2d(kernel_size=3, stride=2, ceil_mode=True),
                Fire(256, 48, 192, 192),
                Fire(384, 48, 192, 192),
                Fire(384, 64, 256, 256),
                Fire(512, 64, 256, 256),
            )

        final_conv = nn.Conv2d(512, self.num_classes, kernel_size=1)
        self.classifier = nn.Sequential(
            nn.Dropout(p=0.5),
            final_conv,
            nn.ReLU(inplace=True),
            nn.AdaptiveAvgPool2d((1, 1))
        )

    def forward(self, x):
        x = self.features(x)
        x = self.classifier(x)
        out = torch.flatten(x, 1)
        return out


def _squeezenet(version, **kwargs):
    model = SqueezeNet(version, **kwargs)
    return model


def squeezenet1_0(**kwargs):
    return _squeezenet('1_0', **kwargs)


def squeezenet1_1(**kwargs):
    return _squeezenet('1_1', **kwargs)


def test():
    net = squeezenet1_0()
    y = net(torch.randn(1, 3, 224, 224))
    print(y.size())
    summary(net, (1, 3, 224, 224))


if __name__ == '__main__':
    test()

输出结果:

torch.Size([1, 1000])
==========================================================================================
Layer (type:depth-idx)                   Output Shape              Param #
==========================================================================================
SqueezeNet                               --                        --
├─Sequential: 1-1                        [1, 512, 13, 13]          --
│    └─Conv2d: 2-1                       [1, 96, 109, 109]         14,208
│    └─ReLU: 2-2                         [1, 96, 109, 109]         --
│    └─MaxPool2d: 2-3                    [1, 96, 54, 54]           --
│    └─Fire: 2-4                         [1, 128, 54, 54]          --
│    │    └─Conv2d: 3-1                  [1, 16, 54, 54]           1,552
│    │    └─ReLU: 3-2                    [1, 16, 54, 54]           --
│    │    └─Conv2d: 3-3                  [1, 64, 54, 54]           1,088
│    │    └─ReLU: 3-4                    [1, 64, 54, 54]           --
│    │    └─Conv2d: 3-5                  [1, 64, 54, 54]           9,280
│    │    └─ReLU: 3-6                    [1, 64, 54, 54]           --
│    └─Fire: 2-5                         [1, 128, 54, 54]          --
│    │    └─Conv2d: 3-7                  [1, 16, 54, 54]           2,064
│    │    └─ReLU: 3-8                    [1, 16, 54, 54]           --
│    │    └─Conv2d: 3-9                  [1, 64, 54, 54]           1,088
│    │    └─ReLU: 3-10                   [1, 64, 54, 54]           --
│    │    └─Conv2d: 3-11                 [1, 64, 54, 54]           9,280
│    │    └─ReLU: 3-12                   [1, 64, 54, 54]           --
│    └─Fire: 2-6                         [1, 256, 54, 54]          --
│    │    └─Conv2d: 3-13                 [1, 32, 54, 54]           4,128
│    │    └─ReLU: 3-14                   [1, 32, 54, 54]           --
│    │    └─Conv2d: 3-15                 [1, 128, 54, 54]          4,224
│    │    └─ReLU: 3-16                   [1, 128, 54, 54]          --
│    │    └─Conv2d: 3-17                 [1, 128, 54, 54]          36,992
│    │    └─ReLU: 3-18                   [1, 128, 54, 54]          --
│    └─MaxPool2d: 2-7                    [1, 256, 27, 27]          --
│    └─Fire: 2-8                         [1, 256, 27, 27]          --
│    │    └─Conv2d: 3-19                 [1, 32, 27, 27]           8,224
│    │    └─ReLU: 3-20                   [1, 32, 27, 27]           --
│    │    └─Conv2d: 3-21                 [1, 128, 27, 27]          4,224
│    │    └─ReLU: 3-22                   [1, 128, 27, 27]          --
│    │    └─Conv2d: 3-23                 [1, 128, 27, 27]          36,992
│    │    └─ReLU: 3-24                   [1, 128, 27, 27]          --
│    └─Fire: 2-9                         [1, 384, 27, 27]          --
│    │    └─Conv2d: 3-25                 [1, 48, 27, 27]           12,336
│    │    └─ReLU: 3-26                   [1, 48, 27, 27]           --
│    │    └─Conv2d: 3-27                 [1, 192, 27, 27]          9,408
│    │    └─ReLU: 3-28                   [1, 192, 27, 27]          --
│    │    └─Conv2d: 3-29                 [1, 192, 27, 27]          83,136
│    │    └─ReLU: 3-30                   [1, 192, 27, 27]          --
│    └─Fire: 2-10                        [1, 384, 27, 27]          --
│    │    └─Conv2d: 3-31                 [1, 48, 27, 27]           18,480
│    │    └─ReLU: 3-32                   [1, 48, 27, 27]           --
│    │    └─Conv2d: 3-33                 [1, 192, 27, 27]          9,408
│    │    └─ReLU: 3-34                   [1, 192, 27, 27]          --
│    │    └─Conv2d: 3-35                 [1, 192, 27, 27]          83,136
│    │    └─ReLU: 3-36                   [1, 192, 27, 27]          --
│    └─Fire: 2-11                        [1, 512, 27, 27]          --
│    │    └─Conv2d: 3-37                 [1, 64, 27, 27]           24,640
│    │    └─ReLU: 3-38                   [1, 64, 27, 27]           --
│    │    └─Conv2d: 3-39                 [1, 256, 27, 27]          16,640
│    │    └─ReLU: 3-40                   [1, 256, 27, 27]          --
│    │    └─Conv2d: 3-41                 [1, 256, 27, 27]          147,712
│    │    └─ReLU: 3-42                   [1, 256, 27, 27]          --
│    └─MaxPool2d: 2-12                   [1, 512, 13, 13]          --
│    └─Fire: 2-13                        [1, 512, 13, 13]          --
│    │    └─Conv2d: 3-43                 [1, 64, 13, 13]           32,832
│    │    └─ReLU: 3-44                   [1, 64, 13, 13]           --
│    │    └─Conv2d: 3-45                 [1, 256, 13, 13]          16,640
│    │    └─ReLU: 3-46                   [1, 256, 13, 13]          --
│    │    └─Conv2d: 3-47                 [1, 256, 13, 13]          147,712
│    │    └─ReLU: 3-48                   [1, 256, 13, 13]          --
├─Sequential: 1-2                        [1, 1000, 1, 1]           --
│    └─Dropout: 2-14                     [1, 512, 13, 13]          --
│    └─Conv2d: 2-15                      [1, 1000, 13, 13]         513,000
│    └─ReLU: 2-16                        [1, 1000, 13, 13]         --
│    └─AdaptiveAvgPool2d: 2-17           [1, 1000, 1, 1]           --
==========================================================================================
Total params: 1,248,424
Trainable params: 1,248,424
Non-trainable params: 0
Total mult-adds (M): 823.27
==========================================================================================
Input size (MB): 0.60
Forward/backward pass size (MB): 34.77
Params size (MB): 4.99
Estimated Total Size (MB): 40.37
==========================================================================================


  • 8
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Horizon John

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值