【Classical Network】EfficientNetV2

news2024/12/28 21:02:05

原文地址
原文代码
pytorch实现1
pytorch实现2
详细讲解

文章目录

  • EfficientNet中存在的问题
  • NAS 搜索
  • EfficientNetV2 网络结构
  • code

EfficientNet中存在的问题

  1. 训练图像尺寸大时,训练速度非常慢。train size = 512, batch = 24时,V100 out of memory
  2. 在网络浅层中使用Depthwise convolutions速度会很慢。因此将原本EfficientNet中的conv1x1 and depthwise conv3x3 (MBConv)替换成conv3x3 (Fused-MBCon![请添加图片描述](https://img-blog.csdnimg.cn/fbc1131820d84da388fd075356f999f6.png) v)。但如果将所有的conv1x1 and depthwise conv3x3都替换成conv3x3后,会明显增加参数数量,降低训练速度,因此使用NAS技术去搜索两者的最佳组合。
    请添加图片描述
  3. 同等放大每个stage是次优的,因为每个stage对网络的训练速度以及参数量贡献不同。

NAS 搜索

与EfficientNet相同,但这次的NAS搜索采用了联合优化策略,联合了accuracy, parameter efficiency, training efficiency三个标准。设计空间包括

  • convolutional operation types {MBConv, Fused-MBConv}
  • number of layers
  • kernel size {3x3, 5x5}
  • expansion ration {1,4,6}
    同时随机采样1000个models,并且对每个models进行了10个epochs的训练。搜索奖励结合了模型准确率A,标准训练一个step所需要的时间S,和参数量P, A ⋅ S − 0.07 ⋅ P − 0.05 A \cdot S^{-0.07} \cdot P^{-0.05} AS0.07P0.05

EfficientNetV2 网络结构

EfficientNetV2-S
与EfficientNet相比,EfficientNetV2有以下区别:

  • 在浅层网络中大量运用了MBConv和新加入的fused-MBConv
  • 使用了较小的expansion ratio,可以达到较小的内存访问开销
  • 偏向于kernel3x3,但这需要增加层数来弥补小kernel感受野的不足
  • 移除了last stride-1 stage,但是这是由于NAS搜索出来的,所以是作者的猜测可能是在参数量和访存开销的优化。

code

# 使用的是https://github.com/WZMIAOMIAO/deep-learning-for-image-processing/blob/master/pytorch_classification/Test11_efficientnetV2/model.py 中的代码!

from collections import OrderedDict
from functools import partial
from typing import Callable, Optional

import torch.nn as nn
import torch
from torch import Tensor



def drop_path(x, drop_prob: float = 0., training: bool = False):
    """
    Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).
    "Deep Networks with Stochastic Depth", https://arxiv.org/pdf/1603.09382.pdf

    This function is taken from the rwightman.
    It can be seen here:
    https://github.com/rwightman/pytorch-image-models/blob/master/timm/models/layers/drop.py#L140
    """
    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):
    """
    Drop paths (Stochastic Depth) per sample  (when applied in main path of residual blocks).
    "Deep Networks with Stochastic Depth", https://arxiv.org/pdf/1603.09382.pdf
    """
    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 ConvBNAct(nn.Module):
    def __init__(self,
                 in_planes: int,
                 out_planes: int,
                 kernel_size: int = 3,
                 stride: int = 1,
                 groups: int = 1,
                 norm_layer: Optional[Callable[..., nn.Module]] = None,
                 activation_layer: Optional[Callable[..., nn.Module]] = None):
        super(ConvBNAct, self).__init__()

        padding = (kernel_size - 1) // 2
        if norm_layer is None:
            norm_layer = nn.BatchNorm2d
        if activation_layer is None:
            activation_layer = nn.SiLU  # alias Swish  (torch>=1.7)

        self.conv = nn.Conv2d(in_channels=in_planes,
                              out_channels=out_planes,
                              kernel_size=kernel_size,
                              stride=stride,
                              padding=padding,
                              groups=groups,
                              bias=False)

        self.bn = norm_layer(out_planes)
        self.act = activation_layer()

    def forward(self, x):
        result = self.conv(x)
        result = self.bn(result)
        result = self.act(result)

        return result


class SqueezeExcite(nn.Module):
    def __init__(self,
                 input_c: int,   # block input channel
                 expand_c: int,  # block expand channel
                 se_ratio: float = 0.25):
        super(SqueezeExcite, self).__init__()
        squeeze_c = int(input_c * se_ratio)
        self.conv_reduce = nn.Conv2d(expand_c, squeeze_c, 1)
        self.act1 = nn.SiLU()  # alias Swish
        self.conv_expand = nn.Conv2d(squeeze_c, expand_c, 1)
        self.act2 = nn.Sigmoid()

    def forward(self, x: Tensor) -> Tensor:
        scale = x.mean((2, 3), keepdim=True)
        scale = self.conv_reduce(scale)
        scale = self.act1(scale)
        scale = self.conv_expand(scale)
        scale = self.act2(scale)
        return scale * x


class MBConv(nn.Module):
    def __init__(self,
                 kernel_size: int,
                 input_c: int,
                 out_c: int,
                 expand_ratio: int,
                 stride: int,
                 se_ratio: float,
                 drop_rate: float,
                 norm_layer: Callable[..., nn.Module]):
        super(MBConv, self).__init__()

        if stride not in [1, 2]:
            raise ValueError("illegal stride value.")

        self.has_shortcut = (stride == 1 and input_c == out_c)

        activation_layer = nn.SiLU  # alias Swish
        expanded_c = input_c * expand_ratio

        # 在EfficientNetV2中,MBConv中不存在expansion=1的情况所以conv_pw肯定存在
        assert expand_ratio != 1
        # Point-wise expansion
        self.expand_conv = ConvBNAct(input_c,
                                     expanded_c,
                                     kernel_size=1,
                                     norm_layer=norm_layer,
                                     activation_layer=activation_layer)

        # Depth-wise convolution
        self.dwconv = ConvBNAct(expanded_c,
                                expanded_c,
                                kernel_size=kernel_size,
                                stride=stride,
                                groups=expanded_c,
                                norm_layer=norm_layer,
                                activation_layer=activation_layer)

        self.se = SqueezeExcite(input_c, expanded_c, se_ratio) if se_ratio > 0 else nn.Identity()

        # Point-wise linear projection
        self.project_conv = ConvBNAct(expanded_c,
                                      out_planes=out_c,
                                      kernel_size=1,
                                      norm_layer=norm_layer,
                                      activation_layer=nn.Identity)  # 注意这里没有激活函数,所有传入Identity

        self.out_channels = out_c

        # 只有在使用shortcut连接时才使用dropout层
        self.drop_rate = drop_rate
        if self.has_shortcut and drop_rate > 0:
            self.dropout = DropPath(drop_rate)

    def forward(self, x: Tensor) -> Tensor:
        result = self.expand_conv(x)
        result = self.dwconv(result)
        result = self.se(result)
        result = self.project_conv(result)

        if self.has_shortcut:
            if self.drop_rate > 0:
                result = self.dropout(result)
            result += x

        return result


class FusedMBConv(nn.Module):
    def __init__(self,
                 kernel_size: int,
                 input_c: int,
                 out_c: int,
                 expand_ratio: int,
                 stride: int,
                 se_ratio: float,
                 drop_rate: float,
                 norm_layer: Callable[..., nn.Module]):
        super(FusedMBConv, self).__init__()

        assert stride in [1, 2]
        assert se_ratio == 0

        self.has_shortcut = stride == 1 and input_c == out_c
        self.drop_rate = drop_rate

        self.has_expansion = expand_ratio != 1

        activation_layer = nn.SiLU  # alias Swish
        expanded_c = input_c * expand_ratio

        # 只有当expand ratio不等于1时才有expand conv
        if self.has_expansion:
            # Expansion convolution
            self.expand_conv = ConvBNAct(input_c,
                                         expanded_c,
                                         kernel_size=kernel_size,
                                         stride=stride,
                                         norm_layer=norm_layer,
                                         activation_layer=activation_layer)

            self.project_conv = ConvBNAct(expanded_c,
                                          out_c,
                                          kernel_size=1,
                                          norm_layer=norm_layer,
                                          activation_layer=nn.Identity)  # 注意没有激活函数
        else:
            # 当只有project_conv时的情况
            self.project_conv = ConvBNAct(input_c,
                                          out_c,
                                          kernel_size=kernel_size,
                                          stride=stride,
                                          norm_layer=norm_layer,
                                          activation_layer=activation_layer)  # 注意有激活函数

        self.out_channels = out_c

        # 只有在使用shortcut连接时才使用dropout层
        self.drop_rate = drop_rate
        if self.has_shortcut and drop_rate > 0:
            self.dropout = DropPath(drop_rate)

    def forward(self, x: Tensor) -> Tensor:
        if self.has_expansion:
            result = self.expand_conv(x)
            result = self.project_conv(result)
        else:
            result = self.project_conv(x)

        if self.has_shortcut:
            if self.drop_rate > 0:
                result = self.dropout(result)

            result += x

        return result


class EfficientNetV2(nn.Module):
    def __init__(self,
                 model_cnf: list,
                 num_classes: int = 1000,
                 num_features: int = 1280,
                 dropout_rate: float = 0.2,
                 drop_connect_rate: float = 0.2):
        super(EfficientNetV2, self).__init__()

        for cnf in model_cnf:
            assert len(cnf) == 8

        norm_layer = partial(nn.BatchNorm2d, eps=1e-3, momentum=0.1)

        stem_filter_num = model_cnf[0][4]

        self.stem = ConvBNAct(3,
                              stem_filter_num,
                              kernel_size=3,
                              stride=2,
                              norm_layer=norm_layer)  # 激活函数默认是SiLU

        total_blocks = sum([i[0] for i in model_cnf])
        block_id = 0
        blocks = []
        for cnf in model_cnf:
            repeats = cnf[0]
            op = FusedMBConv if cnf[-2] == 0 else MBConv
            for i in range(repeats):
                blocks.append(op(kernel_size=cnf[1],
                                 input_c=cnf[4] if i == 0 else cnf[5],
                                 out_c=cnf[5],
                                 expand_ratio=cnf[3],
                                 stride=cnf[2] if i == 0 else 1,
                                 se_ratio=cnf[-1],
                                 drop_rate=drop_connect_rate * block_id / total_blocks,
                                 norm_layer=norm_layer))
                block_id += 1
        self.blocks = nn.Sequential(*blocks)

        head_input_c = model_cnf[-1][-3]
        head = OrderedDict()

        head.update({"project_conv": ConvBNAct(head_input_c,
                                               num_features,
                                               kernel_size=1,
                                               norm_layer=norm_layer)})  # 激活函数默认是SiLU

        head.update({"avgpool": nn.AdaptiveAvgPool2d(1)})
        head.update({"flatten": nn.Flatten()})

        if dropout_rate > 0:
            head.update({"dropout": nn.Dropout(p=dropout_rate, inplace=True)})
        head.update({"classifier": nn.Linear(num_features, num_classes)})

        self.head = nn.Sequential(head)

        # initial weights
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight, mode="fan_out")
                if m.bias is not None:
                    nn.init.zeros_(m.bias)
            elif isinstance(m, nn.BatchNorm2d):
                nn.init.ones_(m.weight)
                nn.init.zeros_(m.bias)
            elif isinstance(m, nn.Linear):
                nn.init.normal_(m.weight, 0, 0.01)
                nn.init.zeros_(m.bias)

    def forward(self, x: Tensor) -> Tensor:
        x = self.stem(x)
        x = self.blocks(x)
        x = self.head(x)

        return x


