YOLOv9改进策略 | Conv篇 | 利用YOLO-MS的MSBlock二次创新RepNCSPELAN4(全网独家创新)

news2024/9/20 3:28:04

一、本文介绍

本文给大家带来的改进机制是利用YOLO-MS提出的一种针对于实时目标检测的MSBlock模块(其其实不能算是Conv但是其应该是一整个模块),我们将其用于RepNCSPELAN中组合出一种新的结构,来替换我们网络中的模块可以达到一种轻量化的作用,我将其用于我的数据集上实验,包括多个类别的数据集,其在轻量网络结构的同时,却能够提高一定的mAP精度,所以这是一种十分高效的模块,该网络结构非常适合那些模型精度已经无法提到,想要从轻量化模型的角度入手的读者使用,同时该机制包含二次创新的机会欢迎大家订阅本专栏,本专栏每周更新3-5篇最新机制,更有包含我所有改进的文件和交流群提供给大家。

欢迎大家订阅我的专栏一起学习YOLO!

 专栏地址:YOLOv9有效涨点专栏-持续复现各种顶会内容-有效涨点-全网改进最全的专栏 

目录

一、本文介绍

二、MSBlock

2.1  MSBlock的基本原理

2.2 多尺度特征表示

2.3 层次化特征融合

2.4 异构卷积核选择

三、MSBlock的核心代码

 四、手把手教你添加MSBlock机制

4.1 细节修改教程

4.1.1 修改一

​4.1.2 修改二

4.1.3 修改三 

4.1.4 修改四

4.2 MSBlock的yaml文件(仔细看这个否则会报错)

4.3 MSBlock运行成功截图

五、本文总结 



二、MSBlock

论文地址:论文官方地址

代码地址:官方代码地址


2.1  MSBlock的基本原理

MSBlock的基本原理在于提高实时目标检测器的多尺度特征表示能力。MSBlock通过采用层次化特征融合策略和异构卷积核选择协议,有效地在网络不同阶段处理不同尺度的特征。这种设计使得检测器能够更好地识别和处理不同尺寸的目标。MSBlock的核心思想是通过改进卷积核的大小和结构,以及优化特征融合方式,来增强模型在处理多尺度信息时的性能,从而提高整体的目标检测精度和效率。

MSBlock的基本原理可以分为以下几点:

1. 多尺度特征表示:MSBlock旨在增强实时目标检测器处理不同尺度目标的能力,通过有效地表示和融合不同尺度的特征。

2. 层次化特征融合:MSBlock采用层次化的方式来融合来自网络不同层次的特征,这有助于模型在处理细粒度和粗粒度信息时的表现。

3. 异构卷积核选择:MSBlock实施一种异构卷积核选择协议,即在网络的不同阶段使用不同大小的卷积核,以适应不同尺度的特征表示。

下面我们可以看到三种不同的网络构建模块,分别是CSP Block、ELAN Block和MS-Block。

MS-Block设计包含以下特点:

1. 输入被分割成多个分支,每个分支处理不同的特征子集。
2. 在分支内部,通过1x1卷积进行特征转换,然后应用了一个kxk的深度卷积(深度可分离卷积),再接一个1x1卷积,以增强特征并减少参数数量。
3. 最后,所有的分支再经过一个1x1卷积进行融合,以整合各个分支的特征。


2.2 多尺度特征表示

在本文中,多尺度特征表示是通过MSBlock实现的,它通过在网络的不同层使用不同大小的卷积核来捕捉不同尺度的图像特征。这使得模型能够在低层捕获细节和小尺寸目标的特征,同时在高层捕捉更大区域的特征,有助于识别大尺寸目标。


2.3 层次化特征融合

层次化特征融合是通过MSBlock实现的,该技术利用多个并行处理的子网络或分支来处理输入特征图。这些分支在处理不同尺度的特征后,再通过特定的结构(如1x1卷积)融合这些特征,这样的结构设计允许网络在多个层次上提取和整合特征,提高了对各种尺寸目标的检测性能。

