Bootstrap

YOLOV11改进1-检测头篇


前言

    目标检测领域里,小目标一直是一个难点问题,虽然我们可以用YOLO+SAHI的方式进行滑动窗口推理以提升准确率,但是他的耗时会线性增强,毕竟一张大图会被切成很多小图去推理,所以在很多场景下无法得到应用。这里,我们从探测头入手,在原有的基础上在增加一个探测头以用于检测小目标。本篇以YOLOV11作为示例。


一、YAML修改

    YOLO的原理讲解网上一大堆,这里不做说明,想了解的可以去找度娘了解下,这里直接开始修改网络结构。
原始的YAML文件(ultralytics/cfg/models/11/yolo11.yaml)如下:

# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLO11 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect

# Parameters
nc: 80 # number of classes
scales: # model compound scaling constants, i.e. 'model=yolo11n.yaml' will call yolo11.yaml with scale 'n'
  # [depth, width, max_channels]
  n: [0.50, 0.25, 1024] # summary: 319 layers, 2624080 parameters, 2624064 gradients, 6.6 GFLOPs
  s: [0.50, 0.50, 1024] # summary: 319 layers, 9458752 parameters, 9458736 gradients, 21.7 GFLOPs
  m: [0.50, 1.00, 512] # summary: 409 layers, 20114688 parameters, 20114672 gradients, 68.5 GFLOPs
  l: [1.00, 1.00, 512] # summary: 631 layers, 25372160 parameters, 25372144 gradients, 87.6 GFLOPs
  x: [1.00, 1.50, 512] # summary: 631 layers, 56966176 parameters, 56966160 gradients, 196.0 GFLOPs

# YOLO11n backbone
backbone:
  # [from, repeats, module, args]
  - [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
  - [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
  - [-1, 2, C3k2, [256, False, 0.25]]
  - [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
  - [-1, 2, C3k2, [512, False, 0.25]]
  - [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
  - [-1, 2, C3k2, [512, True]]
  - [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
  - [-1, 2, C3k2, [1024, True]]
  - [-1, 1, SPPF, [1024, 5]] # 9
  - [-1, 2, C2PSA, [1024]] # 10

# YOLO11n head
head:
  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 6], 1, Concat, [1]] # cat backbone P4
  - [-1, 2, C3k2, [512, False]] # 13

  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 4], 1, Concat, [1]] # cat backbone P3
  - [-1, 2, C3k2, [256, False]] # 16 (P3/8-small)

  - [-1, 1, Conv, [256, 3, 2]]
  - [[-1, 13], 1, Concat, [1]] # cat head P4
  - [-1, 2, C3k2, [512, False]] # 19 (P4/16-medium)

  - [-1, 1, Conv, [512, 3, 2]]
  - [[-1, 10], 1, Concat, [1]] # cat head P5
  - [-1, 2, C3k2, [1024, True]] # 22 (P5/32-large)

  - [[16, 19, 22], 1, Detect, [nc]] # Detect(P3, P4, P5)

建议将原始的yaml文件copy一份,然后在进行修改,不要直接在原来的yaml中修改
增加检测头不需要要额外添加代码,只需对yaml更改即可,更改后的yaml如下:

# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLO11 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect

# Parameters
nc: 80 # number of classes
scales: # model compound scaling constants, i.e. 'model=yolo11n.yaml' will call yolo11.yaml with scale 'n'
  # [depth, width, max_channels]
  n: [0.50, 0.25, 1024] # summary: 319 layers, 2624080 parameters, 2624064 gradients, 6.6 GFLOPs
  s: [0.50, 0.50, 1024] # summary: 319 layers, 9458752 parameters, 9458736 gradients, 21.7 GFLOPs
  m: [0.50, 1.00, 512] # summary: 409 layers, 20114688 parameters, 20114672 gradients, 68.5 GFLOPs
  l: [1.00, 1.00, 512] # summary: 631 layers, 25372160 parameters, 25372144 gradients, 87.6 GFLOPs
  x: [1.00, 1.50, 512] # summary: 631 layers, 56966176 parameters, 56966160 gradients, 196.0 GFLOPs

# YOLO11n backbone
backbone:
  # [from, repeats, module, args]
  - [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
  - [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
  - [-1, 2, C3k2, [256, False, 0.25]]
  - [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
  - [-1, 2, C3k2, [512, False, 0.25]]
  - [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
  - [-1, 2, C3k2, [512, True]]
  - [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
  - [-1, 2, C3k2, [1024, True]]
  - [-1, 1, SPPF, [1024, 5]] # 9
  - [-1, 2, C2PSA, [1024]] # 10

# YOLO11n head
head:
  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 6], 1, Concat, [1]] # cat backbone P4
  - [-1, 2, C3k2, [512, False]] # 13

  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 4], 1, Concat, [1]] # cat backbone P3
  - [-1, 2, C3k2, [256, False]] # 16 (P3/8-small)

  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1,2], 1, Concat, [1]] # cat head P2
  - [-1, 2, C3k2, [128, False]] # 19 (P2/4-xsmall)

  - [-1, 1, Conv, [128, 3, 2]]
  - [[-1, 16], 1, Concat, [1]] # cat head P3
  - [-1, 2, C3k2, [256, False]] # 22 (P4/16-medium)

  - [-1, 1, Conv, [256, 3, 2]]
  - [[-1, 13], 1, Concat, [1]] # cat head P4
  - [-1, 2, C3k2, [512, False]] # 25 (P4/16-medium)

  - [-1, 1, Conv, [512, 3, 2]]
  - [[-1, 10], 1, Concat, [1]] # cat head P5
  - [-1, 2, C3k2, [1024, True]] # 28 (P5/32-large)

  - [[19, 22, 25, 28], 1, Detect, [nc]] # Detect(P2, P3, P4, P5)

