MobileFormer 网络简介

news2024/9/23 23:21:48

        MobileFormer:一种通过双线桥MobileNet 和 Transformer 并行的结构。这种方式融合了 MobileNet 局部性表达能力和 Transformer 全局表达能力的优点,这个桥能将局部性和全局性双向融合。和现有 Transformer 不同,Mobile-Former 使用很少的 tokens(例如 6 个或者更少)随机初始化学习全局先验,计算量更小。

        论文地址:https://openaccess.thecvf.com/content/CVPR2022/papers/Chen_Mobile-Former_Bridging_MobileNet_and_Transformer_CVPR_2022_paper.pdf

1. 并行结构

Mobile-Former 将 MobileNet 和 Transformer 并行化,并通过双向交叉注意力连接(下见图)。Mobile(指 MobileNet)采用图像作为输入,并应用反向瓶颈块提取局部特征。Former(指 Transformers)将可学习的参数(或 tokens)作为输入,表示为 𝑍∈𝑅𝑀×𝑑,其中 M 和 d 分别是 tokens 的数量和维度,这些 tokens 随机初始化。与视觉 Transformer(ViT)不同,其中 tokens 将局部图像 patch 线性化,Former 的 tokens 明显较少(M≤6),每个代表图像的全局先验知识,使得计算成本大大降低。

2. Mobile-Former 块

Mobile-Former 由 Mobile-Former 块组成。每个块包含四部分:Mobile 子块、Former 子块以及双向交叉注意力 Mobile←Former 和 Mobile→Former(如下图所示)。

输入和输出:Mobile-Former 块有两个输入:(a) 局部特征图,以及(b) 全局 tokens。Mobile-Former 块输出更新的局部特征图 𝑋 和全局 tokens Z,用作下一个块的输入。

Mobile 子块:如上图所示,Mobile 子块将特征图 𝑋 作为输入,并将其输出作为 Mobile←Former 的输入,这和反向瓶颈块略有不同,其用动态 ReLU 替换 ReLU 作为激活函数。不同于原始的动态 ReLU,在平均池化特征图上应用两个 MLP 以生成参数。我们从 Former 的第一个全局 tokens 的输出 𝑧′ 应用两个 MLP 层(上图中的θ)保存平均池化。其中所有块的 depth-wise 卷积的核大小为 3×3。