在这张图片中,我们看到了HKS(异构Kernel选择)协议的示意图,这个协议是在YOLO-MS中提出来的。HKS协议通过在网络的不同阶段使用不同大小的卷积核,来优化多尺度特征的提取。在这个图中,从上到下,MS-Block在网络的四个阶段分别使用了9x9、7x7、5x5和3x3的卷积核大小,这种设计允许网络更有效地处理不同尺度的对象,而且每个阶段的输出特征图大小和通道数(C1, C2, C3, C4)也有所不同。最终,通过PAFPN模块将这些特征进一步融合,以增强网络对多尺度特征的捕获能力。


2.4 异构卷积核选择

异构卷积核选择是指在深度学习模型中,根据数据的不同层次和尺度选择不同大小的卷积核。在论文中,通过这种方式,网络可以根据特征图的分辨率调整卷积核的大小,使得在捕捉小目标特征时使用较小的卷积核,在捕捉大目标特征时使用较大的卷积核。这样的设计有助于模型更精细地捕捉不同尺度的图像特征,并提高了目标检测的准确性和效率。


三、MSBlock的核心代码

使用方式看章节四

import torch
import torch.nn as nn

__all__ = ['RepNCSPELAN4_MSBlock']

def autopad(k, p=None, d=1):  # kernel, padding, dilation
    """Pad to 'same' shape outputs."""
    if d > 1:
        k = d * (k - 1) + 1 if isinstance(k, int) else [d * (x - 1) + 1 for x in k]  # actual kernel-size
    if p is None:
        p = k // 2 if isinstance(k, int) else [x // 2 for x in k]  # auto-pad
    return p


class Conv(nn.Module):
    """Standard convolution with args(ch_in, ch_out, kernel, stride, padding, groups, dilation, activation)."""
    default_act = nn.SiLU()  # default activation

    def __init__(self, c1, c2, k=1, s=1, p=None, g=1, d=1, act=True):
        """Initialize Conv layer with given arguments including activation."""
        super().__init__()
        self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p, d), groups=g, dilation=d, bias=False)
        self.bn = nn.BatchNorm2d(c2)
        self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity()

    def forward(self, x):
        """Apply convolution, batch normalization and activation to input tensor."""
        return self.act(self.bn(self.conv(x)))

    def forward_fuse(self, x):
        """Perform transposed convolution of 2D data."""
        return self.act(self.conv(x))


class MSBlockLayer(nn.Module):
    def __init__(self, inc, ouc, k) -> None:
        super().__init__()

        self.in_conv = Conv(inc, ouc, 1)
        self.mid_conv = Conv(ouc, ouc, k, g=ouc)
        self.out_conv = Conv(ouc, inc, 1)

    def forward(self, x):
        return self.out_conv(self.mid_conv(self.in_conv(x)))


class MSBlock(nn.Module):
    def __init__(self, inc, ouc, kernel_sizes, in_expand_ratio=3., mid_expand_ratio=2., layers_num=1,
                 in_down_ratio=2.) -> None:
        super().__init__()

        in_channel = int(inc * in_expand_ratio // in_down_ratio)
        self.mid_channel = in_channel // len(kernel_sizes)
        groups = int(self.mid_channel * mid_expand_ratio)
        self.in_conv = Conv(inc, in_channel)

        self.mid_convs = []
        for kernel_size in kernel_sizes:
            if kernel_size == 1:
                self.mid_convs.append(nn.Identity())
                continue
            mid_convs = [MSBlockLayer(self.mid_channel, groups, k=kernel_size) for _ in range(int(layers_num))]
            self.mid_convs.append(nn.Sequential(*mid_convs))
        self.mid_convs = nn.ModuleList(self.mid_convs)
        self.out_conv = Conv(in_channel, ouc, 1)

        self.attention = None

    def forward(self, x):
        out = self.in_conv(x)
        channels = []
        for i, mid_conv in enumerate(self.mid_convs):
            channel = out[:, i * self.mid_channel:(i + 1) * self.mid_channel, ...]
            if i >= 1:
                channel = channel + channels[i - 1]
            channel = mid_conv(channel)
            channels.append(channel)
        out = torch.cat(channels, dim=1)
        out = self.out_conv(out)
        if self.attention is not None:
            out = self.attention(out)
        return out



class RepNBottleneck_MSBlock(nn.Module):
    # Standard bottleneck
    def __init__(self, c1, c2, shortcut=True, g=1, k=(3, 3), e=0.5):  # ch_in, ch_out, shortcut, kernels, groups, expand
        super().__init__()
        c_ = int(c2 * e)  # hidden channels
        self.cv1 = MSBlock(c1, c_, kernel_sizes=k)
        self.cv2 = Conv(c_, c2, k[1], 1, g=g)
        self.add = shortcut and c1 == c2

    def forward(self, x):
        return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))


