加入BIFPN加权双向金字塔结构,提升不同尺度的检测效果。
第一步: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
如果需要在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)
]