YOLOv11改进 | Neck篇 | 双向特征金字塔网络BiFPN助力YOLOv11有效涨点

一、本文介绍

本文给大家带来的改进机制是 BiFPN双向特征金字塔网络 ,其是一种特征融合层的结构,也就是我们本文改进YOLOv11 模型 中的Neck部分,它的 主要思想 是通过多层级的特征金字塔和双向 信息传递 来提高精度。本文给大家带来的结构可以让大家自行调节网络结构大小,同时能够达到一定的轻量化效果,为什么发 BiFPN 呢因为它算是YOLO系列改进中的常青树了,大家可以借鉴它的双向特征思想来创新自己的Neck结构 本文的BiFPN通过yaml文件配置可以让大家自行调配其结构


目录

一、本文介绍

二、BiFPN原理

2.1 BiFPN的基本原理

2.2 双向特征融合

2.3 加权融合机制

2.4 结构优化

三、BiFPN代码

四、手把手教你修改BiFPN

4.1 修改一

4.2 修改二

4.3 修改三

4.4 修改四

五、正式训练

5.1 yaml文件

5.2 训练代码

5.3 训练过程截图

五、本文总结


二、BiFPN原理

论文地址: 论文官方地址

代码地址: 官方代码地址


2.1 BiFPN的基本原理

BiFPN(Bidirectional Feature Pyramid Network) 双向特征金字塔网络 是一种 高效的多尺度特征融合网络 ,它在传统特征金字塔网络(FPN)的基础上进行了优化。 主要特点 包括:

1. 高效的双向跨尺度连接: BiFPN通过在自顶向下和自底向上路径之间建立双向连接,允许不同尺度特征间的信息更有效地流动和融合。

2. 简化的网络结构: BiFPN通过删除只有一个输入边的节点、在同一层级的输入和输出节点间添加额外边,以及将每个双向路径视为一个特征网络层并重复多次,来优化跨尺度连接。

3. 加权特征融合: BiFPN引入了可学习的权重来确定不同输入特征的重要性,从而提高了特征融合的效果。

我们可以将其基本原理概括分为以下几点:

1. 双向特征融合: BiFPN允许特征在自顶向下和自底向上两个方向上进行融合,从而更有效地结合不同尺度的特征。

2. 加权融合机制: BiFPN通过为每个输入特征添加权重来优化特征融合过程,使得网络可以更加重视信息量更大的特征。

3. 结构优化: BiFPN通过移除只有一个输入边的节点、添加同一层级的输入输出节点之间的额外边,并将每个双向路径视为一个特征网络层,来优化跨尺度连接。

我将通过下图为大家对比展示BiFPN与 其他四种不同特征金字塔网络设计的不同 以及BiFPN如何 更有效地整合特征

(a) FPN (Feature Pyramid Network): 引入了自顶向下的路径来融合从第3层到第7层(P3 - P7)的多尺度特征。
(b) PANet: 在FPN的基础上增加了自底向上的额外路径。
(c) NAS-FPN: 使用神经架构搜索(NAS)来找到不规则的特征网络拓扑,然后重复应用相同的块。
(d) BiFPN: 通过高效的双向跨尺度连接和重复的块结构,改进了准确度和效率之间的权衡。

我们可以看出BiFPN通过双向路径 允许特征信息在不同尺度间双向流动 ,这种双向流动可以看做是在不同尺度之间进行有效信息交换。这样的设计旨在通过 强化特征的双向流动 来提升特征融合的效率和有效性,从而提高目标检测的 性能


2.2 双向特征融合

双向特征融合 在BiFPN(双向特征金字塔网络)中指的是一种机制,它允许在特征网络层中的信息在自顶向下和自底向上两个方向上流动和融合。这种方法与传统的单向特征金字塔网络(如PANet)相比,能够 在不同层级之间更高效地融合特征,而无需增加显著的计算成本。

在BiFPN中,每一条双向路径(自顶向下和自底向上)被视作一个单独的特征网络层,然后这些层可以被重复多次,以促进更高级别的特征融合。这样做的结果是一个简化的双向网络,它增强了网络对特征融合的能力,使网络能够更有效地利用不同尺度的信息,从而提高目标检测的性能。

下图展示的是 EfficientDet架构的具体细节 ,其中包含了EfficientNet作为骨干网络(backbone),以及BiFPN作为特征网络的使用。在这个架构中,BiFPN层通过其双向特征融合的能力,从EfficientNet骨干网络接收多尺度的输入特征,然后生成用于对象分类和边框预测的富有表现力的特征。

