YOLO简介

YOLO系列是one-stage且是基于深度学习的回归方法,而R-CNN、Fast-RCNN、Faster-RCNN等是two-stage且是基于深度学习的分类方法。

YOLO的最大优点是快而准,而且识别能力强。


YOLO的使用

YOLO版本的选择

这里我们使用了YOLOv8的版本,YOLOv8在YOLOv5,在识别和训练的速度上都有了很大的提升。

YOLOv8整合在了Ultralytics项目中。

YOLOv8相关源码的下载需要在这里下载:

ultralytics: YOLOv8 🚀 Ultralytics 同步更新官方最新版 YOLOv8 (gitee.com)

下载后,我们主要是使用cfg/models目录如下:

ultralytics/cfg/models
|-- README.md
|-- rt-detr
|   |-- rtdetr-l.yaml                   # 百度的 RT-DETR 目标检测模型(L 规格),使用的后处理模块为 Detect,使用的预测特征图为 P3, P4, P5
|   |-- rtdetr-x.yaml                   # 百度的 RT-DETR 目标检测模型(X 规格),使用的后处理模块为 Detect,使用的预测特征图为 P3, P4, P5
|   |-- rtdetr-resnet101.yaml           # Backbone 使用 ResNet101 的 RE-DETR 目标检测模型,使用的后处理模块为 Detect,使用的预测特征图为 P3, P4, P5
|   `-- rtdetr-resnet50.yaml            # Backbone 使用 ResNet50  的 RE-DETR 目标检测模型,使用的后处理模块为 Detect,使用的预测特征图为 P3, P4, P5
|-- v3
|   |-- yolov3.yaml                     # YOLOv3 目标检测模型,使用的后处理模块为 Detect,使用的预测特征图为 P3, P4, P5
|   |-- yolov3-tiny.yaml                # YOLOv3 目标检测模型(Tiny 规格),使用的后处理模块为 Detect,💡  使用的预测特征图为 P4, P5,从原来擅长“小中大”目标变为“中大”目标
|   `-- yolov3-spp.yaml                 # 加入 SPP 的 YOLOv3 目标检测模型,使用的后处理模块为 Detect,使用的预测特征图为 P3, P4, P5
|-- v5
|   |-- yolov5.yaml                     # YOLOv5 目标检测模型(可选规格有:n、s、m、l、x),使用的后处理模块为 Detect,使用的预测特征图为 P3, P4, P5
|   `-- yolov5-p6.yaml                  # YOLOv5-p6 目标检测模型(可选规格有:n、s、m、l、x),使用的后处理模块为 Detect,💡  使用的预测特征图为 P3, P4, P5, P6,加强对大目标的检测能力
|-- v6
|   `-- yolov6.yaml                     # YOLOv6 目标检测模型(可选规格有:n、s、m、l、x),使用的后处理模块为 Detect,使用的预测特征图为 P3, P4, P5
|-- v8
|   |-- yolov8.yaml                     # YOLOv8 目标检测模型(可选规格有:n、s、m、l、x),使用的后处理模块为 Detect,使用的预测特征图为 P3, P4, P5
|   |-- yolov8-p2.yaml                  # YOLOv8 目标检测模型(可选规格有:n、s、m、l、x),使用的后处理模块为 Detect,使用的预测特征图为 P2, P3, P4, P5,增加对小目标的检测能力
|   |-- yolov8-p6.yaml                  # YOLOv8 目标检测模型(可选规格有:n、s、m、l、x),使用的后处理模块为 Detect,使用的预测特征图为 P3, P4, P5, P6,增加对大目标的检测能力
|   |-- yolov8-ghost.yaml               # YOLOv8 目标检测模型(可选规格有:n、s、m、l、x),使用的后处理模块为 Detect,使用的卷积是 GhostConv 和 C3Ghost,使用的预测特征图为 P3, P4, P5
|   |-- yolov8-ghost-p2.yaml            # YOLOv8 目标检测模型(可选规格有:n、s、m、l、x),使用的后处理模块为 Detect,使用的卷积是 GhostConv 和 C3Ghost,使用的预测特征图为 P2, P3, P4, P5,增加了对小目标的检测能力
|   |-- yolov8-ghost-p6.yaml            # YOLOv8 目标检测模型(可选规格有:n、s、m、l、x),使用的后处理模块为 Detect,使用的卷积是 GhostConv 和 C3Ghost,使用的预测特征图为 P3, P4, P5, P6,增加了对大目标的检测能力
|   |-- yolov8-cls.yaml                 # YOLOv8 分类模型(可选规格有:n、s、m、l、x),使用的后处理模块为 Classify
|   |-- yolov8-cls-resnet50.yaml        # YOLOv8 分类模型(可选规格有:n、s、m、l、x),使用的后处理模块为 Classify,使用的 Backbone 为 ResNet50
|   |-- yolov8-cls-resnet101.yaml       # YOLOv8 分类模型(可选规格有:n、s、m、l、x),使用的后处理模块为 Classify,使用的 Backbone 为 ResNet101
|   |-- yolov8-seg.yaml                 # YOLOv8 分割模型(可选规格有:n、s、m、l、x),使用的后处理模块为 Segment,使用的预测特征图为 P3, P4, P5
|   |-- yolov8-seg-p6.yaml              # YOLOv8 分割模型(可选规格有:n、s、m、l、x),使用的后处理模块为 Segment,使用的预测特征图为 P3, P4, P5, P6,增加对大目标的分割能力
|   |-- yolov8-obb.yaml                 # YOLOv8 旋转目标检测模型(可选规格有:n、s、m、l、x),使用的后处理模块为 OBB,使用的预测特征图为 P3, P4, P5
|   |-- yolov8-pose.yaml                # YOLOv8 关键点/人体姿态估计模型(可选规格有:n、s、m、l、x),使用的后处理模块为 Pose,使用的预测特征图为 P3, P4, P5
|   |-- yolov8-pose-p6.yaml             # YOLOv8 关键点/人体姿态估计模型(可选规格有:n、s、m、l、x),使用的后处理模块为 Pose,使用的预测特征图为 P3, P4, P5, P6,增加对大目标的估计能力
|   |-- yolov8-rtdetr.yaml              # YOLOv8 加上 RT-DETR 的目标检测模型(可选规格有:n、s、m、l、x),使用的后处理模块为 RTDETRDecoder,使用的预测特征图为 P3, P4, P5
|   |-- yolov8-world.yaml               # YOLOv8 加上 YOLO-World 的目标检测模型(可选规格有:n、s、m、l、x),使用的后处理模块为 WorldDetect,head 部分与 YOLOv8 差异较大,使用的预测特征图为 P3, P4, P5,❌ 不支持导出为 ONNX,mAP 低于 YOLOv8-Worldv2
|   `-- yolov8-worldv2.yaml             # 🌟  YOLOv8 加上 YOLO-World 的目标检测模型(可选规格有:n、s、m、l、x),使用的后处理模块为 WorldDetect,head 部分与 YOLOv8 差异较大,与 YOLOv8-World 也有一些区别,使用的预测特征图为 P3, P4, P5,✅ 支持导出为 ONNX,mAP 高于 YOLOv8-World
`-- v9
    |-- yolov9c.yaml                    # YOLOv6 目标检测模型(规格为 C,t->s->m->c->e),使用的后处理模块为 Detect,使用的预测特征图为 P3, P4, P5
    `-- yolov9e.yaml                    # YOLOv6 目标检测模型(规格为 E,t->s->m->c->e),使用的后处理模块为 Detect,使用的预测特征图为 P3, P4, P5
    |-- yolov9c-seg.yaml                # YOLOv6 分割模型(规格为 C,t->s->m->c->e),使用的后处理模块为 Segment,使用的预测特征图为 P3, P4, P5
    `-- yolov9e-seg.yaml                # YOLOv6 分割模型(规格为 E,t->s->m->c->e),使用的后处理模块为 Segment,使用的预测特征图为 P3, P4, P5

