YOLOv9改进策略【Neck】| 有效且轻量的动态上采样算子:DySample

news2024/11/25 10:02:30

一、本文介绍

本文记录的是利用DySample上采样对YOLOv9的颈部网络进行改进的方法研究YOLOv9采用传统的最近邻插值的方法进行上采样可能无法有效地捕捉特征的细节和语义信息,从而影响模型在密集预测任务中的性能。DySample通过动态采样的方式进行上采样,能够更好地处理特征的细节和语义信息。

文章目录

  • 一、本文介绍
  • 二、DySample介绍
    • 2.1、DySample原理
    • 2.2、优势
  • 三、DySample的实现代码
  • 四、添加步骤
    • 4.1 修改common.py
    • 4.2 修改yolo.py
  • 五、yaml模型文件
    • 5.1 模型改进
  • 六、成功运行结果


二、DySample介绍

通过学习采样来学习上采样

DySample是一种超轻量且有效的动态上采样器,其设计出发点、原理和优势如下:

2.1、DySample原理

  • 初步设计:通过PyTorch的内置函数,假设输入特征通过双线性插值被插值为连续的特征图,然后通过生成内容感知的采样点来重新采样该连续图。具体实现为,给定特征图 X X X和上采样尺度因子 s s s,使用线性层生成偏移 O O O,并通过Pixel Shuffling将其重塑为 2 × s H × s W 2 \times sH \times sW 2×sH×sW,然后将偏移 O O O与原始采样网格 G G G相加得到采样集 S S S,最后通过网格采样函数根据采样集生成上采样后的特征图 X ′ X' X
  • 改进步骤
    • 初始采样位置:在初步版本中,初始采样位置固定且分布不均匀,类似于“最近邻初始化”。为解决此问题,改为“双线性初始化”,即改变初始位置,使零偏移时能得到双线性插值的特征图,从而提高性能。
    • 偏移范围:由于归一化层的存在,输出特征值的范围通常在 [ − 1 , 1 ] [ - 1, 1] [1,1],导致局部采样位置的偏移范围可能重叠,影响边界预测并导致输出伪影。通过将偏移乘以0.25的“静态范围因子”,局部约束了采样位置的偏移范围,缓解了该问题。
    • 分组:组向上采样,将特征图沿通道维度划分为 g g g组,并为每组生成偏移。当 g = 4 g = 4 g=4时,性能得到提升。
    • 动态范围因子:为增加偏移的灵活性,通过线性投影输入特征生成点级的“动态范围因子”,动态范围因子的值在 [ 0 , 0.5 ] [0, 0.5] [0,0.5]范围内,以0.25为中心,进一步提升了性能。
    • 偏移生成方式:研究了两种偏移生成方式,“线性 + 像素洗牌”(LP)和“像素洗牌 + 线性”(PL)。通过实验,根据不同模型设置了不同的组数量,并且发现PL版本在某些模型上表现更好,但在其他模型上略逊于LP版本。
  • 最终变体:根据范围因子(静态/动态)和偏移生成方式(LP/PL),研究了四个变体:DySample(LP风格,静态范围因子)、DySample +(LP风格,动态范围因子)、DySample - S(PL风格,静态范围因子)、DySample - S +(PL风格,动态范围因子)。

在这里插入图片描述

2.2、优势

  • 轻量高效:与其他动态上采样器相比,DySample不需要高分辨率的引导特征作为输入,也不需要除PyTorch之外的任何额外CUDA包,具有更少的推理延迟、内存占用、FLOPs和参数数量。
  • 性能优越:在五个密集预测任务(语义分割、目标检测、实例分割、全景分割和单目深度估计)中,与其他上采样器相比,DySample报告了更好的性能。

论文:https://arxiv.org/pdf/2308.15085
源码:https://github.com/tiny-smart/dysample

三、DySample的实现代码

DySample模块的实现代码如下:

import torch
import torch.nn as nn
import torch.nn.functional as F


