YOLOv8改进实战 | 更换主干网络Backbone(三)之轻量化模型ShuffleNetV2

news2025/4/4 22:01:41

在这里插入图片描述


前言

轻量化网络设计是一种针对移动设备等资源受限环境的深度学习模型设计方法。下面是一些常见的轻量化网络设计方法:

  1. 网络剪枝:移除神经网络中冗余的连接和参数,以达到模型压缩和加速的目的。
  2. 分组卷积:将卷积操作分解为若干个较小的卷积操作,并将它们分别作用于输入的不同通道,从而减少计算量。
  3. 深度可分离卷积:将标准卷积分解成深度卷积和逐点卷积两个步骤,使得在大部分情况下可以大幅减少计算量。
  4. 跨层连接:通过跨越多个层级的连接方式来增加神经网络的深度和复杂性,同时减少了需要训练的参数数量。
  5. 模块化设计:将神经网络分解为多个可重复使用的模块,以提高模型的可调节性和适应性。

传统的YOLOv8系列中,Backbone采用的是较为复杂的C2f网络结构,这使得模型计算量大幅度的增加,检测速度较慢,应用受限,在某些真实的应用场景如移动或者嵌入式设备,如此大而复杂的模型时难以被应用的。为了解决这个问题,本章节通过采用ShuffleNetV2轻量化主干网络作为Backbone的基础结构,从而在保证检测性能的同时,将网络结构精简到最小,大大减小了模型的参数量和计算量。

目录

  • 一、ShuffleNetV2
  • 二、代码实现
    • 2.1 添加ShuffleNetV2
    • 2.2 注册模块
    • 2.3 配置yaml文件
      • yolov8-shufflenetv2.yaml
    • 2.3 模型验证
    • 2.4 模型训练
  • 三、总结

一、ShuffleNetV2

2018 论文链接:ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design
Pytorch code:ShuffleNet-Series

论文总结的四条轻量化模型设计的指导思想

  • G1:卷积层的输入特征channel和输出特征channel相等可以最小化 MAC(Memory Access Cost,即内存占用量);
  • G2过度的分组卷积会增加MAC
    • 分组卷积是现代网络体系结构的核心。通过更改所有通道之间的稀疏卷积(仅在通道组内),可以降低计算复杂度(FLOP)。一方面,在给定固定FLOPs的情况下,它允许使用更多通道,并增加了网络容量(因此具有更高的准确性)。但是,另一方面,增加的通道数会导致更多的MAC。
  • G3:网络碎片化会降低并行化的程度;
    • GoogLeNet系列和自动生成的体系结构中,每个网络模块中广泛采用“多路径”结构,使用了很多不同的小卷积或者pooling。尽管这种零散的结构已显示出对准确率有利,但由于它对具有强大并行计算能力的设备(如GPU)不友好,因此可能会降低效率。它还引入了额外的开销,例如内核启动和同步。
  • G4:不可忽略元素级的操作
    • 对于元素级操作(element-wise operators),比如ReLUAdd,虽然它们的FLOPs较小,但是却需要较大的MAC。深度卷积也算是元素级操作,也具有较高的MAC/FLOPs的比例。实验发现如果将ResNet中残差单元中的ReLU和shortcut移除的话,速度有20%的提升。

总结

  1. 使用“平衡”卷积(输入通道尽可能等于输出通道);
  2. 注意使用组卷积的代价;
  3. 减少碎片程度;
  4. 减少按元素操作。

在这里插入图片描述

二、代码实现

2.1 添加ShuffleNetV2

ultralytics/nn/modules/block.py文件中加入以下代码:

# TODO:build shuffle block
# -------------------------------------------------------------------------

def channel_shuffle(x, groups):
    batchsize, num_channels, height, width = x.data.size()
    channels_per_group = num_channels // groups

    # reshape
    x = x.view(batchsize, groups,
               channels_per_group, height, width)

    x = torch.transpose(x, 1, 2).contiguous()

    # flatten
    x = x.view(batchsize, -1, height, width)

    return x