def efficientnetv2_s(num_classes: int = 1000):
    """
    EfficientNetV2
    https://arxiv.org/abs/2104.00298
    """
    # train_size: 300, eval_size: 384

    # repeat, kernel, stride, expansion, in_c, out_c, operator, se_ratio
    model_config = [[2, 3, 1, 1, 24, 24, 0, 0],
                    [4, 3, 2, 4, 24, 48, 0, 0],
                    [4, 3, 2, 4, 48, 64, 0, 0],
                    [6, 3, 2, 4, 64, 128, 1, 0.25],
                    [9, 3, 1, 6, 128, 160, 1, 0.25],
                    [15, 3, 2, 6, 160, 256, 1, 0.25]]

    model = EfficientNetV2(model_cnf=model_config,
                           num_classes=num_classes,
                           dropout_rate=0.2)
    return model


def efficientnetv2_m(num_classes: int = 1000):
    """
    EfficientNetV2
    https://arxiv.org/abs/2104.00298
    """
    # train_size: 384, eval_size: 480

    # repeat, kernel, stride, expansion, in_c, out_c, operator, se_ratio
    model_config = [[3, 3, 1, 1, 24, 24, 0, 0],
                    [5, 3, 2, 4, 24, 48, 0, 0],
                    [5, 3, 2, 4, 48, 80, 0, 0],
                    [7, 3, 2, 4, 80, 160, 1, 0.25],
                    [14, 3, 1, 6, 160, 176, 1, 0.25],
                    [18, 3, 2, 6, 176, 304, 1, 0.25],
                    [5, 3, 1, 6, 304, 512, 1, 0.25]]

    model = EfficientNetV2(model_cnf=model_config,
                           num_classes=num_classes,
                           dropout_rate=0.3)
    return model


