CVPR 2023 | 主干网络FasterNet 核心解读 代码分析

2023-11-01 04:36

本文主要是介绍CVPR 2023 | 主干网络FasterNet 核心解读 代码分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文分享来自CVPR 2023的论文,提出了一种快速的主干网络,名为FasterNet

论文提出了一种新的卷积算子,partial convolution,部分卷积(PConv),通过减少冗余计算内存访问来更有效地提取空间特征。

创新在于部分卷积(PConv),它选择一部分通道的特性进行常规卷积剩余部分通道的特性保持不变,降低了计算复杂度,从而实现了快速高效的神经网络。

区别于常规卷积:PConv只对输入通道的一部分应用卷积,而保留其余部分不变。

论文地址:Run, Don’t Walk: Chasing Higher FLOPS for Faster Neural Networks

代码地址:https://github.com/JierunChen/FasterNet/tree/master

目录

一、PConv算子设计原理

二、PConv算子的代码解析 

三、FasterNet模型原理

四、FasterNet模型测试

五、实验分析


背景:

  • MobileNet、ShuffleNet和GhostNet等利用深度卷积(DWConv)或 组卷积(GConv)来提取空间特征。
  • 然而,在减少FLOPs的过程中,算子经常会受到内存访问增加的副作用的影响
  • MicroNet进一步分解和稀疏网络,将其FLOPs推至极低水平。尽管这种方法在FLOPs方面有所改进,但其碎片计算效率很低。
  • 上述网络通常伴随着额外的数据操作,如级联、Shuffle和池化这些操作的运行时间对于小型模型来说往往很重要

一、PConv算子设计原理

 1、这种部分卷积的核心思想对输入特征图的部分通道应用卷积操作而保留其他通道不变。这种操作可以有效地减少计算冗余,提高计算效率。

对于连续或规则的内存访问,将第一个或最后一个连续的通道视为整个特征图的代表进行计算。

在不丧失一般性的情况下认为输入和输出特征图具有相同数量的通道

设计原因

通过利用特征图的冗余度可以进一步优化成本。

如下图所示,特征图在不同通道之间具有高度相似性。许多其他著作也涵盖了这种冗余,但很少有人以简单而有效的方式充分利用它。

于是出了PConv,对输入特征图的部分通道应用卷积操作而保留其他通道不变,同时减少计算冗余和内存访问。

2、为了充分有效地利用来自所有通道的信息,进一步将逐点卷积(PWConv)附加到PConv

它们在输入特征图上的有效感受野看起来像一个T形Conv,与均匀处理补丁的常规Conv相比,它更专注于中心位置。

通过实验表明:中心位置是卷积操作中最常见的突出位置,即中心位置的权重比周围的更重。这与集中于中心位置的T形计算一致。

虽然T形卷积可以直接用于高效计算,但作者表明,将T形卷积分解为PConv和PWConv更好,因为该分解利用了卷积操作间冗余并进一步节省了FLOPs。

二、PConv算子的代码解析 

PConv算子的代码:

'''
输入三个参数:dim(输入特征图的通道数),n_div(分割的组数)和forward(前向传播的方法)
输出:卷积后的特征图
'''
class Partial_conv3(nn.Module):def __init__(self, dim, n_div, forward):super().__init__()self.dim_conv3 = dim // n_div # 计算出卷积部分的通道数self.dim_untouched = dim - self.dim_conv3 # 计算出不需要卷积部分的通道数# 定义一个3*3卷积,输入通道数为self.dim_conv3,输出通道数也为self.dim_conv3,步长为1,填充为1,且不使用bias。self.partial_conv3 = nn.Conv2d(self.dim_conv3, self.dim_conv3, 3, 1, 1, bias=False)if forward == 'slicing':self.forward = self.forward_slicingelif forward == 'split_cat':self.forward = self.forward_split_catelse:raise NotImplementedError# 只适合推理def forward_slicing(self, x: Tensor) -> Tensor:# 对输入x进行深拷贝,以保持原始输入的完整性。后面的操作不会改变原始输入x。x = x.clone()   # 对输入x中前self.dim_conv3个通道应用卷积操作,并将结果保存回x中对应的位置。x[:, :self.dim_conv3, :, :] = self.partial_conv3(x[:, :self.dim_conv3, :, :])return x# 适合训练/推理def forward_split_cat(self, x: Tensor) -> Tensor:# 使用torch.split函数将输入x沿着通道维度(即第1维,索引从0开始)分割成两个部分,# 分别为x1和x2。分割的长度为[self.dim_conv3, self.dim_untouched],# 即分割后的x1的通道数为self.dim_conv3,x2的通道数为self.dim_untouched。x1, x2 = torch.split(x, [self.dim_conv3, self.dim_untouched], dim=1)x1 = self.partial_conv3(x1)x = torch.cat((x1, x2), 1)return x