class Mobile(nn.Module):

    def __init__(self, in_channel, expand_size, out_channel, token_demension, kernel_size=3, stride=1, k=2):
        super(Mobile, self).__init__()
        self.in_channel, self.expand_size, self.out_channel = in_channel, expand_size, out_channel
        self.token_demension, self.kernel_size, self.stride, self.k = token_demension, kernel_size, stride, k

        if stride == 2:
            self.strided_conv = nn.Sequential(
                nn.Conv2d(self.in_channel, self.expand_size, kernel_size=3, stride=2, padding=int(self.kernel_size // 2), groups=self.in_channel).cuda(),
                nn.BatchNorm2d(self.expand_size).cuda(),
                nn.ReLU6(inplace=True).cuda()
            )
            self.conv1 = nn.Conv2d(self.expand_size, self.in_channel, kernel_size=1, stride=1).cuda()
            self.bn1 = nn.BatchNorm2d(self.in_channel).cuda()
            self.ac1 = DynamicReLU(self.in_channel, self.token_demension, k=self.k).cuda()      
            self.conv2 = nn.Conv2d(self.in_channel, self.expand_size, kernel_size=3, stride=1, padding=1, groups=self.in_channel).cuda()
            self.bn2 = nn.BatchNorm2d(self.expand_size).cuda()
            self.ac2 = DynamicReLU(self.expand_size, self.token_demension, k=self.k).cuda()          
            self.conv3 = nn.Conv2d(self.expand_size, self.out_channel, kernel_size=1, stride=1).cuda()
            self.bn3 = nn.BatchNorm2d(self.out_channel).cuda()
        else:
            self.conv1 = nn.Conv2d(self.in_channel, self.expand_size, kernel_size=1, stride=1).cuda()
            self.bn1 = nn.BatchNorm2d(self.expand_size).cuda()
            self.ac1 = DynamicReLU(self.expand_size, self.token_demension, k=self.k).cuda()      
            self.conv2 = nn.Conv2d(self.expand_size, self.expand_size, kernel_size=3, stride=1, padding=1, groups=self.expand_size).cuda()
            self.bn2 = nn.BatchNorm2d(self.expand_size).cuda()
            self.ac2 = DynamicReLU(self.expand_size, self.token_demension, k=self.k).cuda()          
            self.conv3 = nn.Conv2d(self.expand_size, self.out_channel, kernel_size=1, stride=1).cuda()
            self.bn3 = nn.BatchNorm2d(self.out_channel).cuda()

    def forward(self, x, first_token):
        if self.stride == 2:
            x = self.strided_conv(x)
        x = self.bn1(self.conv1(x))
        x = self.ac1(x, first_token)
        x = self.bn2(self.conv2(x))
        x = self.ac2(x, first_token)
        return self.bn3(self.conv3(x))

Former 子块:Former 子块是一个标准的 Transformer 块,包括一个多头注意力(MHA)和一个前馈网络(FFN)。在 FFN 中,膨胀率为 2(代替 4)。使用 post 层归一化。Former 在 Mobile→Former 和 Mobile←Former 之间处理。

class Former(nn.Module):

    def __init__(self, head, d_model, expand_ratio=2):
        super(Former, self).__init__()
        self.d_model = d_model
        self.expand_ratio = expand_ratio
        self.eps = 1e-10
        self.head = head
        assert self.d_model % self.head == 0
        self.d_per_head = self.d_model // self.head

        self.QVK = MLP([self.d_model, self.d_model * 3], bn=False).cuda()
        self.Q_to_heads = MLP([self.d_model, self.d_model], bn=False).cuda()
        self.K_to_heads = MLP([self.d_model, self.d_model], bn=False).cuda()
        self.V_to_heads = MLP([self.d_model, self.d_model], bn=False).cuda()
        self.heads_to_o = MLP([self.d_model, self.d_model], bn=False).cuda()
        self.norm = nn.LayerNorm(self.d_model).cuda()
        self.mlp = MLP([self.d_model, self.expand_ratio * self.d_model, self.d_model], bn=False).cuda()
        self.mlp_norm = nn.LayerNorm(self.d_model).cuda()

    def forward(self, x):
        QVK = self.QVK(x)
        Q = QVK[:, :, 0: self.d_model]
        Q = rearrange(self.Q_to_heads(Q), 'n m ( d h ) -> n m d h', h=self.head)  
        K = QVK[:, :, self.d_model: 2 * self.d_model]
        K = rearrange(self.K_to_heads(K), 'n m ( d h ) -> n m d h', h=self.head)   
        V = QVK[:, :, 2 * self.d_model: 3 * self.d_model]
        V = rearrange(self.V_to_heads(V), 'n m ( d h ) -> n m d h', h=self.head)  
        scores = torch.einsum('nqdh, nkdh -> nhqk', Q, K) / (np.sqrt(self.d_per_head) + self.eps)   
        scores_map = F.softmax(scores, dim=-1)
        v_heads = torch.einsum('nkdh, nhqk -> nhqd', V, scores_map) 
        v_heads = rearrange(v_heads, 'n h q d -> n q ( h d )')
        attout = self.heads_to_o(v_heads)
        attout = self.norm(attout)  
        attout = self.mlp(attout)
        attout = self.mlp_norm(attout)  
        return attout  

Mobile→Former:文章提出的轻量级交叉注意力用于将局部特征 X 融合到全局特征 tokens Z。与标准注意力相比,映射矩阵的键 𝑊𝐾 和值 𝑊𝑉(在局部特征 X 上)被移除以节省计算(见上图)。

class Mobile_Former(nn.Module):
    '''局部特征 -> 全局特征'''
    def __init__(self, d_model, in_channel):
        super(Mobile_Former, self).__init__()
        self.d_model, self.in_channel = d_model, in_channel

        self.project_Q = nn.Linear(self.d_model, self.in_channel).cuda()
        self.unproject = nn.Linear(self.in_channel, self.d_model).cuda()
        self.eps = 1e-10
        self.shortcut = nn.Sequential().cuda()

    def forward(self, local_feature, x):
        _, c, _, _ = local_feature.shape
        local_feature = rearrange(local_feature, 'n c h w -> n ( h w ) c')   
        project_Q = self.project_Q(x)   
        scores = torch.einsum('nmc , nlc -> nml', project_Q, local_feature) * (c ** -0.5)
        scores_map = F.softmax(scores, dim=-1)  
        fushion = torch.einsum('nml, nlc -> nmc', scores_map, local_feature)
        unproject = self.unproject(fushion) 
        return unproject + self.shortcut(x)

Mobile-Former:这里的交叉注意力与 Mobile→Former 的方向相反,其将全局 tokens 融入本地特征。局部特征是查询,全局 tokens 是键和值。因此,我们保留键 𝑊𝐾 和值 𝑊𝑉 中的映射矩阵,但移除查询 𝑊𝑄 的映射矩阵以节省计算。

计算复杂度:Mobile-Former 块的四个核心部分具有不同的计算成本。给定输入大小为 𝐻𝑊×𝐶 的特征图,以及尺寸为 d 的 M 个全局 tokens,Mobile 占据了大部分的计算量 𝑂(𝐻𝑊𝐶2)。Former 和双线桥是重量级的,占据不到总计算成本的 20%。具体而言,Former 的自注意力和 FFN 具有复杂度 𝑂(𝑀2𝑑+𝑀𝑑2)。Mobile→Former 和 Mobile←Former 共享交叉注意力的复杂度 𝑂(𝑀𝐻𝑊𝐶+𝑀𝑑𝐶)。

class Former_Mobile(nn.Module):
    '''全局特征 -> 局部特征'''
    def __init__(self, d_model, in_channel):
        super(Former_Mobile, self).__init__()
        self.d_model, self.in_channel = d_model, in_channel
        
        self.project_KV = MLP([self.d_model, 2 * self.in_channel], bn=False).cuda()
        self.shortcut = nn.Sequential().cuda()
    
    def forward(self, x, global_feature):
        res = self.shortcut(x)
        n, c, h, w = x.shape
        project_kv = self.project_KV(global_feature)
        K = project_kv[:, :, 0 : c]  
        V = project_kv[:, :, c : ]  
        x = rearrange(x, 'n c h w -> n ( h w ) c') 
        scores = torch.einsum('nqc, nkc -> nqk', x, K) 
        scores_map = F.softmax(scores, dim=-1) 
        v_agg = torch.einsum('nqk, nkc -> nqc', scores_map, V)  
        feature = rearrange(v_agg, 'n ( h w ) c -> n c h w', h=h)
        return feature + res

3. 网络结构

一个 Mobile-Former 架构,图像大小为 224×224,294M FLOPs,以不同的输入分辨率堆叠 11 个 Mobile-Former 块。所有块都有 6 个维度为 192 的全局 tokens。它以一个 3×3 的卷积作为 stem 和第一阶段的轻量瓶颈块,首先膨胀,然后通过 3×3 depth-wise 卷积和 point-wise 卷积压缩通道数。第 2-5 阶段包括 Mobile-Former 块。每个阶段的下采样,表示为 Mobile-Former 分类头在局部特征应用平均池化,首先和全局 tokens concat 到一起,然后经过两个全连接层,中间是 h-swish 激活函数。Mobile-Former 有七种模型,计算成本从 26M 到 508M FLOPs。它们的结构相似,但宽度和高度不同。

class MobileFormerBlock(nn.Module):
    def __init__(self, in_channel, expand_size, out_channel, d_model, stride=1, k=2, head=8, expand_ratio=2):
        super(MobileFormerBlock, self).__init__()

        self.in_channel, self.expand_size, self.out_channel = in_channel, expand_size, out_channel
        self.d_model, self.stride, self.k, self.head, self.expand_ratio = d_model, stride, k, head, expand_ratio

        self.mobile = Mobile(self.in_channel, self.expand_size, self.out_channel, self.d_model, kernel_size=3, stride=self.stride, k=self.k).cuda()
        self.former = Former(self.head, self.d_model, expand_ratio=self.expand_ratio).cuda()
        self.mobile_former = Mobile_Former(self.d_model, self.in_channel).cuda()
        self.former_mobile = Former_Mobile(self.d_model, self.out_channel).cuda()
    
    def forward(self, local_feature, global_feature):
        z_hidden = self.mobile_former(local_feature, global_feature)
        z_out = self.former(z_hidden)
        x_hidden = self.mobile(local_feature, z_out[:, 0, :])
        x_out = self.former_mobile(x_hidden, z_out)
        return x_out, z_out

4. 小结

  • MobileFormer 通过并行的 MobileNet 和 Transformer 结构以及双线桥技术,实现了局部和全局特征的有效融合。

  • MobileFormer 网络利用轻量级的交叉注意力机制,显著降低了计算成本,同时保持了高效的特征表达能力。

  • MobileFormer 提供了多种模型变体,适应不同计算需求,最高可达 508M FLOPs,为移动和边缘设备上的高效视觉任务提供了灵活的解决方案。

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

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

相关文章

或许改变整个领域的生态!颜宁团队合作最新Cell子刊

电压门控钠(Nav)和钙(Cav)通道负责电信号的起始。长期以来,它们一直是治疗各种疾病的靶标。来自多种生物的Nav和Cav通道的不同亚型的冷冻电镜(cryo-EM)结构越来越多,需要一个通用的残基编号系统来建立结构-功能关系,并有助于合理的药物设计或…

java(基础)

Arrays.toString 依赖于 java.util.* Pearson出版社 Java优势 1 ) 简单性 2 ) 面向对象 3 ) 分布式 4 ) 健壮性 5 ) 安全性 7 ) 可移植性 可移植性指的是 Java 程序可以在不同的操作系统、硬件平台和设备上运行 8 ) 解释型 9 ) 高性能 10 ) 多线程 11 ) 动态性 6 )…