在BiFPN层中,我们可以看到不同尺度的特征(P2至P7)如何通过 上下双向路径进行融合 。这种结构设计的目的是在保持计算效率的同时最大化特征融合的效果,以提高对象检测的整体性能。图中还显示了类别预测网络和边框预测网络,这些是在BiFPN特征融合后用于预测对象类别和定位对象边界框的网络部分。


2.3 加权融合机制

加权融合机制 是BiFPN中用于 改进特征融合效果 的一种技术。在传统的特征金字塔网络中,所有输入特征通常在没有区分的情况下等同对待,这意味着不同分辨率的特征被简单地相加在一起,而不考虑它们对输出特征的不同贡献。然而,在BiFPN中,观察到由于不同的输入特征具有不同的分辨率,它们通常 对输出特征的贡献是不等的

为了解决这个问题,BiFPN提出了 为每个输入添加一个额外的权重 ,并让网络学习每个输入特征的重要性:

O = \sum_i w_i \cdot I_i

其中 w_{i} 是一个可学习的权重,可以是标量(每个特征),向量(每个通道)或多维张量(每个像素)。这些权重是可学习的,可以是标量(针对每个特征),向量(针对每个通道),或者多维张量(针对每个像素)。这种加权融合方法可以在最小化计算成本的同时实现与其他方法可比的准确度。


2.4 结构优化

结构优化 是为了在不同的资源约束下,通过复合缩放方法确定不同的层数,从而在保持效率的同时提高准确性。我们通过分析观察BiFPN的设计, 其结构优化包括:

1. 简化的双向网络: 通过优化结构,减少了网络中的节点数,特别是移除了那些只有一个输入边的节点。这种简化的直觉是如果一个节点没有进行特征融合,即它只有一个输入边,那么它对于融合不同特征的特征网络的贡献会更小。

2. 增加额外的边缘 :在相同层级的原始输入和输出节点之间增加了额外的边缘,以便在不显著增加成本的情况下融合更多的特征。

3. 重复使用双向路径: 与只有单一自顶向下和自底向上路径的PANet不同,BiFPN将每条双向(自顶向下和自底向上)路径视为一个特征网络层,并重复多次,以实现更高级别的特征融合。


三、BiFPN代码

核心代码的使用方式看章节四!

  1. import torch.nn as nn
  2. import torch
  3. class swish(nn.Module):
  4. def forward(self, x):
  5. return x * torch.sigmoid(x)
  6. class Bi_FPN(nn.Module):
  7. def __init__(self, length):
  8. super().__init__()
  9. self.weight = nn.Parameter(torch.ones(length, dtype=torch.float32), requires_grad=True)
  10. self.swish = swish()
  11. self.epsilon = 0.0001
  12. def forward(self, x):
  13. weights = self.weight / (torch.sum(self.swish(self.weight), dim=0) + self.epsilon) # 权重归一化处理
  14. weighted_feature_maps = [weights[i] * x[i] for i in range(len(x))]
  15. stacked_feature_maps = torch.stack(weighted_feature_maps, dim=0)
  16. result = torch.sum(stacked_feature_maps, dim=0)
  17. return result


四、手把手教你修改BiFPN

修改BiFPN的话只需要在代码中注册上面的BiFPN就可以了。


4.1 修改一