Ultralytics 整合了 YOLOv6、YOLOv9、YOLOv8-World、百度的 RT-DETR。

安装

pip install ultralytics -i https://pypi.tuna.tsinghua.edu.cn/simple

模型训练

模型训练我们需要一个X-AnyLabeling,为我们标记我们要识别的目标。

使用YOLO框架实现物品识别功能_YOLO

我们可以给每个图片都加上标注:

使用YOLO框架实现物品识别功能_目标检测_02

全部加好后,使用labelme2yolo,可以把标记结果,转换成yolo的训练模型。

使用YOLO框架实现物品识别功能_CV_03

我们要把生成的文件放在datasets目录下:

使用YOLO框架实现物品识别功能_CV_04

我们使用yolov8.yaml进行训练,yolov8.yaml文件详解如下:

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

# Parameters
nc: 80  # 类别数目,nc代表"number of classes",即模型用于检测的对象类别总数。 80表示该模型配置用于检测80种不同的对象。由于默认使用COCO数据集,这里nc=80;
scales: # 模型复合缩放常数,用于定义模型的不同尺寸和复杂度。例如 'model=yolov8n.yaml' 将调用带有 'n' 缩放的 yolov8.yaml
  # [depth, width, max_channels]
  n: [0.33, 0.25, 1024]  # YOLOv8n概览:225层, 3157200参数, 3157184梯度, 8.9 GFLOPs
  s: [0.33, 0.50, 1024]  # YOLOv8s概览:225层, 11166560参数, 11166544梯度, 28.8 GFLOPs
  m: [0.67, 0.75, 768]   # YOLOv8m概览:295层, 25902640参数, 25902624梯度, 79.3 GFLOPs
  l: [1.00, 1.00, 512]   # YOLOv8l概览:365层, 43691520参数, 43691504梯度, 165.7 GFLOPs
  x: [1.00, 1.25, 512]   # YOLOv8x概览:365层, 68229648参数, 68229632梯度, 258.5 GFLOPs

