YOLO算法改进7【中阶改进篇】:主干网络C3替换为轻量化网络MobileNetV3

解决问题:YOLOv5主干特征提取网络采用C3结构,带来较大的参数量,检测速度较慢,应用受限,在某些真实的应用场景如移动或者嵌入式设备,如此大而复杂的模型时难以被应用的。首先是模型过于庞大,面临着内存不足的问题,其次这些场景要求低延迟,或者说响应速度要快,想象一下自动驾驶汽车的行人检测系统如果速度很慢会发生什么可怕的事情。所以,研究小而高效的CNN模型在这些场景至关重要,至少目前是这样,尽管未来硬件也会越来越快。本文尝试将主干特征提取网络替换为更轻量的MobileNet网络,以实现网络模型的轻量化,平衡速度和精度。

一、MobileNetV3简介

MobileNetV3,是谷歌在2019年3月21日提出的轻量化网络架构,在前两个版本的基础上,加入神经网络架构搜索(NAS)和h-swish激活函数,并引入SE通道注意力机制,性能和速度都表现优异,受到学术界和工业界的追捧。
引用大佬的描述:MobileNet V3 = MobileNet v2 + SE结构 + hard-swish activation +网络结构头尾微调
在这里插入图片描述

摘要: 我们提出下一代的mobilenet基于一种互补搜索技术的组合作为一种新颖的建筑设计。MobileNetV3调到手机cpu通过硬件组合感知网络架构搜索(NAS)的补充NetAdapt算法,然后进行改进通过新颖的建筑进步。这篇论文从探索如何自动搜索算法和网络工作设计可以一起利用互补的工作提高整体技术水平的方法。通过在这个过程中,我们创建了两个新的MobileNet模型:MobileNetV3-Large和MobileNetV3-Small针对高资源和低资源用例。这些然后调整模型并将其应用于对象检测和语义分割任务。为了完成任务语义分割(或任何密集像素预测),我们提出了一种新的高效分割解码器空间金字塔池(LR-ASPP)。我们实现新状态的艺术结果移动分类,检测和分割。MobileNetV3-Large则高出3.2%准确的ImageNet分类,同时减少延迟与MobileNetV2相比减少了20%。MobileNetV3-Small是与MobileNetV2模型相比,准确率提高了6.6%具有相当的延迟。MobileNetV3-Large检测与MobileNetV2在COCO检测上的精度大致相同,速度快了25%以上。MobileNetV3-Large
LRASPP在类似情况下比MobileNetV2 R-ASPP快34%城市景观分割的准确性。

论文地址:https://arxiv.org/abs/1905.02244.pdf
代码:https://github.com/LeBron-Jian/DeepLearningNote

MobileNetV1&MobileNetV2&MobileNetV3总结
在这里插入图片描述
MobileNet V3 相关技术如下:
1,用 MnasNet 搜索网络结构
2,用 MobileNetV1 的深度可分离卷积
3,用 MobileNetV2 的倒置残差线性瓶颈结构
4,引入轻量级注意力 SE模块
5,使用新的激活函数 h-swish(x)
6,网络搜索中利用两个策略:资源受限的 NAS 和 NetAdapt
7,修改MobileNet V2 最后部分减小计算
在这里插入图片描述

二、YOLOv5结合MobileNetV3_small

方 法

第一步修改common.py,增加MobileNetV3模块。

