YOLOv5改进 | 主干网络 | 用EfficientNet卷积替换backbone【教程+代码 】

💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡

在YOLOv5的GFLOPs计算量中,卷积占了其中大多数的比列,为了减少计算量,研究人员提出了用EfficientNet代替backbone。本文给大家带来的教程是将原来的主干网络替换为EfficientNet。文章在介绍主要的原理后,将手把手教学如何进行模块的代码添加和修改,并将修改后的完整代码放在文章的最后,方便大家一键运行小白也可轻松上手实践。以帮助您更好地学习深度学习目标检测YOLO系列的挑战。

专栏地址: YOLOv5改进+入门——持续更新各种有效涨点方法 点击即可跳转

文章目录

  • 1. 原理
    • 2.代码实现
      • 2.1 将EfficientNet添加到YOLOv5中
      • 2.2 新增yaml文件
      • 2.3 注册模块
      • 2.4 执行程序
  • 3. 完整代码分享
  • 4.GFLOPs对比
  • 5. 总结

1. 原理

在这里插入图片描述

论文地址:EfficientNet论文点击即可跳转

官方代码:https://github.com/tensorflow/tpu/tree/ master/models/official/efficientnet

EfficientNet 是一个卷积神经网络架构,旨在通过同时调整深度、宽度和分辨率来实现更好的准确性和效率。它由谷歌的Mingxing Tan和Quoc V. Le在题为《EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks》的论文中提出。

EfficientNet主要的关键组件和概念:

  1. 复合缩放:EfficientNet引入了一种新的缩放方法,该方法使用复合系数均匀地缩放网络宽度、深度和分辨率。传统上,模型是通过简单增加这些维度中的一个来进行缩放的,这可能导致性能不佳。EfficientNet使用复合系数 φ 来统一地缩放这些维度。

  2. 架构设计:EfficientNet从基线网络架构开始,然后使用复合缩放方法进行扩展。基线架构类似于移动反向瓶颈卷积(MBConv)架构,它由带有深度可分离卷积的反向残差块组成。

  3. 深度可分离卷积:EfficientNet广泛使用深度可分离卷积。它将标准卷积操作分解为深度卷积(分别在每个输入通道上操作)后跟点卷积(用于组合输出的1x1卷积)。这样做既减少了计算成本,又保留了表示能力。

  4. 高效缩放:EfficientNet通过高效地缩放网络宽度、深度和分辨率来实现最先进的性能。通过同时缩放所有这些维度,它有效地平衡了模型容量和计算成本。

  5. 模型变种:EfficientNet有几个变种,如EfficientNet-B0到B7,代表不同的缩放级别。B0是最小且计算成本最低的变种,而B7是最大且计算成本最高的变种。

  6. 迁移学习:EfficientNet模型通常在大规模图像数据集(如ImageNet)上预先训练,然后使用较小的数据集进行特定任务的微调。使用EfficientNet的迁移学习在各种计算机视觉任务上都被证明是非常有效的,尤其是在有限的计算资源下达到最先进的性能。

由于其优越的性能和效率平衡,EfficientNet已成为计算机视觉任务的热门选择。其可扩展性使其适用于从手机到云服务器的各种设备,并且仍然能够实现出色的准确性。

在这里插入图片描述

2.代码实现

2.1 将EfficientNet添加到YOLOv5中

关键步骤一: 将下面代码粘贴到/projects/yolov5-6.1/models/common.py文件中
img

class stem(nn.Module):
    def __init__(self, c1, c2, act='ReLU6'):
        super().__init__()
        self.conv = nn.Conv2d(c1, c2, kernel_size=3, stride=2, padding=1, bias=False)
        self.bn = nn.BatchNorm2d(num_features=c2)
        if act == 'ReLU6':
            self.act = nn.ReLU6(inplace=True)
    
    def forward(self, x):
        return self.act(self.bn(self.conv(x)))