class conv_bn_relu_maxpool(nn.Module):
    def __init__(self, c1, c2):  # ch_in, ch_out
        super(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 ShuffleV2Block(nn.Module):
    def __init__(self, inp, oup, stride):
        super(ShuffleV2Block, self).__init__()

        if not (1 <= stride <= 3):
            raise ValueError('illegal stride value')
        self.stride = stride

        branch_features = oup // 2
        assert (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),
            )
        else:
            self.branch1 = nn.Sequential()

        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),
        )

    @staticmethod
    def 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)
            out = 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
# -------------------------------------------------------------------------

2.2 注册模块

修改ultralytics/nn/modules/__init__.py文件:

from .block import (ASFF2, ASFF3, C1, C2, C3, C3TR, DFL, SPP, SPPF, Bottleneck, BottleneckCSP, C2f, C3Ghost, C3x,
                    GhostBottleneck, HGBlock, HGStem, Proto, RepC3, conv_bn_relu_maxpool, ShuffleV2Block)
__all__ = ('Conv', 'Conv2', 'LightConv', 'RepConv', 'DWConv', 'DWConvTranspose2d', 'ConvTranspose', 'Focus',
           'GhostConv', 'ChannelAttention', 'SpatialAttention', 'CBAM', 'Concat', 'TransformerLayer',
           'TransformerBlock', 'MLPBlock', 'LayerNorm2d', 'DFL', 'HGBlock', 'HGStem', 'SPP', 'SPPF', 'C1', 'C2', 'C3',
           'C2f', 'C3x', 'C3TR', 'C3Ghost', 'GhostBottleneck', 'Bottleneck', 'BottleneckCSP', 'Proto', 'Detect',
           'Segment', 'Pose', 'Classify', 'TransformerEncoderLayer', 'RepC3', 'RTDETRDecoder', 'AIFI',
           'DeformableTransformerDecoder', 'DeformableTransformerDecoderLayer', 'MSDeformAttn', 'MLP', 'ASFF2', 'ASFF3',
           'conv_bn_relu_maxpool', 'ShuffleV2Block')

修改ultralytics/nn/tasks.py文件中的parse_model函数:

from ultralytics.nn.modules import (AIFI, ASFF2, ASFF3, C1, C2, C3, C3TR, SPP, SPPF, Bottleneck, BottleneckCSP, C2f,
                                    C3Ghost, C3x, Classify, Concat, Conv, Conv2, ConvTranspose, Detect, DWConv,
                                    DWConvTranspose2d, Focus, GhostBottleneck, GhostConv, HGBlock, HGStem, Pose, RepC3,
                                    RepConv, RTDETRDecoder, Segment, conv_bn_relu_maxpool, ShuffleV2Block)
if m in (Classify, Conv, ConvTranspose, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, Focus,
         BottleneckCSP, C1, C2, C2f, C3, C3TR, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x, RepC3,
         conv_bn_relu_maxpool, ShuffleV2Block):
    c1, c2 = ch[f], args[0]
    if c2 != nc:  # if c2 not equal to number of classes (i.e. for Classify() output)
        c2 = make_divisible(min(c2, max_channels) * width, 8)

    args = [c1, c2, *args[1:]]

2.3 配置yaml文件

这里我们选择替换Backbone中的所有ConvC2f模块。当然也可以将所有ConvC2f模块全部替换掉,哪个效果更好,需要各位去实测一番。

yolov8-shufflenetv2.yaml

第一版

# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLOv8 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect

# Parameters
nc: 80  # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n.yaml' will call yolov8.yaml with scale 'n'
  # [depth, width, max_channels]
  n: [0.33, 0.25, 1024]  # YOLOv8n summary: 225 layers,  3157200 parameters,  3157184 gradients,   8.9 GFLOPs
  s: [0.33, 0.50, 1024]  # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients,  28.8 GFLOPs
  m: [0.67, 0.75, 768]   # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients,  79.3 GFLOPs
  l: [1.00, 1.00, 512]   # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPs
  x: [1.00, 1.25, 512]   # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOPs

# YOLOv8.0n backbone
backbone:
  # [from, repeats, module, args]
  - [-1, 1, conv_bn_relu_maxpool, [32]]  # 0-P1/2

  - [ -1, 1, ShuffleV2Block, [116, 2] ] # 1-P3/8
  - [ -1, 9, ShuffleV2Block, [116, 1] ] # 2

  - [ -1, 1, ShuffleV2Block, [232, 2] ] # 3-P4/16
  - [ -1, 21, ShuffleV2Block, [232, 1] ] # 4

  - [ -1, 1, ShuffleV2Block, [464, 2] ] # 5-P5/32
  - [ -1, 9, ShuffleV2Block, [464, 1] ] # 6

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

# YOLOv8.0n head
head:
  - [-1, 1, nn.Upsample, [None, 2, 'nearest']]
  - [[-1, 4], 1, Concat, [1]]  # cat backbone P4
  - [-1, 3, C2f, [512]]  # 10

  - [-1, 1, nn.Upsample, [None, 2, 'nearest']]
  - [[-1, 2], 1, Concat, [1]]  # cat backbone P3
  - [-1, 3, C2f, [256]]  # 13 (P3/8-small)

  - [-1, 1, Conv, [256, 3, 2]]
  - [[-1, 10], 1, Concat, [1]]  # cat head P4
  - [-1, 3, C2f, [512]]  # 16 (P4/16-medium)

  - [-1, 1, Conv, [512, 3, 2]]
  - [[-1, 7], 1, Concat, [1]]  # cat head P5
  - [-1, 3, C2f, [1024]]  # 19 (P5/32-large)

  - [[13, 16, 19], 1, Detect, [nc]]  # Detect(P3, P4, P5)
YOLOv8n-shufflenetv2 summary: 336 layers, 2005904 parameters, 2005888 gradients, 5.9 GFLOPs

推荐:第二版(结合YOLOv5-Lite思想):

# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLOv8 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect

# Parameters
nc: 80  # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n.yaml' will call yolov8.yaml with scale 'n'
  # [depth, width, max_channels]
  n: [0.33, 0.25, 1024]  # YOLOv8n summary: 225 layers,  3157200 parameters,  3157184 gradients,   8.9 GFLOPs
  s: [0.33, 0.50, 1024]  # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients,  28.8 GFLOPs
  m: [0.67, 0.75, 768]   # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients,  79.3 GFLOPs
  l: [1.00, 1.00, 512]   # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPs
  x: [1.00, 1.25, 512]   # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOPs

# YOLOv8.0n backbone
backbone:
  # [from, repeats, module, args]
  - [-1, 1, conv_bn_relu_maxpool, [32]]  # 0-P1/2

  - [ -1, 1, ShuffleV2Block, [116, 2] ] # 1-P3/8
  - [ -1, 9, ShuffleV2Block, [116, 1] ] # 2

  - [ -1, 1, ShuffleV2Block, [232, 2] ] # 3-P4/16
  - [ -1, 21, ShuffleV2Block, [232, 1] ] # 4

  - [ -1, 1, ShuffleV2Block, [464, 2] ] # 5-P5/32
  - [ -1, 3, ShuffleV2Block, [464, 1] ] # 6


# YOLOv8.0n head
head:
  - [-1, 1, nn.Upsample, [None, 2, 'nearest']]
  - [[-1, 4], 1, Concat, [1]]  # cat backbone P4
  - [-1, 3, C2f, [512]]  # 9

  - [-1, 1, nn.Upsample, [None, 2, 'nearest']]
  - [[-1, 2], 1, Concat, [1]]  # cat backbone P3
  - [-1, 3, C2f, [256]]  # 12 (P3/8-small)

  - [-1, 1, Conv, [256, 3, 2]]
  - [[-1, 9], 1, Concat, [1]]  # cat head P4
  - [-1, 3, C2f, [512]]  # 15 (P4/16-medium)

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

  - [[12, 15, 18], 1, Detect, [nc]]  # Detect(P3, P4, P5)
YOLOv8n-shufflenetv2 summary: 231 layers, 1975560 parameters, 1975544 gradients, 5.8 GFLOPs

2.3 模型验证

from ultralytics import YOLO

# Load a model
model = YOLO("backbone/yolov8n-shufflenetv2.yaml")  # build a new model from scratch

2.4 模型训练

from ultralytics import YOLO

# Load a model
model = YOLO("backbone/yolov8n-shufflenetv2.yaml")  # build a new model from scratch

