G-GhostNet(IJCV 2022)原理与代码解析

news2024/11/27 18:44:51

paper:GhostNets on Heterogeneous Devices via Cheap Operations

code:https://github.com/huawei-noah/Efficient-AI-Backbones/blob/master/g_ghost_pytorch/g_ghost_regnet.py

前言

本文提出了两种轻量网路,用于CPU端的C-GhostNet和用于GPU端的G-GhostNet。前者就是20年的原版GhostNet,这里只是换了个名字,具体可见GhostNet(CVPR 2020) 原理与代码解析,这里不再详细介绍。本文主要介绍新提出的基于GPU端的G-GhostNet。

存在的问题

之前的轻量型骨干网络大都以降低模型FLOPs为准则专门为CPU设计的,但由于CPU和GPU的硬件架构存在明显的差异,一些FLOPs较小的操作(特别是depth-wise convolution和channel shuffle)在GPU上并不是那么高效。实际上这些操作通常具有较低的arithemetic intensity,即计算和内存操作的比值,无法充分利用GPU的并行计算能力。

本文的创新点

在许多CNN骨干网络的架构中,一个stage通常包含多个卷积层或block,C-GhostNet研究的是一个卷积层生成的特征图中通道信息的冗余,而G-GhostNet研究的是多个block之间的特征相似性和冗余,并通过观察发现跨block的特征冗余是存在的,提出了G-Ghost stage,一个stage的最终输出一部分是和原来一样经过多个block得到的,另一部分通过廉价操作得到,最终将两部分拼接得到输出,大大降低了计算成本。

方法介绍

低FLOPs的操作比如深度可分离卷积在GPU上不那么高效,Radosavovic等人提出用激活activation来衡量网络的复杂度,在GPU上相比于FLOPs延迟和激活的相关性更大,也就是说,如果我们可以删去部分特征图减少激活大概率就能降低网络的延迟。通常一个CNN网络由多个stage构成,每个stage又包含多个block,本文旨在减少stage中的特征冗余大大减少中间特征,从而降低计算成本和内存使用。

对于CNN中的某个stage,有 \(n\) 层比如AlexNet或 \(n\) 个block表示为 \(\left \{ L_{1},L_{2},...,L_{n} \right \} \),对于输入 \(X\) 第一个block和最后一个block的输出为

要获得最终的输出 \(Y_{n}\),输入需要经过多个block的处理,这需要大量的计算。下图是ResNet34的第三个stage中第一个block和最后一个block的输出特征图,尽管最后一个block的输出经过了前5个block的处理,其中有些特征与第一个block的输出仍然非常相似,这意味着这些特征可以通过对低级特征的简单转换来得到。

作者将深层特征分为comlicated特征和ghost特征,前者仍然通过多个block来生成,后者可以通过对浅层特征的简单转换来得到。对于一个有 \(n\) 个block的stage,其输出为 \(X\in \mathbb{R}^{c\times h\times w}\),我们将复杂特征表示为 \(Y^{c}_{n}\in \mathbb{R}^{(1-\lambda)c\times h\times w}\),ghost特征表示为 \(Y^{c}_{g}\in \mathbb{R}^{\lambda c\times h\times w}\),其中 \(0\le \lambda \le 1\)。复杂特征通过 \(n\) 个block得到

其中 \(L'_{2},...,L'_{n}\) 是相比于式(7)宽度为 \((1-\lambda)\times width\) 的thin block。\(Y^{g}_{n}\) 可以通过对 \(Y_{1}\) 的廉价操作 \(C\) 得到

其中廉价操作 \(C\) 可以是1x1或3x3卷积。将 \(Y^{c}_{n}\) 和 \(Y^{g}_{n}\) 拼接起来就得到了最终输出

Intrinsic Feature Aggregation