def normal_init(module, mean=0, std=1, bias=0):
    if hasattr(module, 'weight') and module.weight is not None:
        nn.init.normal_(module.weight, mean, std)
    if hasattr(module, 'bias') and module.bias is not None:
        nn.init.constant_(module.bias, bias)


def constant_init(module, val, bias=0):
    if hasattr(module, 'weight') and module.weight is not None:
        nn.init.constant_(module.weight, val)
    if hasattr(module, 'bias') and module.bias is not None:
        nn.init.constant_(module.bias, bias)


class DySample(nn.Module):
    def __init__(self, in_channels, scale=2, style='lp', groups=4, dyscope=False):
        super().__init__()
        self.scale = scale
        self.style = style
        self.groups = groups
        assert style in ['lp', 'pl']
        if style == 'pl':
            assert in_channels >= scale ** 2 and in_channels % scale ** 2 == 0
        assert in_channels >= groups and in_channels % groups == 0

        if style == 'pl':
            in_channels = in_channels // scale ** 2
            out_channels = 2 * groups
        else:
            out_channels = 2 * groups * scale ** 2

        self.offset = nn.Conv2d(in_channels, out_channels, 1)
        normal_init(self.offset, std=0.001)
        if dyscope:
            self.scope = nn.Conv2d(in_channels, out_channels, 1)
            constant_init(self.scope, val=0.)

        self.register_buffer('init_pos', self._init_pos())

    def _init_pos(self):
        h = torch.arange((-self.scale + 1) / 2, (self.scale - 1) / 2 + 1) / self.scale
        return torch.stack(torch.meshgrid([h, h])).transpose(1, 2).repeat(1, self.groups, 1).reshape(1, -1, 1, 1)

    def sample(self, x, offset):
        B, _, H, W = offset.shape
        offset = offset.view(B, 2, -1, H, W)
        coords_h = torch.arange(H) + 0.5
        coords_w = torch.arange(W) + 0.5
        coords = torch.stack(torch.meshgrid([coords_w, coords_h])
                             ).transpose(1, 2).unsqueeze(1).unsqueeze(0).type(x.dtype).to(x.device)
        normalizer = torch.tensor([W, H], dtype=x.dtype, device=x.device).view(1, 2, 1, 1, 1)
        coords = 2 * (coords + offset) / normalizer - 1
        coords = F.pixel_shuffle(coords.view(B, -1, H, W), self.scale).view(
            B, 2, -1, self.scale * H, self.scale * W).permute(0, 2, 3, 4, 1).contiguous().flatten(0, 1)
        return F.grid_sample(x.reshape(B * self.groups, -1, H, W), coords, mode='bilinear',
                             align_corners=False, padding_mode="border").view(B, -1, self.scale * H, self.scale * W)

    def forward_lp(self, x):
        if hasattr(self, 'scope'):
            offset = self.offset(x) * self.scope(x).sigmoid() * 0.5 + self.init_pos
        else:
            offset = self.offset(x) * 0.25 + self.init_pos
        return self.sample(x, offset)

    def forward_pl(self, x):
        x_ = F.pixel_shuffle(x, self.scale)
        if hasattr(self, 'scope'):
            offset = F.pixel_unshuffle(self.offset(x_) * self.scope(x_).sigmoid(), self.scale) * 0.5 + self.init_pos
        else:
            offset = F.pixel_unshuffle(self.offset(x_), self.scale) * 0.25 + self.init_pos
        return self.sample(x, offset)

    def forward(self, x):
        if self.style == 'pl':
            return self.forward_pl(x)
        return self.forward_lp(x)



四、添加步骤

4.1 修改common.py

此处需要修改的文件是models/common.py

common.py中定义了网络结构的通用模块,我们想要加入新的模块就只需要将模块代码放到这个文件内即可。

DySample模块添加后如下:

在这里插入图片描述

注意❗:在4.2小节中的yolo.py文件中需要声明的模块名称为:DySample

4.2 修改yolo.py

此处需要修改的文件是models/yolo.py

yolo.py用于函数调用,我们只需要将common.py中定义的新的模块名添加到parse_model函数下即可。