# YOLOv8.0n backbone 骨干层
backbone:
  # [from, repeats, module, args]
  - [-1, 1, Conv, [64, 3, 2]]  # 0-P1/2 第0层,-1代表将上层的输出作为本层的输入。第0层的输入是640*640*3的图像。Conv代表卷积层,相应的参数:64代表输出通道数,3代表卷积核大小k,2代表stride步长。卷积后输出的特征图尺寸为320*320*64,长宽为初始图片的1/2
  - [-1, 1, Conv, [128, 3, 2]]  # 1-P2/4 第1层,本层和上一层是一样的操作(128代表输出通道数,3代表卷积核大小k,2代表stride步长)。卷积后输出的特征图尺寸为160*160*128,长宽为初始图片的1/4
  - [-1, 3, C2f, [128, True]] # 第2层,本层是C2f模块,3代表本层重复3次。128代表输出通道数,True表示Bottleneck有shortcut。输出的特征图尺寸为160*160*128。
  - [-1, 1, Conv, [256, 3, 2]]  # 3-P3/8 第3层,进行卷积操作(256代表输出通道数,3代表卷积核大小k,2代表stride步长),输出特征图尺寸为80*80*256(卷积的参数都没变,所以都是长宽变成原来的1/2,和之前一样),特征图的长宽已经变成输入图像的1/8。
  - [-1, 6, C2f, [256, True]] # 第4层,本层是C2f模块,可以参考第2层的讲解。6代表本层重复6次。256代表输出通道数,True表示Bottleneck有shortcut。经过这层之后,特征图尺寸依旧是80*80*256。
  - [-1, 1, Conv, [512, 3, 2]]  # 5-P4/16 第5层,进行卷积操作(512代表输出通道数,3代表卷积核大小k,2代表stride步长),输出特征图尺寸为40*40*512(卷积的参数都没变,所以都是长宽变成原来的1/2,和之前一样),特征图的长宽已经变成输入图像的1/16。
  - [-1, 6, C2f, [512, True]] # 第6层,本层是C2f模块,可以参考第2层的讲解。6代表本层重复6次。512代表输出通道数,True表示Bottleneck有shortcut。经过这层之后,特征图尺寸依旧是40*40*512。
  - [-1, 1, Conv, [1024, 3, 2]]  # 7-P5/32 第7层,进行卷积操作(1024代表输出通道数,3代表卷积核大小k,2代表stride步长),输出特征图尺寸为20*20*1024(卷积的参数都没变,所以都是长宽变成原来的1/2,和之前一样),特征图的长宽已经变成输入图像的1/32。
  - [-1, 3, C2f, [1024, True]] #第8层,本层是C2f模块,可以参考第2层的讲解。3代表本层重复3次。1024代表输出通道数,True表示Bottleneck有shortcut。经过这层之后,特征图尺寸依旧是20*20*1024。
  - [-1, 1, SPPF, [1024, 5]]  # 9 第9层,本层是快速空间金字塔池化层(SPPF)。1024代表输出通道数,5代表池化核大小k。结合模块结构图和代码可以看出,最后concat得到的特征图尺寸是20*20*(512*4),经过一次Conv得到20*20*1024。