def efficientnetv2_l(num_classes: int = 1000):
    """
    EfficientNetV2
    https://arxiv.org/abs/2104.00298
    """
    # train_size: 384, eval_size: 480

    # repeat, kernel, stride, expansion, in_c, out_c, operator, se_ratio
    model_config = [[4, 3, 1, 1, 32, 32, 0, 0],
                    [7, 3, 2, 4, 32, 64, 0, 0],
                    [7, 3, 2, 4, 64, 96, 0, 0],
                    [10, 3, 2, 4, 96, 192, 1, 0.25],
                    [19, 3, 1, 6, 192, 224, 1, 0.25],
                    [25, 3, 2, 6, 224, 384, 1, 0.25],
                    [7, 3, 1, 6, 384, 640, 1, 0.25]]

    model = EfficientNetV2(model_cnf=model_config,
                           num_classes=num_classes,
                           dropout_rate=0.4)
    return model

from torchsummary import summary
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model = efficientnetv2_l()
model = model.to(device)
summary(model, (3,256,256))

使用torchsummary输出结果:

================================================================
Total params: 118,515,272
Trainable params: 118,515,272
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.75
Forward/backward pass size (MB): 1576.33
Params size (MB): 452.10
Estimated Total Size (MB): 2029.18
----------------------------------------------------------------

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

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

