pytorch搭建EfficientnetV2网络

news2024/11/17 11:46:20

文章目录

  • 前言
  • 一、EfficientnetV2
  • 二、网络结构
    • 1.Fused_MBConv
    • 2.MBConv
  • 三、整体代码
  • 总结


论文地址:https://arxiv.org/abs/2104.00298
官方代码:https://github.com/google/automl/tree/master/efficientnetv2
参考链接:https://blog.csdn.net/qq_37541097/article/details/116933569
代码参考链接:https://github.com/google/automl/tree/master/efficientnetv2

前言

之前,用pytorch搭建了EfficientnetV1的分类模型的训练流程搭建,可参考链接EfficientnetV1训练,本篇文章主要用于用pytorch搭建EfficientnetV2的网络结构,之后,将在此基础上完成训练框架的搭建。


一、EfficientnetV2

  EfficientnetV1的效果是显而易见的,但是它关注的主要是准确率和参数量,而V2版本中把重心放在了训练和推理速度上。如图:
在这里插入图片描述

二、网络结构

  EfficientnetV2有S、M、L、XL等版本,但是基本都是Fused_MBConv和MBConv的堆叠,这里我们仅展示论文中给出的S版本的结构图,如下:
在这里插入图片描述
需要注意的是,这里面使用到得激活函数默认都是Silu,其余部分参数解释如下:

  • k:卷积核大小
  • stride:每个stage第一次出现的步长,除第一次外,其余的步长均为1。比如stage1里,会有2次Fused_MBConv堆叠,那么第一次的步长为2,第二次及其以后的步长为1.
  • channels:输出通道数
  • layers:堆叠次数

这里我们仅展示Fused_MBConv 和MBConv的代码,整体代码可以跳到三查看

1.Fused_MBConv

基本结构如下:
在这里插入图片描述
这里需要注意的是,虽然官方的结构图中有SE注意力机制,但是代码中并没有添加,所以这里也没有添加。代码如下:

#Fused_MBConv
class Fused_MBConv(nn.Module):
    def __init__(self,in_ch,out_ch,k,s,drop_rate,expand=1):
        '''
        :param in_ch: 输入通道
        :param out_ch: 输出通道
        :param k: 卷积核大小
        :param s: 步长
        :param drop_rate: 神经元失活比例
        :param expand: expand conv层的输出通道,注意,当expand=1时,没有expand conv
        '''
        super(Fused_MBConv, self).__init__()

        self.expand,self.drop_rate=expand,drop_rate
        expand_c = self.expand * in_ch
        if self.expand==1:
            self.pro_conv=Conv(in_ch,out_ch,k,s)
        else:
            self.expand_conv=Conv(in_ch,expand_c,k,s)
            self.pro_conv=Conv(expand_c,out_ch,1,1,have_act=False) #这里没有激活函数


        #当且仅当输入通道和输出通道相同时,并且s=1时才有shortcut
        if in_ch==out_ch and s==1:
            self.have_shortcut=True
        else:
            self.have_shortcut=False

        #当且仅当shortcut为True并且drop_rote>0时使用dropout
        if self.have_shortcut and self.drop_rate>0:
            self.dropout=DropPath(drop_rate)

    def forward(self,x):
        if self.expand==1:
            result=self.pro_conv(x)
        else:
            result=self.expand_conv(x)
            result=self.pro_conv(result)

        if self.have_shortcut:
            #是否有dropout
            if self.drop_rate>0:
                result=self.dropout(result)
            result+=x
        return result

2.MBConv

基本结构如下:
在这里插入图片描述

代码如下:

#SE
class SE(nn.Module):
    def __init__(self,in_ch,out_ch,se_rate):
        '''
        :param in_ch: 输入通道
        :param out_ch: 输出通道
        :param se_rate: SE比例
        '''
        super(SE, self).__init__()
        squeeze_c=int(in_ch*se_rate)
        self.conv1=nn.Conv2d(out_ch,squeeze_c,1)
        self.act1=nn.SiLU()
        self.conv2=nn.Conv2d(squeeze_c,out_ch,1)
        self.act2=nn.Sigmoid()

    def forward(self,x):
        res=x.mean((2,3),keepdim=True)
        res=self.act1(self.conv1(res))
        res=self.act2(self.conv2(res))
        return res*x