class RepNCSP(nn.Module):
    # CSP Bottleneck with 3 convolutions
    def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):  # ch_in, ch_out, number, shortcut, groups, expansion
        super().__init__()
        c_ = int(c2 * e)  # hidden channels
        self.cv1 = Conv(c1, c_, 1, 1)
        self.cv2 = Conv(c1, c_, 1, 1)
        self.cv3 = Conv(2 * c_, c2, 1)  # optional act=FReLU(c2)
        self.m = nn.Sequential(*(RepNBottleneck_MSBlock(c_, c_, shortcut, g, e=1.0) for _ in range(n)))

    def forward(self, x):
        return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), 1))


class RepNCSPELAN4_MSBlock(nn.Module):
    # csp-elan
    def __init__(self, c1, c2, c3, c4, c5=1):  # ch_in, ch_out, number, shortcut, groups, expansion
        super().__init__()
        self.c = c3//2
        self.cv1 = Conv(c1, c3, 1, 1)
        self.cv2 = nn.Sequential(RepNCSP(c3//2, c4, c5), Conv(c4, c4, 3, 1))
        self.cv3 = nn.Sequential(RepNCSP(c4, c4, c5), Conv(c4, c4, 3, 1))
        self.cv4 = Conv(c3+(2*c4), c2, 1, 1)

    def forward(self, x):
        y = list(self.cv1(x).chunk(2, 1))
        y.extend((m(y[-1])) for m in [self.cv2, self.cv3])
        return self.cv4(torch.cat(y, 1))

    def forward_split(self, x):
        y = list(self.cv1(x).split((self.c, self.c), 1))
        y.extend(m(y[-1]) for m in [self.cv2, self.cv3])
        return self.cv4(torch.cat(y, 1))



if __name__ == "__main__":
    # Generating Sample image
    image_size = (1, 64, 240, 240)
    image = torch.rand(*image_size)

    # Model
    mobilenet_v3 = RepNCSPELAN4_MSBlock(64, 64, 32, 32, 1)

    out = mobilenet_v3(image)
    print(out.size())


 四、手把手教你添加MSBlock机制

4.1 细节修改教程

4.1.1 修改一

我们找到如下的目录'yolov9-main/models'在这个目录下创建一个文件目录(注意是目录,因为我这个专栏会出很多的更新,这里用一种一劳永逸的方法)文件目录起名modules,然后在下面新建一个文件,将我们的代码复制粘贴进去。


​4.1.2 修改二

然后新建一个__init__.py文件,然后我们在里面添加一行代码。注意标记一个'.'其作用是标记当前目录。


4.1.3 修改三 

然后我们找到如下文件''models/yolo.py''在开头的地方导入我们的模块按照如下修改->

(如果你看了我多个改进机制此处只需要添加一个即可,无需重复添加。)

​​​​


4.1.4 修改四

然后我们找到parse_model方法,按照如下修改->

到此就修改完成了,复制下面的ymal文件即可运行。


4.2 MSBlock的yaml文件(仔细看这个否则会报错)

下面的配置文件为我修改的MSBlock的位置,参数的位置里面什么都不用添加空着就行,大家复制粘贴我的就可以运行,同时我提供多个版本给大家,根据我的经验可能涨点的位置。

# YOLOv9

# parameters
nc: 80  # number of classes
depth_multiple: 1  # model depth multiple
width_multiple: 1  # layer channel multiple
#activation: nn.LeakyReLU(0.1)
#activation: nn.ReLU()

# anchors
anchors: 3

# YOLOv9 backbone
backbone:
  [
   [-1, 1, Silence, []],
   # conv down
   [-1, 1, Conv, [64, 3, 2]],  # 1-P1/2
   # conv down
   [-1, 1, Conv, [128, 3, 2]],  # 2-P2/4
   # elan-1 block
   [-1, 1, RepNCSPELAN4_MSBlock, [256, 128, 64, 1]],  # 3
   # conv down
   [-1, 1, Conv, [256, 3, 2]],  # 4-P3/8
   # elan-2 block
   [-1, 1, RepNCSPELAN4_MSBlock, [512, 256, 128, 1]],  # 5
   # conv down
   [-1, 1, Conv, [512, 3, 2]],  # 6-P4/16
   # elan-2 block
   [-1, 1, RepNCSPELAN4_MSBlock, [512, 512, 256, 1]],  # 7
   # conv down
   [-1, 1, Conv, [512, 3, 2]],  # 8-P5/32
   # elan-2 block
   [-1, 1, RepNCSPELAN4_MSBlock, [512, 512, 256, 1]],  # 9
  ]

# YOLOv9 head
head:
  [
   # elan-spp block
   [-1, 1, SPPELAN, [512, 256]],  # 10

   # up-concat merge
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 7], 1, Concat, [1]],  # cat backbone P4

   # elan-2 block
   [-1, 1, RepNCSPELAN4_MSBlock, [512, 512, 256, 1]],  # 13

   # up-concat merge
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 5], 1, Concat, [1]],  # cat backbone P3

   # elan-2 block
   [-1, 1, RepNCSPELAN4_MSBlock, [256, 256, 128, 1]],  # 16 (P3/8-small)

   # conv-down merge
   [-1, 1, Conv, [256, 3, 2]],
   [[-1, 13], 1, Concat, [1]],  # cat head P4

   # elan-2 block
   [-1, 1, RepNCSPELAN4_MSBlock, [512, 512, 256, 1]],  # 19 (P4/16-medium)

   # conv-down merge
   [-1, 1, Conv, [512, 3, 2]],
   [[-1, 10], 1, Concat, [1]],  # cat head P5

   # elan-2 block
   [-1, 1, RepNCSPELAN4_MSBlock, [512, 512, 256, 1]],  # 22 (P5/32-large)
   
   # routing
   [5, 1, CBLinear, [[256]]], # 23
   [7, 1, CBLinear, [[256, 512]]], # 24
   [9, 1, CBLinear, [[256, 512, 512]]], # 25
   
   # conv down
   [0, 1, Conv, [64, 3, 2]],  # 26-P1/2

   # conv down
   [-1, 1, Conv, [128, 3, 2]],  # 27-P2/4

   # elan-1 block
   [-1, 1, RepNCSPELAN4_MSBlock, [256, 128, 64, 1]],  # 28

   # conv down fuse
   [-1, 1, Conv, [256, 3, 2]],  # 29-P3/8
   [[23, 24, 25, -1], 1, CBFuse, [[0, 0, 0]]], # 30  

   # elan-2 block
   [-1, 1, RepNCSPELAN4_MSBlock, [512, 256, 128, 1]],  # 31

   # conv down fuse
   [-1, 1, Conv, [512, 3, 2]],  # 32-P4/16
   [[24, 25, -1], 1, CBFuse, [[1, 1]]], # 33 

   # elan-2 block
   [-1, 1, RepNCSPELAN4_MSBlock, [512, 512, 256, 1]],  # 34

   # conv down fuse
   [-1, 1, Conv, [512, 3, 2]],  # 35-P5/32
   [[25, -1], 1, CBFuse, [[2]]], # 36

   # elan-2 block
   [-1, 1, RepNCSPELAN4_MSBlock, [512, 512, 256, 1]],  # 37

   # detect
   [[31, 34, 37, 16, 19, 22], 1, DualDDetect, [nc]],  # DualDDetect(A3, A4, A5, P3, P4, P5)
  ]


