当前位置:   article > 正文

YOLOV8的应用和思考(2)---YOLOV8训练自己的数据集(在线版,本地版)_yolo8模型的应用和训练

yolo8模型的应用和训练

YOLOV8的应用和思考(2)—YOLOV8训练自己的数据集

第一章 初识YOLOV8到上手
第二章 YOLOV8训练自己的数据集

第n章 YOLOV8的部署和应用



前言

上一章分享了yolov8环境的搭建,并且我们跑了一些简单的预测,感受到了yolov8的魅力。接下来我们在项目中大概率会对模型识别的物体有客制化的要求,这时我们就需要自己训练自己的yolo模型,在这一篇中我想给大家分享我训练模型的workflow,并且告知大家我在训练模型时遇到的问题和我自己的解决方法。

补充上篇

如果在环境安装中遇到了ERROR: Could not build wheels for psutil, which is required to install pyproject.toml-based projects
这样的报错以至于有些库无法正确的安装的问题,这是因为电脑此时没有c++编译环境,而这些库是c++ base的库,所以请参考pip 安装报错 required to install pyproject.toml-based projects这篇文章,请注意安装的位置:
在这里插入图片描述
安装的位置在安装前可以修改,但是开始安装之后再想修改好像就没有那么方便了,c盘的空间嘎去两个多G心疼的很。


提示:以下是本篇文章正文内容,下面案例可供参考

一、YOLOV8训练的标注文件的数据结构

在我们开始了解训练流程之前,我想向大家介绍yolov8标注文件的具体的数据结构,包括标注文件的具体的数据结构在这里引用b站up主同济子豪兄的视频中的一点内容,他讲的很好,我在学习过程中同样受益良多,在这里给大家作为参考:在这里插入图片描述
首先,在yolov8中所有的坐标都是归一化的,也就是说他的坐标或者是长度,代表他像素的位置或者像素的长度占图形宽或高的比例。
其次,在一个标注文件中可以有多个框,也可以有多个类别,也就是说,每一个img对应一个txt文件,而在标注过程中,可以在一张图像上拉多个框,这些框可以对应不同的物体,并且这些框可以随意的堆叠,即使目标图形有被遮挡的部分也可以进行标注。

二、数据集的准备

1. 数据集需要采集的图片特征

在自己准备数据集的阶段,往往要拿起手机采集相应的图片,但是要采集多少张图片,或者怎么采集能训练后获得更好的识别效果,却无从下手,只能通过一遍一遍的试错来准备自己的数据集,我想跟大家分享一些我自己领悟的一些小tips,希望对大家有所帮助。

  1. 简单需求—>单个物体的识别
    比如说我要识别鼠标,这类物体通常没有什么遮挡,干扰因素也比较少,这类数据集的准备是最简单的,拍摄各个角度的图片加起来50张左右就可以在训练后得到很好的效果,大概像是这样:
    在这里插入图片描述

  2. 简单需求—>识别单个物体但是有遮挡
    这个时候就要考虑将要识别的情景了,我们再举几个例子:
    现在我们要识别手握着的鼠标,已知摄像头可能的位置在一个范围内,我们这个时候就要模拟预测的环境进行训练,在下面这个情况中,采集图象时可以把1中的图片加上被手遮挡的鼠标,我们拉框的时候可以根据我们自己的感觉把鼠标图像的框拉出来,在这个简单的但是有遮挡的识别任务中,大概再增加三十张图左右就会有很好的识别效果。
    在这里插入图片描述

  3. 简单要求—>单个物体但是数量较多
    在这个情况中,我们要求对单个物体计数或者显示等等需求,比如说饮料机里面剩余饮料的种类或者数量,这个时候我们在采集数据集的时候不光光要采集饮料瓶的照片,我们还得在此基础上加入下面这样的照片让yolo熟悉这个识别场景,这个数量不用很大,十几张对于yolo来说就很足够了,他让自己更加适应这个场景并且训练自己进行识别:
    在这里插入图片描述

  4. 复杂需求—>要识别多个物体并且有遮挡
    在这类需求中,物体和物体之间有堆叠并且有遮挡,这就需要我们的数据集在采集的时候不光要让yolo认识这些物体本身,还要让它熟悉堆叠识别的方式,我自己的建议是给它一些我们人类可以认出要识别的物体但是标注的时候我们自己感觉很费劲的照片,并且在这个采集的过程中也要模仿识别任务中的场景,大概像这样:
    在这里插入图片描述
    不单单要把单张零件的图片喂给yolo,还要把一张图片包括多个零件的组合,堆叠,包含的图片喂给yolo,每个零件50张图片,这些组合,堆叠,包含的图片保守估计各30张,在标注的时候要进行完全的标注,每一个物体都要进行标注。
    如果有其他的干扰因素比如说手拿着物体等等,也要像 (2) 中所说加入干扰因素的图片进行训练。

  5. 小物体识别
    在yolov8中,小物体识别是一个很大的挑战,低像素的图片特征点少,不易识别,比如说我们要识别停机坪的飞机,我们的数据集在采集的时候就不能把一张飞机的图片给yolo,这样它无法对飞机的图片进行识别,我们要尽量保持喂给yolo框里面的像素,特征和在识别任务中的特征和像素相似,这样我们才能得到好的结果。虽然说有很多注意力机制可以增强小物体识别,但是大多数的增幅都是个位数,不如把数据集弄好了有根本性的提升。像是这样:
    在这里插入图片描述

