YOLOv9改进策略【卷积层】| GnConv:一种通过门控卷积和递归设计来实现高效、可扩展、平移等变的高阶空间交互操作

一、本文介绍

本文记录的是利用GnConv优化YOLOv9的目标检测方法研究。YOLOv9在进行目标检测时,需要对不同层次的特征进行融合。GnConv可以考虑更高阶的空间交互,能够更好地捕捉特征之间的复杂关系,从而增强特征融合的效果,提高模型对目标的检测能力。


二、HorNet原理介绍

HorNet: 利用递归门控卷积实现高效高阶空间交互

GnConv(Recursive Gated Convolution,递归门控卷积)是论文中提出的一种高效操作,用于实现长期和高阶空间交互,其设计原理、计算公式和优势如下:

2.1、GnConv设计原理

  • 输入自适应交互与门控卷积Vision Transformer的成功主要依赖于对视觉数据中空间交互的适当建模,与简单使用静态卷积核聚合相邻特征的CNN不同,Vision Transformer应用多头自注意力来动态生成权重以混合空间标记,但自注意力关于输入大小的二次复杂度在很大程度上阻碍了其应用,尤其是在需要更高分辨率特征图的下游任务中。在这项工作中,作者寻求一种更有效和高效的方法来执行空间交互,使用门控卷积(gConv)来实现输入自适应的空间混合。
  • 高阶交互与递归门控:在通过gConv实现了高效的一阶空间交互后,作者设计了递归门控卷积(GnConv)来通过引入高阶交互进一步增强模型容量。具体来说,首先使用多个线性投影层( ϕ i n \phi_{in} ϕin)获得一组投影特征( p 0 p_0 p0 q k q_k qk),然后通过递归的方式执行门控卷积( p k + 1 = f k ( q k ) ⊙ g k ( p k ) / α p_{k + 1} = f_k(q_k) \odot g_k(p_k) / \alpha pk+1=fk(qk)gk(pk)/α),其中 f k f_k fk是一组深度卷积层, g k g_k gk用于匹配不同阶的维度,最后将最后一次递归步骤的输出 q n q_n qn送入投影层 ϕ o u t \phi_{out} ϕout以获得 g n C o n v g^{n}Conv gnConv的结果。从递归公式可以看出, p k p_k pk的交互阶数在每一步后都会增加1,因此 g n C o n v gnConv gnConv实现了 n n n阶空间交互。
  • 大核卷积与长期交互:为了使 G n C o n v GnConv GnConv能够捕捉长期交互,作者采用了两种实现方式来处理深度卷积 f f f
    • 7×7卷积:7×7是Swin TransformersConvNext的默认窗口/核大小,研究表明该核大小在ImageNet分类和各种下游任务中产生良好性能,因此作者遵循此配置以公平地与代表性的Vision Transformer和现代CNN进行比较。
    • 全局滤波器(GF):GF层通过将频域特征与可学习的全局滤波器相乘,相当于在空间域中进行具有全局核大小和循环填充的卷积。作者使用了GF层的修改版本,即处理一半的通道与全局滤波器相乘,另一半与3×3深度卷积相乘,并仅在后期阶段使用GF层以保留更多局部细节。

2.2、GnConv计算公式

门控卷积输出

x ∈ R H W × C x \in \mathbb{R}^{H W \times C} xRHW×C为输入特征,门控卷积 y = g C o n v ( x ) y = gConv(x) y=gConv(x)的输出可写为:
[ p 0 H W × C , q 0 H W × C ] = ϕ i n ( x ) ∈ R H W × 2 C , y = f ( q 0 ) ⊙ p 0 ∈ R H W × C , y = ϕ o u t ( p 1 ) ∈ R H W × C , \begin{array}{r} {\left[p_{0}^{H W \times C}, q_{0}^{H W \times C}\right]=\phi_{in }(x) \in \mathbb{R}^{H W \times 2 C},} \\ y = f\left(q_{0}\right) \odot p_{0} \in \mathbb{R}^{H W \times C}, \\ y = \phi_{out }\left(p_{1}\right) \in \mathbb{R}^{H W \times C}, \end{array} [p0HW×C,q0HW×C]=ϕin(x)RHW×2C,y=f(q0)p0RHW×C,y=ϕout(p1)RHW×C,

