YOLOv5改进 | 主干网络 | 将主干网络替换为轻量化的ShuffleNetv2【原理 + 完整代码】
💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡
目标检测是计算机视觉中一个重要的下游任务。对于边缘盒子的计算平台来说,一个大型模型很难实现实时检测的要求。基于一系列消融实验,研究者提出了几个实用的网络设计效率指导原则。据此,提出了一种新的架构,称为ShuffleNetV2。在本文中,给大家带来的教程是将原来的主干网络中的特征提取网络替换为shufflenetv2网络。文章在介绍主要的原理后,将手把手教学如何进行模块的代码添加和修改,并将修改后的完整代码放在文章的最后,方便大家一键运行,小白也可轻松上手实践。以帮助您更好地学习深度学习目标检测YOLO系列的挑战。
专栏地址: YOLOv5改进+入门——持续更新各种有效涨点方法 点击即可跳转
1.原理
论文地址:ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design——点击即可跳转
官方代码:pytorch官方代码仓库——点击即可跳转
ShuffleNetV2 是一种高效的卷积神经网络架构,旨在优化计算资源的使用,尤其适用于移动设备和嵌入式系统。ShuffleNetV2 由 Megvii (Face++) 团队在 2018 年提出,是 ShuffleNet 的改进版本,主要通过优化信息流和减少内存访问成本来提升性能。
ShuffleNetV2 的设计理念
ShuffleNetV2 主要针对以下几个方面进行了优化:
-
模型计算复杂度:
通过减少冗余计算和优化卷积操作,降低计算复杂度,使得模型在计算资源有限的情况下仍能保持较高性能。 -
内存访问成本:
内存访问成本是影响模型效率的一个重要因素。ShuffleNetV2 通过优化特征图的传递和处理,减少内存带宽的占用。 -
并行度:
设计上考虑了硬件的并行计算能力,确保模型在并行处理器上的高效运行。
核心模块
-
Channel Split(通道分割):
输入特征图被分成两部分,一部分直接传递到下一层,另一部分经过复杂的卷积操作。这种设计减少了每一层的计算量,同时保留了原始信息。 -
Channel Shuffle(通道打乱):
在通道级别打乱特征图。通过这种操作,确保在网络的后续层中,各个通道之间的信息能够充分混合,提高特征的表达能力。 -
Pointwise Group Convolution(逐点分组卷积):
使用逐点分组卷积(1x1 卷积)来减少特征图通道数,同时分组卷积进一步降低计算量。 -
Depthwise Convolution(深度可分离卷积):
深度可分离卷积将标准卷积分解为深度卷积和逐点卷积两部分,从而减少计算量。 -
Element-wise Add(元素级加法):
使用元素级加法而非拼接操作,将原始输入与处理后的特征图结合,这样不仅减少了特征图的数量,还避免了高计算复杂度。
ShuffleNetV2 的性能优化
-
降低内存访问成本:
通过减少特征图的传递和拼接操作,减少了内存访问成本。这一点对资源受限的移动设备尤为重要。 -
提升计算效率:
通过优化卷积操作和特征图处理方式,ShuffleNetV2 能够在计算资源有限的情况下保持高效的计算性能。 -
增加并行度:
ShuffleNetV2 的设计充分考虑了硬件的并行计算能力,通过优化计算操作和数据流,提高了模型的并行计算效率。
总结
ShuffleNetV2 通过优化计算复杂度、内存访问成本和并行度,提供了一种高效的卷积神经网络架构。其设计理念和核心模块,如 Channel Split、Channel Shuffle 和 Depthwise Convolution 等,不仅降低了计算和内存开销,还提高了模型的性能和效率。这使得 ShuffleNetV2 成为一种非常适合在资源受限设备上部署的深度学习模型。
2. ShuffleNetv2的代码实现
2.1 将ShuffleNetv2添加到YOLOv5中
关键步骤一: 将下面代码粘贴到/projects/yolov5-6.1/models/common.py文件中
def channel_shuffle(x, groups):batchsize, num_channels, height, width = x.data.size()channels_per_group = num_channels // groups# reshapex = x.view(batchsize, groups,channels_per_group, height, width)x = torch.transpose(x, 1, 2).contiguous()# flattenx = x.view(batchsize, -1, height, width)return xclass conv_bn_relu_maxpool(nn.Module):def __init__(self, c1, c2): # ch_in, ch_outsuper(conv_bn_relu_maxpool, self).__init__()self.conv = nn.Sequential(nn.Conv2d(c1, c2, kernel_size=3, stride=2, padding=1, bias=False),nn.BatchNorm2d(c2),nn.ReLU(inplace=True),)self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)def forward(self, x):return self.maxpool(self.conv(x))class Shuffle_Block(nn.Module):def __init__(self, inp, oup, stride):super(Shuffle_Block, self).__init__()if not (1 <= stride <= 3):raise ValueError('illegal stride value')self.stride = stridebranch_features = oup // 2assert (self.stride != 1) or (inp == branch_features << 1)if self.stride > 1:self.branch1 = nn.Sequential(self.depthwise_conv(inp, inp, kernel_size=3, stride=self.stride, padding=1),nn.BatchNorm2d(inp),nn.Conv2d(inp, branch_features, kernel_size=1, stride=1, padding=0, bias=False),nn.BatchNorm2d(branch_features),nn.ReLU(inplace=True),)self.branch2 = nn.Sequential(nn.Conv2d(inp if (self.stride > 1) else branch_features,branch_features, kernel_size=1, stride=1, padding=0, bias=False),nn.BatchNorm2d(branch_features),nn.ReLU(inplace=True),self.depthwise_conv(branch_features, branch_features, kernel_size=3, stride=self.stride, padding=1),nn.BatchNorm2d(branch_features),nn.Conv2d(branch_features, branch_features, kernel_size=1, stride=1, padding=0, bias=False),nn.BatchNorm2d(branch_features),nn.ReLU(inplace=True),)@staticmethoddef depthwise_conv(i, o, kernel_size, stride=1, padding=0, bias=False):return nn.Conv2d(i, o, kernel_size, stride, padding, bias=bias, groups=i)def forward(self, x):if self.stride == 1:x1, x2 = x.chunk(2, dim=1) # 按照维度1进行splitout = torch.cat((x1, self.branch2(x2)), dim=1)else:out = torch.cat((self.branch1(x), self.branch2(x)), dim=1)out = channel_shuffle(out, 2)return out
ShuffleNet 的主要流程涉及一系列精心设计的操作,以最大限度地提高计算效率,同时确保模型的表达能力。以下是 ShuffleNet 的主要流程:
1. 初始卷积层
-
输入处理:
-
输入图像首先通过一个标准的卷积层进行处理,这个卷积层的作用是提取初始特征。
-
-
特征图大小和通道数调整:
-
初始卷积层通常会调整特征图的大小和通道数,以便于后续层的处理。
-
2. 分组卷积(Grouped Convolution)
-
特征图分组:
-
特征图在通道维度上分成多个组。分组卷积将特征图分为若干小组,并对每一小组单独进行卷积操作。这种方式可以大幅减少计算量。
-
-
1x1 卷积(Pointwise Convolution):
-
使用 1x1 卷积调整每一组特征图的通道数。1x1 卷积主要用于减少通道数,以减小计算量。
-
3. 通道打乱(Channel Shuffle)
-
通道打乱操作:
-
为了确保不同组之间的信息可以相互交流,使用通道打乱操作。具体来说,将特征图的通道重新排列,以便在下一次分组卷积时,不同组之间的信息能够充分混合。
-
4. 深度可分离卷积(Depthwise Separable Convolution)
-
深度卷积(Depthwise Convolution):
-
在深度卷积中,每个卷积核只在单个通道上进行卷积操作,不改变通道数。这样可以显著减少计算量。
-
-
逐点卷积(Pointwise Convolution):
-
在深度卷积之后,使用逐点卷积(1x1 卷积)来调整通道数。这一步结合了所有通道的信息。
-
5. 残差连接(Residual Connection)
-
特征图合并:
-
将原始输入特征图与经过上述处理后的特征图通过元素级加法(或拼接操作)合并。这一步类似于残差网络(ResNet)中的残差连接,帮助梯度在网络中更好地传播。
-
6. 通道分割(Channel Split)
-
特征图分割:
-
在某些版本中(如 ShuffleNetV2),特征图被分成两部分,一部分直接传递到下一层,另一部分经过复杂操作后再与第一部分合并。这种设计进一步减少了计算量。
-
7. 多次重复上述模块
-
模块重复:
-
上述操作模块会被重复多次,以构建深层网络。这些模块的重复次数和具体配置会根据网络的设计需求而定。
-
8. 最终卷积层和分类层
-
全局池化(Global Pooling):
-
在网络的最后,通常会使用全局平均池化层,将特征图的空间维度压缩到单个数值。
-
-
全连接层:
-
最后,通过一个全连接层(或完全卷积层),将特征映射到分类标签空间,以完成分类任务。
-
2.2 新增yaml文件
关键步骤二:在下/projects/yolov5-6.1/models下新建文件 yolov5-shufflenetv2.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# YOLOv5 v6.0 backbone
backbone:# [from, number, module, args]# Shuffle_Block: [out, stride][[ -1, 1, conv_bn_relu_maxpool, [ 32 ] ], # 0-P2/4[ -1, 1, Shuffle_Block, [ 128, 2 ] ], # 1-P3/8[ -1, 3, Shuffle_Block, [ 128, 1 ] ], # 2[ -1, 1, Shuffle_Block, [ 256, 2 ] ], # 3-P4/16[ -1, 7, Shuffle_Block, [ 256, 1 ] ], # 4[ -1, 1, Shuffle_Block, [ 512, 2 ] ], # 5-P5/32[ -1, 3, Shuffle_Block, [ 512, 1 ] ], # 6]# YOLOv5 v6.0 head
head:[[-1, 1, Conv, [256, 1, 1]],[-1, 1, nn.Upsample, [None, 2, 'nearest']],[[-1, 4], 1, Concat, [1]], # cat backbone P4[-1, 1, C3, [256, False]], # 10[-1, 1, Conv, [128, 1, 1]],[-1, 1, nn.Upsample, [None, 2, 'nearest']],[[-1, 2], 1, Concat, [1]], # cat backbone P3[-1, 1, C3, [128, False]], # 14 (P3/8-small)[-1, 1, Conv, [128, 3, 2]],[[-1, 11], 1, Concat, [1]], # cat head P4[-1, 1, C3, [256, False]], # 17 (P4/16-medium)[-1, 1, Conv, [256, 3, 2]],[[-1, 7], 1, Concat, [1]], # cat head P5[-1, 1, C3, [512, False]], # 20 (P5/32-large)[[14, 17, 20], 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行左右分别添加 ‘ conv_bn_relu_maxpool, Shuffle_Block’
2.4 执行程序
在train.py中,将cfg的参数路径设置为yolov5-ShuffleNetv2.yaml的路径
建议大家写绝对路径,确保一定能找到
🚀运行程序,如果出现下面的内容则说明添加成功🚀
3. 完整代码分享
https://pan.baidu.com/s/1EKQQOCdwIUWrR3LcFaCk8A?pwd=aaus
提取码: aaus
4. GFLOPs
关于GFLOPs的计算方式可以查看:百面算法工程师 | 卷积基础知识——Convolution
未改进的GFLOPs
改进后的GFLOPs
5.总结
ShuffleNet的设计理念主要集中在提高计算效率和减少参数量,同时保持较高的准确性。为了实现这一目标,ShuffleNet引入了两个关键的操作:点卷积(Pointwise Convolution)和通道洗牌(Channel Shuffle)。首先,ShuffleNet采用了一种被称为深度可分离卷积(Depthwise Separable Convolution)的操作。这种操作将标准卷积分解为两个更简单的操作:深度卷积(Depthwise Convolution)和点卷积(Pointwise Convolution)。深度卷积在每个输入通道上独立执行卷积操作,而点卷积则用于将这些独立处理后的通道进行线性组合。通过这种分解方式,计算量和参数量都得到了大幅度的减少。在此基础上,ShuffleNet进一步引入了通道洗牌的概念。在常规的卷积操作中,不同通道之间的信息交流是有限的。为了增强通道间的信息交流,ShuffleNet将通道划分为若干组,并在每一组内进行卷积操作后,将通道重新排列(洗牌),使得下一组操作能够接收到来自不同组的通道信息。这样,通过多层的叠加和洗牌操作,网络能够更有效地捕捉不同通道之间的关联特征,从而提升模型的表现力。此外,ShuffleNet采用了分组卷积(Grouped Convolution)的策略,即将通道划分为多个组,每组独立进行卷积操作。结合通道洗牌,这种策略进一步降低了计算复杂度和参数量,适合在移动设备等资源受限的环境中应用。总的来说,ShuffleNet通过巧妙地设计卷积操作和通道处理方式,显著提升了计算效率和模型的轻量化程度,使得其在保持较高准确率的同时,能够在计算资源有限的设备上高效运行。这种创新的架构设计不仅为移动设备上的实时图像处理提供了可能,也为其他需要高效视觉处理的应用场景提供了有力支持。
相关文章:

YOLOv5改进 | 主干网络 | 将主干网络替换为轻量化的ShuffleNetv2【原理 + 完整代码】
💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡 目标检测是计算机视觉中一个重要的下游任务。对于边缘盒子的计算平台来说,一个大型模型很难实现实时检测的要求。基于一系列消融…...
LeetCode:字母异位词分组
文章收录于LeetCode专栏 LeetCode地址 字母异位词分组 题目 给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。所有输入均为小写字母,且不考虑答案输出的顺序。 示例1: 输入: strs [“…...

技术与业务的完美融合:大数据BI如何真正提升业务价值
数据分析有一点经典案例 沃尔玛的啤酒和尿布案例 开始做BI的时候,大家肯定都看过书,那么一定也看过一个经典的案例,就是沃尔玛的啤酒和尿布的案例。这个案例确实很经典,但其实是一个失败的案例。为什么这么说呢?很明显…...

计网复习资料
一、选择题(每题2分,共40分) 1. Internet 网络本质上属于( )网络。 A.电路交换 B.报文交换 C.分组交换 D.虚电路 2.在 OSI 参考模型中,自下而上第一个提供端到端服务的是( )。 A.数据链路层 B.传输…...
华为策略流控
以下脚本仅做参考,具体IP地址和接口请按照现场实际情况写入。 [Huawei]acl 3001 [Huawei-acl-adv-3001]rule permit ip source 192.168.1.10 0.0.0.0 destination 192.168.2.10 0.0.0.0 //匹配需要做测试的源和目标地址 [Huawei-acl-adv-3001]rule permit ip sour…...

刷代码随想录有感(98):动态规划——爬楼梯
题干: 代码: class Solution { public:int climbStairs(int n) {if(n 1)return 1;if(n 2)return 2;vector<int>dp(n 1);dp[0] 0;dp[1] 1;dp[2] 2;for(int i 3; i < n; i){dp[i] dp[i - 1] dp[i - 2];}return dp[n];} }; 其实就是斐波…...

零基础入门篇①⑦ Python可变序列类型--集合
Python从入门到精通系列专栏面向零基础以及需要进阶的读者倾心打造,9.9元订阅即可享受付费专栏权益,一个专栏带你吃透Python,专栏分为零基础入门篇、模块篇、网络爬虫篇、Web开发篇、办公自动化篇、数据分析篇…学习不断,持续更新,火热订阅中🔥专栏限时一个月(5.8~6.8)重…...

基于NodeJs 的Vue安装和创建项目
基于NodeJs 的Vue安装和创建项目 一、Node.js的下载与安装 下载地址: https://nodejs.org/en/download/prebuilt-installer 安装完之后,启动 cmd命令行,验证 Node.js 是否安装成功 二、配置npm的全局模块的存放路径以及缓存的路径 注&…...

【简单介绍下DALL-E2,什么是DALL-E2?】
🌈个人主页: 程序员不想敲代码啊 🏆CSDN优质创作者,CSDN实力新星,CSDN博客专家 👍点赞⭐评论⭐收藏 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共…...

springboot+mqtt使用总结
1.软件的选型 1.1.使用免费版EMQX 1.1.1.下载 百度搜索的目前是会打开官网,这里提供下免费版的使用链接EMQX使用手册 文档很详细,这里不再记录了。 1.2.使用rabbitmq rabbitmq一般做消息队列用,作为mqtt用我没有找到详细资料,…...

搭建自己的组件库<2>dialog 组件
目录 设置title 插槽显示 控制宽高 关闭对话框 transition实现动画 引入深度选择器 同样创建组件dialogue.vue后全局注册 dialogue模版: <template><!-- 对话框的遮罩 --><div class"miao-dialog_wrapper"><!-- 真的对话框 …...

less学习笔记
一、什么是less? Less是CSS预处理语言,可以使用变量、嵌套、运算等,便于维护项目CSS样式代码。 二、less安装 使用npm包管理工具,全局安装less包 npm install -g lessless安装好的同时,lessc也安装好了 通过 lessc -…...

基于关键词自动采集抖音视频排名及互动数据(点赞、评论、收藏)
在当今的社交媒体时代,抖音作为一个热门短视频平台,吸引了大量用户和内容创作者。对于研究和分析抖音上的热门视频及其互动数据(如点赞、评论、收藏等),自动化的数据采集工具显得尤为重要。本项目旨在开发一个基于关键…...
selenium中switch_to.window切换窗口的用法
打开百度多个窗口,遍历切换每个窗口,切到【百度地图】就停止。 使用了driver.switch_to.window() 来切换, 参数是handle值 from selenium import webdriver import time# 创建浏览器驱动对象 from selenium.webdrive…...

【nerf】nvidia-smi
当cmd下nvidia -smi不能使用时候 沿着以下路径打开cmd,再输入,可以查看cuda版本 然后查看电脑安装的...

测试工具fio
一、安装部署 fio是一款优秀的磁盘IO测试工具,在Linux中比较常用于测试磁盘IO 其下载地址:https://brick.kernel.dk/snaps/fio-2.1.10.tar.gz 或者登录其官网:http://freshmeat.sourceforge.net/projects/fio/ 进行下载。 tar -zxvf fio-…...

详解 Flink 的状态管理
一、Flink 状态介绍 1. 流处理的无状态和有状态 无状态的流处理:根据每一次当前输入的数据直接转换输出结果的过程,在处理中只需要观察每个输入的独立事件。例如, 将一个字符串类型的数据拆分开作为元组输出或将每个输入的数值加 1 后输出。…...

手机怎么压缩视频?归纳了三种快速压缩方案
手机怎么压缩视频?在数字时代,手机已经成为我们记录生活的重要工具,而视频作为其中的一种主要形式,更是占据了极大的存储空间。然而,随着手机拍摄的视频越来越多,如何高效压缩视频以节省存储空间࿰…...

【实战】kafka3.X kraft模式集群搭建
文章目录 前言kafka2.0与3.x对比准备工作JDK安装kafka安装服务器增加hosts 修改Kraft协议配置文件格式化存储目录 启动集群停止集群测试Kafka集群创建topic查看topic列表查看消息详情生产消息消费消息查看消费者组查看消费者组列表 前言 相信很多同学都用过Kafka2.0吧…...

华为防火墙配置 SSL VPN
前言 哈喽,我是ICT大龙。本期给大家更新一次使用华为防火墙实现SSL VPN的技术文章。 本次实验只需要用到两个软件,分别是ENSP和VMware,本次实验中的所有文件都可以在文章的末尾获取。话不多说,教程开始。 什么是VPN 百度百科解…...

测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...

大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...

前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...