学习资源站

RT-DETR改进策略【小目标改进】添加专用于小目标的检测层附YOLO系列的检测头变化详解_rtdetr小目标-

RT-DETR改进策略【小目标改进】| 添加专用于小目标的检测层 附YOLO系列的检测头变化详解

前言

在目标检测领域,小目标检测一直是一个具有挑战性的问题。目前算法以其高效快速的特点受到广泛关注,然而在面对小目标时,仍存在一些局限性。本文将介绍如何在 RT-DETR 添加小目标检测层,以提高对小目标的检测能力。


一、RT-DETR原始模型结构介绍

rt-detr-l 原始模型结构如下:

# Ultralytics YOLO 🚀, AGPL-3.0 license
# RT-DETR-l object detection model with P3-P5 outputs. For details see https://docs.ultralytics.com/models/rtdetr

# Parameters
nc: 80  # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n-cls.yaml' will call yolov8-cls.yaml with scale 'n'
  # [depth, width, max_channels]
  l: [1.00, 1.00, 1024]

backbone:
  # [from, repeats, module, args]
  - [-1, 1, HGStem, [32, 48]]  # 0-P2/4
  - [-1, 6, HGBlock, [48, 128, 3]]  # stage 1

  - [-1, 1, DWConv, [128, 3, 2, 1, False]]  # 2-P3/8
  - [-1, 6, HGBlock, [96, 512, 3]]   # stage 2

  - [-1, 1, DWConv, [512, 3, 2, 1, False]]  # 4-P4/16
  - [-1, 6, HGBlock, [192, 1024, 5, True, False]]  # cm, c2, k, light, shortcut
  - [-1, 6, HGBlock, [192, 1024, 5, True, True]]
  - [-1, 6, HGBlock, [192, 1024, 5, True, True]]  # stage 3

  - [-1, 1, DWConv, [1024, 3, 2, 1, False]]  # 8-P5/32
  - [-1, 6, HGBlock, [384, 2048, 5, True, False]]  # stage 4

head:
  - [-1, 1, Conv, [256, 1, 1, None, 1, 1, False]]  # 10 input_proj.2
  - [-1, 1, AIFI, [1024, 8]]
  - [-1, 1, Conv, [256, 1, 1]]   # 12, Y5, lateral_convs.0

  - [-1, 1, nn.Upsample, [None, 2, 'nearest']]
  - [7, 1, Conv, [256, 1, 1, None, 1, 1, False]]  # 14 input_proj.1
  - [[-2, -1], 1, Concat, [1]]
  - [-1, 3, RepC3, [256]]  # 16, fpn_blocks.0
  - [-1, 1, Conv, [256, 1, 1]]   # 17, Y4, lateral_convs.1

  - [-1, 1, nn.Upsample, [None, 2, 'nearest']]
  - [3, 1, Conv, [256, 1, 1, None, 1, 1, False]]  # 19 input_proj.0
  - [[-2, -1], 1, Concat, [1]]  # cat backbone P4
  - [-1, 3, RepC3, [256]]    # X3 (21), fpn_blocks.1

  - [-1, 1, Conv, [256, 3, 2]]   # 22, downsample_convs.0
  - [[-1, 17], 1, Concat, [1]]  # cat Y4
  - [-1, 3, RepC3, [256]]    # F4 (24), pan_blocks.0

  - [-1, 1, Conv, [256, 3, 2]]   # 25, downsample_convs.1
  - [[-1, 12], 1, Concat, [1]]  # cat Y5
  - [-1, 3, RepC3, [256]]    # F5 (27), pan_blocks.1

  - [[21, 24, 27], 1, RTDETRDecoder, [nc]]  # Detect(P3, P4, P5)

二、有效特征层对应的检测头类别

2.1 P3/8 - small检测头

  • 原始模型中的 P3/8特征层 对应的检测头主要用于检测相对较小的目标。其特征图大小相对较大,空间分辨率较高。
  • 适合检测尺寸大概在 8x8 32x32 像素左右的目标。

2.2 P4/16 - medium检测头

  • 这个检测头对应的 P4/16特征层 经过了更多的下采样操作,相比P3/8特征图空间分辨率降低,但通道数增加,特征更抽象且有语义信息。
  • 它主要用于检测中等大小的目标,尺寸范围大概在 32x32 64x64 像素左右。