4.3 MSBlock运行成功截图

附上我的运行记录确保我的教程是可用的。 


五、本文总结 

到此本文的正式分享内容就结束了,在这里给大家推荐我的YOLOv9改进有效涨点专栏,本专栏目前为新开的平均质量分98分,后期我会根据各种最新的前沿顶会进行论文复现,也会对一些老的改进机制进行补充,目前本专栏免费阅读(暂时,大家尽早关注不迷路~),如果大家觉得本文帮助到你了,订阅本专栏,关注后续更多的更新~

 专栏地址:YOLOv9有效涨点专栏-持续复现各种顶会内容-有效涨点-全网改进最全的专栏 

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

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

相关文章

Flutter MQTT通信(实现聊天功能)

MQTT协议简介: MQTT(Message Queuing Telemetry Transport)是一种轻量级的、开放的、基于发布/订阅模式的消息传输协议,最初由IBM开发。它专门设计用于在低带宽、不稳定的网络环境下进行高效的消息传输。 学习完本篇文章&#x…

ESP32嵌入式物联网开发实战笔记-C编程基础知识点【doc.yotill.com】

乐鑫ESP32入门到精通项目开发参考百例下载: 链接:百度网盘 请输入提取码 5.1 C 语言基础知识复习 本节我们给大家介绍一下 C 语言基础知识,对于 C 语言比较熟练的开发者,可以跳过此节,对于基础比较薄弱的开发者&…