#MBConv
class MBConv(nn.Module):
    def __init__(self,in_ch,out_ch,k,s,drop_rate,se_rate=0.25,expand=1,):
        '''
        :param in_ch: 输入通道
        :param out_ch: 输出通道
        :param k: 卷积核大小
        :param s: 步长
        :param drop_rate: 神经元失活比例
        :param expand: expand conv层的输出通道,注意,当expand=1时,没有expand conv
        :param se_rate: SE比例
        '''
        super(MBConv, self).__init__()
        self.expand, self.drop_rate = expand, drop_rate
        expand_c = self.expand * in_ch

        self.expand_conv=Conv(in_ch,expand_c,1,1)
        self.depwise_conv=Conv(expand_c,expand_c,k,s,expand_c)

        #SE结构
        self.se=SE(in_ch,expand_c,se_rate)

        self.project_conv=Conv(expand_c,out_ch,1,1,1,False)

        #dropout
        # 当且仅当输入通道和输出通道相同时,并且s=1时才有shortcut
        if in_ch == out_ch and s == 1:
            self.have_shortcut = True
        else:
            self.have_shortcut = False
        # 只有在使用shortcut连接时才使用dropout层
        self.drop_rate = drop_rate
        # 当且仅当shortcut为True并且drop_rote>0时使用dropout
        if self.have_shortcut and self.drop_rate > 0:
            self.dropout = DropPath(drop_rate)

    def forward(self,x):
        res=self.expand_conv(x)
        res=self.depwise_conv(res)
        res=self.se(res)
        res=self.project_conv(res)
        if self.have_shortcut:
            #是否有dropout
            if self.drop_rate>0:
                res=self.dropout(res)
            res+=x
        return res

三、整体代码

这里的dropout代码直接用了参考代码里的函数,完整如下:

import torch.nn as nn
import torch

def drop_path(x, drop_prob: float = 0., training: bool = False):
    if drop_prob == 0. or not training:
        return x
    keep_prob = 1 - drop_prob
    shape = (x.shape[0],) + (1,) * (x.ndim - 1)  # work with diff dim tensors, not just 2D ConvNets
    random_tensor = keep_prob + torch.rand(shape, dtype=x.dtype, device=x.device)
    random_tensor.floor_()  # binarize
    output = x.div(keep_prob) * random_tensor
    return output


class DropPath(nn.Module):
    def __init__(self, drop_prob=None):
        super(DropPath, self).__init__()
        self.drop_prob = drop_prob

    def forward(self, x):
        return drop_path(x, self.drop_prob, self.training)


