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

news2024/11/25 1:02:02
💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡

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

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

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

相关文章

PS —— 精修图像

PS —— 精修图像 修复污点修复画笔工具修复画笔工具 美白滤镜去杂锐化加杂减淡和锐化工具 我觉得今天这篇博客,无论是男同胞还是女同胞,都要熟练掌握(哈哈哈哈…) 今天我们来学习如何精修图像,精修图像一般分为几步——修复&…

32 位和 64 位 Linux 上 C 语言的整数大小的分析

在 Linux 系统上进行 C 语言编程时,理解整数大小在 32 位和 64 位系统上的区别是开发高效、可靠程序的基础。本文将深入探讨整数在这两种架构下的大小差异及其原因,并介绍其对程序的影响。 整数类型及其大小 C 语言中主要的整数类型包括 char、short、i…

蓝牙模块技术在智慧养老领域的广泛运用

随着蓝牙模块通信技术的不断提升,蓝牙技术作为物联网无线通信技术之一,正在逐渐渗透到我们生活的各个领域。众所周知,我国人口老龄化日益严峻,传统的“养儿防老”已经满足不了当前的养老需求。养老不仅仅是一个家庭的问题&#xf…

【Linux网络】端口及UDP

文章目录 1.再看四层2.端口号2.1引入linux端口号和进程pid的区别端口号是如何生成的传输层有了pid还设置端口号端口号划分 2.2问题2.3netstat 3.UDP协议3.0每学一个协议 都要讨论一下问题3.1UDP协议3.2谈udp/tcp实际上是在讨论什么? 1.再看四层 2.端口号 端口号(Po…

安全风险 - 切换后台时背景模糊处理

因为安全风险中提到当app处于后台卡片状态时,显示的卡片页面应该为模糊效果,否则容易泄露用户隐私,尤其当前页涉及个人信息、资产信息等,都会造成信息泄露!基于这种场景,我研究了下这种业务下的模糊效果 找…

[JAVASE] 类和对象(三) - 继承

目录 一. 继承的定义 1.1 基本概念 1.2 基本实现 二. 父类 和 子类中的成员访问 2.0 super 与 this 关键字 2.1 访问成员变量 2.2 访问成员方法 三. 父类 和 子类中的构造方法 3.1 访问父类中的构造方法 3.2 注意事项 四. 权限修饰限定符 public: protected: default: …

Spring系列-03-BeanFactory和Application接口和相关实现

BeanFactory BeanFactory和它的子接口们 BeanFactory 接口的所有子接口, 如下图 BeanFactory(根容器)-掌握 BeanFactory是根容器 The root interface for accessing a Spring bean container. This is the basic client view of a bean container; further interfaces such …

GD32F103RCT6/GD32F303RCT6-UCOSIII底层移植(4)消息队列实验

本文章基于兆易创新GD32 MCU所提供的2.2.4版本库函数开发 后续项目主要在下面该专栏中发布: 手把手教你嵌入式国产化_不及你的温柔的博客-CSDN博客 感兴趣的点个关注收藏一下吧! 电机驱动开发可以跳转: 手把手教你嵌入式国产化-实战项目-无刷电机驱动&am…

【LeetCode算法】第58题:最后一个单词的长度

目录 一、题目描述 二、初次解答 三、官方解法 四、总结 一、题目描述 二、初次解答 1. 思路:双指针法。low指向单词头,high指向单词后的空格,则high-low就是每个单词的长度。算法步骤:①low从头往后查找第一个非空格的字符&…

分割文本文件

分割一个.txt文件,可以选择在命令行中使用split指令,或者编写一段脚本进行操作。以下是一个简单的Python脚本来分割文本文件: def split_file(file, lines):# Open source filewith open(file, r) as source:count 0atEOF Falsewhile not …

如果有多个文件夹,怎么快速获得文件夹的名字呢

上一篇写到怎么批量建立文件夹,那么怎么获取批量文件夹的名字呢? 一、啊这,这真是一个好问题二、这个得用Python(文本末尾有打包程序,点击链接运行就可以了)(1)首先建立一个py文件&a…

Python 将文件夹中的图片信息导入到 Excel 的表格

引言 在数据处理和管理的日常任务中,经常需要将文件夹中的图片文件信息(如文件名、路径、创建日期、大小、分辨率等)整理成一个 Excel 表格。这篇博客将介绍如何使用 Python 中的 wxPython 模块创建一个 GUI 应用,用户可以通过这…

jmeter保存测试计划报错——Couldn‘t save test plan to file:

jmeter保存测试计划报错——Couldnt save test plan to file:。。。。。拒绝访问 一、问题描述二、分析三、结果 一、问题描述 Couldn’t save test plan to file:D:\Program Files\apache-jmeter-5.6.2\bin\线程组.jmx D:\Program Files\apache-jmeter-5.6.2\bin\线程组.jmx(…

2024电工杯A题完整代码论文分析

2024年电工杯数学建模竞赛A题论文和代码已完成,代码为B题全部问题的代码,论文包括摘要、问题重述、问题分析、模型假设、符号说明、模型的建立和求解(问题1模型的建立和求解、问题2模型的建立和求解、问题3模型的建立和求解)、模型…

【Mac】电脑任何来源无法打开的问题解决办法

前言 有小伙伴在安装本站软件过程中,遇到过运行脚本1提示 sudo: /etc/sudoers is world writable的问题,其实就是电脑任何来源无法打开。今天就来说一下解决办法。 问题现象 电脑运行「脚本1」时提示: // 错误内容sudo: /etc/sudoers is w…

Navicat 连接 OceanBase 快速入门 | 社区版

Navicat Premium(16.1.9或更高版本)正式支持 OceanBase全线数据库产品。OceanBase为现代数据架构打造的开源分布式数据库。兼容 MySQL 的单机分布式一体化国产开源数据库,具有原生分布式架构,支持金融级高可用、透明水平扩展、分布…

KVM虚拟化基础

一、虚拟化基础 1.传统物理机部署方案 IDC机房优点: IDC机房是分布式的,是全国连锁的。我们将物理服务器部署到IDC机房,由IDC机房帮我们上架服务,管理其内部的网络以及路由转发、服务器资源的分发;而且IDC机房带宽接…

加入MongoDB AI创新者计划,携手MongoDB共同开创AI新纪元

加入MongoDB AI创新者计划! MongoDB对AI创新和初创企业的支持既全面又广泛!无论您是领先的AI初创企业还是刚刚起步,MongoDB Atlas都是支持您愿景的最佳平台。 AI 初创者计划The AI Startup Track AI初创者计划为早期初创企业提供专属福利&…

顺序表及其应用

掌握顺序表的初始化,初始化、查找、插入、删除、遍历、查看实际长度等操作 内容 从键盘输入n个整数,创建顺序表。【创建长度为n的顺序表】从键盘输入1个整数x,在顺序表中查找x所在的位置。若找到,输出该元素所在的位置(即数组下标…

YOLOV10实时端到端目标检测

代码地址:GitHub - THU-MIG/yolov10: YOLOv10: Real-Time End-to-End Object Detection 论文地址:https://arxiv.org/pdf/2405.14458 本文介绍了YOLO系列目标检测器在实时和高效方面的优势,但是仍然存在一些缺陷,包括依赖非极大值…