其中 ϕ i n \phi_{in} ϕin ϕ o u t \phi_{out} ϕout是线性投影层以执行通道混合, f f f是深度卷积。注意到 p 1 ( i , c ) = ∑ j ∈ Ω i w i → j c q 0 ( j , c ) p 0 ( i , c ) p_{1}^{(i, c)}=\sum_{j \in \Omega_{i}} w_{i \to j}^{c} q_{0}^{(j, c)} p_{0}^{(i, c)} p1(i,c)=jΩiwijcq0(j,c)p0(i,c),其中 Ω i \Omega_{i} Ωi是以为 i i i中心的局部窗口, w i → j w_{i \to j} wij代表卷积权重。

  • 递归门控卷积
    [ p 0 H W × C 0 , q 0 H W × C 0 , … , q n − 1 H W × C n − 1 ] = ϕ i n ( x ) ∈ R H W × ( C 0 + ∑ 0 ≤ k ≤ n − 1 C k ) , p k + 1 = f k ( q k ) ⊙ g k ( p k ) / α , k = 0 , 1 , … , n − 1 , \begin{aligned} &\left[p_{0}^{H W \times C_{0}}, q_{0}^{H W \times C_{0}}, \ldots, q_{n - 1}^{H W \times C_{n - 1}}\right]=\phi_{in }(x) \in \mathbb{R}^{H W \times\left(C_{0} + \sum_{0 \leq k \leq n - 1} C_{k}\right)}, \\ &p_{k + 1} = f_{k}\left(q_{k}\right) \odot g_{k}\left(p_{k}\right) / \alpha, k = 0, 1, \ldots, n - 1, \end{aligned} [p0HW×C0,q0HW×C0,,qn1HW×Cn1]=ϕin(x)RHW×(C0+0kn1Ck),pk+1=fk(qk)gk(pk)/α,k=0,1,,n1,
    其中 g k g_{k} gk的定义为: g k = { I d e n t i t y , k = 0 L i n e a r ( C k − 1 , C k ) , 1 ≤ k ≤ n − 1 g_{k}=\begin{cases}Identity, & k = 0 \\Linear\left(C_{k - 1}, C_{k}\right), & 1 \leq k \leq n - 1\end{cases} gk={Identity,Linear(Ck1,Ck),k=01kn1
  • 计算复杂度:总FLOPs为: F L O P s ( g n C o n v ) < H W C ( 2 K 2 + 11 3 × C + 2 ) FLOPs\left(g^{n}Conv\right) < HW C\left(2K^{2} + \frac{11}{3} \times C + 2\right) FLOPs(gnConv)<HWC(2K2+311×C+2),其中 K K K是深度卷积的核大小。

在这里插入图片描述

2.3、优势

  • 高效:基于卷积的实现避免了自注意力的二次复杂度。在执行空间交互时逐渐增加通道宽度的设计也使能够以有限的复杂度实现更高阶的交互。
  • 可扩展:将自注意力中的二阶交互扩展到任意阶,以进一步提高建模能力。由于不对空间卷积的类型做假设,因此(gnConv)与各种核大小和空间混合策略兼容。
  • 平移等变性:完全继承了标准卷积的平移等变性,这为主要视觉任务引入了有益的归纳偏差,并避免了局部注意力带来的不对称性。

论文:https://arxiv.org/pdf/2207.14284
源码:https://github.com/raoyongming/HorNet

三、GnConv的实现代码

GnConv模块的实现代码如下:


def get_dwconv(dim, kernel, bias):
    return nn.Conv2d(dim, dim, kernel_size=kernel, padding=(kernel-1)//2 ,bias=bias, groups=dim)

class gnConv(nn.Module):
    def __init__(self, dim, order=5, gflayer=None, h=14, w=8, s=1.0):
        super().__init__()
        self.order = order
        self.dims = [dim // 2 ** i for i in range(order)]
        self.dims.reverse()
        self.proj_in = nn.Conv2d(dim, 2*dim, 1)
 
        if gflayer is None:
            self.dwconv = get_dwconv(sum(self.dims), 7, True)
        else:
            self.dwconv = gflayer(sum(self.dims), h=h, w=w)
        
        self.proj_out = nn.Conv2d(dim, dim, 1)
 
        self.pws = nn.ModuleList(
            [nn.Conv2d(self.dims[i], self.dims[i+1], 1) for i in range(order-1)]
        )
        self.scale = s
 
    def forward(self, x, mask=None, dummy=False):
        # B, C, H, W = x.shape gnconv [512]by iscyy/air
        fused_x = self.proj_in(x)
        pwa, abc = torch.split(fused_x, (self.dims[0], sum(self.dims)), dim=1)
        dw_abc = self.dwconv(abc) * self.scale
        dw_list = torch.split(dw_abc, self.dims, dim=1)
        x = pwa * dw_list[0]
        for i in range(self.order -1):
            x = self.pws[i](x) * dw_list[i+1]
        x = self.proj_out(x)
 
        return x

四、添加步骤

4.1 修改common.py

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

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

4.1.1 创新模块⭐

模块改进方法:1️⃣先加入gnConv模块
将上方的实现代码粘贴到common.py文件夹下,gnConv模块添加后如下:

在这里插入图片描述

2️⃣基于gnConvRepNCSPELAN4

第二种改进方法是对YOLOv9中的RepNCSPELAN4模块进行改进。将gnConv模块RepNCSPELAN4 结合后,替换其中的普通卷积可以使YOLOv9实现更高阶的空间交互,更好地捕捉特征之间的复杂关系,从而提高模型的建模能力。

改进代码如下:

class GnRepNCSPELAN4(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), gnConv(c4))
        self.cv3 = nn.Sequential(RepNCSP(c4, c4, c5), gnConv(c4))
        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))

在这里插入图片描述

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

4.2 修改yolo.py

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

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

gnConv模块以及GnRepNCSPELAN4模块添加后如下:

在这里插入图片描述


五、yaml模型文件

5.1 模型改进⭐

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

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

yolov9-c.yaml中的内容复制到yolov9-c-GnRepNCSPELAN4.yaml文件下,修改nc数量等于自己数据中目标的数量。
在骨干网络中,将四个RepNCSPELAN4模块替换成GnRepNCSPELAN4模块

# YOLOv9

# parameters
nc: 80  # 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, GnRepNCSPELAN4, [256, 128, 64, 1]],  # 3

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

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

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

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

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

   # elan-2 block
   [-1, 1, GnRepNCSPELAN4, [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)
  ]



六、成功运行结果

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

yolov9-c-GnRepNCSPELAN4

                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   2209152  models.common.GnRepNCSPELAN4            [512, 512, 512, 256, 1]       
10                -1  1    656896  models.common.SPPELAN                   [512, 512, 256]               
11                -1  1         0  torch.nn.modules.upsampling.Upsample    [None, 2, 'nearest']          
12           [-1, 7]  1         0  models.common.Concat                    [1]                           
13                -1  1   3119616  models.common.RepNCSPELAN4              [1024, 512, 512, 256, 1]      
14                -1  1         0  torch.nn.modules.upsampling.Upsample    [None, 2, 'nearest']          
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  21725312  DualDDetect                             [80, [512, 512, 512, 256, 512, 512]]
yolov9-c-GnRepNCSPELAN4 summary: 974 layers, 50533760 parameters, 50533728 gradients, 239.4 GFLOPs
YOLOv7引入了递归门控卷积gnConv)来改善目标检测效果。主干特征提取网络为CNN网络,而CNN具有平移性和局部性,但缺乏全局建模长距离建模的能力。为了解决这个问题,YOLOv7引入了自然语言处理领域的框架Transformer,并将其与CNN网络相结合形成了CNN Transformer架构。 通过引入递归门控卷积gnConv),YOLOv7实现高阶空间交互gnConv一种门控卷积递归设计,它具有高度的灵活性和可定制性,并能够将自注意力中的二阶交互扩展到任意阶,而不会引入大量额外的计算。这使得gnConv可以作为一个即插即用的模块来改进各种视觉Transformer和基于卷积的模型。 通过引入递归门控卷积YOLOv7能够充分利用CNN和Transformer两者的优点,提高目标检测的效果。特别是对于小目标以及密集预测任务,经过实验表明,YOLOv7引入递归门控卷积能够产生一定的提升效果。同时,这种改进方法不仅适用于YOLOv7,也可以应用于其他的YOLO网络以及目标检测网络,如YOLOv6、v4、v3、Faster RCNN、SSD等。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [YOLOv7改进之二十二:涨点神器——引入递归门控卷积gnConv)](https://blog.csdn.net/m0_70388905/article/details/126142505)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Limiiiing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值