class MBConvBlock(nn.Module):
    def __init__(self, inp, final_oup, k, s, expand_ratio, drop_connect_rate, has_se=False):
        super(MBConvBlock, self).__init__()

        self._momentum = 0.01
        self._epsilon = 1e-3
        self.input_filters = inp
        self.output_filters = final_oup
        self.stride = s
        self.expand_ratio = expand_ratio
        self.has_se = has_se
        self.id_skip = True  # skip connection and drop connect
        se_ratio = 0.25

        # Expansion phase
        oup = inp * expand_ratio  # number of output channels
        if expand_ratio != 1:
            self._expand_conv = nn.Conv2d(in_channels=inp, out_channels=oup, kernel_size=1, bias=False)
            self._bn0 = nn.BatchNorm2d(num_features=oup, momentum=self._momentum, eps=self._epsilon)

        # Depthwise convolution phase
        self._depthwise_conv = nn.Conv2d(
            in_channels=oup, out_channels=oup, groups=oup,  # groups makes it depthwise
            kernel_size=k, padding=(k - 1) // 2, stride=s, bias=False)
        self._bn1 = nn.BatchNorm2d(num_features=oup, momentum=self._momentum, eps=self._epsilon)

        # Squeeze and Excitation layer, if desired
        if self.has_se:
            num_squeezed_channels = max(1, int(inp * se_ratio))
            self.se = SeBlock(oup, 4)

        # Output phase
        self._project_conv = nn.Conv2d(in_channels=oup, out_channels=final_oup, kernel_size=1, bias=False)
        self._bn2 = nn.BatchNorm2d(num_features=final_oup, momentum=self._momentum, eps=self._epsilon)
        self._relu = nn.ReLU6(inplace=True)

        self.drop_connect = drop_connect(drop_connect_rate)

    def forward(self, x, drop_connect_rate=None):
        """
        :param x: input tensor
        :param drop_connect_rate: drop connect rate (float, between 0 and 1)
        :return: output of block
        """

        # Expansion and Depthwise Convolution
        identity = x
        if self.expand_ratio != 1:
            x = self._relu(self._bn0(self._expand_conv(x)))
        x = self._relu(self._bn1(self._depthwise_conv(x)))

        # Squeeze and Excitation
        if self.has_se:
            x = self.se(x)

        x = self._bn2(self._project_conv(x))

        # Skip connection and drop connect
        if self.id_skip and self.stride == 1  and self.input_filters == self.output_filters:
            if drop_connect_rate:
                x = self.drop_connect(x, training=self.training)
            x += identity  # skip connection
        return x

EfficientNet模型的主要流程如下:

  1. 输入图像预处理

    • 输入图像首先会经过预处理步骤,包括归一化、缩放等,以使其适应网络的输入要求。
  2. 特征提取

    • 输入图像通过一系列卷积层和池化层,逐步提取特征。这些卷积层通常采用深度可分离卷积(depthwise separable convolution),这种卷积操作可以显著减少参数数量和计算量,从而提高模型的效率。
  3. 特征放缩(Feature Scaling)

    • 在EfficientNet中,为了适应不同分辨率的输入图像,引入了特征放缩模块。这个模块使用全局平均池化将提取的特征向量转换为固定长度的向量,并通过一个可学习的线性变换(通常是一个1x1卷积层)将其映射到固定维度,以确保网络对于不同分辨率的图像具有一致的性能。
  4. 特征组合

    • 将不同尺度的特征图进行组合,通常采用特征级联或者特征融合的方式,以丰富特征表示能力。
  5. 分类或回归

    • 最后一层是用于分类或回归任务的全连接层或者卷积层。对于分类任务,通常使用softmax激活函数输出类别概率分布;对于回归任务,可以输出边界框的位置或者其他相关信息。
  6. 损失计算和反向传播

    • 使用损失函数计算模型预测值与真实标签之间的差异,常见的损失函数包括交叉熵损失(对于分类任务)和均方误差损失(对于回归任务)等。然后通过反向传播算法更新网络参数,使得损失函数最小化。

    整个流程的关键点在于使用了深度可分离卷积来减少计算量,同时通过宽度/深度/分辨率缩放来平衡模型的复杂度和性能。EfficientNet在保持模型轻量级的同时,能够取得很好的性能表现,因此被广泛应用于计算资源受限的设备和场景中。

2.2 新增yaml文件

关键步骤二:在下/projects/yolov5-6.1/models下新建文件 yolov5_shuffle.yaml并将下面代码复制进去

在这里插入图片描述

# YOLOv5 🚀 by Ultralytics, GPL-3.0 license

# Parameters
nc: 80  # number of classes
depth_multiple: 1.0  # model depth multiple
width_multiple: 1.0  # layer channel multiple
anchors:
  - [10,13, 16,30, 33,23]  # P3/8
  - [30,61, 62,45, 59,119]  # P4/16
  - [116,90, 156,198, 373,326]  # P5/32

#  EfficientNetLite backbone
backbone:
  # [from, number, module, args]
  [[-1, 1, stem, [32, 'ReLU6']],             # 0-P1/2  ch_out, act
   [-1, 1, MBConvBlock, [16, 3, 1, 1, 0]],   # 1 ch_out, k_size, s, expand

   [-1, 1, MBConvBlock, [24, 3, 2, 6, 0.028, True]],   # 2-P2/4 ch_out, k_size, s, expand, drop_connect_rate, se
   [-1, 1, MBConvBlock, [24, 3, 1, 6, 0.057]],

   [-1, 1, MBConvBlock, [40, 5, 2, 6, 0.085]],   # 4-P3/8 ch_out, k_size, s, expand, drop_connect_rate, se
   [-1, 1, MBConvBlock, [40, 5, 1, 6, 0.114]],

   [-1, 1, MBConvBlock, [80, 3, 2, 6, 0.142]],   # 6-P4/16 ch_out, k_size, s, expand, drop_connect_rate, se
   [-1, 1, MBConvBlock, [80, 3, 1, 6, 0.171]],
   [-1, 1, MBConvBlock, [80, 3, 1, 6, 0.2]],
   [-1, 1, MBConvBlock, [112, 5, 1, 6, 0.228]],  # 9
   [-1, 1, MBConvBlock, [112, 5, 1, 6, 0.257]],
   [-1, 1, MBConvBlock, [112, 5, 1, 6, 0.285]],

   [-1, 1, MBConvBlock, [192, 5, 2, 6, 0.314]],  # 12-P5/32 ch_out, k_size, s, expand, drop_connect_rate, se
   [-1, 1, MBConvBlock, [192, 5, 1, 6, 0.342]],
   [-1, 1, MBConvBlock, [192, 5, 1, 6, 0.371]],
   [-1, 1, MBConvBlock, [192, 5, 1, 6, 0.4]],
   [-1, 1, MBConvBlock, [320, 3, 1, 6, 0.428]],  # 16

   [-1, 1, SPPF, [1024, 5]], # 17
  ]

# YOLOv5 v6.0 head
head:
  [[-1, 1, Conv, [512, 1, 1]],
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 11], 1, Concat, [1]],  # cat backbone P4
   [-1, 3, C3, [512, False]],  # 21

   [-1, 1, Conv, [256, 1, 1]],
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 5], 1, Concat, [1]],  # cat backbone P3
   [-1, 3, C3, [256, False]],  # 25 (P3/8-small)

   [-1, 1, Conv, [256, 3, 2]],
   [[-1, 22], 1, Concat, [1]], # cat head P4
   [-1, 3, C3, [512, False]],  # 28 (P4/16-medium)

   [-1, 1, Conv, [512, 3, 2]],
   [[-1, 18], 1, Concat, [1]],  # cat head P5
   [-1, 3, C3, [1024, False]],  # 31 (P5/32-large)

   [[25, 28, 31], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)
  ]

