YOLOv9独家原创改进|使用可改变核卷积AKConv改进RepNCSPELAN4


专栏介绍:YOLOv9改进系列 | 包含深度学习最新创新,主力高效涨点!!!


一、改进点介绍

        AKConv是一种具有任意数量的参数和任意采样形状的可变卷积核,对不规则特征有更好的提取效果。

        RepNCSPELAN4是YOLOv9中的特征提取模块,类似YOLOv5和v8中的C2f与C3模块。


二、RepNCSPELAN4-AKConv模块详解

 2.1 模块简介

        RepNCSPELAN4-AKConv的主要思想:  使用AKConv替换RepNCSPELAN4中的Conv模块。


三、 RepNCSPELAN4-AKConv模块使用教程

3.1 RepNCSPELAN4-AKConv模块的代码

class RepNCSP_AKConv(RepNCSP):
    # 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__(c1, c2, n, shortcut, g, e)
        c_ = int(c2 * e)  # hidden channels
        self.cv1 = AKConv(c1, c_)
        self.cv2 = AKConv(c1, c_)
        self.cv3 = AKConv(2 * c_, c2)  # optional act=FReLU(c2)
        self.m = nn.Sequential(*(RepNBottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)))


class RepNCSPELAN4AKConv1(RepNCSPELAN4):
    def __init__(self, c1, c2, c3, c4, c5=1):  # ch_in, ch_out, number, shortcut, groups, expansion
        super().__init__(c1, c2, c3, c4, c5)
        self.cv1 = AKConv(c1, c3)
        self.cv2 = nn.Sequential(RepNCSP_AKConv(c3//2, c4, c5), Conv(c4, c4, 3, 1))
        self.cv3 = nn.Sequential(RepNCSP_AKConv(c4, c4, c5), Conv(c4, c4, 3, 1))
        self.cv4 = AKConv(c3+(2*c4), c2)

from einops import rearrange

class AKConv(nn.Module):
    def __init__(self, inc, outc, num_param=5, stride=1):
        """
        初始化参数说明:
            inc: 输入通道数, outc: 输出通道数, num_param:(卷积核)参数量, stride = 1:卷积步长默认为1, bias = None:默认无偏执
            """
        super(AKConv, self).__init__()
        self.num_param = num_param
        self.stride = stride
        self.conv = Conv(inc, outc, k=(num_param, 1), s=(num_param, 1) )
        self.p_conv = nn.Conv2d(inc, 2 * num_param, kernel_size=3, padding=1, stride=stride)
        nn.init.constant_(self.p_conv.weight, 0)
        self.p_conv.register_full_backward_hook(self._set_lr)

    @staticmethod
    def _set_lr(module, grad_input, grad_output):
        grad_input = (grad_input[i] * 0.1 for i in range(len(grad_input)))
        grad_output = (grad_output[i] * 0.1 for i in range(len(grad_output)))

    def forward(self, x):
        # N is num_param.
        offset = self.p_conv(x)
        dtype = offset.data.type()
        N = offset.size(1) // 2
        # (b, 2N, h, w)
        p = self._get_p(offset, dtype)

        # (b, h, w, 2N)
        p = p.contiguous().permute(0, 2, 3, 1)
        q_lt = p.detach().floor()
        q_rb = q_lt + 1

        q_lt = torch.cat([torch.clamp(q_lt[..., :N], 0, x.size(2) - 1), torch.clamp(q_lt[..., N:], 0, x.size(3) - 1)],
                         dim=-1).long()
        q_rb = torch.cat([torch.clamp(q_rb[..., :N], 0, x.size(2) - 1), torch.clamp(q_rb[..., N:], 0, x.size(3) - 1)],
                         dim=-1).long()
        q_lb = torch.cat([q_lt[..., :N], q_rb[..., N:]], dim=-1)
        q_rt = torch.cat([q_rb[..., :N], q_lt[..., N:]], dim=-1)

        # clip p
        p = torch.cat([torch.clamp(p[..., :N], 0, x.size(2) - 1), torch.clamp(p[..., N:], 0, x.size(3) - 1)], dim=-1)

        # bilinear kernel (b, h, w, N)
        g_lt = (1 + (q_lt[..., :N].type_as(p) - p[..., :N])) * (1 + (q_lt[..., N:].type_as(p) - p[..., N:]))
        g_rb = (1 - (q_rb[..., :N].type_as(p) - p[..., :N])) * (1 - (q_rb[..., N:].type_as(p) - p[..., N:]))
        g_lb = (1 + (q_lb[..., :N].type_as(p) - p[..., :N])) * (1 - (q_lb[..., N:].type_as(p) - p[..., N:]))
        g_rt = (1 - (q_rt[..., :N].type_as(p) - p[..., :N])) * (1 + (q_rt[..., N:].type_as(p) - p[..., N:]))

        # resampling the features based on the modified coordinates.
        x_q_lt = self._get_x_q(x, q_lt, N)
        x_q_rb = self._get_x_q(x, q_rb, N)
        x_q_lb = self._get_x_q(x, q_lb, N)
        x_q_rt = self._get_x_q(x, q_rt, N)

        # bilinear
        x_offset = g_lt.unsqueeze(dim=1) * x_q_lt + \
                   g_rb.unsqueeze(dim=1) * x_q_rb + \
                   g_lb.unsqueeze(dim=1) * x_q_lb + \
                   g_rt.unsqueeze(dim=1) * x_q_rt

        x_offset = self._reshape_x_offset(x_offset, self.num_param)
        out = self.conv(x_offset)

        return out

    # generating the inital sampled shapes for the AKConv with different sizes.
    def _get_p_n(self, N, dtype):
        base_int = round(math.sqrt(self.num_param))
        row_number = self.num_param // base_int
        mod_number = self.num_param % base_int
        p_n_x, p_n_y = torch.meshgrid(
            torch.arange(0, row_number),
            torch.arange(0, base_int), indexing='xy')
        p_n_x = torch.flatten(p_n_x)
        p_n_y = torch.flatten(p_n_y)
        if mod_number > 0:
            mod_p_n_x, mod_p_n_y = torch.meshgrid(
                torch.arange(row_number, row_number + 1),
                torch.arange(0, mod_number), indexing='xy')

            mod_p_n_x = torch.flatten(mod_p_n_x)
            mod_p_n_y = torch.flatten(mod_p_n_y)
            p_n_x, p_n_y = torch.cat((p_n_x, mod_p_n_x)), torch.cat((p_n_y, mod_p_n_y))
        p_n = torch.cat([p_n_x, p_n_y], 0)
        p_n = p_n.view(1, 2 * N, 1, 1).type(dtype)
        return p_n

    # no zero-padding
    def _get_p_0(self, h, w, N, dtype):
        p_0_x, p_0_y = torch.meshgrid(
            torch.arange(0, h * self.stride, self.stride),
            torch.arange(0, w * self.stride, self.stride), indexing='xy')

        p_0_x = torch.flatten(p_0_x).view(1, 1, h, w).repeat(1, N, 1, 1)
        p_0_y = torch.flatten(p_0_y).view(1, 1, h, w).repeat(1, N, 1, 1)
        p_0 = torch.cat([p_0_x, p_0_y], 1).type(dtype)

        return p_0

    def _get_p(self, offset, dtype):
        N, h, w = offset.size(1) // 2, offset.size(2), offset.size(3)

        # (1, 2N, 1, 1)
        p_n = self._get_p_n(N, dtype)
        # (1, 2N, h, w)
        p_0 = self._get_p_0(h, w, N, dtype)
        p = p_0 + p_n + offset
        return p

    def _get_x_q(self, x, q, N):
        b, h, w, _ = q.size()
        padded_w = x.size(3)
        c = x.size(1)
        # (b, c, h*w)
        x = x.contiguous().view(b, c, -1)

        # (b, h, w, N)
        index = q[..., :N] * padded_w + q[..., N:]  # offset_x*w + offset_y
        # (b, c, h*w*N)
        index = index.contiguous().unsqueeze(dim=1).expand(-1, c, -1, -1, -1).contiguous().view(b, c, -1)

        x_offset = x.gather(dim=-1, index=index).contiguous().view(b, c, h, w, N)

        return x_offset

    #  Stacking resampled features in the row direction.
    @staticmethod
    def _reshape_x_offset(x_offset, num_param):
        b, c, h, w, n = x_offset.size()
        x_offset = rearrange(x_offset, 'b c h w n -> b c (h n) w')
        return x_offset

3.2 在YOlO v9中的添加教程

阅读YOLOv9添加模块教程或使用下文操作

        1. 将YOLOv9工程中models下common.py文件中的最下行(否则可能因类继承报错)增加模块的代码。

         2. 将YOLOv9工程中models下yolo.py文件中的第681行(可能因版本变化而变化)增加以下代码。

            RepNCSPELAN4, SPPELAN, RepNCSPELAN4AKConv1}:

3.3 运行配置文件

# YOLOv9
# Powered bu https://blog.csdn.net/StopAndGoyyy

# parameters
nc: 80  # number of classes
#depth_multiple: 0.33  # model depth multiple
depth_multiple: 1  # model depth multiple
#width_multiple: 0.25  # layer channel 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, RepNCSPELAN4AKConv1, [256, 128, 64, 1]],  # 3

   # avg-conv down
   [-1, 1, ADown, [256]],  # 4-P3/8

   # elan-2 block
   [-1, 1, RepNCSPELAN4, [512, 256, 128, 1]],  # 5

   # avg-conv down
   [-1, 1, ADown, [512]],  # 6-P4/16

   # elan-2 block
   [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]],  # 7

   # avg-conv down
   [-1, 1, ADown, [512]],  # 8-P5/32

   # elan-2 block
   [-1, 1, RepNCSPELAN4, [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, [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, [256, 256, 128, 1]],  # 16 (P3/8-small)

   # avg-conv-down merge
   [-1, 1, ADown, [256]],
   [[-1, 13], 1, Concat, [1]],  # cat head P4

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

   # avg-conv-down merge
   [-1, 1, ADown, [512]],
   [[-1, 10], 1, Concat, [1]],  # cat head P5

   # elan-2 block
   [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]],  # 22 (P5/32-large)
   
   
   # multi-level reversible auxiliary branch
   
   # 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, [256, 128, 64, 1]],  # 28

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

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

   # avg-conv down fuse
   [-1, 1, ADown, [512]],  # 32-P4/16
   [[24, 25, -1], 1, CBFuse, [[1, 1]]], # 33 

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

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

   # elan-2 block
   [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]],  # 37
   
   
   
   # detection head

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

