秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转
💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡
专栏目录: 《YOLOv5入门 + 改进涨点》专栏介绍 & 专栏目录 |目前已有80+篇内容,内含各种Head检测头、损失函数Loss、Backbone、Neck、NMS等创新点改进
本文介绍了多边形核初始网络(PKINet)应对遥感图像目标检测的挑战,通过无扩张的多尺度卷积核提取目标特征,并结合上下文锚点注意力(CAA)模块捕获长距离上下文,有效提升了在多个遥感检测基准数据集上的性能。文章在介绍主要的原理后,将手把手教学如何进行模块的代码添加和修改,并将修改后的完整代码放在文章的最后,方便大家一键运行,小白也可轻松上手实践。以帮助您更好地学习深度学习目标检测YOLO系列的挑战。
目录
1. 原理
论文地址:Poly Kernel Inception Network for Remote Sensing Detection——点击即可跳转
官方代码:官方代码仓库——点击即可跳转
PKINet,即多核初始网络,专为遥感物体检测而设计,可解决物体尺度变化大和背景多样化等挑战。PKINet 背后的关键思想是:
1. 多尺度卷积:PKINet 使用初始式深度卷积和不同大小的内核来捕获不同尺度上的物体特征,而无需依赖扩张。这种方法可确保密集的特征提取,同时最大限度地减少由大核卷积引起的问题,例如背景噪声。
2. 上下文锚点注意 (CAA):为了满足对远程上下文信息的需求,PKINet 采用了利用全局平均池化和 1D 条带卷积的 CAA 模块。这有助于捕获远距离像素之间的关系并增强中心区域特征,从而提高对较大物体和上下文信息的理解。
3. 跨阶段部分 (CSP) 结构:网络分为多个阶段,其中输入分为两条路径:一条通过前馈网络 (FFN) 处理,另一条通过 PKI 块处理,后者包括多尺度卷积和 CAA 模块。此结构可在局部和全局上下文中实现高效的特征提取。
总体而言,PKINet 通过比以前的方法更有效地解决尺度变化和上下文挑战,在遥感基准上取得了更好的性能。
2. 将C3_PKIModule添加到yolov5网络中
2.1 C3_PKIModule代码实现
关键步骤一: 将下面的代码粘贴到\yolov5\models\common.py中
class GSiLU(nn.Module):
"""Global Sigmoid-Gated Linear Unit, reproduced from paper <SIMPLE CNN FOR VISION>"""
def __init__(self):
super().__init__()
self.adpool = nn.AdaptiveAvgPool2d(1)
def forward(self, x):
return x * torch.sigmoid(self.adpool(x))
class PKIModule_CAA(nn.Module):
def __init__(self, ch, h_kernel_size = 11, v_kernel_size = 11) -> None:
super().__init__()
self.avg_pool = nn.AvgPool2d(7, 1, 3)
self.conv1 = Conv(ch, ch)
self.h_conv = nn.Conv2d(ch, ch, (1, h_kernel_size), 1, (0, h_kernel_size // 2), 1, ch)
self.v_conv = nn.Conv2d(ch, ch, (v_kernel_size, 1), 1, (v_kernel_size // 2, 0), 1, ch)
self.conv2 = Conv(ch, ch)
self.act = nn.Sigmoid()
def forward(self, x):
attn_factor = self.act(self.conv2(self.v_conv(self.h_conv(self.conv1(self.avg_pool(x))))))
return attn_factor
class PKIModule(nn.Module):
def __init__(self, inc, ouc, kernel_sizes=(3, 5, 7, 9, 11), expansion=1.0, with_caa=True, caa_kernel_size=11, add_identity=True) -> None:
super().__init__()
hidc = make_divisible(int(ouc * expansion), 8)
self.pre_conv = Conv(inc, hidc)
self.dw_conv = nn.ModuleList(nn.Conv2d(hidc, hidc, kernel_size=k, padding=autopad(k), groups=hidc) for k in kernel_sizes)
self.pw_conv = Conv(hidc, hidc)
self.post_conv = Conv(hidc, ouc)
if with_caa:
self.caa_factor = PKIModule_CAA(hidc, caa_kernel_size, caa_kernel_size)
else:
self.caa_factor = None
self.add_identity = add_identity and inc == ouc
def forward(self, x):
x = self.pre_conv(x)
y = x
x = self.dw_conv[0](x)
x = torch.sum(torch.stack([x] + [layer(x) for layer in self.dw_conv[1:]], dim=0), dim=0)
x = self.pw_conv(x)
if self.caa_factor is not None:
y = self.caa_factor(y)
if self.add_identity:
y = x * y
x = x + y
else:
x = x * y
x = self.post_conv(x)
return x
class C3_PKIModule(C3):
def __init__(self, c1, c2, n=1, kernel_sizes=(3, 5, 7, 9, 11), expansion=1.0, with_caa=True, caa_kernel_size=11, add_identity=True, g=1, e=0.5):
super().__init__(c1, c2, n, True, g, e)
c_ = int(c2 * e) # hidden channels
self.m = nn.Sequential(*(PKIModule(c_, c_, kernel_sizes, expansion, with_caa, caa_kernel_size, add_identity) for _ in range(n)))
2.2 C3_PKIModule的神经网络模块代码解析
C3_PKIModule
是一个自定义神经网络模块,它基于 C3
模块的结构,常用于 YOLO 模型。C3
模块通常由一系列卷积层组成,旨在处理输入数据并在各个级别提取特征。C3_PKIModule
通过在其架构中整合更复杂的块 PKIModule
来扩展。
C3_PKIModule
及其相关类的组件:
1. GSiLU 类
-
用途:实现称为全局 S 型门控线性单元 (GSiLU) 的自定义激活函数。此类使用平均池化操作,然后使用 S 型函数,将全局 S 型门应用于输入张量。
-
关键组件:
-
self.adpool = nn.AdaptiveAvgPool2d(1)
:此操作将输入张量的空间维度减小到 1x1,从而有效地计算全局平均值。 -
return x * torch.sigmoid(self.adpool(x))
:将输入张量与其自身的 S 形缩放版本相乘,为数据添加门控效果。
2. PKIModule_CAA 类
-
目的:实现上下文感知注意 (CAA) 机制,通过捕获水平和垂直依赖关系将注意力应用于输入张量。
-
关键组件:
-
self.avg_pool = nn.AvgPool2d(7, 1, 3)
:应用内核大小为 7x7 且步幅为 1 的平均池化,提供输入的平滑版本。 -
self.h_conv
和self.v_conv
:两个卷积层,分别捕获水平和垂直依赖关系。 -
self.act = nn.Sigmoid()
:使用 S 形激活函数生成注意因子,然后将其应用于输入张量。
3. PKIModule 类
-
用途:实现更复杂的块,将深度卷积与注意机制和逐点卷积相结合。
-
关键组件:
-
self.pre_conv
和self.post_conv
:这些是处理输入和输出数据的初始和最终卷积层。 -
self.dw_conv
:具有不同内核大小的深度卷积层列表。深度卷积之所以有效,是因为它们对每个输入通道应用单个卷积。 -
self.pw_conv
:减少或增加通道数量的逐点卷积。 -
self.caa_factor
:根据with_caa
标志,可选择将 CAA 机制 (PKIModule_CAA
) 应用于输入。 -
self.add_identity
:如果输入和输出通道匹配,则将输入张量添加到输出张量,提供残差连接。
4. C3_PKIModule 类
-
用途:通过将
C3
模块的内部块替换为PKIModule
实例来扩展该模块,从而通过复杂的注意和卷积操作增强特征提取过程。 -
关键组件:
-
self.m
:一个顺序容器,可堆叠PKIModule
的多个实例。这些实例的数量由参数n
决定。
2.3 新增yaml文件
关键步骤二:在下/yolov5/models下新建文件 yolov5_C3_PKIModule.yaml并将下面代码复制进去
- 目标检测yaml文件
# Ultralytics YOLOv5 🚀, AGPL-3.0 license
# Parameters
nc: 80 # number of classes
depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple
anchors:
- [10, 13, 16, 30, 33, 23] # P3/8
- [30, 61, 62, 45, 59, 119] # P4/16
- [116, 90, 156, 198, 373, 326] # P5/32
# YOLOv5 v6.0 backbone
backbone:
# [from, number, module, args]
[
[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
[-1, 1, Conv, [128, 3, 2]], # 1-P2/4
[-1, 3, C3_PKIModule, [128]],
[-1, 1, Conv, [256, 3, 2]], # 3-P3/8
[-1, 6, C3_PKIModule, [256]],
[-1, 1, Conv, [512, 3, 2]], # 5-P4/16
[-1, 9, C3_PKIModule, [512]],
[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
[-1, 3, C3_PKIModule, [1024]],
[-1, 1, SPPF, [1024, 5]], # 9
]
# YOLOv5 v6.0 head
head: [
[-1, 1, Conv, [512, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, "nearest"]],
[[-1, 6], 1, Concat, [1]], # cat backbone P4
[-1, 3, C3, [512, False]], # 13
[-1, 1, Conv, [256, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, "nearest"]],
[[-1, 4], 1, Concat, [1]], # cat backbone P3
[-1, 3, C3, [256, False]], # 17 (P3/8-small)
[-1, 1, Conv, [256, 3, 2]],
[[-1, 14], 1, Concat, [1]], # cat head P4
[-1, 3, C3, [512, False]], # 20 (P4/16-medium)
[-1, 1, Conv, [512, 3, 2]],
[[-1, 10], 1, Concat, [1]], # cat head P5
[-1, 3, C3, [1024, False]], # 23 (P5/32-large)
[[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
]
- 语义分割yaml文件
# Ultralytics YOLOv5 🚀, AGPL-3.0 license
# Parameters
nc: 80 # number of classes
depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple
anchors:
- [10, 13, 16, 30, 33, 23] # P3/8
- [30, 61, 62, 45, 59, 119] # P4/16
- [116, 90, 156, 198, 373, 326] # P5/32
# YOLOv5 v6.0 backbone
backbone:
# [from, number, module, args]
[
[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
[-1, 1, Conv, [128, 3, 2]], # 1-P2/4
[-1, 3, C3_PKIModule, [128]],
[-1, 1, Conv, [256, 3, 2]], # 3-P3/8
[-1, 6, C3_PKIModule, [256]],
[-1, 1, Conv, [512, 3, 2]], # 5-P4/16
[-1, 9, C3_PKIModule, [512]],
[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
[-1, 3, C3_PKIModule, [1024]],
[-1, 1, SPPF, [1024, 5]], # 9
]
# YOLOv5 v6.0 head
head: [
[-1, 1, Conv, [512, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, "nearest"]],
[[-1, 6], 1, Concat, [1]], # cat backbone P4
[-1, 3, C3, [512, False]], # 13
[-1, 1, Conv, [256, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, "nearest"]],
[[-1, 4], 1, Concat, [1]], # cat backbone P3
[-1, 3, C3, [256, False]], # 17 (P3/8-small)
[-1, 1, Conv, [256, 3, 2]],
[[-1, 14], 1, Concat, [1]], # cat head P4
[-1, 3, C3, [512, False]], # 20 (P4/16-medium)
[-1, 1, Conv, [512, 3, 2]],
[[-1, 10], 1, Concat, [1]], # cat head P5
[-1, 3, C3, [1024, False]], # 23 (P5/32-large)
[[17, 20, 23], 1, Segment, [nc, anchors, 32, 256]], # Segment (P3, P4, P5)
]
温馨提示:本文只是对yolov5基础上添加模块,如果要对yolov5n/l/m/x进行添加则只需要指定对应的depth_multiple 和 width_multiple。
# YOLOv5n
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.25 # layer channel multiple
# YOLOv5s
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.50 # layer channel multiple
# YOLOv5l
depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple
# YOLOv5m
depth_multiple: 0.67 # model depth multiple
width_multiple: 0.75 # layer channel multiple
# YOLOv5x
depth_multiple: 1.33 # model depth multiple
width_multiple: 1.25 # layer channel multiple
2.4 注册模块
关键步骤三:在yolo.py的parse_model函数替换添加C3_PKIModule
2.5 执行程序
在train.py中,将cfg的参数路径设置为yolov5_C3_PKIModule.yaml的路径
建议大家写绝对路径,确保一定能找到
🚀运行程序,如果出现下面的内容则说明添加成功🚀
from n params module arguments
0 -1 1 7040 models.common.Conv [3, 64, 6, 2, 2]
1 -1 1 73984 models.common.Conv [64, 128, 3, 2]
2 -1 3 156928 models.common.C3_PKIModule [128, 128, 3]
3 -1 1 295424 models.common.Conv [128, 256, 3, 2]
4 -1 6 872448 models.common.C3_PKIModule [256, 256, 6]
5 -1 1 1180672 models.common.Conv [256, 512, 3, 2]
6 -1 9 4221952 models.common.C3_PKIModule [512, 512, 9]
7 -1 1 4720640 models.common.Conv [512, 1024, 3, 2]
8 -1 3 6531072 models.common.C3_PKIModule [1024, 1024, 3]
9 -1 1 2624512 models.common.SPPF [1024, 1024, 5]
10 -1 1 525312 models.common.Conv [1024, 512, 1, 1]
11 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest']
12 [-1, 6] 1 0 models.common.Concat [1]
13 -1 3 2757632 models.common.C3 [1024, 512, 3, False]
14 -1 1 131584 models.common.Conv [512, 256, 1, 1]
15 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest']
16 [-1, 4] 1 0 models.common.Concat [1]
17 -1 3 690688 models.common.C3 [512, 256, 3, False]
18 -1 1 590336 models.common.Conv [256, 256, 3, 2]
19 [-1, 14] 1 0 models.common.Concat [1]
20 -1 3 2495488 models.common.C3 [512, 512, 3, False]
21 -1 1 2360320 models.common.Conv [512, 512, 3, 2]
22 [-1, 10] 1 0 models.common.Concat [1]
23 -1 3 9971712 models.common.C3 [1024, 1024, 3, False]
24 [17, 20, 23] 1 457725 Detect [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [256, 512, 1024]]
YOLOv5_C3_PKIModule summary: 788 layers, 40665469 parameters, 40665469 gradients, 96.6 GFLOPs
3. 完整代码分享
https://pan.baidu.com/s/1GmbyHszqj8_igNO1ld0SUg?pwd=icdb
提取码: icdb
4. GFLOPs
关于GFLOPs的计算方式可以查看:百面算法工程师 | 卷积基础知识——Convolution
未改进的GFLOPs
改进后的GFLOPs
5. 进阶
可以结合损失函数或者卷积模块进行多重改进
YOLOv5改进 | 损失函数 | EIoU、SIoU、WIoU、DIoU、FocuSIoU等多种损失函数——点击即可跳转
6. 总结
PKIModule 是一种旨在提高特征提取能力的卷积模块,特别针对具有多尺度和复杂上下文信息的图像。它通过多个不同大小的深度可分离卷积核并行提取输入特征的多尺度信息,以捕捉图像中不同尺度的物体特征。随后,这些多尺度的特征通过逐点卷积层进行融合,确保在特征提取过程中保持丰富的上下文信息。此外,PKIModule 可以选择性地包含一个上下文锚注意力模块(CAA),该模块通过捕捉长距离的上下文依赖关系来进一步增强特征表示。最后,模块还支持残差连接,将输入特征与输出特征结合,以保留输入信息并防止梯度消失。整体而言,PKIModule 通过有效的多尺度卷积和注意力机制,提高了对图像中不同尺度和上下文复杂性特征的捕捉能力,适用于需要高精度特征提取的计算机视觉任务。