2.3 P5/32 - large检测头

  • P5/32 是经过最多下采样操作得到的特征层,其空间分辨率最低,但语义信息最强、全局感受野最大。
  • 该检测头适合检测较大尺寸的目标,一般是尺寸在 64x64像素以上 的目标。

2.4 新添加针对小目标的检测头

  • 新添加的检测头主要用于检测更小尺寸的目标。尺寸在 4x4 8x8 像素左右的微小目标。

💡这是因为在目标检测任务中,随着目标尺寸的减小,需要更高分辨率的特征图来有效捕捉目标特征。新添加的检测头很可能是基于这样的考虑,通过一系列的卷积、上采样和拼接等操作生成适合微小目标检测的特征图,从而提高模型对微小目标的检测能力。

三、添加小目标的检测层后的网络结构

# Ultralytics YOLO 🚀, AGPL-3.0 license
# RT-DETR-l object detection model with P3-P5 outputs. For details see https://docs.ultralytics.com/models/rtdetr

# Parameters
nc: 80  # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n-cls.yaml' will call yolov8-cls.yaml with scale 'n'
  # [depth, width, max_channels]
  l: [1.00, 1.00, 1024]

backbone:
  # [from, repeats, module, args]
  - [-1, 1, HGStem, [32, 48]]  # 0-P2/4
  - [-1, 6, HGBlock, [48, 128, 3]]  # stage 1

  - [-1, 1, DWConv, [128, 3, 2, 1, False]]  # 2-P3/8
  - [-1, 6, HGBlock, [96, 512, 3]]   # stage 2

  - [-1, 1, DWConv, [512, 3, 2, 1, False]]  # 4-P4/16
  - [-1, 6, HGBlock, [192, 1024, 5, True, False]]  # cm, c2, k, light, shortcut
  - [-1, 6, HGBlock, [192, 1024, 5, True, True]]
  - [-1, 6, HGBlock, [192, 1024, 5, True, True]]  # stage 3

  - [-1, 1, DWConv, [1024, 3, 2, 1, False]]  # 8-P5/32
  - [-1, 6, HGBlock, [384, 2048, 5, True, False]]  # stage 4

head:
  - [-1, 1, Conv, [256, 1, 1, None, 1, 1, False]]  # 10 input_proj.2
  - [-1, 1, AIFI, [1024, 8]]
  - [-1, 1, Conv, [256, 1, 1]]   # 12, Y5, lateral_convs.0

  - [-1, 1, nn.Upsample, [None, 2, 'nearest']]
  - [7, 1, Conv, [256, 1, 1, None, 1, 1, False]]  # 14 input_proj.1
  - [[-2, -1], 1, Concat, [1]]
  - [-1, 3, RepC3, [256]]  # 16, fpn_blocks.0
  - [-1, 1, Conv, [256, 1, 1]]   # 17, Y4, lateral_convs.1

  - [-1, 1, nn.Upsample, [None, 2, 'nearest']]
  - [3, 1, Conv, [256, 1, 1, None, 1, 1, False]]  # 19 input_proj.0
  - [[-2, -1], 1, Concat, [1]]  # cat backbone P3
  - [-1, 3, RepC3, [256]]    # X3 (21), fpn_blocks.1

  - [-1, 1, nn.Upsample, [None, 2, 'nearest']]
  - [1, 1, Conv, [256, 1, 1, None, 1, 1, False]]  # 19 input_proj.0
  - [[-2, -1], 1, Concat, [1]]  # cat backbone P2
  - [-1, 3, RepC3, [128]]    # X3 (25), fpn_blocks.1

  - [-1, 1, Conv, [256, 3, 2]]   # 22, downsample_convs.0
  - [[-1, 21], 1, Concat, [1]]  # cat Y3
  - [-1, 3, RepC3, [256]]    # F4 (28), pan_blocks.0

  - [-1, 1, Conv, [256, 3, 2]]   # 25, downsample_convs.1
  - [[-1, 17], 1, Concat, [1]]  # cat Y4
  - [-1, 3, RepC3, [256]]    # F5 (31), pan_blocks.1

  - [-1, 1, Conv, [256, 3, 2]]   # 25, downsample_convs.1
  - [[-1, 12], 1, Concat, [1]]  # cat Y5
  - [-1, 3, RepC3, [256]]    # F5 (34), pan_blocks.1

  - [[25, 28, 31, 34], 1, RTDETRDecoder, [nc]]  # Detect(P3, P4, P5)