def parse_model(d, ch)中将DySample模块添加后如下:

在这里插入图片描述

elif m in [DySample]:
    args = [ch[f], *args[0:]]

五、yaml模型文件

5.1 模型改进

在代码配置完成后,配置模型的YAML文件。

此处以models/detect/yolov9-c.yaml为例,在同目录下创建一个用于自己数据集训练的模型文件yolov9-c-dysamlpe.yaml

yolov9-c.yaml中的内容复制到yolov9-c-dysamlpe.yaml文件下,修改nc数量等于自己数据中目标的数量。

📌 修改方法是将DySample模块替换YOLOv9颈部网络中的上采样模块nn.Upsample

# YOLOv9

# parameters
nc: 1  # number of classes
depth_multiple: 1.0  # model depth multiple
width_multiple: 1.0  # 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, [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, DySample, []],
   [[-1, 7], 1, Concat, [1]],  # cat backbone P4

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

   # up-concat merge
   [-1, 1, DySample, []],
   [[-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)
  ]


六、成功运行结果

分别打印网络模型可以看到DySample模块已经加入到模型中,并可以进行训练了。

yolov9-c-dysample

                 from  n    params  module                                  arguments                     
  0                -1  1         0  models.common.Silence                   []                            
  1                -1  1      1856  models.common.Conv                      [3, 64, 3, 2]                 
  2                -1  1     73984  models.common.Conv                      [64, 128, 3, 2]               
  3                -1  1    212864  models.common.RepNCSPELAN4              [128, 256, 128, 64, 1]        
  4                -1  1    164352  models.common.ADown                     [256, 256]                    
  5                -1  1    847616  models.common.RepNCSPELAN4              [256, 512, 256, 128, 1]       
  6                -1  1    656384  models.common.ADown                     [512, 512]                    
  7                -1  1   2857472  models.common.RepNCSPELAN4              [512, 512, 512, 256, 1]       
  8                -1  1    656384  models.common.ADown                     [512, 512]                    
  9                -1  1   2857472  models.common.RepNCSPELAN4              [512, 512, 512, 256, 1]       
 10                -1  1    656896  models.common.SPPELAN                   [512, 512, 256]               
 11                -1  1     16416  models.common.DySample                  [512]                         
 12           [-1, 7]  1         0  models.common.Concat                    [1]                           
 13                -1  1   3119616  models.common.RepNCSPELAN4              [1024, 512, 512, 256, 1]      
 14                -1  1     16416  models.common.DySample                  [512]                         
 15           [-1, 5]  1         0  models.common.Concat                    [1]                           
 16                -1  1    912640  models.common.RepNCSPELAN4              [1024, 256, 256, 128, 1]      
 17                -1  1    164352  models.common.ADown                     [256, 256]                    
 18          [-1, 13]  1         0  models.common.Concat                    [1]                           
 19                -1  1   2988544  models.common.RepNCSPELAN4              [768, 512, 512, 256, 1]       
 20                -1  1    656384  models.common.ADown                     [512, 512]                    
 21          [-1, 10]  1         0  models.common.Concat                    [1]                           
 22                -1  1   3119616  models.common.RepNCSPELAN4              [1024, 512, 512, 256, 1]      
 23                 5  1    131328  models.common.CBLinear                  [512, [256]]                  
 24                 7  1    393984  models.common.CBLinear                  [512, [256, 512]]             
 25                 9  1    656640  models.common.CBLinear                  [512, [256, 512, 512]]        
 26                 0  1      1856  models.common.Conv                      [3, 64, 3, 2]                 
 27                -1  1     73984  models.common.Conv                      [64, 128, 3, 2]               
 28                -1  1    212864  models.common.RepNCSPELAN4              [128, 256, 128, 64, 1]        
 29                -1  1    164352  models.common.ADown                     [256, 256]                    
 30  [23, 24, 25, -1]  1         0  models.common.CBFuse                    [[0, 0, 0]]                   
 31                -1  1    847616  models.common.RepNCSPELAN4              [256, 512, 256, 128, 1]       
 32                -1  1    656384  models.common.ADown                     [512, 512]                    
 33      [24, 25, -1]  1         0  models.common.CBFuse                    [[1, 1]]                      
 34                -1  1   2857472  models.common.RepNCSPELAN4              [512, 512, 512, 256, 1]       
 35                -1  1    656384  models.common.ADown                     [512, 512]                    
 36          [25, -1]  1         0  models.common.CBFuse                    [[2]]                         
 37                -1  1   2857472  models.common.RepNCSPELAN4              [512, 512, 512, 256, 1]       
 38[31, 34, 37, 16, 19, 22]  1  21542822  DualDDetect                             [1, [512, 512, 512, 256, 512, 512]]