打字侠支持新世纪五笔、86版五笔、98版五笔打字练习:初学者的最佳选择

在当今数字化时代,打字已经成为我们日常生活和工作中必不可少的一部分。尽管拼音输入法因其易学易用的特点占据了主导地位,但对于那些追求高效打字和提高汉字输入速度的人来说,五笔输入法仍然是一种极具吸引力的选择。无论是新世纪五笔、86版…

C++的发展史及前景

🌈个人主页:Yui_ 🌈Linux专栏:Linux 🌈C语言笔记专栏:C语言笔记 🌈数据结构专栏:数据结构 🌈C专栏:C 文章目录 1. 什么是C2. C的发展史3. C的重要性3.1 C的使…

Linux日常运维-任务计划(crontab)

作者介绍:简历上没有一个精通的运维工程师。希望大家多多关注作者,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 本小章内容就是Linux进阶部分的日常运维部分,掌握这些日常运维技巧或者方法在我们的日常运维过程中会带来很多方…

2024年软件测试经典面试题(全三篇)【包含答案】做完面试进入大厂不是梦

前言 迎来的便是金九银十,一直想着说分享一些软件测试的面试题,这段时间做了一些收集和整理,下面共有三篇经典面试题,大家可以试着做一下,答案附在后面,希望能帮助到大家。 软件测试经典面试题&#xff0…