主要的修改部分在head部分,具体如下图:
在这里插入图片描述

到这里我们便完成了结构的修改,接下来我们开始训练。

二、模型训练

1.数据集准备

  数据集的话,我们用常规的VOC或者COCO格式均可。由于我的小目标数据集不方便公开,所以这里就不给链接了,我的数据分布大致如下:
在这里插入图片描述
  由上图可知,我的数据集里都为小目标,你可以想象成在一张640*480大小的图里有一个网球之类(距离较远)的。接下来,我们基于这个数据集看下改进后的效果

2.环境准备

  能进行网络修改,说明搭建一个yolo的环境对你来说不是个问题,这里也不详细展开,只挑重点说明。

  • torch:请根据你的电脑环境安装对应的pytorch版本,注意torchvision版本也要对应上,建议根据pytorch官方文档里进行安装。
  • 在你的虚拟环境里最好不要安装官方封装好的ultralytics包,否则即使你改了代码也不会生效。比如你增加了注意力机制、改了Loss等。
  • 其他依赖直接缺啥装啥即可。

3.训练

这里为了对比,我们分别拿原始结构和更改后的结构进行训练。

3.1原结构训练

yolov11的代码早已封装的很简单,所以直接运行以下代码即可开始训练。请注意,涉及到的模型路径、data.yaml路径、batchsize均需要根据自己的实际情况进行修改。为快速得到结果,这里只训练了100轮。

from ultralytics import YOLO

model=YOLO(model="./yolo11n.pt")  #加载预训练模型
model.train(data="./mydatasets.yaml",epochs=100,imgsz=[640,640],batch=32) 

部分训练日志如下:
在这里插入图片描述

3.2更改后的模型

更改后的训练代码如下: 和3.1注意事项相同,均需将涉及到的路径改为自己的,这里的yolo11-p2.yaml就是我复制一份修改后的网路结构。

from ultralytics import YOLO

model=YOLO(model="./ultralytics/cfg/models/11/updete/yolo11-p2.yaml").load("./yolo11n.pt")  
model.train(data="./mydatasets.yaml",epochs=100,imgsz=[640,640],batch=32) 

部分训练日志如下:
在这里插入图片描述
由红框可见,我们的修改是生效的。

三.效果对比

1.原始结构

原始结构的训练结果如下图:
在这里插入图片描述
PR结果图如下:
在这里插入图片描述

2.修改后的结果

修改后的训练结果如下所示:
在这里插入图片描述
PR结果图如下所示:
在这里插入图片描述
由图可见,涨点是非常明显的。

3.详细对比

网络结构模型大小训练时间PRmap50map50-95
原始结构5.5M0.338 h0.7290.2180.290.114
增加探测头5.8M0.501 h0.8180.3530.4190.171

  由此可知,追加探测头后,模型的性能均得到了大幅提升,同时它也引入了新的问题,那就是模型参数量变大、训练时间变长。所以,如果你的场景对模型大小有严格要求,还需在此基础上进行模型轻量化尝试,如剪枝、量化等。


总结

以上就是本篇的全部内容,如有问题,欢迎评论区交流,或+企鹅群:995760755交流;如觉得有用,欢迎三连

;