class StemBlock(nn.Module):def __init__(self, c1, c2, k=3, s=2, p=None, g=1, act=True):super(StemBlock, self).__init__()self.stem_1 = Conv(c1, c2, k, s, p, g, act)self.stem_2a = Conv(c2, c2 // 2, 1, 1, 0)self.stem_2b = Conv(c2 // 2, c2, 3, 2, 1)self.stem_2p = nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True)self.stem_3 = Conv(c2 * 2, c2, 1, 1, 0)def forward(self, x):stem_1_out = self.stem_1(x)stem_2a_out = self.stem_2a(stem_1_out)stem_2b_out = self.stem_2b(stem_2a_out)stem_2p_out = self.stem_2p(stem_1_out)out = self.stem_3(torch.cat((stem_2b_out, stem_2p_out), 1))return outclass h_sigmoid(nn.Module):def __init__(self, inplace=True):super(h_sigmoid, self).__init__()self.relu = nn.ReLU6(inplace=inplace)def forward(self, x):return self.relu(x + 3) / 6class h_swish(nn.Module):def __init__(self, inplace=True):super(h_swish, self).__init__()self.sigmoid = h_sigmoid(inplace=inplace)def forward(self, x):y = self.sigmoid(x)return x * yclass SELayer(nn.Module):def __init__(self, channel, reduction=4):super(SELayer, self).__init__()self.avg_pool = nn.AdaptiveAvgPool2d(1)self.fc = nn.Sequential(nn.Linear(channel, channel // reduction),nn.ReLU(inplace=True),nn.Linear(channel // reduction, channel),h_sigmoid())def forward(self, x):b, c, _, _ = x.size()y = self.avg_pool(x)y = y.view(b, c)y = self.fc(y).view(b, c, 1, 1)return x * yclass conv_bn_hswish(nn.Module):"""This equals todef conv_3x3_bn(inp, oup, stride):return nn.Sequential(nn.Conv2d(inp, oup, 3, stride, 1, bias=False),nn.BatchNorm2d(oup),h_swish())"""def __init__(self, c1, c2, stride):super(conv_bn_hswish, self).__init__()self.conv = nn.Conv2d(c1, c2, 3, stride, 1, bias=False)self.bn = nn.BatchNorm2d(c2)self.act = h_swish()def forward(self, x):return self.act(self.bn(self.conv(x)))def fuseforward(self, x):return self.act(self.conv(x))class MobileNetV3_InvertedResidual(nn.Module):def __init__(self, inp, oup, hidden_dim, kernel_size, stride, use_se, use_hs):super(MobileNetV3_InvertedResidual, self).__init__()assert stride in [1, 2]self.identity = stride == 1 and inp == oup# 输入通道图 = 扩张通道数 则不进行通道扩张if inp == hidden_dim:self.conv = nn.Sequential(# dwnn.Conv2d(hidden_dim, hidden_dim, kernel_size, stride, (kernel_size - 1) // 2, groups=hidden_dim,bias=False),nn.BatchNorm2d(hidden_dim),h_swish() if use_hs else nn.ReLU(inplace=True),# Squeeze-and-ExciteSELayer(hidden_dim) if use_se else nn.Sequential(),# Eca_layer(hidden_dim) if use_se else nn.Sequential(),#1.13.2022# pw-linearnn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False),nn.BatchNorm2d(oup),)else:# 否则先进行扩张  self.conv = nn.Sequential(# pwnn.Conv2d(inp, hidden_dim, 1, 1, 0, bias=False),nn.BatchNorm2d(hidden_dim),h_swish() if use_hs else nn.ReLU(inplace=True),# dwnn.Conv2d(hidden_dim, hidden_dim, kernel_size, stride, (kernel_size - 1) // 2, groups=hidden_dim,bias=False),nn.BatchNorm2d(hidden_dim),# Squeeze-and-ExciteSELayer(hidden_dim) if use_se else nn.Sequential(),# Eca_layer(hidden_dim) if use_se else nn.Sequential(),  # 1.13.2022h_swish() if use_hs else nn.ReLU(inplace=True),# pw-linearnn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False),nn.BatchNorm2d(oup),)def forward(self, x):y = self.conv(x)if self.identity:return x + yelse:return y

第二步:将yolo.py中注册模块。

if m in [Conv,MobileNetV3_InvertedResidual,ShuffleNetV2_InvertedResidual,]:
# 加入h_sigmoid,h_swish,SELayer,conv_bn_hswish,MobileNetV3_InvertedResidual五个模块

第三步:修改yaml文件

backbone:# MobileNetV3-large# [from, number, module, args][[-1, 1, conv_bn_hswish, [16, 2]],                   # 0-p1/2[-1, 1, MobileNetV3_InvertedResidual, [ 16,  16, 3, 1, 0, 0]],  # 1-p1/2[-1, 1, MobileNetV3_InvertedResidual, [ 24,  64, 3, 2, 0, 0]],  # 2-p2/4[-1, 1, MobileNetV3_InvertedResidual, [ 24,  72, 3, 1, 0, 0]],  # 3-p2/4[-1, 1, MobileNetV3_InvertedResidual, [ 40,  72, 5, 2, 1, 0]],  # 4-p3/8[-1, 1, MobileNetV3_InvertedResidual, [ 40, 120, 5, 1, 1, 0]],  # 5-p3/8[-1, 1, MobileNetV3_InvertedResidual, [ 40, 120, 5, 1, 1, 0]],  # 6-p3/8[-1, 1, MobileNetV3_InvertedResidual, [ 80, 240, 3, 2, 0, 1]],  # 7-p4/16[-1, 1, MobileNetV3_InvertedResidual, [ 80, 200, 3, 1, 0, 1]],  # 8-p4/16[-1, 1, MobileNetV3_InvertedResidual, [ 80, 184, 3, 1, 0, 1]],  # 9-p4/16[-1, 1, MobileNetV3_InvertedResidual, [ 80, 184, 3, 1, 0, 1]],  # 10-p4/16[-1, 1, MobileNetV3_InvertedResidual, [112, 480, 3, 1, 1, 1]],  # 11-p4/16[-1, 1, MobileNetV3_InvertedResidual, [112, 672, 3, 1, 1, 1]],  # 12-p4/16[-1, 1, MobileNetV3_InvertedResidual, [160, 672, 5, 1, 1, 1]],  # 13-p4/16[-1, 1, MobileNetV3_InvertedResidual, [160, 960, 5, 2, 1, 1]],  # 14-p5/32   原672改为原算法960[-1, 1, MobileNetV3_InvertedResidual, [160, 960, 5, 1, 1, 1]],  # 15-p5/32]

根据MobileNetv3的网络结构来修改配置文件。
在这里插入图片描述
根据网络结构我们可以看出MobileNetV3模块包含六个参数[out_ch, hidden_ch, kernel_size, stride, use_se, use_hs]:
out_ch: 输出通道
hidden_ch: 表示在Inverted residuals中的扩张通道数
kernel_size: 卷积核大小
stride: 步长
use_se: 表示是否使用 SELayer,使用了是1,不使用是0
use_hs: 表示使用 h_swish 还是 ReLU,使用h_swish是1,使用 ReLU是0
修改的时候,需要注意/8,/16,/32等位置特征图的变换
在这里插入图片描述
同样的,head部分这几个concat的层也要做修改:
在这里插入图片描述
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# Mobilenetv3-small backbone# MobileNetV3_InvertedResidual [out_ch, hid_ch, k_s, stride, SE, HardSwish]
backbone:# [from, number, module, args][[-1, 1, conv_bn_hswish, [16, 2]],             # 0-p1/2   320*320[-1, 1, MobileNetV3, [16,  16, 3, 2, 1, 0]],  # 1-p2/4   160*160[-1, 1, MobileNetV3, [24,  72, 3, 2, 0, 0]],  # 2-p3/8   80*80[-1, 1, MobileNetV3, [24,  88, 3, 1, 0, 0]],  # 3        80*80[-1, 1, MobileNetV3, [40,  96, 5, 2, 1, 1]],  # 4-p4/16  40*40[-1, 1, MobileNetV3, [40, 240, 5, 1, 1, 1]],  # 5        40*40[-1, 1, MobileNetV3, [40, 240, 5, 1, 1, 1]],  # 6        40*40[-1, 1, MobileNetV3, [48, 120, 5, 1, 1, 1]],  # 7        40*40[-1, 1, MobileNetV3, [48, 144, 5, 1, 1, 1]],  # 8        40*40[-1, 1, MobileNetV3, [96, 288, 5, 2, 1, 1]],  # 9-p5/32  20*20[-1, 1, MobileNetV3, [96, 576, 5, 1, 1, 1]],  # 10       20*20[-1, 1, MobileNetV3, [96, 576, 5, 1, 1, 1]],  # 11       20*20]# YOLOv5 v6.0 head
head:[[-1, 1, Conv, [96, 1, 1]],  # 12                         20*20[-1, 1, nn.Upsample, [None, 2, 'nearest']], # 13         40*40[[-1, 8], 1, Concat, [1]],  # cat backbone P4            40*40[-1, 3, C3, [144, False]],  # 15                         40*40[-1, 1, Conv, [144, 1, 1]], # 16                         40*40[-1, 1, nn.Upsample, [None, 2, 'nearest']],# 17          80*80[[-1, 3], 1, Concat, [1]],  # cat backbone P3            80*80[-1, 3, C3, [168, False]],  # 19 (P3/8-small)            80*80[-1, 1, Conv, [168, 3, 2]], # 20                         40*40[[-1, 16], 1, Concat, [1]], # cat head P4                40*40[-1, 3, C3, [312, False]],  # 22 (P4/16-medium)          40*40[-1, 1, Conv, [312, 3, 2]], # 23                         20*20[[-1, 12], 1, Concat, [1]], # cat head P5                20*20[-1, 3, C3, [408, False]],  # 25 (P5/32-large)           20*20[[19, 22, 25], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)]

三、YOLOv5结合MobileNetV3_large

MobileNetV3_large和MobileNetV3_small区别在于yaml文件中head中concat连接不同,深度因子和宽度因子不同。接下来我们就直接改动yaml的部分,其余参考上面步骤。

然后根据MobileNetv3的网络结构来修改配置文件。
在这里插入图片描述
修改后代码如下:

# Parameters
nc: 20  # 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:[[-1, 1, conv_bn_hswish, [16, 2]],                  # 0-p1/2[-1, 1, MobileNetV3, [ 16,  16, 3, 1, 0, 0]],  # 1-p1/2[-1, 1, MobileNetV3, [ 24,  64, 3, 2, 0, 0]],  # 2-p2/4[-1, 1, MobileNetV3, [ 24,  72, 3, 1, 0, 0]],  # 3-p2/4[-1, 1, MobileNetV3, [ 40,  72, 5, 2, 1, 0]],  # 4-p3/8[-1, 1, MobileNetV3, [ 40, 120, 5, 1, 1, 0]],  # 5-p3/8[-1, 1, MobileNetV3, [ 40, 120, 5, 1, 1, 0]],  # 6-p3/8[-1, 1, MobileNetV3, [ 80, 240, 3, 2, 0, 1]],  # 7-p4/16[-1, 1, MobileNetV3, [ 80, 200, 3, 1, 0, 1]],  # 8-p4/16[-1, 1, MobileNetV3, [ 80, 184, 3, 1, 0, 1]],  # 9-p4/16[-1, 1, MobileNetV3, [ 80, 184, 3, 1, 0, 1]],  # 10-p4/16[-1, 1, MobileNetV3, [112, 480, 3, 1, 1, 1]],  # 11-p4/16[-1, 1, MobileNetV3, [112, 672, 3, 1, 1, 1]],  # 12-p4/16[-1, 1, MobileNetV3, [160, 672, 5, 1, 1, 1]],  # 13-p4/16[-1, 1, MobileNetV3, [160, 960, 5, 2, 1, 1]],  # 14-p5/32   原672改为原算法960[-1, 1, MobileNetV3, [160, 960, 5, 1, 1, 1]],  # 15-p5/32]
# YOLOv5 v6.0 head
head:[ [ -1, 1, Conv, [ 256, 1, 1 ] ],[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ],[ [ -1, 13], 1, Concat, [ 1 ] ],  # cat backbone P4[ -1, 1, C3, [ 256, False ] ],  # 13[ -1, 1, Conv, [ 128, 1, 1 ] ],[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ],[ [ -1, 6 ], 1, Concat, [ 1 ] ],  # cat backbone P3[ -1, 1, C3, [ 128, False ] ],  # 17 (P3/8-small)[ -1, 1, Conv, [ 128, 3, 2 ] ],[ [ -1, 20 ], 1, Concat, [ 1 ] ],  # cat head P4[ -1, 1, C3, [ 256, False ] ],  # 20 (P4/16-medium)[ -1, 1, Conv, [ 256, 3, 2 ] ],[ [ -1, 16 ], 1, Concat, [ 1 ] ],  # cat head P5[ -1, 1, C3, [ 512, False ] ],  # 23 (P5/32-large)[ [ 23, 26, 29 ], 1, Detect, [ nc, anchors ] ],  # Detect(P3, P4, P5)]

网络运行结果:
在这里插入图片描述
我们可以看到MobileNetV3-large模型比MobileNetV3-small多了更多的MobileNet_Block结构,残差倒置结构中通道数维度也增大了许多,速度比YOLOv5s慢将近一半,但是参数变少,效果介乎MobileNetV3-small和YOLOv5s之间,可以作为模型对比,凸显自己模型优势。

结 果:如果训练之后发现掉点纯属正常现象,因为轻量化网络在提速减少计算量的同时会降低精度。

:主干网络的替换不仅仅是适用改进YOLOv5,也可以改进其他的YOLO网络以及目标检测网络,比如YOLOv4、v3等。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL运维实战(1.3)安装部署:源码编译安装

作者:俊达 引言 在大多数情况下,我们不需要自己编译MySQL源码,因为编译的MySQL和二进制包的内容基本一致。然而,有些特殊情况可能需要我们采用源码编译的方式安装MySQL: 安装非标准版本的MySQL:有些特殊…

轻松管理固定资产,易点易动固定资产管理系统为企业开启新篇章

在现代企业运营中,固定资产管理是一个不可忽视的关键环节。有效地管理和维护固定资产不仅可以提升企业运营效率,还能最大限度地发挥资产的价值。为了满足企业对固定资产管理的需求,我们推出了易点易动固定资产管理系统,一款功能强…

PyTorch官网demo解读——第一个神经网络(3)

上一篇:PyTorch官网demo解读——第一个神经网络(2)-CSDN博客 上一篇文章我们讲解了第一个神经网络的模型,这一篇我们来聊聊梯度下降。 大佬说梯度下降是深度学习的灵魂;梯度是损失函数(代价函数&#xff…

labelme目标检测数据类型转换

1. labelme数据类型 LabelMe是一个开源的在线图像标注工具,旨在帮助用户创建和标记图像数据集。它提供了一个用户友好的界面,让用户可以直观地在图像上绘制标记框、多边形、线条等,以标识和注释图像中的对象或区域。 GitHub:http…

python使用apscheduler定时任务,固定周几运行程序

在add_job中添加参数day_of_week即可: day_of_week "0"表示:只有周一运行day_of_week "0-4"表示:周一到周五运行day_of_week "0,1,2"表示:周一二三运行 示例程序 from datetime import datet…

Docker介绍、常用命令与操作

Docker介绍、常用命令与操作 学习前言为什么要学习DockerDocker里的必要基础概念常用命令与操作1、基础操作a、查看docker相关信息b、启动或者关闭docker 2、容器操作a、启动一个镜像i、后台运行ii、前台运行 b、容器运行情况查看c、日志查看d、容器删除 3、镜像操作a、镜像拉取…

Unity网格篇Mesh(一)

Unity网格篇Mesh(一) 本文的目标1.渲染仔细看下面的图你会发现,锯齿状 2.创建网格顶点4 x 2网格网格的顶点 3.创建网格网格只在Play模式下显示逆时针和顺时针三角形第一个三角面一个四边形由两个三角面组成第一个四边形填充剩余网格 接下一篇…

Wordpress对接Lsky Pro 兰空图床插件

Wordpress对接Lsky Pro 兰空图床插件 wordpress不想存储图片到本地,访问慢,wordpress图片没有cdn想要使用图床,支持兰空自定义接口 安装教程—在wp后台选择插件zip—然后启用—设置自己图床API接口就ok了,文件全部解密&#xff0c…

LazyForEach常见使用问题

目录 1、渲染结果非预期 2、重新渲染时图片闪烁 3、ObjectLink属性变化UI未更新 上篇文章中我们介绍了LazyForEach的基本使用,展示了如何使用LazyForEach构造一个列表,并演示数据的添加、删除、修改如何与LazyForEach配合并正确的更新UI。本篇将介绍使…

全自动洗衣机什么牌子好?最好用的四款内衣洗衣机推荐

随着科技的快速发展,现在的人们越来越注重自己的卫生问题,不仅在吃上面会注重卫生问题,在用的上面也会更加严格要求,而衣服做为我们最贴身的东西,我们对它的要求也会更加高,所以最近这几年较火爆的无疑是内…

游戏行业变天,游戏股遭暴击,腾讯网易等股票还能投资吗?

来源:猛兽财经 作者:猛兽财经 国家新闻出版署发布游戏新规 12月22日国家新闻出版署发布了《网络游戏管理办法》(草案征求意见稿),其中提到网络游戏不得设置每日登陆、首次充值、连续充值等诱导性奖励,而且…

Ubuntu系统如何安装SVN服务端并通过客户端无公网ip实现远程访问?

文章目录 前言1. Ubuntu安装SVN服务2. 修改配置文件2.1 修改svnserve.conf文件2.2 修改passwd文件2.3 修改authz文件 3. 启动svn服务4. 内网穿透4.1 安装cpolar内网穿透4.2 创建隧道映射本地端口 5. 测试公网访问6. 配置固定公网TCP端口地址6.1 保留一个固定的公网TCP端口地址6…