HCF-Net:用于红外小目标检测的分层上下文融合网络

摘要 红外小目标检测是一项重要的计算机视觉任务,涉及在红外图像中识别和定位微小物体,这些物体通常仅包含几个像素。然而,由于物体尺寸极小以及红外图像中通常复杂的背景,这项任务面临困难。在本文中,我们提出了一种…

40.Vue 应用

Vue 应用 应用实例 每个 Vue 应用都是通过 createApp函数创建一个新的 应用实例 import { createApp } from vueconst app createApp({/* 根组件选项 */ })根组件 我们传入 createApp 的对象实际上是一个组件,每个应用都需要一个“根组件”,其他组件…

HarmonyOS NEXT 使用XComponent + Vsync 实现自定义动画

介绍 XComponent 提供了应用在 native 侧调用 OpenGLES 图形接口的能力,本文主要介绍如何配合 Vsync 事件,完成自定义动画。在这种实现方式下,自定义动画的绘制不在 UI 主线程中完成,即使主线程卡顿,动画效果也不会受…

【Camera Sensor Driver笔记】二、点亮指南之Sensor Module XML

Camera Sensor module XML详解: cameraId 与 slot id 一一对应 (即:dtsi中相对应的sensor的 cell-index ) moduleName 模组厂名称 sensorName sensor 名称 actuatorName 马达名称 oisName …

Xavier 初始化