尽管简单特征可以通过廉价操作近似得到,但式(9)中的 \(Y^{g}_{n}\) 可能缺乏需要多层才能提取到的深层信息,为了弥补缺乏的信息,作者提出用complicated分支的中间特征来提高廉价操作的表示能力。首先提取复杂分支的中间特征 \(Z\in \mathbb{R}^{c'\times h\times w}=[Y^{c}_{2},Y^{c}_{3},...,Y^{c}_{n}]\) 将其按通道concat起来,其中 \(c'\) 是通道总数,如下图所示

通过转换函数 \(\tau \) 对 \(Z\) 进行变换,然后与 \(Y^{g}_{n}\) 进行融合。

转换函数 \(\tau\) 包括一个全局平均池化和一个全连接层

其中 \(W\in \mathbb{R}^{c'\times \lambda c}\),\(b\in \mathbb{R}^{\lambda c}\) 分别是权重和偏置。

下图分别是原始的CNN结构、没有特征聚合的G-Ghost stage和有特征聚合的G-Ghost stage

代码解析

下面是G-Ghost stage的官方实现,好像和文章中的描述有些出入。forward函数中首先self.base就是上图中的Block 1,出入一是文中Block 1的输出好像是完整的分别进入complicated分支和cheap分支,而实现中是将Block 1的输出按 \(\lambda\) 沿通道分为两部分分别进入两个分支。出入二是从上图可以看出是对Block 2 - Block n进行特征聚合,而实现中还包括Block 1,即代码中的x0self.merge是转换函数 \(\tau\),其中全连接层用卷积层实现。

class Stage(nn.Module):
    def __init__(self, block, inplanes, planes, group_width, blocks, stride=1, dilate=False, cheap_ratio=0.5):
        super(Stage, self).__init__()
        norm_layer = nn.BatchNorm2d
        downsample = None
        self.dilation = 1
        previous_dilation = self.dilation
        if dilate:
            self.dilation *= stride
            stride = 1
        if stride != 1 or self.inplanes != planes:
            downsample = nn.Sequential(
                conv1x1(inplanes, planes, stride),
                norm_layer(planes),
            )

        self.base = block(inplanes, planes, stride, downsample, group_width,
                          previous_dilation, norm_layer)
        self.end = block(planes, planes, group_width=group_width,
                         dilation=self.dilation,
                         norm_layer=norm_layer)

        group_width = int(group_width * 0.75)
        raw_planes = int(planes * (1 - cheap_ratio) / group_width) * group_width
        cheap_planes = planes - raw_planes
        self.cheap_planes = cheap_planes
        self.raw_planes = raw_planes

        self.merge = nn.Sequential(
            nn.AdaptiveAvgPool2d(1),
            nn.Conv2d(planes + raw_planes * (blocks - 2), cheap_planes,
                      kernel_size=1, stride=1, bias=False),
            nn.BatchNorm2d(cheap_planes),
            nn.ReLU(inplace=True),
            nn.Conv2d(cheap_planes, cheap_planes, kernel_size=1, bias=False),
            nn.BatchNorm2d(cheap_planes),
        )
        self.cheap = nn.Sequential(
            nn.Conv2d(cheap_planes, cheap_planes,
                      kernel_size=1, stride=1, bias=False),
            nn.BatchNorm2d(cheap_planes),
        )
        self.cheap_relu = nn.ReLU(inplace=True)

        layers = []
        downsample = nn.Sequential(
            LambdaLayer(lambda x: x[:, :raw_planes])
        )

        layers = []
        layers.append(block(raw_planes, raw_planes, 1, downsample, group_width,
                            self.dilation, norm_layer))
        inplanes = raw_planes
        for _ in range(2, blocks - 1):
            layers.append(block(inplanes, raw_planes, group_width=group_width,
                                dilation=self.dilation,
                                norm_layer=norm_layer))

        self.layers = nn.Sequential(*layers)

    def forward(self, input):
        x0 = self.base(input)

        m_list = [x0]
        e = x0[:, :self.raw_planes]
        for l in self.layers:
            e = l(e)
            m_list.append(e)
        m = torch.cat(m_list, 1)
        m = self.merge(m)

        c = x0[:, self.raw_planes:]
        c = self.cheap_relu(self.cheap(c) + m)

        x = torch.cat((e, c), 1)
        x = self.end(x)
        return x

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

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

相关文章

你是真的“C”——Visual Studio 2022(VS2022)编译器 -—实用调试技巧

你是真的“C”——Visual Studio 2022(VS2022)编译器 -—实用调试技巧😎前言🙌1. 什么是bug?🙌2. 调试是什么?有多重要?🙌2.1 调试是什么?2.2 调试的基本步骤…

hgame202301 week1 web writeup

目录前言一、Classic Childhood Game二、Become A Member三、Show Me Your Beauty四、Guess Who I Am后记前言 记录2023年1月的hgame比赛week1的web题 第一周还是比较简单的,除了那个涉及到网页爬虫的题一度不会写(本「待入门」选手还是太菜了 一、Cla…

网络安全-字典生成-crunch

网络安全-字典生成-crunch crunch工具,在kali已经集成好了 2是代表最小字符长度 4是最大字符长度 生成了一个2M的文件 还有我们来查看这个密码本 从abcd26个英文字母的2位到4位的组合,他全部排列了一次 还可以自定义数字,特殊字符&#xf…

feign进行文件上传报错解决方案及有多个入参时的注意事项

一、情景回顾1、简单的文件上传的接口/*** 文件上传MultipartFile格式** param multipartFile 源文件* param filename 自定义文件名称,允许为空,为空时直接从源文件中拿* return*/RequestMapping("/uploadFileForMultipartFile")LogModuleAnn…

ActiveReports.NET 17.0 Crack by Xacker

一个完整的报告解决方案,用于在您的业务应用程序中设计、定制、发布和查看报告。 ActiveReports.NET 通过直观的 Visual Studio 集成报表设计器和丰富的控件帮助您提供精美的报表。ActiveReports 提供基于代码的跨平台报告、易于使用的设计器和灵活的 API。适用于桌…

Windows11去掉不满足系统要求的提示水印

我的电脑是LEGION的拯救者R70002021,预装的是Windows 11 家庭中文版,没有折腾重装过系统,今天突然注意到右下角出现了这个提示:“不满足系统要求。转到’设置"了解详细信息”。 在进入设置 - 系统 面板中也提示不满足系统要…

Linux系列 操作系统安装及服务控制(笔记)

作者简介:一名在校云计算网络运维学生、每天分享网络运维的学习经验、和学习笔记。 座右铭:低头赶路,敬事如仪 个人主页:网络豆的主页​​​​​​ 目录 前言 一.操作系统 1.Linux系统三大类 (1)ubu…

操作系统题目收录(九)

1、有两个并发进程&#xff0c;对于如下程序的运行&#xff0c;正确的说法是&#xff08;&#xff09;。 int x,y,z,t,u; P1() {while(1){x1;y0;if x>1 then yy1;zy;} }P2() {while(1){x0;t0;if x<1 then tt2;ut;} }A&#xff1a;程序能正确运行&#xff0c;结果唯一B&…

SSTI漏洞基础解析

flask基础 flask是python编写的一个WEB应用程序框架&#xff0c;flask由Armin Ronacher带领的一个Pocco团队开发&#xff0c;flask基于werkzeug WSGI工具包个jinjia2模板引擎。 WSGI&#xff1a;Web Server Gateway Interface&#xff0c;即WEB服务器网关接口。 第一个flask…

openai chatgpt 相关

父文章 大数据模型 能做什么? 报告类: 剧本,报告, 标题, 大纲 (都是启发式的), 聊天类: 聊天, 反馈, 心理uu ds 搜索类: 搜索, 书本推荐 几乎可以完成自然语言处理的绝大部分任务 &#xff0c;例如面向问题的搜索、阅读理解、语义推断、机器翻译、文章生成和自动问答等等。…

C/【静态通讯录】

&#x1f331;博客主页&#xff1a;大寄一场. &#x1f331;系列专栏&#xff1a;C语言学习笔记 &#x1f618;博客制作不易欢迎各位&#x1f44d;点赞⭐收藏➕关注 前言 往期回顾&#xff1a; C/扫雷 C/N子棋 通讯录作为通讯录地址的书本&#xff0c;当今的通讯录可以涵盖多项…

彻底理解 cookie、session、token (二)

Cookie cookie 是一个非常具体的东西&#xff0c;指的就是浏览器里面能永久存储的一种数据&#xff0c;仅仅是浏览器实现的一种数据存储功能。 cookie由服务器生成&#xff0c;发送给浏览器&#xff0c;浏览器把cookie以kv形式保存到某个目录下的文本文件内&#xff0c;下一次…

vue2+微前端qiankun从搭建到部署的实践(主子应用切换;集成vue3+vite3子应用)

一、最终效果 二、微前端&#xff08;qiankun&#xff09;介绍及为什么选择用微前端&#xff0c;可以看官网 三、目录结构如下 四、具体配置 一、主应用配置 1、主应用技术栈 Vue-cli4搭建项目Vue2Element-Uiqiankun&#xff1b;Vue2Element-Uiqiankun 2、搭建好主项目&…

Java集合:Map的使用

1.Map框架l----Map:双列数据&#xff0c;存储key-value对的数据 ---类似于高中的函数: y f(x)|----HashMap:作为Map的主要实现类&#xff0c; 线程不安全的&#xff0c;效率高&#xff1b;可以存储null的key和value|----LinkedHashMap:保证在遍历map元素时&#xff0c;可以按照…

【Android】系统源码下载及编译

源码及编译 步骤 1&#xff1a;创建一个空目录来存放源码&#xff1a; mkdir aosp cd aosp步骤 2&#xff1a;获取最新版本的 repo 并签出 android-8.1.0_r1 分支&#xff1a; repo init -u https://android.googlesource.com/platform/manifest -b android-8.1.0_r1其中&am…

数据结构-考研难点代码突破(C++实现树型查找-二叉搜索树(二叉排序树))

文章目录1.二叉搜索树基本操作二叉搜索树的效率分析2. C实现1.二叉搜索树基本操作 二叉排序树是具有下列特性的二叉树&#xff1a; 若左子树非空&#xff0c;则左子树上所有结点的值均小于根结点的值。若右子树非空&#xff0c;则右子树上所有结点的值均大于根结点的值。左、…

蓝牙耳机哪个品牌性价比高?性价比高的无线蓝牙耳机

现如今耳机已经十分普及&#xff0c;大多数人会随身佩戴蓝牙耳机&#xff0c;相较于传统耳机&#xff0c;无线耳机不仅携带方便&#xff0c;舒适度上也更加出色。不过市面上的无线耳机种类繁多&#xff0c;很多朋友不知道该如何挑选&#xff0c;所以小编特意整理了一期性价比高…

从零开始搭建kubernetes集群环境(虚拟机/kubeadm方式)

文章目录1 Kubernetes简介&#xff08;k8s&#xff09;2 安装实战2.1 主机安装并初始化2.2 安装docker2.3 安装Kubernetes组件2.4 准备集群镜像2.5 集群初始化2.6 安装flannel网络插件3 部署nginx 测试3.1 创建一个nginx服务3.2 暴漏端口3.3 查看服务3.4 测试服务1 Kubernetes简…

2023如何选购适合游戏设计的电脑硬件

游戏设计涉及许多不同的学科&#xff0c;因此涉及许多不同的软件包。有游戏引擎本身&#xff0c;例如 Unreal Engine 和 Unity&#xff0c;以及 3D 设计软件&#xff0c;例如 3ds Max、Blender 和 ZBrush——等等&#xff01;大多数软件开发人员都维护着这些不同应用程序的系统…

C++设计模式(14)——享元模式

亦称&#xff1a; 缓存、Cache、Flyweight 意图 享元模式是一种结构型设计模式&#xff0c; 它摒弃了在每个对象中保存所有数据的方式&#xff0c; 通过共享多个对象所共有的相同状态&#xff0c; 让你能在有限的内存容量中载入更多对象。 问题 假如你希望在长时间工作后放…