介绍

计算机视觉有两大模型类别,目标分类模型与目标检测模型,前者输入一张图片,输出的是对这张照片的类型判定,而目标检测更深一步,不仅要标识出目标的类型还要标识出其位置。
yolo(You Only Look Once)便是一个非常优秀的目标检测模型,本文以其v5版本讲解。

获取官方代码

在github上的官方页面中,我们在左上角选择master,在其下拉属性中可选择分支与tags,我们按照tag选择,笔者选择的为v7.0版本,右上角点击CODE,在下拉菜单点击”Download ZIP”可将文件打包下载,解压到自己的项目文件夹,注意目录不要有中文,否则opencv等库可能会崩溃。

软件需求

需要用的软件有:pycharm、anaconda,具体安装教程可在网上查找,安装完成后,由于目前中国大陆境内对国际网的访问时常被阻断,而anaconda需要访问假设在国外的服务器来获取python包,我们需要将anaconda的目标服务器设置为国内的镜像源,使用以下指令切换为中国科技大学的镜像源:

1
2
3
4
5
6
7
conda config --remove-key channels
conda config --add channels https://mirrors.ustc.edu.cn/anaconda/pkgs/main/
conda config --add channels https://mirrors.ustc.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.bfsu.edu.cn/anaconda/cloud/pytorch/
conda config --set show_channel_urls yes
pip config set global.index-url https://mirrors.ustc.edu.cn/pypi/web/simple


如果使用的是Nvidia的显卡,在cmd中输入nvidia-smi查看本地cuda的版本,如果提示没有此命令请上网搜索显卡驱动的安装,虽然YOLOv5支持cpu运算,但是慢得令人发指,在笔者的笔记本电脑上显卡的运算效率为cpu的十倍以上。

环境配置

创建虚拟环境

需要在anaconda里面创建虚拟环境,防止不同版本的机器学习框架pytorch互相影响:

1
2
conda creat -n YOLOv5 python=3.8.5
conda activate YOLOv5

配置相关软件包

  1. pytorch
    这是一个深度学习框架,在Pytoch官网中可以找到安装的指令,笔者使用的是1.8的旧版,注意30系以上显卡要使用CUDA11.1,指令如下:
1
2
3
4
5
6
7
8
# CUDA 10.2
conda install pytorch==1.8.0 torchvision==0.9.0 torchaudio==0.8.0 cudatoolkit=10.2 -c pytorch

# CUDA 11.1
conda install pytorch==1.8.0 torchvision==0.9.0 torchaudio==0.8.0 cudatoolkit=11.1 -c pytorch -c conda-forge

# CPU Only
conda install pytorch==1.8.0 torchvision==0.9.0 torchaudio==0.8.0 cpuonly -c pytorch
  1. 数据处理软件
    pycocotools:用于处理COCO数据集,labelme:标记图片数据,安装指令:

    1
    2
    pip install pycocotools-windows
    pip install labelme
  2. 安装环境
    在从github中下载的文件中,有一个名为”requirements.txt”的文件,里面存放的就是YOLOv5所需的包目录,我们并不需要手动逐一安装,使用该指令:

    1
    pip install -r requirements.txt

    你可能会问,既然能够通过这个txt文件一次安装完,为什么前面几个模块不写在txt里而要手动安装?原因是这两个模块应用广泛,在使用yolo前,可能环境中已经安装了符合用户要求的版本,创作者为了让yolo有更好地适配使用者的项目,故而不对这两个模块进行收录。

使用官方模型识别

我们可以直接使用detect.py文件,参数也很明显,一个是需要识别的文件,一个是所要调用的权重文件(即模型),结果保留在runs\detect中

1
python detect.py --source data/images/bus.jpg --weights pretrained/yolov5s.pt

在官方给出的例程中,还有如下代码,除了图片外,还可以实现对摄像头、视频等进行识别预测:
1
2
3
4
5
6
7
python detect.py --source 0  # webcam
file.jpg # image
file.mp4 # video
path/ # directory
path/*.jpg # glob
'https://youtu.be/NUsoVlDFqZg' # YouTube video
'rtsp://example.com/media.mp4' # RTSP, RTMP, HTTP stream

训练自己的模型

上面我们调用了官方的模型来进行识别,现在我们来研究怎么训练出自己的模型

数据处理

训练集文档结构:

1
2
3
4
5
6
7
8
9
├── score
├─ images
│ ├─ test # 下面放测试集图片
│ ├─ train # 下面放训练集图片
│ └─ val # 下面放验证集图片
└─ labels
├─ test # 下面放测试集标签
├─ train # 下面放训练集标签
├─ val # 下面放验证集标签

参考博文

开始训练

参数调节

参考博文

Yolov5在嵌入式平台的使用

Yolo官方使用的是.pt模型,是 PyTorch 的模型文件扩展名,通常包含了模型的结构以及训练后的权重。这种格式是特定于 PyTorch 的,主要用于在 PyTorch 环境中加载和运行模型。
而在嵌入式领域中,需要将其转换为更普遍的模型.onnx,ONNX 是一个开放的模型格式,用于在不同的深度学习框架之间转移和部署模型。它是框架无关的,意味着一个以ONNX 格式保存的模型可以在任何支持 ONNX 的平台上加载和执行,不论这个模型最初是在哪个框架下创建的。
常用的嵌入式领域模型:瑞星微的rknn,用于适配其其下芯片的npu,如rk1103;ncnn,是一个为移动端和边缘设备优化的高性能神经网络推理框架。

竞赛经历

在DoubleQ中,成功训练出气球模型,在此对相关文件进行留存

  1. 数据集配置文件
    /yolov5-7.0/data/balloon_data.yaml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # Custom data for safety helmet


    # train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/]
    train: balloon_dataset/balloon/images/train/ # 训练集位置
    val: balloon_dataset/balloon/images/val/ # 验证集位置

    # number of classes
    nc: 1 # 数据集类别

    # class names
    names: ['balloon'] # 目标名称
  2. 模型配置文件
    /yolov5-7.0/models/balloon_yolov5s.yaml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    # YOLOv5 🚀 by Ultralytics, GPL-3.0 license

    # Parameters
    nc: 1 # number of classes
    depth_multiple: 0.33 # model depth multiple
    width_multiple: 0.50 # layer channel multiple
    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 v6.0 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]], # 9
    ]

    # YOLOv5 v6.0 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)
    ]