相关文章

联想笔记本无法下载 Lenovo Vantage

状况 在 Microsoft Store 下载时发生错误,可能是如下代码:0x80070005, 0x80073D05, or 0x80070017. 解决方法 1.在“开始”菜单搜索栏中输入PowerShell 2.当Windows PowerShell出现在“开始”菜单中,右键点击此图标,然后选择以…

AWS攻略——使用中转网关(Transit Gateway)连接同区域(Region)VPC

文章目录环境准备创建VPC配置中转网关给每个VPC创建Transit Gateway专属挂载子网创建中转网关创建中转网关挂载修改VPC的路由验证创建业务Private子网创建可被外网访问的环境测试子网连通性Public子网到Private子网Private子网到Private子网知识点参考资料在《AWS攻略——Peeri…

I.MX6ULL_Linux_系统篇(18) uboot移植

原厂uboot 编译 uboot 的移植并不是说我们完完全全的从零开始将 uboot 移植到我们现在所使用的开发板或者开发平台上。这个对于我们来说基本是不可能的,这个工作一般是半导体厂商做的, 半导体厂商负责将 uboot 移植到他们的芯片上,因此半导体…

网易云音乐财报解读:收入大增亏损收窄,“云村”草长莺飞

独家版权时代结束后,在线音乐产业进入了新的发展阶段,各家音乐平台经营状况备受关注。 2月23日,网易云音乐公布了2022年全年财务业绩。财报显示,网易云音乐2022年全年收入为90亿元,较2021年同比增长28.5%。 值得一提的…

IDEA集成Git

1:IDEA集合Git1.1:配置Git忽略文件-IDEA特定文件问题 1:为什么要忽略他们?答: 与项目的实际功能无关, 不参与服务器上部署运行。把它们忽略掉能够屏蔽 IDE 工具之间的差异。问题 2:怎么忽略?1&a…

分布式锁zookeeper实现详解原理及落地方案

吐血推荐:最近整理之前面试BAT的材料,写了一份《Java面试BATJ通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。 领取方法: Java面试BATJ通关手册 介绍 当一个应用程序需要在分布式系统中对共…

cmake demo

工程描述 1,为工程添加一个子目录src,用来存储源代码; 2,添加一个子目录doc,用来存储这个工程的文档hello.txt 3,在工程目录添加文本文件COPYRIGHT, README; 4,在工程目录添加一个runhello.sh …

18_FreeRTOS任务通知

目录 任务通知的简介 任务通知值的更新方式 任务通知的优势 任务通知的劣势 任务通知值和通知状态 发送通知相关API函数 接收通知相关API函数 任务通知模拟信号量实验 任务通知模拟消息邮箱实验 任务通知模拟事件标志组实验 任务通知的简介 任务通知:用来通知任务的…

JVM 学习(1)—JVM 与 JMM 内存模型简单理解

一、JVM 内存模型概述 (1) 为什么会出现 JVM 内存模型呢? JVM 内存模型是为规范描述 Java 虚拟机在执行 Java 程序时,将程序中的数据和代码存储到计算机内存中的方式和规则。JVM 内存模型定义 Java 虚拟机所使用的内存结构以及内存区域之间的关系&…