# YOLOv8.0n head 头部层
head:
  - [-1, 1, nn.Upsample, [None, 2, 'nearest']] # 第10层,本层是上采样层。-1代表将上层的输出作为本层的输入。None代表上采样的size=None(输出尺寸)不指定。2代表scale_factor=2,表示输出的尺寸是输入尺寸的2倍。mode=nearest代表使用的上采样算法为最近邻插值算法。经过这层之后,特征图的长和宽变成原来的两倍,通道数不变,所以最终尺寸为40*40*1024。
  - [[-1, 6], 1, Concat, [1]]  # cat backbone P4 第11层,本层是concat层,[-1, 6]代表将上层和第6层的输出作为本层的输入。[1]代表concat拼接的维度是1。从上面的分析可知,上层的输出尺寸是40*40*1024,第6层的输出是40*40*512,最终本层的输出尺寸为40*40*1536。
  - [-1, 3, C2f, [512]]  # 12 第12层,本层是C2f模块,可以参考第2层的讲解。3代表本层重复3次。512代表输出通道数。与Backbone中C2f不同的是,此处的C2f的bottleneck模块的shortcut=False。

  - [-1, 1, nn.Upsample, [None, 2, 'nearest']] # 第13层,本层也是上采样层(参考第10层)。经过这层之后,特征图的长和宽变成原来的两倍,通道数不变,所以最终尺寸为80*80*512。
  - [[-1, 4], 1, Concat, [1]]  # cat backbone P3 第14层,本层是concat层,[-1, 4]代表将上层和第4层的输出作为本层的输入。[1]代表concat拼接的维度是1。从上面的分析可知,上层的输出尺寸是80*80*512,第6层的输出是80*80*256,最终本层的输出尺寸为80*80*768。
  - [-1, 3, C2f, [256]]  # 15 (P3/8-small) 第15层,本层是C2f模块,可以参考第2层的讲解。3代表本层重复3次。256代表输出通道数。经过这层之后,特征图尺寸变为80*80*256,特征图的长宽已经变成输入图像的1/8。

  - [-1, 1, Conv, [256, 3, 2]] # 第16层,进行卷积操作(256代表输出通道数,3代表卷积核大小k,2代表stride步长),输出特征图尺寸为40*40*256(卷积的参数都没变,所以都是长宽变成原来的1/2,和之前一样)。
  - [[-1, 12], 1, Concat, [1]]  # cat head P4 第17层,本层是concat层,[-1, 12]代表将上层和第12层的输出作为本层的输入。[1]代表concat拼接的维度是1。从上面的分析可知,上层的输出尺寸是40*40*256,第12层的输出是40*40*512,最终本层的输出尺寸为40*40*768。
  - [-1, 3, C2f, [512]]  # 18 (P4/16-medium) 第18层,本层是C2f模块,可以参考第2层的讲解。3代表本层重复3次。512代表输出通道数。经过这层之后,特征图尺寸变为40*40*512,特征图的长宽已经变成输入图像的1/16。

  - [-1, 1, Conv, [512, 3, 2]] # 第19层,进行卷积操作(512代表输出通道数,3代表卷积核大小k,2代表stride步长),输出特征图尺寸为20*20*512(卷积的参数都没变,所以都是长宽变成原来的1/2,和之前一样)。
  - [[-1, 9], 1, Concat, [1]]  # cat head P5 第20层,本层是concat层,[-1, 9]代表将上层和第9层的输出作为本层的输入。[1]代表concat拼接的维度是1。从上面的分析可知,上层的输出尺寸是20*20*512,第9层的输出是20*20*1024,最终本层的输出尺寸为20*20*1536。
  - [-1, 3, C2f, [1024]]  # 21 (P5/32-large) 第21层,本层是C2f模块,可以参考第2层的讲解。3代表本层重复3次。1024代表输出通道数。经过这层之后,特征图尺寸变为20*20*1024,特征图的长宽已经变成输入图像的1/32。

  - [[15, 18, 21], 1, Detect, [nc]]  # Detect(P3, P4, P5) 第20层,本层是Detect层,[15, 18, 21]代表将第15、18、21层的输出(分别是80*80*256、40*40*512、20*20*1024)作为本层的输入。nc是数据集的类别数。