Xavier 初始化 为什么在 W [ l ] n p . r a n d o m . r a n d n ( s h a p e ) n p . s q r t ( 1 n [ l − 1 ] ) W^{[l]}np.random.randn(shape)\times np.sqrt(\frac{1}{n^{[l-1]}}) W[l]np.random.randn(shape)np.sqrt(n[l−1]1​) 中需要乘以 n p . s q r t ( 1 n […

宽带上网技术发展(xDSL、PON)

文章目录 xDSL(x数字用户线,x Digital Subscriber Line)IDSL(基于ISDN数字用户线路)ADSL(不对称数字用户线路)RADSL(速率自适应数字用户线路)HDSL(高速率数字用户线路)VDSL(极高速率数字用户线路)SDSL(单对线路/对称数字用户线路) PON&#x…

Linux驱动开发——(三)并发与竞争

目录 一、并发与竞争简介 二、原子操作 2.1 原子操作简介 2.2 原子整形操作API 2.3 原子位操作API 2.4 原子操作驱动代码 三、自旋锁 3.1 自旋锁简介 3.2 自旋锁API 3.3 自旋锁驱动代码 四、信号量 4.1 信号量简介 4.2 信号量API 4.3 信号量驱动代码 一、并发与…

SpringCloud系列(4)--SpringCloud微服务工程构建

前言:在上节我们新建了一个SpringCloud父工程,这一节主要是构建微服务工程,通过实现订单模块和支付模块来熟悉微服务的概念和构建过程。 1、在父工程下新建模块 2、选择模块的项目类型为Maven并选择模块要使用的JDK版本 3、填写子模块的名称&…

算法|最大堆、最小堆和堆排序的实现(JavaScript)

一些概念 堆&#xff1a;特殊的完全二叉树&#xff0c;具有特定性质的完全二叉树。大根堆&#xff1a;父节点 > 子节点小根堆&#xff1a;父节点 < 子节点 二叉堆也属于完全二叉树&#xff0c;所以可以用数组表示。 若下标从1开始&#xff0c;左节点为 2*i &#xff0…

Java的Future机制详解

Java的Future机制详解 一、为什么出现Future机制二、Future的相关类图2.1 Future 接口2.2 FutureTask 类 三、FutureTask的使用方法四、FutureTask源码分析4.1 state字段4.2 其他变量4.4 构造函数4.5 run方法及其他 一、为什么出现Future机制 常见的两种创建线程的方式。一种是…

高架学习笔记之软件架构风格

目录 零、什么是软件架构风格 一、常见的软件架构风格 二、数据流风格 2.1. 批处理风格 2.2. 管道-过滤器风格 三、调用/返回风格 3.1. 主/子程序风格 3.2. 面向对象风格 3.3. 层次型风格 3.4. 客户端/服务器风格 3.4.1. 两层C/S体系结构 3.4.2. 三层C/S体系结构 …

MBD_入门篇_20_Simulink子系统

20.Simulink子系统 20.1 概述 Simulink的子系统&#xff0c;相当于代码的function函数&#xff0c;但是模型的子系统又不完全等效于代码的函数。虚拟子系统并不会生成函数&#xff0c;而是以代码块的形式放在相应的调用位置上。模型层面我们使用子系统去做模块化的设计&#xf…

Mini-Gemini: 探索多模态视觉语言模型的新境界

一、背景 在数字化时代&#xff0c;人工智能的发展正以前所未有的速度推进。特别是在多模态学习领域&#xff0c;结合视觉和语言的能力已成为研究的热点。最近&#xff0c;一篇名为“Mini-Gemini: Mining the Potential of Multi-modality Vision Language Models”的文章在arX…

[已解决]react打包部署

react打包部署 问题 npm install 命令无反应 思路 换成 yarn install 安装完hadoop的环境后&#xff0c;使用node的yarn会报错&#xff1a; 我们在cmd使用where yarn&#xff0c;如下&#xff1a; 看你想保留哪一个&#xff0c;我平时node用的多&#xff0c;就把hadoop的y…

飞书API(5):查看多维表 28 种数据类型的数据结构

一、引入 前面我们用于测试的数据集其实都是比较常用的数据&#xff0c;比如说文本、数字、单选等&#xff0c;但飞书多维表并不仅仅只有这些数据&#xff0c;截止发文&#xff0c;飞书多维表应用上支持28种数据类型&#xff0c;在数据层面飞书官方只提供了23种数据类型&#…

Cadence软件安装

Cadence软件 iscape 用于安装cadence家的安装软件 解压缩安装包tar -xvf IScape04.23.tar.gz运行bash IScape/iscape/bin/iscape.sh 设置默认安装路径(可选)IC618 这里使用的是IC618.320版本作为示例,其他版本安装过程差不多 安装 首先安装终端模拟器,不然安装之后会失败…

【前端】校园二手书交易系统javascript+css+html (源码)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

Vnode是如何产生的?

源码 流程图 源码解读 Vue.js2.0中有两种生成方式&#xff1a;第一种是直接在Vue对象的option中添加render字段&#xff1b;第二种是像Vue.js 1.x版本那样写一个模板或者指定一个el根元素&#xff0c;它会首先转换成模板&#xff0c;经过HTMI语法解析器生成一个 ast 抽象语法树…