MicroNet关键代码解读(Micro-block与Dynamic Shift-Max的实现代码)

news2024/9/20 1:03:32

论文地址:https://arxiv.org/pdf/2011.12289
中文翻译:https://hpg123.blog.csdn.net/article/details/141772832?spm=1001.2014.3001.5502
发表时间:2022
项目地址:https://github.com/liyunsheng13/micronet

在MicroNet论文中提出了Micro-block与Dynamic Shift-Max,这里对其代码实现进行深入分析。最终结论是Micro-block的定义实现十分混乱,MicroNet比Moblienet强主要是深度分离卷积的性能没有充分挖掘到位,可以替换成conv1xk_group+convkx1_group的组合,从而在低flop的约束条件下实现了5个点左右的提升;另外一点是使用了带参数的激活函数,同时激活函数中提供了group间的数据交互,故再次提升了模型精度。

1、Micro-block

1.1 模块定义

在MicroNet论文中一共有Micro-Block-A、Micro-Block-B、Micro-Block-C三种模块设计。

Micro-Block-A 采用微因式点卷积和深度卷积的精简组合(见图 2-右),它主要适用在模型的浅层。需要注意的是,微因数深度卷积扩大了通道数,而分组自适应卷积则压缩了通道数。

Micro-Block-B 用于连接 Micro-Block-A 和 Micro-Block-C。与 Micro-Block-A 不同的是,它使用的是全 Micro-Factorized 点式卷积,其中包括两个组自适应卷积(如图 5b 所示)。前者压缩了通道数,后者则扩大了通道数。

微块-C(如图 5c 所示)使用了常规组合。 深度卷积和点卷积的正则组合。它用于模型的深层,因为与精简组合相比,它在通道融合(点上)上花费的计算量更大。
在这里插入图片描述

基于下列图片可以发现,Micro-block虽然使用了group conv,但基于Φ函数的shitf操作,是可以实现数据在不同group间的交互。
在这里插入图片描述

1.2 模块效果

首先通过论文中的表1可以发现Micro-Block-B 是一直只有一个,且介于A与C之间。
在这里插入图片描述
在block级别的对比中,可以发现Micro-block具备明显的涨点效果。
在这里插入图片描述
在与MobileNet的对比中可以发现在没有Shift-Max操作时,Micro就可以比Mobile高6个点了。这主要是因为MobileNet只是将conv拆解为深度分离卷积与点卷积,conv3x3的操作没有拆解;而在Micro中,将conv拆解为了conv3x1_group+full_group_connect+conv1x3_group,这种拆解相比MobileNet更高效。同时在保证相同flop的时候能具备更深的网络结构。
在这里插入图片描述

1.3 代码实现

以下代码推测是Micro-Block-A 的实现,可以发现是 kx1+bn+1xk+ChannelShuffle操作,对比DepthSpatialSepConv函数,发现实现上高度接近。

class ChannelShuffle(nn.Module):
    def __init__(self, groups):
        super(ChannelShuffle2, self).__init__()
        self.groups = groups

    def forward(self, x):
        b, c, h, w = x.size()

        channels_per_group = c // self.groups

        # reshape
        x = x.view(b, self.groups, channels_per_group, h, w)

        x = torch.transpose(x, 1, 2).contiguous()
        out = x.view(b, -1, h, w)

        return out

######################################################################3
# part 3: new block
#####################################################################3