再增加dataset.yaml文件,用来指明训练文件的位置和数据分类

train: images/train/
val: images/val/
test: images/test/
nc: 1
names: ["laili"]

使用:

yolo task=detect mode=train model=yolov8.yaml data=dataset.yaml epochs=300 batch=1 save=true workers=0 device=0

就可以开始模型训练了,我这里使用了epoches使用了300。

训练结果放在下面的文件夹中:

使用YOLO框架实现物品识别功能_目标检测_05

使用YOLO框架实现物品识别功能_CV_06

从结果可以看出box_loss,训练完成后,值只有1左右,已经符合检测的能力了。

使用训练好的模型进行检测任务

yolo task=detect mode=predict model=mymodel/last.pt source=test/img.png
E:\code\test\python\yolov8>yolo task=detect mode=predict model=mymodel/best.pt source=test/img.png
Ultralytics YOLOv8.2.35 🚀 Python-3.8.19 torch-2.3.0 CUDA:0 (Quadro P2000, 5120MiB)
D:\Anaconda3\envs\cv\lib\site-packages\torch\nn\modules\conv.py:456: UserWarning: Plan failed with a cudnnException: CUDNN_BACKEND_EXECUTION_PLAN_DESCRIPTOR: cudnnFinalize Descriptor Failed cudnn_status: CUDNN_STATUS_NOT_SUPPORTED (Triggered internally at C:\cb\pytorch_1000000000000\work\aten\src\ATen\native\cudnn\Conv_v8.cpp:919.)
  return F.conv2d(input, weight, bias, self.stride,
YOLOv8 summary (fused): 168 layers, 3005843 parameters, 0 gradients, 8.1 GFLOPs

image 1/1 E:\code\test\python\yolov8\test\img.png: 448x640 1 laili, 32.2ms
Speed: 2.0ms preprocess, 32.2ms inference, 2.0ms postprocess per image at shape (1, 3, 448, 640)
Results saved to runs\detect\predict4
💡 Learn more at https://docs.ultralytics.com/modes/predict

执行完成,这里提示结果保存在predict4文件夹中了,在文件中,我们找到结果图片:

使用YOLO框架实现物品识别功能_YOLO_07

这里我们让它检测小女孩的头,它成功检测出来了。

使用官方的模型进行检测

我们要在官方下载模型。

https://github.com/ultralytics/assets/releases/download/v8.2.0/yolov8n.pt

https://github.com/ultralytics/assets/releases/download/v8.2.0/yolov8s.pt

https://github.com/ultralytics/assets/releases/download/v8.2.0/yolov8m.pt

https://github.com/ultralytics/assets/releases/download/v8.2.0/yolov8l.pt

https://github.com/ultralytics/assets/releases/download/v8.2.0/yolov8x.pt

不同的后缀表示不同的模型规模,具体如下:

Model

size

(pixels)

mAPval
50-95

Speed

CPU ONNX
(ms)

Speed

A100 TensorRT
(ms)

params

(M)

FLOPs

(B)

YOLOv8n

640

37.3

80.4

0.99

3.2

8.7

YOLOv8s

640

44.9

128.4

1.20

11.2

28.6

YOLOv8m

640

50.2

234.7

1.83

25.9

78.9

YOLOv8l

640

52.9

375.2

2.39

43.7

165.2

YOLOv8x

640

53.9

479.1

3.53

68.2

257.8

这里我们选择n模式的,速度是最快的。

使用命令:

yolo task=detect mode=predict model=yolov8n.pt source=test/1.png

识别的结果:

使用YOLO框架实现物品识别功能_YOLO_08

结语

YOLO框架是一个优秀的CV框架,简单易用。现在清华大学在YOLO的基础上,推出了YOLOv10,比YOLOv8更加强大,以后我也会继续学习。