# Use the model
model.train(
    data="./mydata/data.yaml",
    epochs=300,
    batch=48)  # train the model

三、总结

  • 模型的训练具有很大的随机性,您可能需要点运气和更多的训练次数才能达到最高的 mAP。

在这里插入图片描述

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

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

相关文章

2023 中国 VR 50 强企业名单发布;OpenAI 新模型性能远低于预期丨 RTE 开发者日报 Vol.71

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE &#xff08;Real Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有…

低代码软件:开发老手的新选择?

数字化的来临使得低代码进入人们的视野。它成本低、灵活度高、操作难度小、开发周期短&#xff0c;这些优势把他带入到了众多企业中。有些人可能会有疑问&#xff0c;开发老手可以用低代码软件吗&#xff1f;会不会不好用&#xff1f;今天这篇文章就来为您揭秘&#xff01; 先…

c++数组教程

今天来讲讲数组 什么是数组&#xff1a; 我们来看一道题目&#xff1a; 【题目部分】 输入n个数,逆序输出它们. 输入 第一行一个整数n (0 < n < 60 ) 第二行n个整数 输出 一行,n个整数。 输入样例 1 5 1 6 2 8 4 输出样例 1 4 8 2 6 1 这下就难住很多人了&…

单点登录与网络犯罪生态系统

这不仅仅是你的感觉&#xff0c;网络犯罪正以惊人的速度增长。在Flare&#xff0c;我们发现2023年的数据勒索勒索软件攻击比2022年增加了112&#xff05;&#xff0c;并且网络犯罪生态系统的活动也在不断增加。 导语&#xff1a;网络犯罪的惊人增长 网络犯罪在当今社会中变得越…

分布式事务无压力:轻松整合Spring Cloud与Alibaba Seata,事务管理so easy

今天我们聊聊在SpringCloud微服务架构中如何解决分布式事务这一技术难题&#xff0c;本文主要包含三个方面内容&#xff1a; 讲解分布式事务的解决方案&#xff1b;介绍 Alibaba Seata 分布式事务中间件&#xff1b;分析 Seata 的 AT 模式实现原理。 分布式事务的解决方案 下…

专业修图软件 Affinity Photo 2 mac中文版编辑功能

Affinity Photo for Mac是应用在MacOS上的专业修图软件&#xff0c;支持多种文件格式&#xff0c;包括psD、PDF、SVG、Eps、TIFF、JPEG等。 Affinity Photo mac提供了许多高级图像编辑功能&#xff0c;如无限制的图层、非破坏性操作、高级的选择工具、高级的调整层、HDR合成、全…

2023最新Google play 开发者账号注册矩阵批量,提高注册成功率需要注意什么?

Google play作为全球最大的应用市场&#xff0c;是很多开发者推广应用的首选平台。不过&#xff0c;不少开发者会通过上传多个马甲包的方式来抢占更多的市场份额&#xff0c;获得更多的收益。 但上传马甲包的行为严重扰乱了Google play的市场环境&#xff0c;是不被谷歌官方允许…

MySQL基本操作之修改表结构

1、末尾增加字段 在表结构末尾增加一个名为 beizhu 的字段,类型为 varchar(250),并添加注释 trie: ALTER TABLE student ADD beizhu VARCHAR(250) COMMENT trie; 2、在表结构开头增加一个名为 xxx 的字段,类型为 varchar(20): ALTER TABLE student ADD xxx VARCHAR(20)…

4 OpenCV实现多目三维重建(多张图片增量式生成稀疏点云)【附源码】

本文是基于 OpenCV4.80 进行的&#xff0c;关于环境的配置可能之后会单独说&#xff0c;先提一嘴 vcpkg 真好用 1 大致流程 从多张图片逐步生成稀疏点云&#xff0c;这个过程通常包括以下步骤&#xff1a; 初始重建&#xff1a; 初始两张图片的选择十分重要&#xff0c;这是整…

nginx+nodejs 一台服务器站架多个网站

一、一台服务器架设多个 nodejs 网站的拓扑结构 二、搭建 Nodejs 生产环境 1、下载 下载 nodejs 二进制代码包或者&#xff0c;然后减压到 /usr/local/nodejs 2、配置环境变量 (1).vi /etc/profile (2).最后面添加&#xff1a; export NODE_HOME/usr/local/nodejs/bin…