#基本卷积块
class Conv(nn.Module):
    def __init__(self,in_ch,out_ch,k,s,group=1,have_act=True):
        '''
        :param in_ch: 输入通道
        :param out_ch: 输出通道
        :param k: 卷积核大小
        :param s: 步长
        :param group: 按通道卷积
        :param have_act: 是否有激活函数
        :return:
        '''
        super(Conv, self).__init__()
        self.conv=nn.Conv2d(in_ch,out_ch,k,s,padding=k//2,groups=group)
        self.bn = nn.BatchNorm2d(out_ch, eps=1e-3, momentum=0.1)
        if have_act:
            self.act = nn.SiLU()
        else:
            self.act=nn.Identity()


    def forward(sellf,x):
        x=sellf.conv(x)
        out=sellf.act(sellf.bn(x))
        return out

#Fused_MBConv
class Fused_MBConv(nn.Module):
    def __init__(self,in_ch,out_ch,k,s,drop_rate,expand=1):
        '''
        :param in_ch: 输入通道
        :param out_ch: 输出通道
        :param k: 卷积核大小
        :param s: 步长
        :param drop_rate: 神经元失活比例
        :param expand: expand conv层的输出通道,注意,当expand=1时,没有expand conv
        '''
        super(Fused_MBConv, self).__init__()

        self.expand,self.drop_rate=expand,drop_rate
        expand_c = self.expand * in_ch
        if self.expand==1:
            self.pro_conv=Conv(in_ch,out_ch,k,s)
        else:
            self.expand_conv=Conv(in_ch,expand_c,k,s)
            self.pro_conv=Conv(expand_c,out_ch,1,1,have_act=False) #这里没有激活函数


        #当且仅当输入通道和输出通道相同时,并且s=1时才有shortcut
        if in_ch==out_ch and s==1:
            self.have_shortcut=True
        else:
            self.have_shortcut=False

        #当且仅当shortcut为True并且drop_rote>0时使用dropout
        if self.have_shortcut and self.drop_rate>0:
            self.dropout=DropPath(drop_rate)

    def forward(self,x):
        # print(x.shape)
        if self.expand==1:
            result=self.pro_conv(x)
        else:
            result=self.expand_conv(x)
            result=self.pro_conv(result)

        if self.have_shortcut:
            #是否有dropout
            if self.drop_rate>0:
                result=self.dropout(result)
            result+=x
        # print(result.shape)
        return result

#SE
class SE(nn.Module):
    def __init__(self,in_ch,out_ch,se_rate):
        '''
        :param in_ch: 输入通道
        :param out_ch: 输出通道
        :param se_rate: SE比例
        '''
        super(SE, self).__init__()
        squeeze_c=int(in_ch*se_rate)
        self.conv1=nn.Conv2d(out_ch,squeeze_c,1)
        self.act1=nn.SiLU()
        self.conv2=nn.Conv2d(squeeze_c,out_ch,1)
        self.act2=nn.Sigmoid()

    def forward(self,x):
        res=x.mean((2,3),keepdim=True)
        res=self.act1(self.conv1(res))
        res=self.act2(self.conv2(res))
        return res*x

#MBConv
class MBConv(nn.Module):
    def __init__(self,in_ch,out_ch,k,s,drop_rate,se_rate=0.25,expand=1,):
        '''
        :param in_ch: 输入通道
        :param out_ch: 输出通道
        :param k: 卷积核大小
        :param s: 步长
        :param drop_rate: 神经元失活比例
        :param expand: expand conv层的输出通道,注意,当expand=1时,没有expand conv
        :param se_rate: SE比例
        '''
        super(MBConv, self).__init__()
        self.expand, self.drop_rate = expand, drop_rate
        expand_c = self.expand * in_ch

        self.expand_conv=Conv(in_ch,expand_c,1,1)
        self.depwise_conv=Conv(expand_c,expand_c,k,s,expand_c)

        #SE结构
        self.se=SE(in_ch,expand_c,se_rate)

        self.project_conv=Conv(expand_c,out_ch,1,1,1,False)

        #dropout
        # 当且仅当输入通道和输出通道相同时,并且s=1时才有shortcut
        if in_ch == out_ch and s == 1:
            self.have_shortcut = True
        else:
            self.have_shortcut = False
        # 只有在使用shortcut连接时才使用dropout层
        self.drop_rate = drop_rate
        # 当且仅当shortcut为True并且drop_rote>0时使用dropout
        if self.have_shortcut and self.drop_rate > 0:
            self.dropout = DropPath(drop_rate)

    def forward(self,x):
        res=self.expand_conv(x)
        res=self.depwise_conv(res)
        res=self.se(res)
        res=self.project_conv(res)
        if self.have_shortcut:
            #是否有dropout
            if self.drop_rate>0:
                res=self.dropout(res)
            res+=x
        return res


class EfficientnetV2(nn.Module):
    def __init__(self,model_type,class_num,drop_connect_rate=0.2,se_rate=0.25):
        '''
        :param model_type: 网络结构,可选s,m,l
        :param class_num: 类倍数
        :param drop_connect_rate: 最大的神经元失活比例
        :param se_rate: SE结构中使用的节点比例
        '''
        super(EfficientnetV2, self).__init__()
        self.class_num=class_num
        #根据结构类型进行参数确定
        if model_type=="S" or model_type=="s":
            # [[每层重复的次数,该层对应的expand,k,s,in_ch,out_ch,conv_type]]
            # conv_type为0表示Fused_MBConv,为1表示MBConv
            repeat_expand_list=[[2,1,3,1,24,24,0],
                                [4,4,3,2,24,48,0],
                                [4,4,3,2,48,64,0],
                                [6,4,3,2,64,128,1],
                                [9,6,3,1,128,160,1],
                                [15,6,3,2,160,256,1]]
        elif model_type=="M" or model_type=="m":
            # [[每层重复的次数,该层对应的expand,k,s,in_ch,out_ch,conv_type]]
            # conv_type为0表示Fused_MBConv,为1表示MBConv
            repeat_expand_list = [[3, 1,3,1,24,24,0],
                                  [5, 4,3,2,24,48,0],
                                  [5, 4,3,2,48,80,0],
                                  [7, 4,3,2,80,160,1],
                                  [14, 6,3,1,160,176,1],
                                  [18, 6,3,2,176,304,1],
                                  [5,6,3,1,304,512,1]]

        elif model_type == "L" or model_type == "l":
            # [[每层重复的次数,该层对应的expand,k,s,in_ch,out_ch,conv_type]]
            # conv_type为0表示Fused_MBConv,为1表示MBConv
            repeat_expand_list = [[4, 1,3,1,32,32,0],
                                  [7, 4,3,2,32,64,0],
                                  [7, 4,3,2,64,96,0],
                                  [10, 4,3,2,96,192,1],
                                  [19, 6,3,1,192,224,1],
                                  [25, 6,3,2,224,384,1],
                                  [7,6,3,1,384,640,1]]

        #第一个卷积层
        self.conv1=Conv(3,repeat_expand_list[0][4],3,2)

        #backbone
        blocks=[]
        num=0 #同于确定expand—Conv的输出通道数
        total_num=sum(i[0] for i in repeat_expand_list)
        for repeat_expand in repeat_expand_list:
            # repeat,expand=repeat_expand[0],repeat_expand[1] #某层堆叠次数,expand参数
            if repeat_expand[-1]==0:
                for r in range(repeat_expand[0]):
                    drop_rate=drop_connect_rate * num / total_num
                    in_ch=repeat_expand[4] if r==0 else repeat_expand[5]
                    s=repeat_expand[3] if r==0 else 1
                    blocks.append(Fused_MBConv(in_ch,repeat_expand[5],repeat_expand[2],s,drop_rate,repeat_expand[1]))
                    num+=1
            else:
                for r in range(repeat_expand[0]):
                    drop_rate = drop_connect_rate * num / total_num
                    in_ch=repeat_expand[4] if r==0 else repeat_expand[5]
                    s = repeat_expand[3] if r == 0 else 1
                    blocks.append(MBConv(in_ch, repeat_expand[5], repeat_expand[2],s, drop_rate,se_rate,repeat_expand[1]))
                    num += 1
        self.block=nn.Sequential(*blocks)

        #class head
        heads=[]
        features=1280
        head_conv=Conv(repeat_expand_list[-1][5],features,1,1)
        avg=nn.AdaptiveAvgPool2d(1)
        flatten=nn.Flatten()
        heads.append(head_conv)
        heads.append(avg)
        heads.append(flatten)
        if drop_connect_rate > 0:
            drop_out = nn.Dropout(drop_connect_rate, inplace=True)
            heads.append(drop_out)
        linear=nn.Linear(features,self.class_num)
        heads.append(linear)
        self.head=nn.Sequential(*heads)


    def forward(self,x):
        res=self.conv1(x)
        res=self.block(res)
        res=self.head(res)
        return res

整体看下来的话, 大体和参考代码里的代码差不多,只是改成了自己觉得方便的封装格式。


总结

以上就是本篇的全部内容,想更加了解网络结构的话,可以去看下大佬的讲解视频,讲的很清楚,也感谢大佬贡献的代码。如本篇文章发现有不对的地方,欢迎评论区指正。另外,训练部分的代码将在几天后发布。

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

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

相关文章

经典:DotNetBar Suite UI 7.9 for WPF Crack

创建专业的 WPF 应用程序 DotNetBar Suite for WPF 是超过 38 个本机 Windows Presentation Foundation 控件的工具箱,用于创建专业的 WPF 应用程序。 Office 2016 类样式添加到功能区、日程安排和其他控件... 我们痴迷于控制性能和像素级细节。我们很自豪地说&…

2023年杭州助理工程师职称申报评审流程是什么呢?社保单位不一致怎么办?

助理工程师证,又称为初级工程证或者初级职称。助理工程师,是指初级工程技术人员的职务名称。有了助理工程师证你可以评中级工程师证,也可以应聘、在职、上岗、加薪、企业升资质和招投标都用的到。助理工程师证是评审获得的,评审报…

如何正确使用 Facebook 反链,增强网站在搜索引擎中的曝光度

在当今数字化时代,拥有一个强大的在线存在感是企业成功的关键之一。而在建立有效的在线存在感时,搜索引擎优化(SEO)扮演着重要的角色。而其中一个重要的SEO策略是利用反链来增强网站在搜索引擎中的曝光度。 然而,许多…

【服务器数据恢复】HP双循环Raid5磁盘阵列数据恢复案例

服务器数据恢复环境: 一台HP DL系列服务器,通过hp smart array控制器挂载一台磁盘阵列设备,作为公司内部的文件服务器使用; 该磁盘阵列设备中有一组由十几块SCSI硬盘组建的RAID5; 上层安装LINUX操作系统并部署了NFSFTP…

结算更高效,成本更节省,风控更全面,用友银企联助力万家企业加速数字变革

数字经济蓬勃发展的当下,在业绩增长和管理提效的双重压力下,企业纷纷投身于数字化、智能化转型升级,通过大数据及新一代人工智能技术寻求产业变革,以实现企业业务创新与管控升级。银企联作为企业与银行信息交互的通道,…

SpringBoot——pom文件:parent

先看一看&#xff1a; 本次我们主要介绍SpringBoot的文件&#xff0c;先来看一看里面都有什么内容&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <!--XML文件的抬头--> <!--一些约束以及明明空间信息--> <project xmlns&qu…

知识图谱实现全域数据资产智能管理与运营

案例名称 基于知识图谱的全域数据资产智能管理与运营 案例简介 该方案通过数据资产元数据构建引擎、列算子血缘引擎、关系挖掘引擎和数据资产目录挂载引擎的部署&#xff0c;可快速实现金融机构数据资产的业务目录分类以及数据资产标签集合建设。通过可视化引擎管…

Ubuntu配置Samba服务

Ubuntu配置Samba服务 一、安装samba二、配置samba服务器三、win系统配置四、检查你的虚拟机五、注意 一、安装samba 前提&#xff1a;已经换好源&#xff0c;不然下载很慢或者不成功 未换执行以下命令 sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak sudo vim/etc…

虹科案例 | 使用PRP协议解决广播行业中实现高可用性和亚微秒同步难题

案例背景 BROADCASTING PUBLIC ENTITY主要为用户提供电视频道和广播频道&#xff0c;为了带来更好的视听体验&#xff0c;该公司必须更新其无线电前端系统的基础设施。前端的主要功能是接收来自广播电台的现场音频并将其编码为压缩格式&#xff0c;例如AAC&#xff0c;然后将多…

unity 完全复刻flappy bird

文章目录 一、 介绍制作bird向右移动的效果基本动画转场渐隐效果dotween 平滑摇头效果柱子控制器碰撞检测下载项目文件 一、 介绍 Flappy Bird是一款由越南开发者Dong Nguyen于2013年发布的2D跳跃游戏。玩家需要控制一只小鸟躲避障碍物&#xff0c;通过不断飞行获得分数。游戏…

如果把ChatGPT和“挖呀挖”的黄老师结合起来,她可以为你做什么事情?

ChatGPT曾经2个月用户过亿的事情已成为过去&#xff0c;虽然我也成为了其中的一份子&#xff0c;感受着他的无所不能&#xff0c;但从中也的确发现了他的一些不能做的事情。而近期爆火的“挖呀挖”的黄老师&#xff0c;几天粉丝疯涨几百万&#xff0c;也的确值得我们思考。 那么…

kafka安装及环境搭建

1. 下载 下载地址&#xff1a;Apache Kafka 我这里下载的是 3.2.1 版本。 2. 上传并解压 上传到 linux 下的 /home/software/ 目录下&#xff0c;然后解压 kafka_2.13-3.2.1.tgz 包到/usr/local/ cd /home/software tar -zxvf kafka_2.13-3.2.1.tgz -C /usr/local # -C 选…

odoo的一些基础概念

概述 三层体系结构&#xff0c;表示层是HTML5、JavaScript和CSS的组合&#xff0c;逻辑层专门用Python编写&#xff0c;而数据层只支持PostgreSQL作为RDBMS。 服务器和客户端扩展都打包为模块&#xff0c;可选地加载到数据库中。模块是针对单一目的的函数和数据的集合。Odoo中…

拉取远程分支到本地修改后上传

在git之前最好保证网络通畅 如果之前本地有项目且有git控制&#xff0c;直接更新就行了 git pull 1、拉取仓库 git clone https://github.com/用户名/仓库名.git 2、对项目进行修改(略) 3、将所有更改添加到暂存区 git add . git add .命令将所有更改添加到暂存区&#…

OpenPCDet系列 | 3.OpenPCDet点云检测框架训练准备流程

文章目录 训练准备流程1. dataloader部分2. network部分3. optimizer部分4. scheduler部分训练准备流程 对于OpenPCDet中模型的训练过程如下所示,在训练前一般需要进行4个部分的准备:数据准备、网络模型准备、以及优化器和学习率调度器。下面对这4个大部分分别介绍。主要就是…

delete方法删除对象数组中元素导致原始数据被修改

记录一个自己在码代码过程中遇到的问题。 要求&#xff1a;删除数组对象中每一组对象中的一个属性。 下面是我原始的写法(当然是错误的)。 const { log } require("console");// 用于测试delete方法&#xff0c;删除对象中的指定元素 const testForDelete () >…

【中创数智人】“周杰伦?数智人周同学!”7×24小时直播不间断,他做到了

迈进Web 3.0&#xff0c;离不开数智人。 品牌代言、公司宣传、产品介绍、直播带货......数智人扮演的角色正在不断增加。无论是替代真人服务、多模态AI助手、还是作为虚拟世界的第二分身&#xff0c;对于数智人而言都已经是触手可及的未来。 5月8日&#xff0c;周杰伦亮相中国…

【JavaEE】线程安全(难点)

目录 前言 1、线程安全的概念 2、线程不安全的原因 3、产生抢占式执行与原子性问题 4、产生多个线程修改同一个变量的问题 5、解决上述三个导致线程不安全的问题 5.1、锁 synchronized关键字 5.1.1、使用synchronized关键字进行加锁 6、由内存可见性引起的线程不安全…

KubeEdge节点分组特性简介

01 边缘应用跨地域部署场景及问题 应用生命周期管理复杂导致运维成本提高 02 边缘节点分组管理 节点分组&#xff1a;将不同地区的边缘节点按照节点组的形式组织 边缘应用&#xff1a;将应用资源整体打包并满足不同节点组之间的差异化部署需求 流量闭环&#xff1a;将服务流量…

Oracle内存管理

文章目录 概念内存管理方式自动内存管理自动共享内存管理手工内存管理 内存管理的转换方式相关内存参数相关数据字典 概念 为满足数据库的需求&#xff0c;通过内存管理来维护 Oracle 实例内存结构的最优大小。Oracle数 据库基于与内存相关的初始化参数设置来管理内存。 内存管…