前 言:作为当前先进的深度学习目标检测算法YOLOv5,已经集合了大量的trick,但是在处理一些复杂背景问题的时候,还是容易出现错漏检的问题。此后的系列文章,将重点对YOLOv5的如何改进进行详细的介绍,目的是为了给那些搞科研的同学需要创新点或者搞工程项目的朋友需要达到更好的效果提供自己的微薄帮助和参考。
解决问题:加入BIFPN加权双向金字塔结构,提升不同尺度的检测效果。
2023.1.8更新
有朋友问在添加小目标检测层,四个检测层的基础上如何改进特征融合网络,改进方法其他不变,需要修改yaml文件,有需要可关注私信我。 部分yaml内容如下所示:完整见百度网盘链接:链接:https://pan.baidu.com/s/1Qnn6QtGbZ7H3_h89QYA2vQ
提取码:关注私信后获取
# parameters
nc: 80 # number of classes
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.50 # layer channel multiple
# anchors
anchors:
- [ 19,27, 44,40, 38,94 ] # P3/8
- [ 96,68, 86,152, 180,137 ] # P4/16
- [ 140,301, 303,264, 238,542 ] # P5/32
- [ 436,615, 739,380, 925,792 ] # P6/64
# YOLOv5 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, [ 128 ] ],
[ -1, 1, Conv, [ 256, 3, 2 ] ], # 3-P3/8
[ -1, 6, C3, [ 256 ] ], #4
[ -1, 1, Conv, [ 512, 3, 2 ] ], # 5-P4/16
[ -1, 9, C3, [ 512 ] ], #6
[ -1, 1, Conv, [ 768, 3, 2 ] ], # 7-P5/32
[ -1, 3, C3, [ 768 ] ], #8
[ -1, 1, Conv, [ 1024, 3, 2 ] ], # 9-P6/64
[ -1, 3, C3, [ 1024 ] ],
[ -1, 1, SPPF, [ 1024, 5 ] ], # 11
]
# BIFPN garph
#
# p6 ----------------- --------Concat_bifpn----> P6(out)
# / \ \ \
# /-------------------------------------------->
# / Upsample Concat_bifpn Concat_bifpn
# / | \ |
# p5 ---Concat_bifpn---> head 5 ---Concat_bifpn----> P5(out)
# \ \
# Upsample Concat_bifpn
# ---------------- | -----------------------> /
# / \ \ \
# / | Concat_bifpn |
# / \ \ |
# p4 ---Concat_bifpn---> head 4 ---Concat_bifpn---> P4(out)
# \ \
# ----Upsample----> Concat_bifpn
# \ /
# p3 ---Concat_bifpn------------------------------> P3(out)
# YOLOv5 head
head:
[ [ -1, 1, Conv, [ 768, 1, 1 ] ], # 12 head
[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ],
[ [ -1, 8 ], 1, Concat_bifpn, [ 384,384] ], # cat backbone P5
[ -1, 3, C3, [ 768, False ] ], # 15
[ -1, 1, Conv, [ 512, 1, 1 ] ],
[ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ],
[ [ -1, 6 ], 1, Concat_bifpn, [ 256,256] ], # cat backbone P4
[ -1, 3, C3, [ 512, False ] ], # 19
添加方法(以下改进步骤方法为在三个检测层的基础上):
第一步:common.py构建Concat_BIFPN模块
class Concat_bifpn(nn.Module):
# Concatenate a list of tensors along dimension
def __init__(self, c1, c2):
super(Concat_bifpn, self).__init__()
self.w1 = nn.Parameter(torch.ones(2, dtype=torch.float32), requires_grad=True)
self.w2 = nn.Parameter(torch.ones(3, dtype=torch.float32), requires_grad=True)
# self.w3 = nn.Parameter(torch.ones(3, dtype=torch.float32), requires_grad=True)
self.epsilon = 0.0001
self.conv = Conv(c1, c2, 1 ,1 ,0 )
self.act= nn.ReLU()
def forward(self, x): # mutil-layer 1-3 layers #ADD or Concat
#print("bifpn:",x.shape)
if len(x) == 2:
w = self.w1
weight = w / (torch.sum(w, dim=0) + self.epsilon)
x = self.conv(self.act(weight[0] * x[0] + weight[1] * x[1]))
elif len(x) == 3:
w = self.w2
weight = w / (torch.sum(w, dim=0) + self.epsilon)
x = self.conv(self.act (weight[0] * x[0] + weight[1] * x[1] + weight[2] * x[2]))
# elif len(x) == 4:
# w = self.w3
# weight = w / (torch.sum(w, dim=0) + self.epsilon)
# x = self.conv(self.act(weight[0] * x[0] + weight[1] * x[1] + weight[2] *x[2] + weight[3]*x[3] ))
return x
第二步:yolo.py中注册Concat_BIFPNt模块
elif m is Concat_bifpn:
c2 = max([ch[x] for x in f])
第三步:修改yaml文件(以修改官方YOLOv5s.yaml为例),需要修改head(特征融合网络)
# parameters
nc: 80 # number of classes
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.50 # layer channel multiple
# anchors
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 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, [128]],
[-1, 1, Conv, [256, 3, 2]], # 3-P3/8
[-1, 6, C3, [256]],
[-1, 1, Conv, [512, 3, 2]], # 5-P4/16
[-1, 9, C3, [512]],
[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
[-1, 3, C3, [1024]],
[-1, 1, SPPF, [1024, 5]],
]
# YOLOv5 head
head:
[[-1, 1, Conv, [512, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
[[-1,6], 1, Concat_bifpn, [256,256]], # 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_bifpn, [128,128]], # cat backbone P3
[-1, 3, C3, [256, False]], # 17 (P3/8-small)
[-1, 1, Conv, [512, 3, 2]], # 320, 640 #
[[-1, 6, 13], 1, Concat_bifpn, [256,256]], # cat head P4
[-1, 3, C3, [512, False]], # 20 (P4/16-medium)
[-1, 1, Conv, [1024, 3, 2]], # 640, 1280 #
[[-1, 9], 1, Concat_bifpn, [512, 512]], # cat head P5 cat 20,20 #22
[-1, 3, C3, [1024, False]], # 25 (P5/32-large) # 1280, 1280 #23
[[17, 20, 23], 1, Detect, [nc, anchors]] # Detect(P3, P4, P5)
]
Model Summary: 290 layers, 8114651 parameters, 8114651 gradients, 17.4 GFLOPs
2023.2.19补充:如果需要在YOLOv5l.yaml等网络结构进行修改的话,不可直接用以上的yaml文件或者就简单修改depth_multiple为1.0,而是 需要修改Concat_bifpn, [256,256]中的通道数为对应网络实际通道数。具体如下所示:
# parameters
nc: 80 # number of classes
depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple
# anchors
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 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, [128]],
[-1, 1, Conv, [256, 3, 2]], # 3-P3/8
[-1, 6, C3, [256]],
[-1, 1, Conv, [512, 3, 2]], # 5-P4/16
[-1, 9, C3, [512]],
[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
[-1, 3, C3, [1024]],
[-1, 1, SPPF, [1024, 5]],
]
# YOLOv5 head
head:
[[-1, 1, Conv, [512, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
[[-1,6], 1, Concat_bifpn, [512,512]], # 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_bifpn, [256,256]], # cat backbone P3
[-1, 3, C3, [256, False]], # 17 (P3/8-small)
[-1, 1, Conv, [512, 3, 2]], # 320, 640 #
[[-1, 6, 13], 1, Concat_bifpn, [512,512]], # cat head P4
[-1, 3, C3, [512, False]], # 20 (P4/16-medium)
[-1, 1, Conv, [1024, 3, 2]], # 640, 1280 #
[[-1, 9], 1, Concat_bifpn, [1024, 1024]], # cat head P5 cat 20,20 #22
[-1, 3, C3, [1024, False]], # 25 (P5/32-large) # 1280, 1280 #23
[[17, 20, 23], 1, Detect, [nc, anchors]] # Detect(P3, P4, P5)
]
第四步:将train.py中改为本文的yaml文件即可,开始训练
结 果:本人在多个数据集上做了大量实验,针对不同的数据集效果不同,同一个数据集的不同添加位置方法也是有差异,需要大家进行实验。有效果有提升的情况占大多数。
预告一下:下一篇内容分享增加小目标检测层。有兴趣的朋友可以关注一下我,有问题可以留言或者私聊我哦
PS:,不仅仅是可以添加进YOLOv5,也可以添加进任何其他的深度学习网络,不管是分类还是检测还是分割,主要是计算机视觉领域,都可能会有不同程度的提升效果。
最后,四个检测层的基础上改进特征融合网络为BIFPN的话,需要修改yaml文件,有需要可关注私信我。