前言:Hello大家好,我是小哥谈。小目标检测层是指在目标检测任务中用于检测小尺寸目标的特定网络层。由于小目标具有较小的尺寸和低分辨率,它们往往更加难以检测和定位。YOLOv5算法的检测速度与精度较为平衡,但是对于小目标的检测效果不佳,根据一些论文,我们可以通过增加检测层来提高对小目标的特征提取能力,以提高算法在密集场景下的表现。🌈
前期回顾:
YOLOv5算法改进(1)— 如何去改进YOLOv5算法
YOLOv5算法改进(2)— 添加SE注意力机制
YOLOv5算法改进(3)— 添加CBAM注意力机制
YOLOv5算法改进(4)— 添加CA注意力机制
YOLOv5算法改进(5)— 添加ECA注意力机制
YOLOv5算法改进(6)— 添加SOCA注意力机制
YOLOv5算法改进(7)— 添加SimAM注意力机制
YOLOv5算法改进(8)— 替换主干网络之MobileNetV3
YOLOv5算法改进(9)— 替换主干网络之ShuffleNetV2
YOLOv5算法改进(10)— 替换主干网络之GhostNet
YOLOv5算法改进(11)— 替换主干网络之EfficientNetv2
YOLOv5算法改进(12)— 替换主干网络之Swin Transformer
YOLOv5算法改进(13)— 替换主干网络之PP-LCNet
YOLOv5算法改进(14)— 更换Neck之BiFPN
YOLOv5算法改进(15)— 更换Neck之AFPN
目录
🚀1.小目标检测介绍
💥💥1.1 小目标定义
💥💥1.2 小目标检测难点
💥💥1.3 小目标检测意义
💥💥1.4 YOLOv5中的小目标检测
🚀2.增加小目标检测层的方法
💥💥2.1 网络结构
💥💥2.2 添加步骤
💥💥步骤1:创建自定义yaml文件
💥💥步骤2:验证是否添加成功
🚀1.小目标检测介绍
💥💥1.1 小目标定义
🍀(1)以目标检测领域的通用数据集COCO为例,小目标是指小于32×32个像素点(中目标是指32×32 ~ 96×96,大目标是指大于96×96);
🍀(2)在实际应用场景中,通常更倾向于使用相对于原图的比例来定义,比如物体标注框的长宽乘积,除以整个图像的长宽乘积,再开根号,如果结果小于3%,就称之为小目标。
💥💥1.2 小目标检测难点
🍀(1)包含小目标的样本数量较少,这样潜在的让目标检测模型更关注中大目标的检测;
🍀(2)由于小目标覆盖的区域更小,这样小目标的位置会缺少多样性。我们推测这使得小目标检测的在验证时的通用性变得很难。
💥💥1.3 小目标检测意义
小目标检测的意义在于它可以提高技术的应用范围,同时可以帮助大家更好地理解图像中的细节信息。此外,小目标检测其实在我们日常生活中的许多领域均有广泛的应用,例如交通监控、医学影像分析、无人机航拍等。🌴
举个例子:
在交通监控领域,小目标检测可用于识别交通信号灯、车牌等;
在医学影像分析领域,小目标检测可用于识别微小的肿瘤细胞等;
在自动驾驶领域,小目标检测可用于识别微小的障碍物,以弥补激光雷达难以探测的窘况。
等等......🍉 🍓 🍑 🍈 🍌 🍐
💥💥1.4 YOLOv5中的小目标检测
针小目标检测,YOLOv5的效果可能不好的原因是由于小目标样本的尺寸较小,而YOLOv5模型的下采样倍数较大,导致较深的特征图难以学习到小目标的特征信息。为了改善这个问题,可以考虑在YOLOv5模型中增加小目标检测层,将较浅的特征图与深特征图拼接后进行检测。🍄
这种方式实现简单有效,只需要修改YOLOv5模型文件的yaml即可增加小目标检测层。然而,增加检测层后会带来计算量的增加,从而导致推理检测的速度降低。但是对于小目标的检测,这种改进确实能够取得良好的效果。✅
🚀2.增加小目标检测层的方法
💥💥2.1 网络结构
YOLOv5 - 5.0网络结构图:
YOLOv5 - 6.0网络结构图:
由YOLOv5 - 5.0和YOLOv5 - 6.0网络结构图可知,都是由输入端+主干网络Backbone+Neck网络+输出端四部分组成的。
关于YOLOv5的相关知识,请参考文章:👇
YOLOv5基础知识入门(2)— YOLOv5核心基础知识讲解
由网络结构图可知,YOLOv5原始只有3个检测头,分别是20×20(大目标)、40×40(中目标)和80×80(小目标),我们要增加小目标检测层,可以在80×80(小目标)的上面增加,也就是增加160×160检测层。🌱
YOLOv5s模型只有3个预测层,当将尺寸为640×640的图像输入网络时,Neck 网络分别进行8倍、16倍、32倍下采样,对应的预测层特征图尺寸为80×80、40×40、20×20,用来检测小目标、中目标和大目标。在YOLOv5s原始网络上增加一个预测层,在Neck网络中增加1次上采样,第3次上采样后,与主干网络第2层融合,得到新增加的160×160的预测层,用以检测小目标。整个模型改进后采用4个预测尺度的预测层,将底层特征高分辨率和深层特征高语义信息充分利用,并且未显著增加网络复杂度。🌄
当增加了一层之后,网络结构就变成下面这样子了。👇
YOLOv5 - 5.0版本:
YOLOv5 - 6.0版本:
说明:♨️♨️♨️
上图中,红框部分为新增的检测层,随着箭头往上走,将Neck网络中80×80的特征图经过上采样变成160×160。
💥💥2.2 添加步骤
💥💥步骤1:创建自定义yaml文件
在models文件夹中复制yolov5s.yaml,粘贴并重命名为yolov5s_SmallTarget.yaml。
针对增加小目标检测层,我们需要做两处修改。
修改1:
🍀(1)修改Anchor:增加一组较小的anchor
#---原始的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
若输入图像的尺寸是640×640,
# P3/8 对应的检测特征图大小为 80×80,用于检测大小在 8×8 以上的目标。
# P4/16 对应的检测特征图大小为 40×40,用于检测大小在 16×16 以上的目标。
# P5/32 对应的检测特征图大小为 20×20,用于检测大小在 32×32 以上的目标。
#---修改后的anchors---#
anchors:
- [4,5, 8,10, 22,18] # P2/4
- [10,13, 16,30, 33,23] # P3/8
- [30,61, 62,45, 59,119] # P4/16
- [116,90, 156,198, 373,326] # P5/32
# P2/4 新增加的anchors,对应的检测特征图大小为 160×160,用于检测大小在 4×4 以上的目标。
修改2:
YOLOv5中的head包括 Neck 和Detect(输出端) 两部分。修改head部分,增加一层网络结构。
#---原始的head部分---#
head:
[[-1, 1, Conv, [512, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, 'nearest']],
[[-1, 6], 1, Concat, [1]], # 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, [1]], # cat backbone P3
[-1, 3, C3, [256, False]], # 17 (P3/8-small)
[-1, 1, Conv, [256, 3, 2]],
[[-1, 14], 1, Concat, [1]], # cat head P4
[-1, 3, C3, [512, False]], # 20 (P4/16-medium)
[-1, 1, Conv, [512, 3, 2]],
[[-1, 10], 1, Concat, [1]], # cat head P5
[-1, 3, C3, [1024, False]], # 23 (P5/32-large)
[[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
]
修改后的head部分如下所示:
#---修改后的head部分---#
head:
#neck
#[512,20,20]
[[-1, 1, Conv, [512, 1, 1]], #10 卷积层 [512,20,20]
[-1, 1, nn.Upsample, [None, 2, 'nearest']], #11 上采样 [512,40,40]
[[-1, 6], 1, Concat, [1]], #12 Concat [1024,40,40]
[-1, 3, C3, [512, False]], #13 C3 [512,40,40]
[-1, 1, Conv, [256, 1, 1]], #14 卷积层 [256,40,40]
[-1, 1, nn.Upsample, [None, 2, 'nearest']], #15 上采样 [256,80,80]
[[-1, 4], 1, Concat, [1]], #16 Concat [512,80,80]
#[-1, 3, C3, [256, False]], # 被删了
#下面是我们自己加的
[-1, 3, C3, [256, False]], #17 C3 [256,80,80]
[-1, 1, Conv, [128, 1, 1]], #18 卷积层 [128,80,80]
[-1, 1, nn.Upsample, [None, 2, 'nearest']], #19 上采样 [256,160,160]
[[-1, 2], 1, Concat, [1]], #20 Concat [512,160,160]
#head
[-1, 3, C3, [128, False]], #21 C3 [128,160,160]
[-1, 1, Conv, [128, 3, 2]], #22 卷积层 [128,80,80]
[[-1, 18], 1, Concat, [1]], #23 Concat [512,160,160]
[-1, 3, C3, [256, False]], #24 C3 [256,160,160]
[-1, 1, Conv, [256, 3, 2]], #25 卷积层 [256,40,40]
[[-1, 14], 1, Concat, [1]], #26 Concat [512,160,160]
[-1, 3, C3, [512, False]], #27 C3 [512,40,40]
[-1, 1, Conv, [512, 3, 2]], #28 卷积层 [512,20,20]
[[-1, 10], 1, Concat, [1]], #29 特征融合 [1024,20,20]
[-1, 3, C3, [1024, False]], #30 C3 [1027,20,20]
[[21, 24, 27, 30], 1, Detect, [nc, anchors]], # 将21, 24, 27, 30传入检测头
]
yaml文件修改后的完整代码如下:
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# Parameters
nc: 80
depth_multiple: 0.67
width_multiple: 0.75
anchors:
- [4,5, 8,10, 22,18] # P2/4
- [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 v6.0 backbone
backbone:
[[-1, 1, Conv, [64, 6, 2, 2]], #0 卷积层 [64,320,320 ]
[-1, 1, Conv, [128, 3, 2]], #1 卷积层 [128,160,160]
[-1, 3, C3, [128]], #2 C3 [128,160,160]
[-1, 1, Conv, [256, 3, 2]], #3 卷积层 [256,80,80]
[-1, 6, C3, [256]], #4 C3 [256,80,80]
[-1, 1, Conv, [512, 3, 2]], #5 卷积层 [512,40,40]
[-1, 9, C3, [512]], #6 C3 [512,40,40]
[-1, 1, Conv, [1024, 3, 2]], #7 卷积层 [1024,20,20]
[-1, 3, C3, [1024]], #8 C3 [1024,20,20]
[-1, 1, SPPF, [1024, 5]], #9 SPPF [1024,20,20]
]
head:
#neck
#[512,20,20]
[[-1, 1, Conv, [512, 1, 1]], #10 卷积层 [512,20,20]
[-1, 1, nn.Upsample, [None, 2, 'nearest']], #11 上采样 [512,40,40]
[[-1, 6], 1, Concat, [1]], #12 Concat [1024,40,40]
[-1, 3, C3, [512, False]], #13 C3 [512,40,40]
[-1, 1, Conv, [256, 1, 1]], #14 卷积层 [256,40,40]
[-1, 1, nn.Upsample, [None, 2, 'nearest']], #15 上采样 [256,80,80]
[[-1, 4], 1, Concat, [1]], #16 Concat [512,80,80]
#[-1, 3, C3, [256, False]], # 被删了
#下面是添加的
[-1, 3, C3, [256, False]], #17 C3 [256,80,80]
[-1, 1, Conv, [128, 1, 1]], #18 卷积层 [128,80,80]
[-1, 1, nn.Upsample, [None, 2, 'nearest']], #19 上采样 [128,160,160]
[[-1, 2], 1, Concat, [1]], #20 Concat [512,160,160]
#head
[-1, 3, C3, [128, False]], #21 C3 [128,160,160]
[-1, 1, Conv, [128, 3, 2]], #22 卷积层 [128,80,80]
[[-1, 18], 1, Concat, [1]], #23 Concat [512,160,160]
[-1, 3, C3, [256, False]], #24 C3 [256,160,160]
[-1, 1, Conv, [256, 3, 2]], #25 卷积层 [256,40,40]
[[-1, 14], 1, Concat, [1]], #26 Concat [512,160,160]
[-1, 3, C3, [512, False]], #27 C3 [512,40,40]
[-1, 1, Conv, [512, 3, 2]], #28 卷积层 [512,20,20]
[[-1, 10], 1, Concat, [1]], #29 特征融合 [1024,20,20]
[-1, 3, C3, [1024, False]], #30 C3 [1027,20,20]
[[21, 24, 27, 30], 1, Detect, [nc, anchors]], # 将21, 24, 27, 30传入检测头
]
💥💥步骤2:验证是否添加成功
在yolo.py文件里,配置我们刚才自定义的yolov5s_SmallTarget.yaml。
然后运行yolo.py,得到结果。👇
这样就算添加成功了。🎉🎉🎉