温馨提示:本文只是对yolov5l基础上添加swin模块,如果要对yolov8n/l/m/x进行添加则只需要指定对应的depth_multiple 和 width_multiple。

# YOLOv5n
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.25  # layer channel multiple
 
# YOLOv5s
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.50  # layer channel multiple
 
# YOLOv5l 
depth_multiple: 1.0  # model depth multiple
width_multiple: 1.0  # layer channel multiple
 
# YOLOv5m
depth_multiple: 0.67  # model depth multiple
width_multiple: 0.75  # layer channel multiple
 
# YOLOv5x
depth_multiple: 1.33  # model depth multiple
width_multiple: 1.25  # layer channel multiple

2.3 注册模块

关键步骤:在yolo.py中注册, 大概在260行左右添加 ‘MBConvBlock’和‘stem’

在这里插入图片描述

2.4 执行程序

在train.py中,将cfg的参数路径设置为yolov5_efficient.yaml的路径

建议大家写绝对路径,确保一定能找到
在这里插入图片描述

🚀运行程序,如果出现下面的内容则说明添加成功🚀

在这里插入图片描述

3. 完整代码分享

https://pan.baidu.com/s/1Y9WuMkKBmYONl0MdshEiIA?pwd=9wsd

提取码: 9wsd

4.GFLOPs对比