四、修改及调用步骤

4.1 修改步骤

新建一个模型文件,将上方修改后的模型结构复制到其中,注意修改 nc: 80 # number of classes

无需任何其他地方的修改。

运行即可。

4.2 运行结果

                   from  n    params  module                                       arguments                     
  0                  -1  1     25248  ultralytics.nn.modules.block.HGStem          [3, 32, 48]                   
  1                  -1  6    155072  ultralytics.nn.modules.block.HGBlock         [48, 48, 128, 3, 6]           
  2                  -1  1      1408  ultralytics.nn.modules.conv.DWConv           [128, 128, 3, 2, 1, False]    
  3                  -1  6    839296  ultralytics.nn.modules.block.HGBlock         [128, 96, 512, 3, 6]          
  4                  -1  1      5632  ultralytics.nn.modules.conv.DWConv           [512, 512, 3, 2, 1, False]    
  5                  -1  6   1695360  ultralytics.nn.modules.block.HGBlock         [512, 192, 1024, 5, 6, True, False]
  6                  -1  6   2055808  ultralytics.nn.modules.block.HGBlock         [1024, 192, 1024, 5, 6, True, True]
  7                  -1  6   2055808  ultralytics.nn.modules.block.HGBlock         [1024, 192, 1024, 5, 6, True, True]
  8                  -1  1     11264  ultralytics.nn.modules.conv.DWConv           [1024, 1024, 3, 2, 1, False]  
  9                  -1  6   6708480  ultralytics.nn.modules.block.HGBlock         [1024, 384, 2048, 5, 6, True, False]
 10                  -1  1    524800  ultralytics.nn.modules.conv.Conv             [2048, 256, 1, 1, None, 1, 1, False]
 11                  -1  1    789760  ultralytics.nn.modules.transformer.AIFI      [256, 1024, 8]                
 12                  -1  1     66048  ultralytics.nn.modules.conv.Conv             [256, 256, 1, 1]              
 13                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']          
 14                   7  1    262656  ultralytics.nn.modules.conv.Conv             [1024, 256, 1, 1, None, 1, 1, False]
 15            [-2, -1]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           
 16                  -1  3   2232320  ultralytics.nn.modules.block.RepC3           [512, 256, 3]                 
 17                  -1  1     66048  ultralytics.nn.modules.conv.Conv             [256, 256, 1, 1]              
 18                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']          
 19                   3  1    131584  ultralytics.nn.modules.conv.Conv             [512, 256, 1, 1, None, 1, 1, False]
 20            [-2, -1]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           
 21                  -1  3   2232320  ultralytics.nn.modules.block.RepC3           [512, 256, 3]                 
 22                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']          
 23                   1  1     33280  ultralytics.nn.modules.conv.Conv             [128, 256, 1, 1, None, 1, 1, False]
 24            [-2, -1]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           
 25                  -1  3    624640  ultralytics.nn.modules.block.RepC3           [512, 128, 3]                 
 26                  -1  1    295424  ultralytics.nn.modules.conv.Conv             [128, 256, 3, 2]              
 27            [-1, 21]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           
 28                  -1  3   2232320  ultralytics.nn.modules.block.RepC3           [512, 256, 3]                 
 29                  -1  1    590336  ultralytics.nn.modules.conv.Conv             [256, 256, 3, 2]              
 30            [-1, 17]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           
 31                  -1  3   2232320  ultralytics.nn.modules.block.RepC3           [512, 256, 3]                 
 32                  -1  1    590336  ultralytics.nn.modules.conv.Conv             [256, 256, 3, 2]              
 33            [-1, 12]  1         0  ultralytics.nn.modules.conv.Concat           [1]                           
 34                  -1  3   2232320  ultralytics.nn.modules.block.RepC3           [512, 256, 3]                 
 35    [25, 28, 31, 34]  1   7485219  ultralytics.nn.modules.head.RTDETRDecoder    [1, [128, 256, 256, 256]]     
rtdetr-l-xsmall summary: 766 layers, 36,175,107 parameters, 36,175,107 gradients, 199.6 GFLOPs

