一、本文介绍
本文记录的是基于Shuffle Attention注意力模块的YOLOv9目标检测改进方法研究。Shuffle Attention模块
通过独特的设计原理,在保持轻量级的同时实现了高效的特征注意力机制,增强了网络的表示能力。本文对YOLOv9
的RepNCSPELAN4模块
进行二次创新,以增强模型性能。
专栏目录:YOLOv9改进目录一览 | 涉及卷积层、轻量化、注意力、损失函数、Backbone、SPPF、Neck、检测头等全方位改进
文章目录
二、Shuffle Attention注意力原理
深度卷积神经网络的Shuffle Attention
Shuffle Attention(SA)模块
是一种用于深度卷积神经网络的高效注意力模块,其设计原理和优势如下:
2.1、设计原理
- 特征分组(Feature Grouping):对于给定的特征图
X
∈
R
C
×
H
×
W
X \in R^{C \times H \times W}
X∈RC×H×W(其中
C
C
C、
H
H
H、
W
W
W分别表示通道数、空间高度和宽度),
SA
首先沿着通道维度将 X X X分为 G G G组,即 X = [ X 1 , ⋯ , X G ] X = [X_1, \cdots, X_G] X=[X1,⋯,XG], X k ∈ R C G × H × W X_k \in R^{\frac{C}{G} \times H \times W} Xk∈RGC×H×W。在每个注意力单元开始时, X k X_k Xk的输入沿着通道维度被拆分为两个分支 X k 1 X_{k1} Xk1和 X k 2 X_{k2} Xk2( X k 1 , X k 2 ∈ R C 2 G × H × W X_{k1}, X_{k2} \in R^{\frac{C}{2G} \times H \times W} Xk1,Xk2∈R2GC×H×W)。一个分支用于通过利用通道间的相互关系来生成通道注意力图,另一个分支用于通过利用特征的空间间关系来生成空间注意力图,从而使模型能够关注“什么”和“哪里”是有意义的。 - 通道注意力(Channel Attention):为了充分捕获通道间的依赖关系,
SA
使用全局平均池化(GAP)
来生成通道级别的统计信息 s ∈ R C 2 G × 1 × 1 s \in R^{\frac{C}{2G} \times 1 \times 1} s∈R2GC×1×1,即 s = F g p ( X k 1 ) = 1 H × W ∑ i = 1 H ∑ j = 1 W X k 1 ( i , j ) s = \mathcal{F}_{gp}(X_{k1}) = \frac{1}{H \times W} \sum_{i = 1}^{H} \sum_{j = 1}^{W} X_{k1}(i, j) s=Fgp(Xk1)=H×W1∑i=1H∑j=1WXk1(i,j)。然后,通过一个简单的带有sigmoid激活的门控机制创建一个紧凑的特征,以实现精确和自适应的选择指导。通道注意力的最终输出通过 X k 1 ′ = σ ( F c ( s ) ) ⋅ X k 1 = σ ( W 1 s + b 1 ) ⋅ X k 1 X_{k1}' = \sigma(\mathcal{F}_{c}(s)) \cdot X_{k1} = \sigma(W_1 s + b_1) \cdot X_{k1} Xk1′=σ(Fc(s))⋅Xk1=σ(W1s+b1)⋅Xk1获得,其中 W 1 ∈ R C 2 G × 1 × 1 W_1 \in R^{\frac{C}{2G} \times 1 \times 1} W1∈R2GC×1×1和 b 1 ∈ R C 2 G × 1 × 1 b_1 \in R^{\frac{C}{2G} \times 1 \times 1} b1∈R2GC×1×1是用于缩放和移动 s s s的参数。 - 空间注意力(Spatial Attention):与通道注意力不同,空间注意力关注“哪里”是信息丰富的部分,这与通道注意力是互补的。首先,使用
组归一化(GN)
对 X k 2 X_{k2} Xk2进行处理以获得空间级别的统计信息,然后采用 F c ( ⋅ ) Fc(\cdot) Fc(⋅)来增强 X ^ k 2 \hat{X}_{k2} X^k2的表示。空间注意力的最终输出通过 X k 2 ′ = σ ( W 2 ⋅ G N ( X k 2 ) + b 2 ) ⋅ X k 2 X_{k2}' = \sigma(W_2 \cdot GN(X_{k2}) + b_2) \cdot X_{k2} Xk2′=σ(W2⋅GN(Xk2)+b2)⋅Xk2获得,其中 W 2 W_2 W2和 b 2 b_2 b2是形状为 R C 2 G × 1 × 1 R^{\frac{C}{2G} \times 1 \times 1} R2GC×1×1的参数。 - 聚合(Aggregation):之后,所有子特征被聚合。最后,类似于
ShuffleNet v2
,采用“通道洗牌”(channel shuffle)操作来实现跨组信息在通道维度上的流动。
2.2、优势
- 轻量级且高效:
SA模块
通过将通道维度分组为子特征,并利用Shuffle Unit
为每个子特征集成互补的通道和空间注意力模块,参数和计算量相对较少。例如,在ResNet50中,SA的参数为300,计算量为2.76e - 3 GFLOPs,而ResNet50的参数为25.56M,计算量为4.12 GFLOPs,但SA在Top - 1准确率上的提升超过了1.34%。 - 增强语义表示:通过特征分组和通道洗牌,
SA
能够显著增强特征图的语义表示。实验表明,在使用SA模块后,Top - 1准确率统计上有所提高,并且“通道洗牌”使得每个组的平均得分增加(约0.4%)。 - 验证有效性:通过对不同深度的平均激活分布的观察以及使用GradCAM进行可视化,验证了
SA模块
能够使分类模型更关注相关区域,从而有效提高分类准确率。 - 在各种任务中表现出色:在ImageNet - 1k分类、MS COCO对象检测和实例分割等任务的实验中,
SA
相比于当前的SOTA方法,在实现更高准确率的同时具有更低的模型复杂度,验证了其在各种计算机视觉任务中具有良好的泛化能力。
论文:https://arxiv.org/pdf/2102.00240
源码:https://github.com/wofmanaf/SA-Net
三、Shuffle Attention的实现代码
Shuffle Attention模块
的实现代码如下:
from torch.nn.parameter import Parameter
from torch.nn import init
class ShuffleAttention(nn.Module):
def __init__(self, channel=512, reduction=16, G=8):
super().__init__()
self.G = G
self.channel = channel
self.avg_pool = nn.AdaptiveAvgPool2d(1)
self.gn = nn.GroupNorm(channel // (2 * G), channel // (2 * G))
self.cweight = Parameter(torch.zeros(1, channel // (2 * G), 1, 1))
self.cbias = Parameter(torch.ones(1, channel // (2 * G), 1, 1))
self.sweight = Parameter(torch.zeros(1, channel // (2 * G), 1, 1))
self.sbias = Parameter(torch.ones(1, channel // (2 * G), 1, 1))
self.sigmoid = nn.Sigmoid()
def init_weights(self):
for m in self.modules():
if isinstance(m, nn.Conv2d):
init.kaiming_normal_(m.weight, mode='fan_out')
if m.bias is not None:
init.constant_(m.bias, 0)
elif isinstance(m, nn.BatchNorm2d):
init.constant_(m.weight, 1)
init.constant_(m.bias, 0)
elif isinstance(m, nn.Linear):
init.normal_(m.weight, std=0.001)
if m.bias is not None:
init.constant_(m.bias, 0)
@staticmethod
def channel_shuffle(x, groups):
b, c, h, w = x.shape
x = x.reshape(b, groups, -1, h, w)
x = x.permute(0, 2, 1, 3, 4)
# flatten
x = x.reshape(b, -1, h, w)
return x
def forward(self, x):
b, c, h, w = x.size()
# group into subfeatures
x = x.view(b * self.G, -1, h, w) # bs*G,c//G,h,w
# channel_split
x_0, x_1 = x.chunk(2, dim=1) # bs*G,c//(2*G),h,w
# channel attention
x_channel = self.avg_pool(x_0) # bs*G,c//(2*G),1,1
x_channel = self.cweight * x_channel + self.cbias # bs*G,c//(2*G),1,1
x_channel = x_0 * self.sigmoid(x_channel)
# spatial attention
x_spatial = self.gn(x_1) # bs*G,c//(2*G),h,w
x_spatial = self.sweight * x_spatial + self.sbias # bs*G,c//(2*G),h,w
x_spatial = x_1 * self.sigmoid(x_spatial) # bs*G,c//(2*G),h,w
# concatenate along channel axis
out = torch.cat([x_channel, x_spatial], dim=1) # bs*G,c//G,h,w
out = out.contiguous().view(b, -1, h, w)
# channel shuffle
out = self.channel_shuffle(out, 2)
return out
四、添加步骤
4.1 修改common.py
此处需要修改的文件是models/common.py
common.py中定义了网络结构的通用模块
,我们想要加入新的模块就只需要将模块代码放到这个文件内即可。
4.1.1 基础模块1
模块改进方法1️⃣:直接加入ShuffleAttention模块
。
ShuffleAttention模块
添加后如下:
注意❗:在4.2小节
中的yolo.py
文件中需要声明的模块名称为:ShuffleAttention
。
4.1.2 创新模块2⭐
模块改进方法2️⃣:基于ShuffleAttention模块
的RepNCSPELAN4
。
相较方法一中的直接插入注意力模块,利用注意力模块对卷积等其他模块进行改进,其新颖程度会更高一些,训练精度可能会表现的更高。
第二种改进方法是对YOLOv9
中的RepNCSPELAN4模块
进行改进,将ShuffleAttention注意力模块
替换RepNCSPELAN4
中的卷积模块。Shuffle Attention模块
能够关注特征的空间和通道维度的依赖关系,在与RepNCSPELAN4模块
结合可以更全面地提取和强调重要特征,从而增强特征提取的效果。
改进代码如下:
class SARepNCSPELAN4(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), ShuffleAttention(c4, c4))
self.cv3 = nn.Sequential(RepNCSP(c4, c4, c5), ShuffleAttention(c4, 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
文件中需要声明的模块名称为:SARepNCSPELAN4
。
4.2 修改yolo.py
此处需要修改的文件是models/yolo.py
yolo.py用于函数调用
,我们只需要将common.py
中定义的新的模块名添加到parse_model函数
下即可。
ShuffleAttention模块
以及SARepNCSPELAN4模块
添加后如下:
4.3 修改train_dual.py
在train_dual.py
文件的第314行关闭amp
,将其设置为False
。
with torch.cuda.amp.autocast(False):
pred = model(imgs) # forward
loss, loss_items = compute_loss(pred, targets.to(device)) # loss scaled by batch_size
if RANK != -1:
loss *= WORLD_SIZE # gradient averaged between devices in DDP mode
if opt.quad:
loss *= 4.
若修改完成后仍报错:RuntimeError: CUDA error: CUBLAS_STATUS_ALLOC_FAILED when calling cublasCreate(handle)
则调低 batch_size
。
五、yaml模型文件
5.1 模型改进版本一
在代码配置完成后,配置模型的YAML文件。
此处以models/detect/yolov9-c.yaml
为例,在同目录下创建一个用于自己数据集训练的模型文件yolov9-c-sa.yaml
。
将yolov9-c.yaml
中的内容复制到yolov9-c-sa.yaml
文件下,修改nc
数量等于自己数据中目标的数量。
在骨干网络的最后一层添加ShuffleAttention模块
,即下方代码中的第45行,只需要填入一个参数,通道数,和前一层通道数一致。
📌 Shuffle Attention模块
能够有效地捕捉特征的空间和通道维度的依赖关系,从而使模型更加关注输入中相关的元素。在骨干网络的最后一层添加该模块,可以对高层特征进行重新校准,突出重要特征,抑制不重要的特征,提高特征的表达能力。
# 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
[-1, 1, ShuffleAttention, [512]], # 10 # 注意力添加在此处
]
# 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, 14], 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, 11], 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
[[24, 25, 26, -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
[[25, 26, -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
[[26, -1], 1, CBFuse, [[2]]], # 36
# elan-2 block
[-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 37
# detection head
# detect
[[32, 35, 38, 17, 20, 23], 1, DualDDetect, [nc]], # DualDDetect(A3, A4, A5, P3, P4, P5)
]
5.2 模型改进版本二⭐
此处同样以models/detect/yolov9-c.yaml
为例,在同目录下创建一个用于自己数据集训练的模型文件yolov9-c-SARepNCSPELAN4.yaml
。
将yolov9-c.yaml
中的内容复制到yolov9-c-SARepNCSPELAN4.yaml
文件下,修改nc
数量等于自己数据中目标的数量。
📌 模型的修改方法是将骨干网络中的所有RepNCSPELAN4模块
替换成SARepNCSPELAN4模块
。
# 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, SARepNCSPELAN4, [256, 128, 64, 1]], # 3
# avg-conv down
[-1, 1, ADown, [256]], # 4-P3/8
# elan-2 block
[-1, 1, SARepNCSPELAN4, [512, 256, 128, 1]], # 5
# avg-conv down
[-1, 1, ADown, [512]], # 6-P4/16
# elan-2 block
[-1, 1, SARepNCSPELAN4, [512, 512, 256, 1]], # 7(可替换)
# avg-conv down
[-1, 1, ADown, [512]], # 8-P5/32
# elan-2 block
[-1, 1, SARepNCSPELAN4, [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)
]
六、成功运行结果
分别打印网络模型可以看到ShuffleAttention模块
和SARepNCSPELAN4
已经加入到模型中,并可以进行训练了。
yolov9-c-sa:
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 192 models.common.ShuffleAttention [512, 512]
11 -1 1 656896 models.common.SPPELAN [512, 512, 256]
12 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest']
13 [-1, 7] 1 0 models.common.Concat [1]
14 -1 1 3119616 models.common.RepNCSPELAN4 [1024, 512, 512, 256, 1]
15 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest']
16 [-1, 5] 1 0 models.common.Concat [1]
17 -1 1 912640 models.common.RepNCSPELAN4 [1024, 256, 256, 128, 1]
18 -1 1 164352 models.common.ADown [256, 256]
19 [-1, 14] 1 0 models.common.Concat [1]
20 -1 1 2988544 models.common.RepNCSPELAN4 [768, 512, 512, 256, 1]
21 -1 1 656384 models.common.ADown [512, 512]
22 [-1, 11] 1 0 models.common.Concat [1]
23 -1 1 3119616 models.common.RepNCSPELAN4 [1024, 512, 512, 256, 1]
24 5 1 131328 models.common.CBLinear [512, [256]]
25 7 1 393984 models.common.CBLinear [512, [256, 512]]
26 9 1 656640 models.common.CBLinear [512, [256, 512, 512]]
27 0 1 1856 models.common.Conv [3, 64, 3, 2]
28 -1 1 73984 models.common.Conv [64, 128, 3, 2]
29 -1 1 212864 models.common.RepNCSPELAN4 [128, 256, 128, 64, 1]
30 -1 1 164352 models.common.ADown [256, 256]
31 [24, 25, 26, -1] 1 0 models.common.CBFuse [[0, 0, 0]]
32 -1 1 847616 models.common.RepNCSPELAN4 [256, 512, 256, 128, 1]
33 -1 1 656384 models.common.ADown [512, 512]
34 [25, 26, -1] 1 0 models.common.CBFuse [[1, 1]]
35 -1 1 2857472 models.common.RepNCSPELAN4 [512, 512, 512, 256, 1]
36 -1 1 656384 models.common.ADown [512, 512]
37 [26, -1] 1 0 models.common.CBFuse [[2]]
38 -1 1 2857472 models.common.RepNCSPELAN4 [512, 512, 512, 256, 1]
39[32, 35, 38, 17, 20, 23] 1 21542822 DualDDetect [1, [512, 512, 512, 256, 512, 512]]
yolov9-c-sa summary: 608 layers, 50698470 parameters, 48373702 gradients, 236.6 GFLOPs
yolov9-c-SARepNCSPELAN4:
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 138928 models.common.SARepNCSPELAN4 [128, 256, 128, 64, 1]
4 -1 1 164352 models.common.ADown [256, 256]
5 -1 1 552288 models.common.SARepNCSPELAN4 [256, 512, 256, 128, 1]
6 -1 1 656384 models.common.ADown [512, 512]
7 -1 1 1676992 models.common.SARepNCSPELAN4 [512, 512, 512, 256, 1]
8 -1 1 656384 models.common.ADown [512, 512]
9 -1 1 1676992 models.common.SARepNCSPELAN4 [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 21542822 DualDDetect [1, [512, 512, 512, 256, 512, 512]]
yolov9-c-SARepNCSPELAN4 summary: 620 layers, 47969462 parameters, 45644694 gradients, 224.4 GFLOPs