这段代码定义了一个名为 Partial_conv3 的 PyTorch 模块,它是nn.Module的子类。这个模块主要实现了一种部分卷积(Partial Convolution); 

这种部分卷积的核心思想对输入特征图的部分通道应用卷积操作而保留其他通道不变。这种操作可以有效地减少计算冗余,提高计算效率。

方式1:slicing

 # 只适合推理def forward_slicing(self, x: Tensor) -> Tensor:# 对输入x进行深拷贝,以保持原始输入的完整性。后面的操作不会改变原始输入x。x = x.clone()   # 对输入x中前self.dim_conv3个通道应用卷积操作,并将结果保存回x中对应的位置。x[:, :self.dim_conv3, :, :] = self.partial_conv3(x[:, :self.dim_conv3, :, :])return x

方式2:split_cat

    # 适合训练/推理def forward_split_cat(self, x: Tensor) -> Tensor:# 使用torch.split函数将输入x沿着通道维度(即第1维,索引从0开始)分割成两个部分,# 分别为x1和x2。分割的长度为[self.dim_conv3, self.dim_untouched],# 即分割后的x1的通道数为self.dim_conv3,x2的通道数为self.dim_untouched。x1, x2 = torch.split(x, [self.dim_conv3, self.dim_untouched], dim=1)x1 = self.partial_conv3(x1)x = torch.cat((x1, x2), 1)return x

三、FasterNet模型原理

基于部分卷积算子PConv逐点卷积PWConv,作为主要的算子,进一步提出FasterNet。

这是一个新的神经网络家族,运行速度非常快,对许多视觉任务有效。模型架构如下:

它有4个层次级,每个层次级前面都有一个嵌入层(步长为4的常规4×4卷积)或一个合并层(步长为2的常规2×2卷积),用于空间下采样和通道数量扩展。每个阶段都有一堆FasterNet块。

每个FasterNet块有一个PConv层,后跟2个PWConv(或Conv 1×1)层。它们一起显示为倒置残差块,其中中间层具有扩展的通道数量,并且放置了Shorcut以重用输入特征。

最后两个阶段中的块消耗更少的内存访问,并且倾向于具有更高的FLOPS,因此,放置了更多FasterNet块,并相应地将更多计算分配给最后两个阶段。

补充一下标准化和激活层

标准化和激活层对于高性能神经网络也是不可或缺的。

然而,许多先前的工作在整个网络中过度使用这些层,这可能会限制特征多样性,从而损害性能。它还可以降低整体计算速度。

相比之下,只将它们放在每个中间PWConv之后,以保持特征多样性并实现较低的延迟。

四、FasterNet模型测试

使用默认的参数构建FasterNet

        mlp_ratio=2.0,

        embed_dim=96,

        depths=(1, 2, 8, 2),

        drop_path_rate=0.10,

看一下的模型参数 :

感觉模型也不小的。。。。。。。

测试代码分享给大家(代码存放路径:models/model_summary.py)

import torch.nn as nn
from fasternet import FasterNet
from torchsummary import summary# 默认参数
def fasternet(**kwargs):model = FasterNet(**kwargs)return model# S
def fasternet_s(**kwargs):model = FasterNet(mlp_ratio=2.0,embed_dim=128,depths=(1, 2, 13, 2),drop_path_rate=0.15,act_layer='RELU',fork_feat=True,**kwargs)return model# M
def fasternet_m(**kwargs):model = FasterNet(mlp_ratio=2.0,embed_dim=144,depths=(3, 4, 18, 3),drop_path_rate=0.2,act_layer='RELU',fork_feat=True,**kwargs)return model# L
def fasternet_l(**kwargs):model = FasterNet(mlp_ratio=2.0,embed_dim=192,depths=(3, 4, 18, 3),drop_path_rate=0.3,act_layer='RELU',fork_feat=True,**kwargs)return modelprint("fasternet:", fasternet)
model = fasternet()
summary(model, input_size=(3, 224, 224))print("fasternet_s:", fasternet_s)
model = fasternet_s()
summary(model, input_size=(3, 224, 224))print("fasternet_m:", fasternet_m)
model = fasternet_m()
summary(model, input_size=(3, 224, 224))print("fasternet_l:", fasternet_l)
model = fasternet_l()
summary(model, input_size=(3, 224, 224))

github有各个版本的预训练模型,大家可以测试一下。