yolov9-c-dysample summary: 964 layers, 51032422 parameters, 51032390 gradients, 238.9 GFLOPs

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

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

相关文章

Brave编译指南2024 Windows篇:安装depot_tools(三)

1.引言 在编译Brave浏览器的过程中,depot_tools是不可或缺的一部分。这是一组由Chromium项目提供的脚本和工具,用于获取、管理和更新Chromium及其衍生项目的源码。通过depot_tools,开发者可以方便地同步最新的源码版本,并进行项目…

NVD系列语音芯片在报警器中通常应用在哪些场景中

语音芯片在各类场景中应用的最大作用就是进行语音提示和警报提示。本文将对NVD系列语音芯片应用在报警器中的场景。 1.提升电动车的安全性 当电动车遭受震动或异常移动时,报警器会感应到并触发报警装置,通常是通过发出高分贝的声音警报来吸引人们的注意…

基于HTML+JS+CSS+Echarts实现的设备环境监测可视化平台前端整套模板

效果图 基于HTMLJSCSSEcharts实现的设备环境监测可视化平台前端整套模板。可用过修改源码快速完成需求。 源码结构 下载地址

Shell实用功能及文件权限

1、使用命令“cat /etc/named.conf”设置为别名named,然后再取消别名。 设置别名:alias namedcat /etc/named.conf 取消别名:unalias named 2、使用echo命令和输出重定向创建文本文件/root/nn,内容是hello,然后再使用…

C++笔记---list

1. list的介绍 list其实就是就是我们所熟知的链表(双向循环带头结点),但其是作为STL中的一个类模板而存在。 也就是说,list是可以用来存储任意类型数据的顺序表,既可以是内置类型,也可以是自定义类型&…

【目标检测数据集】工具钳子、剪刀、螺丝刀检测数据集3668张3类VOC+YOLO格式

数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):3668 标注数量(xml文件个数):3668 标注数量(txt文件个数):3668 标注…

安卓13系统导航方式分析以及安卓13修改默认方式为手势导航 android13修改导航方式

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析4.代码修改5.彩蛋1.前言 系统导航方式默认一般是按键的,如果要改成手势的话,我们来看看用户怎么修改的: 设置=>系统=>手势=>系统导航,在这里进行修改。我们来分析下这个流程,并且将其修改为…

Stage模型UIAbility组件【单任务列表/多任务列表】

什么是多线程 比如你在微信中聊天 突然打开一个小程序 然后查看手机进程 如果一个软件有多个那就是多进程 (目前小编看下来 只有安卓有 苹果看不出来) 进程之间是可以相互跳转的 UIAbility组件可以是单个任务列表或多个任务列表 启动页想用哪个就设置哪个…

《python语言程序设计》2018版第8章第14题金融:信用卡号合法性 利用6.29题

一、之前6.29题我做的代码 这是用数字来进行分辨的 is_txt 4383576018402626 #合法def split_the_data_even(vis_n):current_a1 vis_n // 10000a_t1 vis_n % 10000# print("1th", a_t1)a_t2 current_a1 % 10000# print("2th", a_t2)current_a3 curre…

【自用23.】C++-const数据成员及const成员函数