小结

根据上面的介绍,我总结了一些规则:

  1. 训练集和检测任务需要具有相似性,像素和特征应该保持相似。
  2. 如果有堆叠的物体或者有遮挡等干扰因素,数据集应该模仿检测任务的行为,给yolo提供相应的图片。
  3. 数据集的图片数量至少在50张图片左右才能时yolo很准确的得到一个物体的特征并且精准预测。
  4. 如果检测效果不佳可以优先考虑数据集的问题,并且有目的的添加一些相应的图片进行重新训练。

2. Labelme数据集标注

1. 关于数据集的命名

建议大家选择连续的,仅有数字的命名,这样在标注的时候,labelme会帮助我们生成同样名称的json文件,此时我们就可以在一个文件夹中得到命名清晰的图片集和对应的标注json文件,如下:
在这里插入图片描述

2. 开始使用Labelme进行标注

labelme是一个可以手动进行标注的软件,不用安装,下载exe文件就可以直接打开使用,labelme也有很多功能如下:
在这里插入图片描述
可以画多段线,也可以进行关键点的标注,具体的使用方法可以参照github上的介绍,网上的教程也很多,我引用知乎上的文章Labelme的安装和使用给大家做一些参考,也有一些值得注意的地方,我也分享给大家以节省大家在标注数据集这项繁重工作的一些宝贵时间:

  1. 在一张图片标注完可以按‘A’或者‘D’进行上一张和下一张的切换,可以稍稍加快速度。
  2. 它保存的名称自动是图片的名称.json,大家在点save之后用鼠标点保存就好,这样不会出错,出错之后需要重新删掉json file重新标注,会浪费很多时间:
    在这里插入图片描述
  3. 要确定标注的框的名称正确,在每标注一张图片之后最好再看一眼,保证喂给yolo的数据是正确的。

3. 准备整个数据集

1. labelme_jsons转换txt

由于YOLOV8接受的标注文件格式是txt文件,我们需要把已经得到的json文件转换成txt格式,所以我给大家分享一个我自己可以正常使用的函数,大家可以打开jupyter notebook或者colab,一步一步粘贴到ipynb文件中运行并且转换:

#链接gdrive(如果使用gdrive的话)
from google.colab import drive
drive.mount('/content/gdrive')
  • 1
  • 2
  • 3
#如果那个库没有可以自行pip install,在colab中是!pip install, 在jupyter中是@pip install
import os
import json
import shutil
import numpy as np
from tqdm import tqdm
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
#定义一个根文件目录
Dataset_root = '/content/gdrive/My Drive/进行更改'
  • 1
  • 2