nameresolutionacc#paramsFLOPsmodel
FasterNet-T0224x22471.93.9M0.34Gmodel
FasterNet-T1224x22476.27.6M0.85Gmodel
FasterNet-T2224x22478.915.0M1.90Gmodel
FasterNet-S224x22481.331.1M4.55Gmodel
FasterNet-M224x22483.053.5M8.72Gmodel
FasterNet-L224x22483.593.4M15.49Gmodel

官方给的数据:

五、实验分析

FasterNet在不同设备(CPU、GPU、ARM),精度-吞吐量和精度-延迟权衡方面具有最高的效率。

图像分类中,比较ImageNet-1k基准。具有类似TOP-1精度的模型被组合在一起。除MobileViT和EdgeNeXt的分辨率为256×256外,所有型号的分辨率均为224×224。OOM是内存不足的缩写。

关于COCO目标检测实例分割基准的结果,Flop是根据图像大小(1280,800)计算的。

分享完成~

这篇关于CVPR 2023 | 主干网络FasterNet 核心解读 代码分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/320530

相关文章

Java 接口定义变量的示例代码

《Java接口定义变量的示例代码》文章介绍了Java接口中的变量和方法,接口中的变量必须是publicstaticfinal的,用于定义常量,而方法默认是publicabstract的,必须由实现类... 在 Java 中,接口是一种抽象类型,用于定义类必须实现的方法。接口可以包含常量和方法,但不能包含实例

Mybatis对MySQL if 函数的不支持问题解读

《Mybatis对MySQLif函数的不支持问题解读》接手项目后,为了实现多租户功能,引入了Mybatis-plus,发现之前运行正常的SQL语句报错,原因是Mybatis不支持MySQL的if函... 目录MyBATis对mysql if 函数的不支持问题描述经过查询网上搜索资料找到原因解决方案总结Myb

Java中的CompletableFuture核心用法和常见场景

《Java中的CompletableFuture核心用法和常见场景》CompletableFuture是Java8引入的强大的异步编程工具,支持链式异步编程、组合、异常处理和回调,介绍其核心用法,通过... 目录1、引言2. 基本概念3. 创建 CompletableFuture3.1. 手动创建3.2.

Java线程池核心参数原理及使用指南

《Java线程池核心参数原理及使用指南》本文详细介绍了Java线程池的基本概念、核心类、核心参数、工作原理、常见类型以及最佳实践,通过理解每个参数的含义和工作原理,可以更好地配置线程池,提高系统性能,... 目录一、线程池概述1.1 什么是线程池1.2 线程池的优势二、线程池核心类三、ThreadPoolE

使用Redis实现会话管理的示例代码

《使用Redis实现会话管理的示例代码》文章介绍了如何使用Redis实现会话管理,包括会话的创建、读取、更新和删除操作,通过设置会话超时时间并重置,可以确保会话在用户持续活动期间不会过期,此外,展示了... 目录1. 会话管理的基本概念2. 使用Redis实现会话管理2.1 引入依赖2.2 会话管理基本操作

Springboot请求和响应相关注解及使用场景分析

《Springboot请求和响应相关注解及使用场景分析》本文介绍了SpringBoot中用于处理HTTP请求和构建HTTP响应的常用注解,包括@RequestMapping、@RequestParam... 目录1. 请求处理注解@RequestMapping@GetMapping, @PostMappin

mybatis-plus分表实现案例(附示例代码)

《mybatis-plus分表实现案例(附示例代码)》MyBatis-Plus是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生,:本文主要介绍my... 目录文档说明数据库水平分表思路1. 为什么要水平分表2. 核心设计要点3.基于数据库水平分表注意事项示例

Nginx服务器部署详细代码实例

《Nginx服务器部署详细代码实例》Nginx是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务,:本文主要介绍Nginx服务器部署的相关资料,文中通过代码... 目录Nginx 服务器SSL/TLS 配置动态脚本反向代理总结Nginx 服务器Nginx是一个‌高性

HTML5的input标签的`type`属性值详解和代码示例

《HTML5的input标签的`type`属性值详解和代码示例》HTML5的`input`标签提供了多种`type`属性值,用于创建不同类型的输入控件,满足用户输入的多样化需求,从文本输入、密码输入、... 目录一、引言二、文本类输入类型2.1 text2.2 password2.3 textarea(严格

JAVA项目swing转javafx语法规则以及示例代码

《JAVA项目swing转javafx语法规则以及示例代码》:本文主要介绍JAVA项目swing转javafx语法规则以及示例代码的相关资料,文中详细讲解了主类继承、窗口创建、布局管理、控件替换、... 目录最常用的“一行换一行”速查表(直接全局替换)实际转换示例(JFramejs → JavaFX)迁移建