第一还是建立文件,我们找到如下 ultralytics /nn文件夹下建立一个目录名字呢就是'Addmodules'文件夹( !然后在其内部建立一个新的py文件将核心代码复制粘贴进去即可。


4.2 修改二

第二步我们在该目录下创建一个新的py文件名字为'__init__.py'( ,然后在其内部导入我们的检测头如下图所示。

​​


4.3 修改三

第三步我门中到如下文件'ultralytics/nn/tasks.py'进行导入和注册我们的模块( !

​​


4.4 修改四

按照我的添加在ultralytics/nn/tasks.py文件下的parse_model里添加即可。

  1. elif m is Bi_FPN:
  2. length = len([ch[x] for x in f])
  3. args = [length]

到此就修改完成了,大家可以复制下面的yaml文件运行。


五、正式训练


5.1 yaml文件

训练信息:YOLO11-BiFPN summary: 410 layers, 2,618,823 parameters, 2,618,807 gradients, 7.1 GFLOPs

  1. # Ultralytics YOLO 🚀, AGPL-3.0 license
  2. # YOLO11 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect
  3. # Parameters
  4. nc: 80 # number of classes
  5. scales: # model compound scaling constants, i.e. 'model=yolo11n.yaml' will call yolo11.yaml with scale 'n'
  6. # [depth, width, max_channels]
  7. n: [0.50, 0.25, 1024] # summary: 319 layers, 2624080 parameters, 2624064 gradients, 6.6 GFLOPs
  8. s: [0.50, 0.50, 1024] # summary: 319 layers, 9458752 parameters, 9458736 gradients, 21.7 GFLOPs
  9. m: [0.50, 1.00, 512] # summary: 409 layers, 20114688 parameters, 20114672 gradients, 68.5 GFLOPs
  10. l: [1.00, 1.00, 512] # summary: 631 layers, 25372160 parameters, 25372144 gradients, 87.6 GFLOPs
  11. x: [1.00, 1.50, 512] # summary: 631 layers, 56966176 parameters, 56966160 gradients, 196.0 GFLOPs
  12. # YOLO11n backbone
  13. backbone:
  14. # [from, repeats, module, args]
  15. - [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
  16. - [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
  17. - [-1, 2, C3k2, [256, False, 0.25]]
  18. - [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
  19. - [-1, 2, C3k2, [512, False, 0.25]]
  20. - [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
  21. - [-1, 2, C3k2, [512, True]]
  22. - [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
  23. - [-1, 2, C3k2, [1024, True]]
  24. - [-1, 1, SPPF, [1024, 5]] # 9
  25. - [-1, 2, C2PSA, [1024]] # 10
  26. # YOLO11n head
  27. head:
  28. - [4, 1, Conv, [256]] # 11-P3/8
  29. - [6, 1, Conv, [256]] # 12-P4/16
  30. - [10, 1, Conv, [256]] # 13-P5/32
  31. - [-1, 1, nn.Upsample, [None, 2, 'nearest']] # 14 P5->P4
  32. - [[-1, 12], 1, Bi_FPN, []] # 15
  33. - [-1, 3, C3k2, [256, False]] # 16-P4/16
  34. - [-1, 1, nn.Upsample, [None, 2, 'nearest']] # 17 P4->P3
  35. - [[-1, 11], 1, Bi_FPN, []] # 18
  36. - [-1, 3, C3k2, [256, False]] # 19-P3/8
  37. - [1, 1, Conv, [256, 3, 2]] # 20 P2->P3
  38. - [[-1, 11, 19], 1, Bi_FPN, []] # 21
  39. - [-1, 3, C3k2, [256, False]] # 22-P3/8
  40. - [-1, 1, Conv, [256, 3, 2]] # 23 P3->P4
  41. - [[-1, 12, 16], 1, Bi_FPN, []] # 24
  42. - [-1, 3, C3k2, [512, False]] # 25-P4/16
  43. - [-1, 1, SCDown, [256, 3, 2]] # 26 P4->P5
  44. - [[-1, 13], 1, Bi_FPN, []] # 27
  45. - [-1, 3, C3k2, [1024, True]] # 28-P5/32
  46. - [[22, 25, 28], 1, Detect, [nc]] # Detect(P3, P4, P5)

5.2 训练代码

大家可以创建一个py文件将我给的代码复制粘贴进去,配置好自己的文件路径即可运行。

  1. import warnings
  2. warnings.filterwarnings('ignore')
  3. from ultralytics import YOLO
  4. if __name__ == '__main__':
  5. model = YOLO('模型配置文件')
  6. # 如何切换模型版本, 上面的ymal文件可以改为 yolov8s.yaml就是使用的v8s,
  7. # 类似某个改进的yaml文件名称为yolov8-XXX.yaml那么如果想使用其它版本就把上面的名称改为yolov8l-XXX.yaml即可(改的是上面YOLO中间的名字不是配置文件的)!
  8. # model.load('yolov8n.pt') # 是否加载预训练权重,科研不建议大家加载否则很难提升精度
  9. model.train(data=r"C:\Users\Administrator\PycharmProjects\yolov5-master\yolov5-master\Construction Site Safety.v30-raw-images_latestversion.yolov8\data.yaml",
  10. # 如果大家任务是其它的'ultralytics/cfg/default.yaml'找到这里修改task可以改成detect, segment, classify, pose
  11. cache=False,
  12. imgsz=640,
  13. epochs=150,
  14. single_cls=False, # 是否是单类别检测
  15. batch=16,
  16. close_mosaic=0,
  17. workers=0,
  18. device='0',
  19. optimizer='SGD', # using SGD
  20. # resume='runs/train/exp21/weights/last.pt', # 如过想续训就设置last.pt的地址
  21. amp=True, # 如果出现训练损失为Nan可以关闭amp
  22. project='runs/train',
  23. name='exp',
  24. )


5.3 训练过程截图


五、本文总结

到此本文的正式分享内容就结束了,在这里给大家推荐我的YOLOv11改进有效涨点专栏,本专栏目前为新开的平均质量分98分,后期我会根据各种最新的前沿顶会进行论文复现,也会对一些老的改进机制进行补充,如果大家觉得本文帮助到你了,订阅本专栏,关注后续更多的更新~