常见问题-找不到vcruntime140.dll无法继续执行代码解决方案

本文将介绍五种不同的解决方案&#xff0c;帮助大家解决这个问题。 首先&#xff0c;我们需要了解为什么会出现找不到vcruntime140.dll的情况。这种情况通常是由于以下几个原因导致的&#xff1a; 1. 系统环境变量设置不正确&#xff1a;系统环境变量中可能没有包含vcruntime…

卷积神经网络CNN学习笔记

目录 1.全连接层存在的问题2.卷积运算3.填充(padding)3.1填充(padding)的意义 4.步幅(stride)5.三维数据的卷积运算6.结合方块思考7.批处理8.conv2d代码参考文章 1.全连接层存在的问题 在全连接层中&#xff0c;相邻层的神经元全部连接在一起&#xff0c;输出的数量可以任意决…

大数据之LibrA数据库系统概览

实时监控 “实时监控”页面如图1所示&#xff0c;用户可单击刷新按钮手动刷新当前页面&#xff0c;也可在点刷新按钮前选择自动刷新时长&#xff0c;刷新时长包括&#xff1a;每30秒刷新一次、每60秒刷新一次、停止刷新。 实时监控数据&#xff08;监控时间轴产生的新曲线&am…

win32汇编-PUSHAD和POPAD指令

PUSHAD是一个x86汇编指令&#xff0c;用于将当前程序的所有通用寄存器&#xff08;EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI&#xff09;的值依次入栈 PUSHAD指令压入32位寄存器 其堆栈指针SP将加32 PUSHAD POPAD不会影响标志位 POPAD指令则是PUSHAD指令的逆操作。POPAD指令…

家装、家居两不误,VR全景打造沉浸式家装体验

当下&#xff0c;用户对生活品质要求日益提升&#xff0c;越来越多的用户对多功能家装用品需求较大&#xff0c;由此造就了VR全景家装开始盛行。VR全景家装打破传统二维空间模式&#xff0c;通过视觉、交互等功能让用户更加真实、直观的体验和感受家居布置的效果。 一般来说&am…

数据结构-----图(graph)的储存和创建

目录 前言 图的储存结构 1.邻接矩阵 无向图的邻接矩阵 有向图的邻接矩阵 网&#xff08;赋权图&#xff09;的邻接矩阵 代码表示 2.邻接表 无向图的邻接表 有向图的邻接表 代码表示 3.邻接矩阵和邻接表对比 邻接矩阵 邻接表 图的创建 1.邻接矩阵创建图&#xff0…

idea2023配置maven

看过【黑马程序员Maven全套教程&#xff0c;maven项目管理从基础到高级&#xff0c;Java项目开发必会管理工具maven】https://www.bilibili.com/video/BV1Ah411S7ZE?p9&vd_sourceedf9d91e5a0a27db51e3d6d4b9400637 配置的&#xff0c;前提要素配置也在这个课程里有啦&…

在 Tubi 做 Tech Lead 有多刺激!

上周我们发布了一篇《当你在 Tubi 是一位 Tech Lead》采访稿&#xff0c;后台收到了这样一条留言&#xff0c;说出了许多技术人在选择管理岗位还是继续深耕技术方向时的纠结&#xff1a; ‘有些同事更喜欢投入精力处理有挑战的事情&#xff0c;而不愿花费太多时间进行人际沟通&…

Janus: 逆向思维,以数据为中心的MoE训练范式

文章链接&#xff1a;Janus: A Unified Distributed Training Framework for Sparse Mixture-of-Experts Models 发表会议: ACM SIGCOMM 2023 (计算机网络顶会) 目录 1.背景介绍all-to-allData-centric Paradigm 2.内容摘要关键技术Janus细粒度任务调度拓扑感知优先级策略预取…

30二叉树-了解二叉树

目录 树的定义 二叉树&#xff08;Binary Tree&#xff09; 二叉树的存储方式 链式存储 顺序存储 二叉树的遍历方式 LeetCode之路——144. 二叉树的前序遍历 分析 树的定义 树结构&#xff08;Tree Structure&#xff09;是一种分层的非线性数据结构&#xff0c;它由节…