未改进的YOLOv5l的GFLOPs

img
在这里插入图片描述

GFLOPs减少一半以上

5. 总结

EfficientNet是一种卓越的卷积神经网络架构,通过复合缩放和深度可分离卷积等技术,以及特征放缩模块的引入,实现了在保持高准确性的同时显著提升了模型的效率和性能。其提供的多个预定义模型变种,以及在各种计算机视觉任务中广泛的应用领域,使其成为了业界的热门选择,为图像分类、目标检测和其他相关任务提供了可靠且高效的解决方案。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

霍启刚弟弟求婚成功❗霍启仁豪门家族地位与爱情如何抉择?

霍启刚的弟弟霍启仁在社交媒体上宣布求婚成功 他与泰国女友在浪漫的船上场景中 单膝下跪为她戴上象征爱情的戒指 两人紧紧相握的双手,在镜头前展现了无尽的甜蜜与温馨 霍启仁,出生于1988年10月12日 是香港特别行政区立法会议员霍震霆与朱玲玲的第三个…

pytorch-13_2 模型结构选择策略:层数、激活函数、神经元个数

一、拟合度概念 在所有的模型优化问题中,最基础的也是最核心的问题,就是关于模型拟合程度的探讨与优化。根据此前的讨论,模型如果能很好的捕捉总体规律,就能够有较好的未知数据的预测效果。但限制模型捕捉总体规律的原因主要有两点…

CAD怎么画角度?介绍三种具体操作

CAD怎么画角度?在现代设计与制造领域,计算机辅助设计(CAD)软件的存在极大地提高了设计师和工程师的工作效率。在CAD软件中,绘制角度是一项基础而重要的技能,它广泛应用于机械设计、建筑设计、电子电路布局等…

WPF水流动画(使用转换器模拟逻辑门控制水流信号)

前言 在使用WPF绘制流程图并模拟水流动画时,往往既需要控制阀泵的开合,又要控制动画启停。倘若能够将阀泵的开合与动画播放建立逻辑关系,这样就能够让业务代码“专心”地去控制阀泵开关,而不需要处理界面的展示。 动画示例 说明…

【设计模式深度剖析】【5】【创建型】【原型模式】| 类比群发邮件,加深理解

👈️上一篇:建造者模式 | 下一篇:创建型设计模式对比👉️ 目录 原型模式(Prototype Pattern)概览定义英文原话直译 3个角色类图1. 抽象原型(Prototype)角色2. 具体原型(Concrete Prototype)角色3. 客户…

Upstream最新发布2024年汽车网络安全报告-百度网盘下载

Upstream最新发布2024年汽车网络安全报告-百度网盘下载 2024年2月7日,Upstream Security发布了2024年Upstream《GLOBAL AUTOMOTIVE CYBERSECURITY REPORT》。这份报告的第六版着重介绍了汽车网络安全的拐点:从实验性的黑客攻击发展到规模庞大的攻击&…

【文心智能体】创建一个属于自己的生活情感类智能体

文章目录 前言一、创建智能体二、体验 前言 智能体技术的快速发展,进一步激发了各行业开发者对其实际应用及用户需求的深入探索。 创建一个属于自己的智能体。文心一言提供了一个很好的平台。 提示:以下是本篇文章正文内容,下面案例可供参考…

“智”造产业新生态,2024SIA上海自动化展会乘势而来!

今年两会,我们频频听到一个热词“新质生产力”。当前,“加快形成新质生产力”已成为实体经济创新发展的具体指向。如何在加快形成新质生产力的新赛道上快马加鞭,成为下一个时代的领跑者,是制造业亟需面临的思考题。 在良好的市场环…

---随笔--Redis的学习以及在Spring Boot中的整合使用(RedisTemplate、Redisson分布式锁)