3.4 训练过程


欢迎关注!


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ArcGIS Runtime For Android开发之符号化和图层渲染

一、用Symbol对要素进行符号化 首先我们看一下Symbol 接口关系: 1、SimpleFillSymbol 他是用来进行简单的Graphic面要素填充符号化的,它可以设置要素的填充颜色,边线颜色、线宽,其用法如下: Polygon polygonnew Po…

python中的类与对象(3)

目录 一. 类的多继承 二. 类的封装 三. 类的多态 四. 类与对象综合练习:校园管理系统 一. 类的多继承 在(2)第四节中我们介绍了什么是类的继承,在子类的括号里面写入要继承的父类名。上一节我们只在括号内写了一个父类名&…

怎么删除CSDN上发布的文章(电脑版)

怎么删除CSDN上发布的文章(电脑版) 第一步:回到个人主页 第二步:点击右上角的“创作中心” 第三步:点击进去之后找到“管理”——“内容管理” 第四步:找到要删除的文章,点击右侧的三个小点点 第五步:然后…

js优雅的统计字符串字符出现次数

题目如下 统计一串字符串中每个字符出现的频率 示例字符串 let str asdfasqwerqwrdfafafasdfopasdfopckpasdfassfd小白写法 let str asdfasqwerqwrdfafafasdfopasdfopckpasdfassfdlet result {}; for (let i 0; i < str.length; i) {if (result[str[i]]) {result[str[…

了解游戏中的数据同步

数据同步 在联机游戏中&#xff0c;我的操作和数据要同步给同一局游戏中其他所有玩家&#xff0c;其他玩家的操作和数据也会同步给我。这叫做数据同步&#xff0c;目前数据同步的方式则有帧同步和状态同步。 状态同步&#xff1a;将操作发送给服务端&#xff0c;服务端对操作…

springboot-基础-eclipse打包jar包和war包的方法与排错

目录 打jar包打war包排错获取包外位置eclipse找不到*.jar 打jar包 修改 application-dev.yml spring.thymeleaf.prefixfile:./templates/ &#xff08;非必须&#xff01;如果遇到找不到模板的情况这样做&#xff09;把templates文件夹复制到jar文件同级的目录。 但是无法解…

Linux 基础IO(1)内存文件

文章目录 铺垫文件的系统调用接口文件描述符缓冲区 铺垫 文件文件内容 文件属性访问文件之前&#xff0c;都要先打开文件&#xff0c;而要访问&#xff0c;修改&#xff0c;编辑文件&#xff0c;文件就必须加载到内存中程序运行起来变成进程&#xff0c;被CPU调度&#xff0c;…

基于YOLOv的目标追踪与无人机前端查看系统开发

一、背景与简介 随着无人机技术的快速发展&#xff0c;目标追踪成为无人机应用中的重要功能之一。YOLOv作为一种高效的目标检测算法&#xff0c;同样适用于目标追踪任务。通过集成YOLOv模型&#xff0c;我们可以构建一个无人机前端查看系统&#xff0c;实现实时目标追踪和可视化…

构建高效的接口自动化测试框架思路

在选择接口测试自动化框架时&#xff0c;需要根据团队的技术栈和项目需求来综合考虑。对于测试团队来说&#xff0c;使用Python相关的测试框架更为便捷。无论选择哪种框架&#xff0c;重要的是确保 框架功能完备&#xff0c;易于维护和扩展&#xff0c;提高测试效率和准确性。今…

循序渐进,搞懂什么是回溯算法

循序渐进&#xff0c;搞懂什么是回溯算法 回溯算法简介 回溯算法&#xff08;backtracking algorithm&#xff09;实际上是一个类似枚举的搜索尝试过程&#xff0c;主要是在搜索尝试过程中寻找问题的解&#xff0c;当发现已不满足求解条件时&#xff0c;就“回溯”返回&#…

【高数】常数项级数概念与性质

下面为个人数学笔记&#xff0c;有需要借鉴即可。 一、常数项级数概念 二、常数项级数性质 三、调和级数 完。

文件底层的深入理解之文件输入输出重定向

目录 一、文件fd的分配规则 二、对输出重定向现象的理解 三、输出输入重定向的简单实现 1、输出重定向 2、输入重定向 一、文件fd的分配规则 最小的没有被使用的数组下标&#xff0c;会被分配给最新打开的文件。 二、对输出重定向现象的理解 正如上面这段代码所示&#xff0…

IO多路复用:提高网络应用性能的利器

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

WEB APIs (5)

window对象 BOM&#xff08;浏览器对象模型&#xff09; 其为js操作浏览器提供了方法 window对象是一个全局变量&#xff0c;是BOM树根节点 BOM的属性和方法都是window的&#xff0c;如document、console.log()等 var定义在全局全局作用域中的变量、函数都会变成window对象…

138.乐理基础-等音、等音程的意义

上一个内容&#xff1a;137.乐理基础-协和音程、不协和音程 上一个内容里练习的答案&#xff1a; 等音、等音程的意义&#xff0c;首先在 19.音阶 里写了&#xff0c;一个调使用的音阶应当是从主音快开始&#xff0c;以阶梯状的形式进行到主音结束&#xff0c;这样才能明显从乐…

VMware Workstation Pro 17 虚拟机软件安装教程

VMware软件介绍 VMware Workstation是一款功能强大的桌面虚拟计算机软件&#xff0c;提供用户可在宿主机操作系统上同时运行不同的操作系统(虚拟化技术)&#xff0c;所运行的操作系统可方便的进行复制和移动&#xff0c;突破传统架构的限制。本文将以VMware Workstation Pro 1…

tomcat 反向代理 自建博客 修改状态页 等

一 自建博客 随后&#xff0c;拷贝到webapps下面 并且做软连接 随后重定向 并且下载 cat >/etc/yum.repos.d/mysql.repo <<EOF [mysql57-community] nameMySQL 5.7 Community Server baseurlhttp://repo.mysql.com/yum/mysql-5.7-community/el/7/x86_64/ enabled1 g…

excel中如何使用VLOOKUP和EXACT函数实现区分大小写匹配数据

在 Excel 中&#xff0c;VLOOKUP 函数默认情况下是不区分大小写的&#xff1a; 比如下面的案例&#xff0c;直接使用VLOOKUP函数搜索&#xff0c;只会搜索匹配到不区分大小写的第一个 如果我们想要实现区分大小写的精确匹配&#xff0c;可以使用 EXACT 函数结合 VLOOKUP 函数 …

openGauss学习笔记-234 openGauss性能调优-系统调优-资源负载管理-资源管理准备-设置控制组

文章目录 openGauss学习笔记-234 openGauss性能调优-系统调优-资源负载管理-资源管理准备-设置控制组234.1 背景信息234.2 前提条件234.3 操作步骤234.3.1 创建子Class控制组和Workload控制组234.3.2 更新控制组的资源配额234.3.3 删除控制组 234.4 查看控制组的信息 openGauss…

QT Mingw32/64编译ffmpeg源码生成32/64bit库以及测试

文章目录 前言下载msys2ysamFFmpeg 搭建编译环境安装msys2安装QT Mingw编译器到msys环境中安装ysam测试 编译FFmpeg测试 前言 FFmpeg不像VLC有支持QT的库文件&#xff0c;它仅提供源码&#xff0c;需要使用者自行编译成对应的库&#xff0c;当使用QTFFmpeg实现播放视频以及视频…
最新文章