class SpatialSepConvSF(nn.Module):
    def __init__(self, inp, oups, kernel_size, stride):
        super(SpatialSepConvSF, self).__init__()

        oup1, oup2 = oups
        self.conv = nn.Sequential(
            nn.Conv2d(inp, oup1,
                (kernel_size, 1),
                (stride, 1),
                (kernel_size//2, 0),
                bias=False, groups=1
            ),
            nn.BatchNorm2d(oup1),
            nn.Conv2d(oup1, oup1*oup2,
                (1, kernel_size),
                (1, stride),
                (0, kernel_size//2),
                bias=False, groups=oup1
            ),
            nn.BatchNorm2d(oup1*oup2),
            ChannelShuffle(oup1),
        )

    def forward(self, x):
        out = self.conv(x)
        return out

在追溯DYMicroBlock代码中并为明确发现Micro-Block-A、Micro-Block-B、Micro-Block-C的定义。但发现了不少ChannelShuffle操作,这表明在conv_group模型中,通道间的交互是不可少的。
在这里插入图片描述

2、Dynamic Shift-Max

2.1 模块定义

在MicroNet中提到了一种新的激活函数–动态 Shift-Max函数,以增强非线性。它能动态地将输入特征图与它的环形组移动进行动态融合,以group为移动单位进行移动。Dynamic Shift-Max 还能
加强组之间的联系。这是对Micro-Factorized pointwise convolution的补充,侧重于组内连接的互补性。

其具体作用如图4所示,对channel以group为单位进行循环移动,并基于fc映射后动态输出max值。
在这里插入图片描述

2.2 模块效果

Shift-Max模块的效果如下所示,可以看到相比于不加之前,top1 acc提升了2.7%,而当使用dynamic shift-max后,top1 acc相比于不加提升了6.8%。可以发现Shift-Max模块是MicroNet的涨点关键。其对于分组卷积提供了group间的特征互动,同时相比于普通的激活函数,其是带可训练参数的模型。
在这里插入图片描述
同时在与其他同类型激活函数对比中,可以发现使用Dynamic Shift-Max时更加有效;同时Dynamic ReLU也证明了在低flop模型中也具有显著的作用,只是在group conv中略有不殆。
在这里插入图片描述

2.3 代码实现

class DYShiftMax(nn.Module):
    def __init__(self, inp, oup, reduction=4, act_max=1.0, act_relu=True, init_a=[0.0, 0.0], init_b=[0.0, 0.0], relu_before_pool=False, g=None, expansion=False):
        super(DYShiftMax, self).__init__()
        self.oup = oup
        self.act_max = act_max * 2
        self.act_relu = act_relu
        self.avg_pool = nn.Sequential(
                nn.ReLU(inplace=True) if relu_before_pool == True else nn.Sequential(),
                nn.AdaptiveAvgPool2d(1)
            )

        self.exp = 4 if act_relu else 2
        self.init_a = init_a
        self.init_b = init_b

        # determine squeeze
        squeeze = _make_divisible(inp // reduction, 4)
        if squeeze < 4:
            squeeze = 4
        print('reduction: {}, squeeze: {}/{}'.format(reduction, inp, squeeze))
        print('init-a: {}, init-b: {}'.format(init_a, init_b))

        self.fc = nn.Sequential(
                nn.Linear(inp, squeeze),
                nn.ReLU(inplace=True),
                nn.Linear(squeeze, oup*self.exp),
                h_sigmoid()
        )
        if g is None:
            g = 1
        self.g = g[1]
        if self.g !=1  and expansion:
            self.g = inp // self.g
        print('group shuffle: {}, divide group: {}'.format(self.g, expansion))
        self.gc = inp//self.g
        index=torch.Tensor(range(inp)).view(1,inp,1,1)
        index=index.view(1,self.g,self.gc,1,1)
        indexgs = torch.split(index, [1, self.g-1], dim=1)
        indexgs = torch.cat((indexgs[1], indexgs[0]), dim=1)
        indexs = torch.split(indexgs, [1, self.gc-1], dim=2)
        indexs = torch.cat((indexs[1], indexs[0]), dim=2)
        self.index = indexs.view(inp).type(torch.LongTensor)
        self.expansion = expansion

    def forward(self, x):
        x_in = x
        x_out = x

        b, c, _, _ = x_in.size()
        y = self.avg_pool(x_in).view(b, c)
        y = self.fc(y).view(b, self.oup*self.exp, 1, 1)
        y = (y-0.5) * self.act_max

        n2, c2, h2, w2 = x_out.size()
        x2 = x_out[:,self.index,:,:]

        if self.exp == 4:
            a1, b1, a2, b2 = torch.split(y, self.oup, dim=1)

            a1 = a1 + self.init_a[0]
            a2 = a2 + self.init_a[1]

            b1 = b1 + self.init_b[0]
            b2 = b2 + self.init_b[1]

            z1 = x_out * a1 + x2 * b1
            z2 = x_out * a2 + x2 * b2

            out = torch.max(z1, z2)

        elif self.exp == 2:
            a1, b1 = torch.split(y, self.oup, dim=1)
            a1 = a1 + self.init_a[0]
            b1 = b1 + self.init_b[0]
            out = x_out * a1 + x2 * b1

        return out

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2095857.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

查文献技巧,数模国赛必须掌握!

参加数学建模竞赛&#xff0c;拿到题目后第一件事就是去查文献&#xff0c;把题目的背景知识看懂。本文介绍查文献的一些技巧。 先看硕博士论文 硕博论文会对研究的问题有详细的背景和基础知识介绍&#xff0c;可帮助我们快速理解题目。 有个经典段子&#xff1a;学士、硕士…

对字符、字符串的研究

每日一背 C的字符串很特殊 //返回字符 char test2() {return p; } //返回整数 int test2() {return 90; } 其实字符串本就是很特殊的存在。字符型、整数算一类&#xff0c;但是字符串型区别前两个类。整数、字符都返回的是一个值&#xff0c;所以可以直接在主函数里面cout不…

《黑神话:悟空》火出圈儿,揭秘幕后实时渲染技术

游戏一度因被贴上“不务正业”、“虚度光阴”的标签而备受争议&#xff0c;然而随着该产业的蓬勃发展&#xff0c;一些游戏被纳入体育竞技项目&#xff0c;如今游戏领域吸引越来越多人的目光。当下火爆全网的《黑神话&#xff1a;悟空》&#xff0c;凭借炫酷逼真的3D效果和独特…

wordpress 页面URL自动跳转到图片地址?

比如你打开关于我们页面&#xff1a; yourdomain.com/about-us/ 结果自动跳转到了&#xff1a; yourdomain.com/wp-content/uploads/2024/08/about-us.jpg 刚开始以为是不是哪里设置了自动跳转&#xff0c;比如YOAST SEO里&#xff0c;但是结果发现不是。 结果发现&#x…

好用的运动耳机品牌推荐?几款开放式蓝牙耳机推荐

论好用的运动耳机推荐&#xff0c;我觉得开放式运动耳机是个不错的选择。主要是因为下面几点&#xff1a; 1舒适度&#xff1a;开放式耳机不封闭耳朵也不塞入耳朵耳道&#xff0c;所以就能够减少长时间佩戴可能造成的压耳感以及不舒服的体验。 2安全性&#xff1a;因为开放式…

鸿蒙(API 12 Beta3版)图形【AR Engine简介】 AR引擎服务

AR Engine&#xff08;AR引擎服务&#xff09;是一个用于在HarmonyOS上构建增强现实应用的引擎&#xff0c;提供了运动跟踪、环境跟踪和命中检测等空间计算能力。通过这些能力&#xff0c;您的应用可以实现虚拟世界与现实世界的融合&#xff0c;给消费者提供全新的视觉体验和交…

【数据结构初阶】二叉树--堆(顺序结构实现)

hello&#xff01; 目录 一、实现顺序结构二叉树 1.1 堆的概念和结构 1.2 堆及二叉树的性质 1.3 堆的实现 1.3.1 创建堆的结构 1.3.2 初始化和销毁 1.3.3 入堆向上调整算法&#xff08;创建一个小堆&#xff09; 1.3.4 出堆向下调整算法&#xff08;小堆&#x…

linux组合命令:删除一个目录树中所有的空目录(包括嵌套空目录)

目录 一、需求 二、实现方式 1、结合使用 find 命令删除空目录 &#xff08;1&#xff09;删除目录的方式 &#xff08;2&#xff09;只删除空目录 2、更高效的方法 &#xff08;1&#xff09;使用 find 搭配 -delete &#xff08;2&#xff09;实际效果 三、相关命令…

STM32MP157_uboot_命令使用

STM32MP157_uboot_命令使用 前言&#xff1a; 进入 uboot 的命令行模式以后输入“help”或者“&#xff1f;”&#xff0c;然后按下回车即可查看当前 uboot 所支持的命令&#xff0c;图 中只是 uboot 的一部分命令&#xff0c;具体的命令列表以实际为准。图中的命令并不是 uboo…

SpringBoot2:IOC容器的相关操作以及常用注解说明

一、查看容器中的Bean实例 查看springboot中的容器实例&#xff0c;首先&#xff0c;我们要获取到IOC容器。 //1、返回我们的IOC容器ConfigurableApplicationContext run SpringApplication.run(MainApplication.class, args);//2、查看容器里面的组件String[] names run.ge…

线性代数基础(2)——特征值和特征向量

第一节博客已经整理了求导的公式&#xff0c;一些常用的概念。链接如下&#xff1a;高等数学基础&#xff08;1&#xff09;-CSDN博客。 第二节博客整理了微积分的公式及其相关概念。链接如下&#xff1a;高等数学基础&#xff08;2&#xff09;——微积分-CSDN博客 第三节博客…

JavaWeb JavaScript ⑩ 日程管理 第一期

自我消耗&#xff0c;敏感是我&#xff0c; 明媚是我&#xff0c; 我横跳在不同的情绪中 —— 24.8.31 一、登录页及校验 1.校验账号格式 // 校验账号格式function checkUsername(){// 定义正则表达式表示字符串规则var usernameReg /^[a-zA-Z0-9]{5,10}$/;// 获取用户名输入…

96.WEB渗透测试-信息收集-Google语法(10)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;95.WEB渗透测试-信息收集-Google语法&#xff08;9&#xff09; • site &#xff1a; x…

【硬件操作入门】3--同步与异步、半双工传输、UART硬件介绍、bps速率计算

【硬件操作入门】3–同步与异步、半双工传输、UART硬件介绍、bps速率计算 文章目录 【硬件操作入门】3--同步与异步、半双工传输、UART硬件介绍、bps速率计算一、同步与异步1.1. 概念1.2 同步信号1.3 异步信号1.4 举个例子&#xff1a;红外遥控器解码器&#xff08;异步&#x…

一分钟学会系列-1电烙铁(焊台)

目录&#xff1a; ‌1、概述 2、电烙铁的种类 3、焊接步骤 4、电烙铁的保养 ‌1、概述 电烙铁‌是一种电子制作和电器维修中常用的工具&#xff0c;主要用于焊接元件及导线。使用电烙铁时&#xff0c;需要注意安全&#xff0c;并采取适当的预防措施&#xff0c;如使用风扇…

最新ssl证书在线申请源码+网站ICP备案查询源码

最新ssl证书在线申请源码网站ICP备案查询源码 经过精心调试和修复&#xff0c;我们对源码进行了优化&#xff0c;确保了证书价格的准确显示。现在&#xff0c;您可以放心使用我们的在线生成网站源码&#xff0c;完整地展示证书价格&#xff0c;并在生成证书时提供准确的价格计…

SQL-函数

1、字符串函数 # 字符函数 select concat(hello , mysql!); select lower(HELLO); select upper(hello); select lpad(01,5,-);# 左填充 select rpad(01,5,-);# 右填充 select trim( hello mysql ! );# 去除前后空格 select substring(hello mysql!,1,7);# 截取一部分字符前7…

【教学类-35-21】20240901 中2班描字帖(学号+姓名、虚拟姓名、杨任东竹石体 Regular)

背景需求&#xff1a; 8月底通知我成为中2班的班主任&#xff0c;为了快速识别幼儿的脸、姓名、学号&#xff0c;再次制作描字帖&#xff0c;并拍照。 最近做的一份字帖是中4班描字帖 【教学类-35-20】20240328 中4班描字帖&#xff08;学号姓名 A4竖版2份 横面&#xff09;…

--- 数据结构 链表 --- java

与顺序表相比&#xff0c;链表的最大优点就是不会存在空间的浪费 链表是通过将一个一个储存数据的节点&#xff08;对象&#xff09;连起来&#xff08;通过记录下他们的地址&#xff09;&#xff0c;这些数据在逻辑上就是线性的&#xff0c;但在物理上不是&#xff0c;因为地…

[Leetcode 216][Medium]组合总和 III--回溯(组合问题)

目录 一、题目描述 二、整体思路 三、代码 一、题目描述 原题地址 二、整体思路 对于组合问题&#xff0c;首先要想到回溯法。那么可以根据回溯法模版进行设计。 void backtrace(元素){if(满足题目要求的条件){保存目前路径/状态/结果;return;}for循环,往目前状态相邻的所…