const数据成员 const数据成员的初始化方式: 使用类内值(C11支持)使用构造函数的初始化列表 (如果同时使用这两种方式,以初始化列表中的值为最终初始化结果) 注意: 不能在构造函数或其他成员…

全新的训练算法:Reflection 70B进入大众的视野

在2024年9月6日,大模型的圈子迎来了一位新成员——Reflection 70B,它横扫了MMLU、MATH、IFEval、GSM8K等知名的模型基准测试,完美超越了GPT-4o,同时也超越了Claude3.5 Sonnet成为了新的大模型之王,Reflection 70B到底是…

Linux: network: esp:收到了重复的包

最近遇到一个问题,是说收到了dup的ESP包。 这个目前还是未解的谜题,不知道到底是谁发的重复包。 但是从wireshark里确实可以看到在相同SPI下,收到了两个序号相同的ESP包。 这个时候,就会触发防火墙的防御机制。下面是一个大模型给出的一个解答(主要介绍的是anti-replay的…

10款企业图纸加密软件大盘点|2024企业图纸加密软件推荐

在数字化时代,企业图纸数据的安全性显得尤为重要。图纸数据往往包含企业的核心技术、设计方案和知识产权,一旦泄露,将对企业造成不可估量的损失。因此,选择一款合适的图纸加密软件,成为企业保护核心资产的重要手段。以…

ComsolMatlab 互阻抗法计算多孔材料吸声(背腔无反射)

互阻抗法是一种用于计算多孔材料吸声性能的方法。它基于材料的声学参数来预测其吸声特性。互阻抗法的基本原理是考虑多孔材料中孔隙和固体相之间的相互作用,通过定义互阻抗来描述声波在材料中传播时的复杂情况。 在互阻抗法中,孔隙和固体相的声波反射和透…

第十五节:学习Springboot 的响应结果封装(自学Spring boot 3.x的第四天)

这节记录下如何使用枚举类和响应封装类实现响应结果封装。 第一步:新建立一个枚举类。枚举类的要求有两个变量,响应码code,响应信息desc。响应码需要跟前端约定好。 public enum ResponseCode {SUCCESS("success",101),ERROR(&qu…

2024年好用的10款图纸加密软件排行榜|图纸加密的最佳选择

随着企业对知识产权和数据安全需求的日益增加,图纸加密软件已经成为各行业保护敏感设计文档的关键工具。2024年,市场上涌现了多款优质的图纸加密软件,帮助企业有效防范数据泄露、维护信息安全。本文将为您介绍2024年好用的10款图纸加密软件&a…

入驻国际数字影像产业园有哪些优势?

在数字文创产业蓬勃发展的今天,选择入驻国际数字影像产业园,意味着您已踏上了一条通往行业前沿的快车道。这里,不仅是数字影像产业的聚集地,更是创新与梦想的孵化器。那么,入驻国际数字影像产业园究竟有哪些优势呢&…

vmware虚拟机 windows下查看进程id(pid)

在日常运维过程中, 发现宿主机cpu占用高, 经常要看是那一个虚拟机占用内存或cpu高. 但是在windows资源管理器中,所有的虚拟机都显示的是vmware-vmx.exe. 目前手动情况下就需要一个挨着一个去看. 有没有直接查看虚拟机进程id虚拟机运行目录的方法?? 实现步骤 1. 通过 vm…

【Python进阶】一篇文章教你如何使用PyCharm的调试功能?

要使用 PyCharm 的调试功能,可以按照以下步骤进行操作: 1、打开 PyCharm 启动 PyCharm,并打开你的 Python 项目。 2、设置断点 在你想要调试的代码行上,点击行号左侧的空白处,或者使用快捷键 Ctrl F8。这将在该行…

【C++ 高频面试题】指针和引用、关于内存泄漏和野指针问题

文章目录 1. 静态变量、全局变量、局部变量2. 指针和引用的区别3. 内存泄漏4. 野指针 1. 静态变量、全局变量、局部变量 ①局部变量: 作用范围:局部变量只在定义它的函数或代码块内有效,函数执行结束后,局部变量即失效。 生命周…