从打印的网络结果可以看出, Backbone 部分没有改变, 颈部 中加入了用于提取小目标特征的特征层, 检测头 中传入了 个特征层分别为 P2 P3 P4 P5 ,其中 P2 就是新加入的 针对小目标的检测层

💡第 25 层是专门针对更小尺寸目标(尺寸在 4x4 到 8x8 像素左右的微小目标)设计的。
通过特定的卷积和上采样等操作,该特征层能够提取到小目标更细致的特征,并且与其他层的特征进行合理的融合,从而提高模型对小目标的检测精度和召回率。弥补了原始模型在小目标检测方面的不足,使得模型在处理包含大量小目标的场景时能够有更好的表现。

五 YOLO系列模型的检测头比较

YOLOv1~YOLOv11

  1. YOLOv1的检测头 :(论文地址: https://arxiv.org/pdf/1506.02640 )
    • 结构特点
      • YOLOv1 的检测头是 全连接层 。在模型结构中,经过一系列的卷积层对图像进行特征提取后,最后连接两个全连接层。这两个全连接层是参数量最大的部分,也是模型中最值得改进的部分。
    • 性能表现
      • 这种设计使得模型能够直接对图像进行预测,输出目标的类别概率和边界框坐标。然而,全连接层的使用导致模型对输入图像的尺寸有严格要求,并且在检测精度和速度的平衡上还有较大的提升空间。

在这里插入图片描述

  1. YOLOv2的检测头 :(论文地址: https://arxiv.org/pdf/1804.02767 )
    • 引入Anchor Box
      • YOLOv2 借鉴了 Faster R-CNN 中的 Anchor Box 概念。 Anchor Box 是预先定义好的不同尺寸和比例的框,作为预测目标边界框的参考。每个网格可以预测多个Anchor Box,这大大增加了模型对不同形状和大小目标的检测能力,解决了YOLOv1中每个网格只能预测一个目标的问题,提高了召回率。
    • 基于Grid的偏移量预测
      • 在位置预测方面, YOLOv2 从直接预测目标的绝对坐标改为预测相对于 Anchor Box 和网格的偏移量。这种方式使得预测的值范围变小,更有利于神经网络的学习,提高了模型的稳定性和准确性。

在这里插入图片描述

  • 使用卷积层代替全连接层
    • YOLOv2 使用 卷积网络 代替了全连接网络作为检测头,这使得模型能够接受任意尺寸的输入图像,为多尺度训练和预测提供了可能,也减少了模型的参数数量,提高了运行效率。
  1. YOLOv3的检测头 :(论文地址: https://arxiv.org/pdf/1612.08242#page=4.24 )

    • 多尺度预测
      • 检测头分成了 三个分支 ,分别对应不同的下采样倍数(32倍、16倍、8倍), 用于预测大、中、小不同尺寸的目标 。每个分支都有独立的卷积层结构,能够更好地提取不同尺度目标的特征,从而提高了对各种尺寸目标的检测性能。
    • 增加先验框数量
      • 每个网格设置 9 先验框 ,分为 3个大的、3个中的、3个小的 。这样的设计可以更好地适应不同形状和大小的目标,提高了模型的检测精度和召回率。
  2. YOLOv4的检测头 :(论文地址: https://arxiv.org/pdf/2004.10934 )

    • 细节改进
      • 整体上仍然是 多尺度的检测头结构 ,但在一些细节上进行了改进。例如,使用了更多的锚点(anchor)来适应不同的目标形状和大小,并且对锚点的设置进行了优化,提高了检测的准确性。
    • 损失函数改进
      • 在检测头的损失函数方面,采用了一些新的损失函数,如 CIoU Loss 等,这些损失函数能够更好地衡量预测框和真实框之间的差异,提高了模型的边界框回归精度。

在这里插入图片描述

  1. YOLOv5的检测头 :(代码地址: https://github.com/ultralytics/yolov5 )

    • 结构优化
      • 在检测头部分进行了结构上的优化,同样采用卷积层组合,提高了特征提取的能力。同时,对特征图的处理也进行了改进,使得模型能够更好地利用 多尺度特征信息 进行目标检测。
    • 自适应锚框
      • YOLOv5可以根据不同的数据集 自动调整锚框的尺寸和比例 ,提高了模型的泛化能力和检测精度。
  2. YOLOv6的检测头 :(论文地址: https://arxiv.org/pdf/2209.02976.pdf )

    • 解耦操作
      • YOLOX 一样,对检测头进行了 解耦 ,将边框回归和类别分类的过程分开。这样做可以避免两者之间的相互影响,加快模型的收敛速度,降低检测头的复杂度。
    • 高效结构设计
      • 基于高效的策略重新设计了检测头结构,在不明显降低精度的情况下降低了计算延时,实现了速度与精度的平衡。

在这里插入图片描述

  1. YOLOv7的检测头 :(论文地址: https://arxiv.org/pdf/2207.02696.pdf )
    • 辅助训练头
      • YOLOv7在训练过程中引入了 辅助训练头 ,与主检测头一起进行训练。辅助训练头可以帮助模型更好地学习特征表示,提高检测精度。在推理阶段,只使用主检测头进行预测,不会增加额外的计算负担。
    • 更灵活的特征融合
      • 在检测头中采用了更灵活的特征融合方式,能够更好地结合不同层次的特征信息,提高模型对复杂场景下目标的检测能力。

在这里插入图片描述

  1. YOLOv8的检测头 :(代码地址: https://github.com/ultralytics/ultralytics )

    • 并行分支结构
      • 检测头有 两个主要的分支 ,分别用于 预测目标的边界框 类别信息 。每个分支都包含一系列的卷积层,通过并行的方式对特征进行处理,最后将两个分支的结果进行合并。这种结构可以更高效地提取特征,提高检测的准确性。
    • 动态调整
      • 具有动态调整的能力,可以根据输入图像的特点和模型的训练状态自动调整检测头的参数,进一步提高了模型的性能和适应性。
  2. YOLOv9的检测头 :(论文地址: https://arxiv.org/pdf/2402.13616.pdf )

    • YOLOv9的检测头与v8一致。
  3. YOLOv10的检测头 :(论文地址: https://arxiv.org/pdf/2405.14458 )

  • YOLOv10的检测头使用了无 NMS 的一致双分配的训练策略,主要包括 双标签分配 一致匹配度量 两个关键部分,具体如下:

  • 双标签分配

    • 一对一分配(one-to-one matching) :在训练过程中,仅一个预测框被分配给一个真实物体标签。这种方式避免了非极大值抑制(NMS)的后处理操作,使得在推理阶段可以更加高效地得到预测结果。但是,一对一分配存在一定的局限性,它可能会导致弱监督的问题,使得模型的精度欠佳,并且影响模型的收敛速度。
    • 一对多分配(one-to-many matching) :与一对一分配不同,一对多分配在训练期间允许多个预测框被分配给一个真实物体标签。这种策略能够为模型提供丰富的监督信号,让模型学习到更多的目标特征和模式,从而优化效果更好。通过一对多分配,模型可以更好地处理目标的多样性和复杂性,提高对不同场景下目标的检测能力。
    • 双头架构 :为了充分利用两种分配策略的优势,YOLOv10 在训练期间使用两个预测头,一个采用一对多分配,另一个采用一对一分配。这样的架构设计使得模型在训练时能够同时受益于丰富的监督信号和高效的推理方式。在训练过程中,骨干网络和颈部网络可以从一对多分配的预测头中获得丰富的监督信息,从而更好地学习目标的特征;而在推理阶段,则可以利用一对一分配的预测头,快速且无额外计算成本地得到预测结果,避免了 NMS 带来的延迟。
  • 一致匹配度量

    • 为了实现两个分支的预测感知匹配,作者提出了一致匹配度量。在训练过程中,通过调整匹配度量的参数,使得一对一分配和一对多分配的监督信号保持一致。这样可以减少两个分配策略之间的监督差距,避免模型在训练过程中因为不同的分配策略而产生混淆或不稳定的情况。
    • 一致匹配度量能够确保一个分配策略中的最佳样本在另一个分配策略中也是最佳的,从而使两个分支的预测结果更加一致和准确。通过这种方式,模型可以更好地融合两种分配策略的优点,提高整体的预测质量。

在这里插入图片描述

  1. YOLOv11的检测头 :(代码地址: https://github.com/ultralytics/ultralytics )
  • YOLOv11 的检测头同样与 v8 类似,只是在 类别损失分支 中使用 深度可分离卷积 替代常规卷积降低计算量。