数据归档,存储的完美储备军

数据爆炸性增长的同时,存储成为了大家首要担心的问题大家都希望自家数据保存20年、50年后仍完好无损但是,N年后的数据量已达到一个无法预测的峰值如此大量的数据在保存时极可能存在丢失、损坏等问题这时需要提前对数据进行“备份”、“归档”备份是对数据…

Linux->进程概念于基本创建

1. 进程基本概念 当一个可执行程序被加载到内存当中,并由操作系统将其管理起来,此时这个程序就被称之为进程。也就是下方的: 程序的一个执行实例,正在执行的程序等 担当分配系统资源(CPU时间,内存&#xff…

阿里云云通信风控系统的架构与实践

作者:铭杰 阿里云云通信创立于 2017 年,历经 5 年发展已经孵化出智能消息、智能语音、隐私号、号码百科等多个热门产品。目前,已成为了国内云通信市场的领头羊,在国际市场上服务范围也覆盖了 200 多个国家。随着业务的不断壮大&am…

正则表达式是如何运作的?

在日常的开发工作当中&#xff0c;我们必不可免的会碰到需要使用正则的情况。 正则在很多时候通过不同的组合方式最后都可以达到既定的目标结果。比如我们有一个需要匹配的字符串&#xff1a; hello&#xff0c;我们可以通过 / .</p>/ 以及 / .?</p>/ 来匹配&…

数据分析与SAS学习笔记8

过程步&#xff1a;一个典型的SAS完整程序&#xff1a; 代码说明&#xff1a; 1&#xff09;reg&#xff1a;回归分析&#xff1b; 2&#xff09;model&#xff1a;因变量和自变量。 proc开头部分叫过程步。 常用过程&#xff1a; SORT过程&#xff1a; PRINT过程与FORTMAT…

Linux环境下绕过长度限制写入webshell

前提当命令执行漏洞对长度有限制时&#xff0c;我们可以通过一些Linux命令生成文件进行执行。如果应用程序是使用shell解析器来执行命令或文件&#xff0c;那么不需要该文件具有执行属性(x)如果应用程序没有shell解析器&#xff0c;那么写入文件内容时&#xff0c;可以第一条语…

终极方案,清理 docker 占用磁盘过大问题, 亲测有效!

背景 在笔者的工作测试环境中&#xff0c;使用过程中突然出现根磁盘快吃满了&#xff08;docker也是使用的根池盘的/var/lib/docker&#xff09;&#xff0c; wtf &#xff1f; 服务用不了&#xff1f; 当然网上找到了一些常规的清楚docker 日志文件 但是通过df -hT 查看到over…

2023年Java面试题精选(蚂蚁金服/滴滴/美团/拼多多腾讯)

作为一名优秀的程序员&#xff0c;技术面试都是不可避免的一个环节&#xff0c;一般技术面试官都会通过自己的方式去考察程序员的技术功底与基础理论知识。 如果你参加过一些大厂面试&#xff0c;肯定会遇到一些这样的问题&#xff1a; 1、看你项目都用的框架&#xff0c;熟悉…

Linux 中使用 docker-compose 部署 MongoDB 6 以上版本副本集及配置 SSL / TLS 协议

一、准备环境 MongoDB 副本集部署至少 3 个节点&#xff08;奇数节点&#xff09;&#xff0c;为了保障数据安全性&#xff0c;可考虑将 MongoDB 节点分布在不同的主机上&#xff0c;本示例使用一台主机部署 3 个 MongoDB示例。 1、创建 MongoDB 集群数据相关目录 # 创建 Mo…

大数据|大数据基础(概念向)

目录 &#x1f4da;大数据概念 &#x1f407;常见数据存储单位 &#x1f407;大数据的特点&#xff08;5V&#xff09; &#x1f407;大数据 VS 数据库 &#x1f31f;数据库 &#x1f31f;大数据 &#x1f4da;大数据业务分析基本步骤 &#x1f407;收集数据 &#x1f4…

RockerMQ简介和单节点部署

目录一、RockerMQ简介二、Linux中单节点部署1、准备工作2、下载和解压3、修改初始内存4、启动5、查看进程6、发送接收消息测试7、关闭三、控制台的安装与启动(可视化页面)1、修改配置&#xff08;1&#xff09;修改端口号&#xff08;2&#xff09;指定RocketMQ的name server地…