---随笔--Redis的学习以及在Spring Boot中的整合使用(RedisTemplate、Redisson分布式锁) 引言1. 什么是Redis2. Redis的数据结构3. Redis其它常用命令4. 小插曲之Redis面试常考5. 正篇:Redis在Spring Boot中的使用!(着…

NE555+74ls160+74LS20数电数字钟Multisim仿真设计

设计框图 数字钟电路的基本组成框架图如图一所示,它主要由多谐振荡器、计数器、译码器和数码显示器4个部分组成。 图一 数字钟电路的基本组成(方框图) 2、设计方案 数字钟是一个将“时”,“分”,“秒”显示于人的视…

初始MyBatis ,详细步骤运行第一个MyBatis程序,同时对应步骤MyBatis底层剖析

1. 初始MyBatis ,详细步骤运行第一个MyBatis程序,同时对应步骤MyBatis底层剖析 文章目录 1. 初始MyBatis ,详细步骤运行第一个MyBatis程序,同时对应步骤MyBatis底层剖析每博一文案2. 前沿知识2.1 框架(framework&#…

jdk17安装教程详细(jdk17安装超详细图文)

2021年9月14日JDK17 发布,其中不仅包含很多新语言功能,而且与旧版 JDK 相比,性能提升也非常明显。与之前 LTS 版本的 JDK 8 和 JDK 11 相比,JDK17 的性能提升尤为明显,本文将教你如何安装 相比于JDK1.8,JD…

【Crypto】看我回旋踢

文章目录 一、看我回旋踢二、知识点什么是ROT13?工作原理分析字符串格式 解题感悟 一、看我回旋踢 关键词回旋,盲猜ROT13 因为以 synt{ 开头,并以 } 结束,基本可以判断是ROT13 小小flag,拿下! 二、知识点 …

Python中动态调用C#的dll动态链接库中方法

在Python中调用C#的dll库_哔哩哔哩_bilibili 环境准备: 安装 pythonnet pip install pythonnet在Python中调用C#动态链接库(DLL),可以使用pythonnet库,它允许直接使用 .NET 的程序集。以下是一个示例,…

1+x(Java)中级题库易混淆理论题

<ALL表示小于最小 小于最高等同于小于ANY 使用USING子句&#xff0c;在使用连接字段时&#xff0c;都不能在前面加上表的前缀&#xff0c;因为此时这个字段已经是连接字段&#xff0c;不再属于某个单独的表。 数据库提供的自动将提供的数据类型数据转换为期望的数据类…

go select 原理

编译器会使用如下的流程处理 select 语句&#xff1a; 将所有的 case 转换成包含 channel 以及类型等信息的 runtime.scase 结构体。调用运行时函数 runtime.selectgo 从多个准备就绪的 channel 中选择一个可执行的 runtime.scase 结构体。通过 for 循环生成一组 if 语句&…

AIGC:AI整活!万物皆可建筑设计

在过去的一年里 AI设计爆火 各行业纷纷将之用于工作中 同时不少网友也在借助它整活 万物皆可设计 甲方骂我方案像屎一样 于是我就回馈他屎一样的方案 他有点惊喜&#xff0c;但是没话 不是吧&#xff0c;随便找了个充电头图片 也能生成建筑设计&#xff01;这都能行 鸟…

人工智能应用-实验7-胶囊网络分类minst手写数据集

文章目录 &#x1f9e1;&#x1f9e1;实验内容&#x1f9e1;&#x1f9e1;&#x1f9e1;&#x1f9e1;代码&#x1f9e1;&#x1f9e1;&#x1f9e1;&#x1f9e1;分析结果&#x1f9e1;&#x1f9e1;&#x1f9e1;&#x1f9e1;实验总结&#x1f9e1;&#x1f9e1; &#x1f9…

微信小程序的自定义组件

一、创建自定义组件 &#xff08;1&#xff09;定义&#xff1a; 把页面重复的代码部分封装成为一个自定义组件&#xff0c;以便在不同的页面中重复使用&#xff0c;有助于代码的维护。 &#xff08;2&#xff09;组成&#xff1a; 自定义组件的组成&#xff1a;json文件&a…

Flutter 中如何优雅地使用弹框

日常开发中&#xff0c;Flutter 弹框&#xff08;Dialog&#xff09;是我们使用频率非常高的控件。无论是提示用户信息、确认用户操作&#xff0c;还是表单填写&#xff0c;弹框都能派上用场。然而&#xff0c;看似简单的弹框&#xff0c;实际使用起来却有不少坑和使用的技巧。…