YOLOv8目标检测创新改进与实战案例专栏
专栏目录: YOLOv8有效改进系列及项目实战目录 包含卷积,主干 注意力,检测头等创新机制 以及 各种目标检测分割项目实战案例
专栏链接: YOLOv8基础解析+创新改进+实战案例
介绍
摘要
在传统的目标检测框架中,通常采用从图像识别模型继承的主干网络来提取深层潜在特征,然后通过颈部模块融合这些潜在特征,以捕捉不同尺度的信息。由于目标检测中的分辨率远高于图像识别,主干网络的计算成本往往占据总推理成本的主要部分。这种重型主干设计范式主要是由于将图像识别模型转移到目标检测中时的历史遗留,而不是针对目标检测进行的端到端优化设计。在本研究中,我们表明这种范式确实导致了次优的目标检测模型。为此,我们提出了一种新颖的重型颈部范式,GiraffeDet,这是一种类长颈鹿的高效目标检测网络。GiraffeDet使用极其轻量级的主干网络和非常深且大的颈部模块,鼓励在不同空间尺度和不同潜在语义层次之间进行密集的信息交换。这种设计范式使检测器即使在网络的早期阶段也能以同等优先级处理高级语义信息和低级空间信息,从而在检测任务中更加有效。对多个流行的目标检测基准的数值评估表明,GiraffeDet在各种资源约束下始终优于先前的SOTA模型。源码可在 https://github.com/jyqi/GiraffeDet 获取。
文章链接
论文地址:论文地址
代码地址:代码地址
基本原理
GiraffeDet 基本原理和组件
GiraffeDet 是一个创新的对象检测框架,其设计宗旨是通过轻量级骨干网络和深度、庞大的颈部模块实现高效的多尺度信息交换,从而提高检测性能。其核心思想包括轻量级的空间到深度链(Space-to-Depth Chain, S2D-chain)和广义特征金字塔网络(Generalized Feature Pyramid Network, GFPN),共同组成了一个“长颈鹿”形网络。
1. 基本原理
轻量级骨干(Lightweight Backbone):
- GiraffeDet 使用轻量级的空间到深度链(S2D-chain)作为骨干网络,取代传统的CNN骨干,减少了计算成本和域迁移问题【10:7†source】。
- S2D-chain 包括两个 3x3 卷积层和多个 S2D 块,每个 S2D 块由一个 S2D 层和一个 1x1 卷积组成,通过将空间维度的信息转移到深度维度来实现特征的下采样【10:7†source】。
广义特征金字塔网络(Generalized FPN, GFPN):
- GFPN 提供了跨层次和跨尺度的特征融合,通过“Queen-Fusion”实现像国际象棋中的王后路径般的高效信息交换【10:7†source】。
- GFPN 设计中包含跳跃层连接(log2n-link),能够有效传递早期节点到后期节点的信息,并减少冗余【10:13†source】。
2. 组件
S2D链:
- 包含初始下采样的 3x3 卷积和多个 S2D 块。S2D 块通过固定间隔的均匀采样和重组特征实现空间维度到深度维度的转换【10:7†source】。
GFPN:
- 由多个深度和宽度可调的层组成。每层包括多种尺度和层次的特征融合,使用跳跃层连接和跨尺度连接【10:8†source】【10:13†source】。
- Queen-Fusion 融合了当前层和相邻层的特征,提供了高效的高低层信息交换【10:17†source】。
预测网络(Prediction Network):
- 负责生成对象的边界框和分类标签。通过 GFPN 提供的丰富特征进行准确的对象检测【10:7†source】。
3. GiraffeDet 家族
- 多样化模型:
- 根据 GFPN 的深度和宽度,GiraffeDet 开发了多个适应不同计算资源限制的模型,包括 Giraffe-D7、D11、D14、D16、D25 和 D29【10:8†source】。
- 实验结果表明,GiraffeDet 在各个 FLOPs 级别上都表现出了较高的准确性和效率【10:10†source】。
GFPN (广义特征金字塔网络) 详解
GFPN 是 GiraffeDet 中的一个关键组件,其设计旨在高效地融合多尺度特征,以提升目标检测性能。GFPN 结合了跳跃层连接(skip-layer connections)和跨尺度连接(cross-scale connections)等创新技术,解决了传统特征金字塔网络(FPN)设计中的局限性,增强了不同特征层次之间的信息交换。
核心代码
class SPPV4(BaseModule):
# CSP SPP https://github.com/WongKinYiu/CrossStagePartialNetworks
def __init__(self,
in_channels,
out_channels,
expansion=0.5,
pooling_kernel_size=(5, 9, 13),
csp_act_cfg=dict(type='Mish'),
init_cfg=None,
**kwargs):
super(SPPV4, self).__init__(init_cfg)
hidden_channels = int(2 * out_channels * expansion) # hidden channels
self.conv1 = Conv(
in_channels, hidden_channels, kernel_size=1, **kwargs)
self.conv2 = nn.Conv2d(in_channels, hidden_channels, 1, 1, bias=False)
self.conv3 = Conv(
hidden_channels, hidden_channels, kernel_size=3, **kwargs)
self.conv4 = Conv(
hidden_channels, hidden_channels, kernel_size=1, **kwargs)
self.maxpools = nn.ModuleList([
nn.MaxPool2d(kernel_size=x, stride=1, padding=x // 2)
for x in pooling_kernel_size
])
self.conv5 = Conv(
4 * hidden_channels, hidden_channels, kernel_size=1, **kwargs)
self.conv6 = Conv(
hidden_channels, hidden_channels, kernel_size=3, **kwargs)
csp_norm_cfg = kwargs.get('norm_cfg', dict(type='BN')).copy()
self.bn = build_norm_layer(csp_norm_cfg, 2 * hidden_channels)[-1]
csp_act_cfg_ = csp_act_cfg.copy()
if csp_act_cfg_['type'] not in [
'Tanh', 'PReLU', 'Sigmoid', 'HSigmoid', 'Swish'
]:
csp_act_cfg_.setdefault('inplace', True)
self.csp_act = build_activation_layer(csp_act_cfg_)
self.conv7 = Conv(
2 * hidden_channels, out_channels, kernel_size=1, **kwargs)
def forward(self, x):
x1 = self.conv4(self.conv3(self.conv1(x)))
y1 = self.conv6(
self.conv5(
torch.cat([x1] + [maxpool(x1) for maxpool in self.maxpools],
1)))
y2 = self.conv2(x)
return self.conv7(self.csp_act(self.bn(torch.cat((y1, y2), dim=1))))
class Focus(BaseModule):
# Focus wh information into c-space
# Implement with ordinary Conv2d with
# doubled kernel/padding size & stride 2
def __init__(self,
in_channels,
out_channels,
kernel_size=1,
stride=1,
groups=1,
init_cfg=None,
**kwargs):
super(Focus, self).__init__(init_cfg)
padding = kernel_size // 2
kernel_size *= 2
padding *= 2
stride *= 2
self.conv = Conv(
in_channels,
out_channels,
kernel_size=kernel_size,
stride=stride,
padding=padding,
groups=groups,
**kwargs)
def forward(self, x):
return self.conv(x)
class CSPStage(BaseModule):
def __init__(self,
in_channels,
out_channels,
repetition,
init_cfg=None,
**kwargs):
super(CSPStage, self).__init__(init_cfg)
self.conv_downscale = Conv(
in_channels, out_channels, kernel_size=3, stride=2, **kwargs)
self.conv_csp = BottleneckCSP(out_channels, out_channels, repetition,
**kwargs)
def forward(self, x):
return self.conv_csp(self.conv_downscale(x))
task与yaml配置
详见: https://blog.csdn.net/shangyanaf/article/details/140459446