YOLO26改进 - 特征融合 | GIRAFFEDET之GFPN :广义特征金字塔网络,高效地融合多尺度特征
前言本文介绍了创新的对象检测框架GiraffeDet在YOLO26中的结合应用。GiraffeDet旨在通过轻量级骨干网络和深度、庞大的颈部模块实现高效的多尺度信息交换其核心包括轻量级的空间到深度链S2D-chain和广义特征金字塔网络GFPN。其中S2D-chain减少计算成本和域迁移问题GFPN提供跨层次和跨尺度的特征融合。我们将GFPN集成进YOLO26替代原有的特征融合模块实现更高效的信息交换。本次接入保留 YOLO26 主干在 Neck 中引入 GFPN 特征融合阶段检测精度和速度的具体变化需要在目标数据集上进行完整训练及基线对比。文章目录 YOLO26改进大全卷积层、轻量化、注意力机制、损失函数、Backbone、SPPF、Neck、检测头全方位优化汇总专栏链接: 最新YOLO26改进专栏文章目录前言介绍摘要文章链接基本原理GiraffeDet 基本原理和组件1. 基本原理2. 组件3. GiraffeDet 家族GFPN (广义特征金字塔网络) 详解GFPN 设计要点GFPN 详细设计实验结果与性能核心代码YOLO26引入代码tasks注册步骤1导包步骤2注册基础模块和重复模块配置yolo26-GFPN.yaml实验脚本结果介绍摘要在传统的目标检测框架中通常采用从图像识别模型继承的主干网络来提取深层潜在特征然后通过颈部模块融合这些潜在特征以捕捉不同尺度的信息。由于目标检测中的分辨率远高于图像识别主干网络的计算成本往往占据总推理成本的主要部分。这种重型主干设计范式主要是由于将图像识别模型转移到目标检测中时的历史遗留而不是针对目标检测进行的端到端优化设计。在本研究中我们表明这种范式确实导致了次优的目标检测模型。为此我们提出了一种新颖的重型颈部范式GiraffeDet这是一种类长颈鹿的高效目标检测网络。GiraffeDet使用极其轻量级的主干网络和非常深且大的颈部模块鼓励在不同空间尺度和不同潜在语义层次之间进行密集的信息交换。这种设计范式使检测器即使在网络的早期阶段也能以同等优先级处理高级语义信息和低级空间信息从而在检测任务中更加有效。对多个流行的目标检测基准的数值评估表明GiraffeDet在各种资源约束下始终优于先前的SOTA模型。源码可在 https://github.com/jyqi/GiraffeDet 获取。文章链接论文地址论文地址代码地址代码地址基本原理GiraffeDet 基本原理和组件GiraffeDet 是一个创新的对象检测框架其设计宗旨是通过轻量级骨干网络和深度、庞大的颈部模块实现高效的多尺度信息交换从而提高检测性能。其核心思想包括轻量级的空间到深度链Space-to-Depth Chain, S2D-chain和广义特征金字塔网络Generalized Feature Pyramid Network, GFPN共同组成了一个“长颈鹿”形网络。1. 基本原理轻量级骨干Lightweight BackboneGiraffeDet 使用轻量级的空间到深度链S2D-chain作为骨干网络取代传统的CNN骨干减少了计算成本和域迁移问题。S2D-chain 包括两个 3x3 卷积层和多个 S2D 块每个 S2D 块由一个 S2D 层和一个 1x1 卷积组成通过将空间维度的信息转移到深度维度来实现特征的下采样。广义特征金字塔网络Generalized FPN, GFPNGFPN 提供了跨层次和跨尺度的特征融合通过“Queen-Fusion”实现像国际象棋中的王后路径般的高效信息交换。GFPN 设计中包含跳跃层连接log2n-link能够有效传递早期节点到后期节点的信息并减少冗余。2. 组件S2D链包含初始下采样的 3x3 卷积和多个 S2D 块。S2D 块通过固定间隔的均匀采样和重组特征实现空间维度到深度维度的转换。GFPN由多个深度和宽度可调的层组成。每层包括多种尺度和层次的特征融合使用跳跃层连接和跨尺度连接。Queen-Fusion 融合了当前层和相邻层的特征提供了高效的高低层信息交换。预测网络Prediction Network负责生成对象的边界框和分类标签。通过 GFPN 提供的丰富特征进行准确的对象检测。3. GiraffeDet 家族多样化模型根据 GFPN 的深度和宽度GiraffeDet 开发了多个适应不同计算资源限制的模型包括 Giraffe-D7、D11、D14、D16、D25 和 D29。实验结果表明GiraffeDet 在各个 FLOPs 级别上都表现出了较高的准确性和效率。GFPN (广义特征金字塔网络) 详解GFPN 是 GiraffeDet 中的一个关键组件其设计旨在高效地融合多尺度特征以提升目标检测性能。GFPN 结合了跳跃层连接skip-layer connections和跨尺度连接cross-scale connections等创新技术解决了传统特征金字塔网络FPN设计中的局限性增强了不同特征层次之间的信息交换。GFPN 设计要点多尺度特征融合GFPN 的目的是汇聚从骨干网络提取的不同分辨率的特征。它基于传统 FPN 的概念但引入了更复杂的连接以增强信息流动。特征金字塔网络的演进传统 FPN引入自上而下的路径来融合多尺度特征。PANet在 FPN 结构的基础上增加了自下而上的路径增强了双向信息流。BiFPN移除只有一个输入边的节点并增加同一级别原始输入的额外边进一步提高了连接性。GFPN结合跳跃层连接和跨尺度连接优化了水平和垂直方向上的信息流。跳跃层连接Skip-layer Connection设计用于减少深层网络中的梯度消失问题。具体实现方式有两种密集连接dense-link和 log2n 连接log2n-link。跨尺度连接Cross-scale Connection设计用于克服大尺度变异问题。以前的工作仅考虑相邻层之间的特征连接而 GFPN 提出了新的融合方法——皇后融合Queen-fusion考虑了相同层次和邻近层次的特征。GFPN 详细设计跳跃层连接密集连接dense-link每一层都接收所有前一层的特征图并进行卷积操作。log2n 连接log2n-link每一层接收至多 log2(l) 1 层的前一层特征图减少了计算复杂度并有效传递信息。皇后融合Queen-fusion类似于国际象棋中的皇后路径融合了当前层和相邻层的特征。例如在 P5 层融合了上一层 P4 的下采样、上一层 P6 的上采样、上一层 P5 和当前层 P4 的特征。实验结果与性能实验结果表明GFPN 在处理大尺度变异方面表现优异在各个 FLOPs 级别上均实现了更高的准确性和效率。连接分析显示log2n 连接在信息传输方面比密集连接更有效而皇后融合则能实现充分的高低层信息交换。GFPN 的创新设计使得 GiraffeDet 能够在目标检测任务中提供卓越的性能并在处理不同尺度的对象时表现出色。通过跳跃层连接和跨尺度连接GFPN 实现了高效的信息融合提高了检测的准确性和效率。核心代码import torch import torch.nn as nn from ultralytics.nn.modules.conv import Conv, RepConv def get_activation(namesilu, inplaceTrue): Resolve the activation names used by the article. if name is None: return nn.Identity() if isinstance(name, nn.Module): return name activations { silu: lambda: nn.SiLU(inplaceinplace), swish: lambda: nn.SiLU(inplaceinplace), relu: lambda: nn.ReLU(inplaceinplace), lrelu: lambda: nn.LeakyReLU(0.1, inplaceinplace), hardsigmoid: lambda: nn.Hardsigmoid(inplaceinplace), identity: nn.Identity, } if name not in activations: raise ValueError(fUnsupported GFPN activation: {name}) return activations[name]() class ConvBNAct(Conv): Reuse the YOLO26 convolution while preserving the articles activation options. def __init__(self, in_channels, out_channels, ksize, stride1, groups1, actsilu): super().__init__(in_channels, out_channels, kksize, sstride, ggroups, actget_activation(act)) class BasicBlock_3x3_Reverse(nn.Module): RepConv channel transform followed by a spatial convolution and optional residual. def __init__(self, ch_in, ch_hidden_ratio, ch_out, actrelu, shortcutTrue): super().__init__() if ch_in ! ch_out: raise ValueError(GFPN reverse block requires equal input and output channels) ch_hidden max(1, int(ch_in * ch_hidden_ratio)) self.conv1 ConvBNAct(ch_hidden, ch_out, 3, actact) # The articles RepConv has no BN identity branch; bnFalse preserves this structure. self.conv2 RepConv(ch_in, ch_hidden, k3, s1, p1, actget_activation(act), bnFalse) self.shortcut shortcut def forward(self, x): y self.conv1(self.conv2(x)) return x y if self.shortcut else y class SPP(nn.Module): Parallel spatial pooling used by the optional GFPN stage branch. def __init__(self, ch_in, ch_out, k1, pool_size(5, 9, 13), actswish): super().__init__() self.pool nn.ModuleList(nn.MaxPool2d(size, 1, size // 2) for size in pool_size) self.conv ConvBNAct(ch_in, ch_out, k, actact) def forward(self, x): return self.conv(torch.cat([x, *(pool(x) for pool in self.pool)], dim1)) class CSPStage(nn.Module): Concatenate the bypass and every reverse block output before the final projection. def __init__( self, ch_in, ch_out, n1, block_fnBasicBlock_3x3_Reverse, ch_hidden_ratio1.0, actsilu, sppFalse, ): super().__init__() if ch_out 2 or n 1: raise ValueError(GFPN CSPStage requires ch_out 2 and n 1) if block_fn ! BasicBlock_3x3_Reverse: raise ValueError(fUnsupported GFPN block: {block_fn}) ch_first ch_out // 2 ch_mid ch_out - ch_first self.conv1 ConvBNAct(ch_in, ch_first, 1, actact) self.conv2 ConvBNAct(ch_in, ch_mid, 1, actact) self.convs nn.ModuleList( BasicBlock_3x3_Reverse(ch_mid, ch_hidden_ratio, ch_mid, actact, shortcutTrue) for _ in range(n) ) self.spp SPP(ch_mid * 4, ch_mid, actact) if spp else nn.Identity() self.spp_index (n - 1) // 2 self.conv3 ConvBNAct(ch_first ch_mid * n, ch_out, 1, actact) def forward(self, x): y1 self.conv1(x) y2 self.conv2(x) mid_out [y1] for i, conv in enumerate(self.convs): y2 conv(y2) if i self.spp_index: y2 self.spp(y2) # SPP transforms the block output rather than adding another concatenation branch. mid_out.append(y2) return self.conv3(torch.cat(mid_out, dim1))YOLO26引入代码在根目录下的ultralytics/nn/目录新建一个featureFusion目录然后新建一个以GFPN为文件名的py文件 把代码拷贝进去。importtorchimporttorch.nnasnnfromultralytics.nn.modules.convimportConv,RepConvdefget_activation(namesilu,inplaceTrue):Resolve the activation names used by the article.ifnameisNone:returnnn.Identity()ifisinstance(name,nn.Module):returnname activations{silu:lambda:nn.SiLU(inplaceinplace),swish:lambda:nn.SiLU(inplaceinplace),relu:lambda:nn.ReLU(inplaceinplace),lrelu:lambda:nn.LeakyReLU(0.1,inplaceinplace),hardsigmoid:lambda:nn.Hardsigmoid(inplaceinplace),identity:nn.Identity,}ifnamenotinactivations:raiseValueError(fUnsupported GFPN activation:{name})returnactivations[name]()classConvBNAct(Conv):Reuse the YOLO26 convolution while preserving the articles activation options.def__init__(self,in_channels,out_channels,ksize,stride1,groups1,actsilu):super().__init__(in_channels,out_channels,kksize,sstride,ggroups,actget_activation(act))classBasicBlock_3x3_Reverse(nn.Module):RepConv channel transform followed by a spatial convolution and optional residual.def__init__(self,ch_in,ch_hidden_ratio,ch_out,actrelu,shortcutTrue):super().__init__()ifch_in!ch_out:raiseValueError(GFPN reverse block requires equal input and output channels)ch_hiddenmax(1,int(ch_in*ch_hidden_ratio))self.conv1ConvBNAct(ch_hidden,ch_out,3,actact)# The articles RepConv has no BN identity branch; bnFalse preserves this structure.self.conv2RepConv(ch_in,ch_hidden,k3,s1,p1,actget_activation(act),bnFalse)self.shortcutshortcutdefforward(self,x):yself.conv1(self.conv2(x))returnxyifself.shortcutelseyclassSPP(nn.Module):Parallel spatial pooling used by the optional GFPN stage branch.def__init__(self,ch_in,ch_out,k1,pool_size(5,9,13),actswish):super().__init__()self.poolnn.ModuleList(nn.MaxPool2d(size,1,size//2)forsizeinpool_size)self.convConvBNAct(ch_in,ch_out,k,actact)defforward(self,x):returnself.conv(torch.cat([x,*(pool(x)forpoolinself.pool)],dim1))classCSPStage(nn.Module):Concatenate the bypass and every reverse block output before the final projection.def__init__(self,ch_in,ch_out,n1,block_fnBasicBlock_3x3_Reverse,ch_hidden_ratio1.0,actsilu,sppFalse,):super().__init__()ifch_out2orn1:raiseValueError(GFPN CSPStage requires ch_out 2 and n 1)ifblock_fn!BasicBlock_3x3_Reverse:raiseValueError(fUnsupported GFPN block:{block_fn})ch_firstch_out//2ch_midch_out-ch_first self.conv1ConvBNAct(ch_in,ch_first,1,actact)self.conv2ConvBNAct(ch_in,ch_mid,1,actact)self.convsnn.ModuleList(BasicBlock_3x3_Reverse(ch_mid,ch_hidden_ratio,ch_mid,actact,shortcutTrue)for_inrange(n))self.sppSPP(ch_mid*4,ch_mid,actact)ifsppelsenn.Identity()self.spp_index(n-1)//2self.conv3ConvBNAct(ch_firstch_mid*n,ch_out,1,actact)defforward(self,x):y1self.conv1(x)y2self.conv2(x)mid_out[y1]fori,convinenumerate(self.convs):y2conv(y2)ifiself.spp_index:y2self.spp(y2)# SPP transforms the block output rather than adding another concatenation branch.mid_out.append(y2)returnself.conv3(torch.cat(mid_out,dim1))tasks注册在ultralytics/nn/tasks.py中进行如下操作步骤1导包fromultralytics.nn.featureFusion.GFPNimportCSPStageasGFPN_CSPStage步骤2注册基础模块和重复模块在parse_model(d, ch, verboseTrue)中的两个现有集合中各加入 GFPN_CSPStage。下方只展示新增位置保留原集合中的其他模块base_modulesfrozenset({GFPN_CSPStage,})repeat_modulesfrozenset(# modules with repeat arguments{GFPN_CSPStage,})配置yolo26-GFPN.yaml# Ultralytics AGPL-3.0 License - https://ultralytics.com/license# Ultralytics YOLO26 object detection model with P3/8 - P5/32 outputs# Model docs: https://docs.ultralytics.com/models/yolo26# Task docs: https://docs.ultralytics.com/tasks/detect# Parametersnc:80# number of classesend2end:True# whether to use end-to-end modereg_max:1# DFL binsscales:# model compound scaling constants, i.e. modelyolo26n.yaml will call yolo26.yaml with scale n# [depth, width, max_channels]n:[0.50,0.25,1024]s:[0.50,0.50,1024]m:[0.50,1.00,512]l:[1.00,1.00,512]x:[1.00,1.50,512]# YOLO26n backbonebackbone:# [from, repeats, module, args]-[-1,1,Conv,[64,3,2]]# 0-P1/2-[-1,1,Conv,[128,3,2]]# 1-P2/4-[-1,2,C3k2,[256,False,0.25]]-[-1,1,Conv,[256,3,2]]# 3-P3/8-[-1,2,C3k2,[512,False,0.25]]-[-1,1,Conv,[512,3,2]]# 5-P4/16-[-1,2,C3k2,[512,True]]-[-1,1,Conv,[1024,3,2]]# 7-P5/32-[-1,2,C3k2,[1024,True]]-[-1,1,SPPF,[1024,5,3,True]]# 9-[-1,2,C2PSA,[1024]]# 10# YOLO26n head: GFPN CSP stages in a PAN comparison configurationhead:-[10,1,nn.Upsample,[None,2,nearest]]# 11-[[-1,6],1,Concat,[1]]# 12 backbone P4 fusion-[-1,3,GFPN_CSPStage,[512]]# 13-[-1,1,nn.Upsample,[None,2,nearest]]# 14-[[-1,4],1,Concat,[1]]# 15 backbone P3 fusion-[-1,3,GFPN_CSPStage,[256]]# 16 P3/8-small-[-1,1,Conv,[256,3,2]]# 17-[[-1,13],1,Concat,[1]]# 18 head P4 fusion-[-1,3,GFPN_CSPStage,[512]]# 19 P4/16-medium-[-1,1,Conv,[512,3,2]]# 20-[[-1,10],1,Concat,[1]]# 21 backbone P5 fusion-[-1,3,GFPN_CSPStage,[1024]]# 22 P5/32-large-[[16,19,22],1,Detect,[nc]]# Detect(P3, P4, P5)实验脚本importwarnings warnings.filterwarnings(ignore)fromultralyticsimportYOLOif__name____main__:# 修改为自己的配置文件地址modelYOLO(./ultralytics/cfg/models/26/yolo26-GFPN.yaml)# 修改为自己的数据集地址model.train(data./ultralytics/cfg/datasets/coco8.yaml,cacheFalse,imgsz640,epochs10,single_clsFalse,# 是否是单类别检测batch8,close_mosaic10,workers0,optimizerMuSGD,# optimizerSGD,ampFalse,projectruns/train,nameGFPN,)结果