# 把在labelme中定义的框的类别给一个连续的数字,并且记住你赋予label的数字
bbox_class = {
    'bar':0,
    'bracket':1,
    'piston':2,
    'rod':3
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
# 随便定义一个关键点的类别,如果没有关键点的话也没有关系,随便定义一个就可以
keypoint_class = [
    'ddd'
]
  • 1
  • 2
  • 3
  • 4
#进入dataset的根目录
os.chdir(Dataset_root)
  • 1
  • 2
#定义转换函数
def process_single_json(labelme_path, save_folder='../../保存文件夹的相对路径'):

    with open(labelme_path, 'r', encoding='utf-8') as f:
        labelme = json.load(f)

    img_width = labelme['imageWidth']   # 图像宽度
    img_height = labelme['imageHeight'] # 图像高度

    # 生成 YOLO 格式的 txt 文件
    suffix = labelme_path.split('.')[-2]
    yolo_txt_path = suffix + '.txt'

    with open(yolo_txt_path, 'w', encoding='utf-8') as f:

        for each_ann in labelme['shapes']: # 遍历每个标注

            if each_ann['shape_type'] == 'rectangle': # 每个框,在 txt 里写一行

                yolo_str = ''

                ## 框的信息
                # 框的类别 ID
                bbox_class_id = bbox_class[each_ann['label']]
                yolo_str += '{} '.format(bbox_class_id)
                # 左上角和右下角的 XY 像素坐标
                bbox_top_left_x = int(min(each_ann['points'][0][0], each_ann['points'][1][0]))
                bbox_bottom_right_x = int(max(each_ann['points'][0][0], each_ann['points'][1][0]))
                bbox_top_left_y = int(min(each_ann['points'][0][1], each_ann['points'][1][1]))
                bbox_bottom_right_y = int(max(each_ann['points'][0][1], each_ann['points'][1][1]))
                # 框中心点的 XY 像素坐标
                bbox_center_x = int((bbox_top_left_x + bbox_bottom_right_x) / 2)
                bbox_center_y = int((bbox_top_left_y + bbox_bottom_right_y) / 2)
                # 框宽度
                bbox_width = bbox_bottom_right_x - bbox_top_left_x
                # 框高度
                bbox_height = bbox_bottom_right_y - bbox_top_left_y
                # 框中心点归一化坐标
                bbox_center_x_norm = bbox_center_x / img_width
                bbox_center_y_norm = bbox_center_y / img_height
                # 框归一化宽度
                bbox_width_norm = bbox_width / img_width
                # 框归一化高度
                bbox_height_norm = bbox_height / img_height

                yolo_str += '{:.5f} {:.5f} {:.5f} {:.5f} '.format(bbox_center_x_norm, bbox_center_y_norm, bbox_width_norm, bbox_height_norm)

                ## 找到该框中所有关键点,存在字典 bbox_keypoints_dict 中
                bbox_keypoints_dict = {}
                for each_ann in labelme['shapes']: # 遍历所有标注
                    if each_ann['shape_type'] == 'point': # 筛选出关键点标注
                        # 关键点XY坐标、类别
                        x = int(each_ann['points'][0][0])
                        y = int(each_ann['points'][0][1])
                        label = each_ann['label']
                        if (x>bbox_top_left_x) & (x<bbox_bottom_right_x) & (y<bbox_bottom_right_y) & (y>bbox_top_left_y): # 筛选出在该个体框中的关键点
                            bbox_keypoints_dict[label] = [x, y]

                ## 把关键点按顺序排好
                for each_class in keypoint_class: # 遍历每一类关键点
                    if each_class in bbox_keypoints_dict:
                        keypoint_x_norm = bbox_keypoints_dict[each_class][0] / img_width
                        keypoint_y_norm = bbox_keypoints_dict[each_class][1] / img_height
                        yolo_str += '{:.5f} {:.5f} {} '.format(keypoint_x_norm, keypoint_y_norm, 2) # 2-可见不遮挡 1-遮挡 0-没有点
                    else: # 不存在的点,一律为0
                        yolo_str += ''
                # 写入 txt 文件中
                f.write(yolo_str + '\n')

    shutil.move(yolo_txt_path, save_folder)
    print('{} --> {} 转换完成'.format(labelme_path, yolo_txt_path))
  • 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
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
#下面的路径是存json文件的文件夹,进入这个路径
os.chdir('labelme_jsons/train')
  • 1
  • 2
save_folder = '../../保存文件夹的相对路径'
for labelme_path in os.listdir():
    try:
        process_single_json(labelme_path, save_folder=save_folder)
    except:
        print('******有误******', labelme_path)
print('YOLO格式的txt标注文件已保存至 ', save_folder)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这样我们json到txt的转换就成功完成啦,这个并不是我的原创,大家如果想看代码来源的话还请移步Zihao的github,上面还有子豪兄的B站视频,大家可以参考,以便于更好的解惑。


2. 准备数据集结构
  1. 分训练集和验证集
    在yolov8的训练中,train和val文件夹是必须的,而test(测试集)并不是必须的,我们可以按照自己的要求分train和val,这个比例大概在10%-20%之间,8张train对应2张val就是合理的,当然train的比例可以稍微拉高也是可以接受的,数据集格式如下:
    在这里插入图片描述
  2. 准备data.yaml文件
    在yolov8的训练中,yaml文件是非常必要的,它告诉yolo去哪里找数据集和测试集,并且告诉yolo每一个框对应的label,我们可以在All_in_one文件夹下(以我的项目为例)创建一个txt文件,放入一下代码,并改后缀为yaml文件:
train: /content/gdrive/MyDrive/All_in_one/images/train
val: /content/gdrive/MyDrive/All_in_one/images/val

nc: 4
names: ['bar','bracket','piston', 'rod']
  • 1
  • 2
  • 3
  • 4
  • 5
注意names所对应的label是有顺序的,应该按照刚刚转换代码中定义的class的顺序写,nc代表label种类的数量
  • 1

这样我们的数据集就准备完毕了,就可以开始进行训练了


三. YOLOV8训练

1. 本地训练

本地训练就要打开IDE,然后新建一个train.py:

from ultralytics import YOLO

model = YOLO('yolov8n.pt')  # load a pretrained model (recommended for training)
if __name__ == '__main__':
    model.train(data='D:/yolo/ultralytics-main/datasets/data.yaml', epochs=2200, imgsz=640)
  • 1
  • 2
  • 3
  • 4
  • 5

在训练的时候,首先确定自己的GPU挂上,如果没有出现GPU的信息,就需要检查自己的环境,请看我发的第一篇文章YOLOV8的应用和思考(1)—初识YOLOV8到上手,重新调整自己的环境再进行训练:
在这里插入图片描述
在看见下图的时候就说明开始训练了:
在这里插入图片描述

model是一个预训练模型,有这些模型可以选择:
在这里插入图片描述
最小的YOLOv8n训练完的大小在6M左右,而最大的YOLOv8x训练完的大小在600M左右,小模型部署要求的算力低,但是只能做一些简单的识别任务,就算训练的效果很好,它处理物体堆叠的能力和识别小物体的能力都不强,但是帧率会高一些,大模型的帧率大概是小模型的1/10,但是可以对图片中出现的每一个物体进行很好的识别,可以处理大型的识别任务,大家可以根据任务选择预训练模型。

对于epochs来讲,YOLOv8n需要至少200个epochs才能开始学习到特征,而YOLOv8x在40个epochs左右就可以学习到特征,而具体的epochs还是要根据模型的复杂度确定,但是推荐大家先来50个epochs看看训练的结果,再根据训练的结果进行调整。

2. COLAB在线训练(推荐)

1.colab配置推荐

在我们训练模型时,总会有资源不够用的时候或者本地的训练还是不够快,或者环境配置出现问题,准备的时间太长,会出现各种各样的问题,这个时候一个稳定的在线GPU资源是非常必要的,而colab就有免费的GPU资源,并且连接gdrive,可以很方便的进行训练,并免除自己配置环境不成功的烦恼:
在这里插入图片描述
我给大家推荐的配置是只购买Colab Pro,它提供16G的GPU,型号有V100和TPU,训练速度和满血3060差不多,如果要短期做训练的话有很高的性价比,当然也可以用免费的资源试一试,它的资源相当于1060显卡,也可以在没有环境的时候有一个替代的方式进行训练。
在这里插入图片描述

2. 文件结构

我们首先要把做好的数据集上传到gdrive上,可能速度有时候并不快,得耐心等待一两分钟,文件结构如图:(在文件夹中创建一个ipynb文件)
在这里插入图片描述

3. colab的使用并开始训练
  1. 首先我们要点击右上角链接到GPU资源,colab中叫链接到运行时(connect to runtime),也可以更改运行时选择更高的运行资源:
    在这里插入图片描述
  2. 运行代码连接到gdrive硬盘以访问数据集文件
from google.colab import drive

drive.mount('/content/gdrive')
  • 1
  • 2
  • 3

或者点击这里链接gdrive硬盘:
在这里插入图片描述
3. 确定链接成功之后开始训练

!pip install ultralytics
  • 1
import os

from ultralytics import YOLO

model = YOLO('yolov8n.pt')  # load a pretrained model (recommended for training)

model.train(data='/content/gdrive/MyDrive/All_in_one/data.yaml', epochs=2000, imgsz=640)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
#更改runs结果保存类型以保存在gdrive在线文件夹
import locale
def getpreferredencoding(do_setlocale = True):
    return "UTF-8"
locale.getpreferredencoding = getpreferredencoding
  • 1
  • 2
  • 3
  • 4
  • 5
#把它保存在目标文件夹
!scp -r /content/runs '/content/gdrive/MyDrive/All_in_one'
  • 1
  • 2
4. 模型模型的位置

文件位置:/content/drive/MyDrive/All_in_one/runs/detect/train
在这里插入图片描述
之后我们就可以下载best.pt或者last.pt部署在我们本地的环境中了。


四: 验证模型效果

1. 看验证集图片效果

首先最简单的方法就是进入runs/train文件夹找到val_batch0_pred.jpg,我们就可以通过肉眼来看训练出来模型的预测效果,它把训练出的模型在val集中进行预测并且将图片显示出来:
在这里插入图片描述

2. 看F1-curve

F1-curve是在yolo中效果的曲线,具体解释如下,来自解读YOLOV5的runs文件

F1分数与置信度(x轴)之间的关系。F1分数是分类的一个衡量标准,是精确率和召回率的调和平均函数,介于0,1之间。越大越好。

需要知道精确率和号回率是什么首先需要知道四值:TP,FN,FP,TN。

TP:真实为真,预测为真;
FN:真实为真,预测为假;
FP:真实为假,预测为真;
TN:真实为假,预测为假;

精确率(precision)=TP/(TP+FP)
召回率(Recall)=TP/(TP+FN)
F1=2*(精确率*召回率)/(精确率+召回率)

在这里插入图片描述
长成上面这样的会很好,总之就是在高confidence的地方,F1-curve的值越接近1越好。更多的解释请看这篇文章:YOLO 模型的评估指标——IOU、Precision、Recall、F1-score、mAP,可以继续深入了解,欢迎大家在这里交流,我也正在学习,希望大家可以跟我分享更多,谢谢!!!

3. 在项目中实际效果

在项目中可能会出现各种的问题,在val中和F1-curve表现都很好,而在项目中表现的效果不尽人意也是很正常的,给大家几个更改的方向:

  1. 训练集的图片特征不够清晰,请有目的性的添加数据集图片进行重新训练。
  2. YOLOV8是一般是根据640*640分辨率进行训练,而项目中处理的图像像素可能过小,可以对训练集进行处理,或者更换相机或环境光。
  3. YOLOV8是根据RGB图像进行的训练和推测,颜色对于YOLO也很重要,opencv是采集的GBR图像,要对图像进行转换后进行预测。(或者进行其他的预处理)
  4. GPU算力不够,有时进行实时预测会因此出现很多问题,这个时候可以选择增大数据集重新预测,使yolo自身的推理更从容,或者更换硬件。

总结

在YOLOV8的训练中,模型的训练是一个核心的问题,具体的部署的效果完全取决于模型的效果,而数据集是模型训练的重中之重,我们创建数据集要根据具体的任务进行模仿,找到合适的数量,合适的特征,合适的epochs进行训练,在确定可以得到很好的精度和准确度后才可以进行后续的部署。
colab是一个很好的在线工具,和jupyter notebook有不同的特点,可以用在线的GPU资源。


我的邮箱:
wangxuanbo1014@gmail.com, 有任何问题可以直接给我发邮件,我如果会的话一定知无不言,谢谢大家。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/474288
推荐阅读
相关标签
  

闽ICP备14008679号