HTTP协议详细图解(请求报文格式,响应报文格式,get和post的区别,状态码详解)

文章目录 什么是Http协议?HTTP报文格式HTTP 请求格式HTTP响应格式什么是 URL请求和响应中的“方法”GET 和 POST 的区别认识“Header”状态码详解 什么是Http协议? Http协议是“超文本传输协议”(不仅可以传输文本,也可以传输图片…

六大桌面管理系统一次性打包分享,寻找最好的桌面管理系统

桌面乱了需要好好整理,不仅看着干净还能迅速找到想要的东西。对于电脑也一样,尤其是员工的电脑桌面,如果不监控,你不知道员工会在电脑上进行什么神奇的操作,也许删除了一个重要文件,也许下载了一个病毒软件…

VBA技术资料MF186:读取文件属性及自定义属性

我给VBA的定义:VBA是个人小型自动化处理的有效工具。利用好了,可以大大提高自己的工作效率,而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套,分为初级、中级、高级三大部分,教程是对VBA的系统讲解&#…

MaxKB(二):Ubuntu24.04搭建maxkb开发环境

接上文:windows10搭建maxkb开发环境(劝退指南) 上文在windows10环境搭建maxkb开发环境遇到各种坑,后面就转战ubuntu平台,果然比较顺利的完成开发环境搭建。当然遇到相关的问题还是可以参考上文《windows10搭建maxkb开发…

c++ | 模板进阶

前言 本篇博客讲解c中的模板的一些其他知识 💓 个人主页:普通young man-CSDN博客 ⏩ 文章专栏:C_普通young man的博客-CSDN博客 ⏩ 本人giee: 普通小青年 (pu-tong-young-man) - Gitee.com 若有问题 评论区见📝 🎉欢…

社区防疫物资申报系统--论文pf

TOC springboot414社区防疫物资申报系统--论文pf 第1章 绪论 1.1选题动因 当前的网络技术,软件技术等都具备成熟的理论基础,市场上也出现各种技术开发的软件,这些软件都被用于各个领域,包括生活和工作的领域。随着电脑和笔记本…

容器编排简介

1.1 什么是容器编排 容器编排是管理和自动化容器化应用程序的部署、扩展、运行和维护的过程。随着微服务架构的普及,应用程序被拆分成许多小型、独立的服务,每个服务都可以封装在容器中独立运行。容器编排工具应运而生,帮助开发者和运维团队更…

嵌入式系统实时任务调度算法优化与实现

嵌入式系统实时任务调度算法优化与实现 目录 嵌入式系统实时任务调度算法优化与实现 引言 1.1 嵌入式系统的重要性 1.2 实时任务调度的重要性 实时任务的定义与分类 2.1 实时任务的定义 2.2 实时任务的分类 2.3 实时任务的其他分类方法 硬实时与软实时系统 3.1 硬实…

STM32CubeMX 配置CAN通信 HAL库

一、CAN总线波特率计算 CAN总线通信的各节点通信时会产生相位差,所以要进行位同步,两个节点保持步调一致。 CAN_SJW:重新同步跳跃宽度(SJW) 。定义了在每位中可以延长或缩短多少个时间单元的上限。其值可以编程为1到4个时间单元。 CAN_BS1&a…

记录一次搭建uniapp-vue3的基础项目

1.使用 HBuilder X 创建uniapp vue3的基础项目 2.安装 自动导包插件 unplugin-auto-import npm install unplugin-auto-import或者 pnpm install unplugin-auto-import2.1 根目录下创建 vite.config.js 复制粘贴以下内容 import { defineConfig } from vite import uni fro…

QT基础知识4

思维导图 项目文件里面要加texttospeech模块 widget.h: #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTime>//时间类 #include <QTextToSpeech>//语音播报类QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass…

“论数据分片技术及其应用”写作框架,软考高级,系统架构设计师

论文真题 数据分片就是按照一定的规则&#xff0c;将数据集划分成相互独立、正交的数据子集&#xff0c;然后将数据子集分布到不同的节点上。通过设计合理的数据分片规则&#xff0c;可将系统中的数据分布在不同的物理数据库中&#xff0c;达到提升应用系统数据处理速度的目的…

企业高性能web服务器---nginx详解(基础介绍配置,核心配置)

目录 一、web服务器介绍 1.1 Apache prefork 模型 1.2 Apache worker 模型 ​编辑 1.3 Apache event模型 1.4 Nginx-高性能的web服务端 1.5 服务端 I/O 流程 1.5.1 磁盘 I/O 1.5.2 网络 I/O 二 、nginx 架构及安装 2.1 nginx 进程结构 2.2源码编译安装nginx 2.2.1…

vscode+pyqt5环境搭建

参考&#xff1a;https://blog.csdn.net/qq_37080185/article/details/121616507 一、安装Python 从Python官网上下载安装包&#xff08;https://www.python.org/&#xff09; 安装Python&#xff0c;将安装目录添加到环境变量中。 二、安装Pyqt5 PyQt5以及PyQt5-tools(des…