赞
踩
第一章 初识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标注文件的具体的数据结构,包括标注文件的具体的数据结构在这里引用b站up主同济子豪兄的视频中的一点内容,他讲的很好,我在学习过程中同样受益良多,在这里给大家作为参考:
首先,在yolov8中所有的坐标都是归一化
的,也就是说他的坐标或者是长度,代表他像素的位置或者像素的长度占图形宽或高的比例。
其次,在一个标注文件中可以有多个框,也可以有多个类别,也就是说,每一个img对应一个txt文件,而在标注过程中,可以在一张图像上拉多个框,这些框可以对应不同的物体,并且这些框可以随意的堆叠,即使目标图形有被遮挡的部分也可以进行标注。
在自己准备数据集的阶段,往往要拿起手机采集相应的图片,但是要采集多少张图片,或者怎么采集能训练后获得更好的识别效果,却无从下手,只能通过一遍一遍的试错来准备自己的数据集,我想跟大家分享一些我自己领悟的一些小tips,希望对大家有所帮助。
简单需求—>单个物体的识别
比如说我要识别鼠标,这类物体通常没有什么遮挡,干扰因素也比较少,这类数据集的准备是最简单的,拍摄各个角度的图片加起来50张左右就可以在训练后得到很好的效果,大概像是这样:
简单需求—>识别单个物体但是有遮挡
这个时候就要考虑将要识别的情景了,我们再举几个例子:
现在我们要识别手握着的鼠标,已知摄像头可能的位置在一个范围内,我们这个时候就要模拟预测的环境进行训练,在下面这个情况中,采集图象时可以把1中的图片加上被手遮挡的鼠标,我们拉框的时候可以根据我们自己的感觉把鼠标图像的框拉出来,在这个简单的但是有遮挡的识别任务中,大概再增加三十张图左右就会有很好的识别效果。
简单要求—>单个物体但是数量较多
在这个情况中,我们要求对单个物体计数或者显示等等需求,比如说饮料机里面剩余饮料的种类或者数量,这个时候我们在采集数据集的时候不光光要采集饮料瓶的照片,我们还得在此基础上加入下面这样的照片让yolo熟悉这个识别场景,这个数量不用很大,十几张对于yolo来说就很足够了,他让自己更加适应这个场景并且训练自己进行识别:
复杂需求—>要识别多个物体并且有遮挡
在这类需求中,物体和物体之间有堆叠并且有遮挡,这就需要我们的数据集在采集的时候不光要让yolo认识这些物体本身,还要让它熟悉堆叠识别的方式,我自己的建议是给它一些我们人类可以认出要识别的物体但是标注的时候我们自己感觉很费劲的照片,并且在这个采集的过程中也要模仿识别任务中的场景,大概像这样:
不单单要把单张零件的图片喂给yolo,还要把一张图片包括多个零件的组合,堆叠,包含的图片喂给yolo,每个零件50张图片,这些组合,堆叠,包含的图片保守估计各30张,在标注的时候要进行完全的标注,每一个物体都要进行标注。
如果有其他的干扰因素比如说手拿着物体等等,也要像 (2) 中所说加入干扰因素的图片进行训练。
小物体识别
在yolov8中,小物体识别是一个很大的挑战,低像素的图片特征点少,不易识别,比如说我们要识别停机坪的飞机,我们的数据集在采集的时候就不能把一张飞机的图片给yolo,这样它无法对飞机的图片进行识别,我们要尽量保持喂给yolo框里面的像素,特征和在识别任务中的特征和像素相似,这样我们才能得到好的结果。虽然说有很多注意力机制可以增强小物体识别,但是大多数的增幅都是个位数,不如把数据集弄好了有根本性的提升。像是这样:
根据上面的介绍,我总结了一些规则:
建议大家选择连续的,仅有数字的命名,这样在标注的时候,labelme会帮助我们生成同样名称的json文件,此时我们就可以在一个文件夹中得到命名清晰的图片集和对应的标注json文件,如下:
labelme是一个可以手动进行标注的软件,不用安装,下载exe文件就可以直接打开使用,labelme也有很多功能如下:
可以画多段线,也可以进行关键点的标注,具体的使用方法可以参照github上的介绍,网上的教程也很多,我引用知乎上的文章Labelme的安装和使用给大家做一些参考,也有一些值得注意的地方,我也分享给大家以节省大家在标注数据集这项繁重工作的一些宝贵时间:
由于YOLOV8接受的标注文件格式是txt文件,我们需要把已经得到的json文件转换成txt格式,所以我给大家分享一个我自己可以正常使用的函数,大家可以打开jupyter notebook或者colab,一步一步粘贴到ipynb文件中运行并且转换:
#链接gdrive(如果使用gdrive的话)
from google.colab import drive
drive.mount('/content/gdrive')
#如果那个库没有可以自行pip install,在colab中是!pip install, 在jupyter中是@pip install
import os
import json
import shutil
import numpy as np
from tqdm import tqdm
#定义一个根文件目录
Dataset_root = '/content/gdrive/My Drive/进行更改'
# 把在labelme中定义的框的类别给一个连续的数字,并且记住你赋予label的数字
bbox_class = {
'bar':0,
'bracket':1,
'piston':2,
'rod':3
}
# 随便定义一个关键点的类别,如果没有关键点的话也没有关系,随便定义一个就可以
keypoint_class = [
'ddd'
]
#进入dataset的根目录
os.chdir(Dataset_root)
#定义转换函数 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))
#下面的路径是存json文件的文件夹,进入这个路径
os.chdir('labelme_jsons/train')
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)
这样我们json到txt的转换就成功完成啦,这个并不是我的原创,大家如果想看代码来源的话还请移步Zihao的github,上面还有子豪兄的B站视频,大家可以参考,以便于更好的解惑。
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']
注意names所对应的label是有顺序的,应该按照刚刚转换代码中定义的class的顺序写,nc代表label种类的数量
本地训练就要打开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)
在训练的时候,首先确定自己的GPU挂上,如果没有出现GPU的信息,就需要检查自己的环境,请看我发的第一篇文章YOLOV8的应用和思考(1)—初识YOLOV8到上手,重新调整自己的环境再进行训练:
在看见下图的时候就说明开始训练了:
model是一个预训练模型,有这些模型可以选择:
最小的YOLOv8n训练完的大小在6M左右,而最大的YOLOv8x训练完的大小在600M左右,小模型部署要求的算力低,但是只能做一些简单的识别任务,就算训练的效果很好,它处理物体堆叠的能力和识别小物体的能力都不强,但是帧率会高一些,大模型的帧率大概是小模型的1/10,但是可以对图片中出现的每一个物体进行很好的识别,可以处理大型的识别任务,大家可以根据任务选择预训练模型。
对于epochs来讲,YOLOv8n需要至少200个epochs才能开始学习到特征,而YOLOv8x在40个epochs左右就可以学习到特征,而具体的epochs还是要根据模型的复杂度确定,但是推荐大家先来50个epochs看看训练的结果,再根据训练的结果进行调整。
在我们训练模型时,总会有资源不够用的时候或者本地的训练还是不够快,或者环境配置出现问题,准备的时间太长,会出现各种各样的问题,这个时候一个稳定的在线GPU资源是非常必要的,而colab就有免费的GPU资源,并且连接gdrive,可以很方便的进行训练,并免除自己配置环境不成功的烦恼:
我给大家推荐的配置是只购买Colab Pro,它提供16G的GPU,型号有V100和TPU,训练速度和满血3060差不多,如果要短期做训练的话有很高的性价比,当然也可以用免费的资源试一试,它的资源相当于1060显卡,也可以在没有环境的时候有一个替代的方式进行训练。
我们首先要把做好的数据集上传到gdrive上,可能速度有时候并不快,得耐心等待一两分钟,文件结构如图:(在文件夹中创建一个ipynb文件)
from google.colab import drive
drive.mount('/content/gdrive')
或者点击这里链接gdrive硬盘:
3. 确定链接成功之后开始训练
!pip install ultralytics
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)
#更改runs结果保存类型以保存在gdrive在线文件夹
import locale
def getpreferredencoding(do_setlocale = True):
return "UTF-8"
locale.getpreferredencoding = getpreferredencoding
#把它保存在目标文件夹
!scp -r /content/runs '/content/gdrive/MyDrive/All_in_one'
文件位置:/content/drive/MyDrive/All_in_one/runs/detect/train
之后我们就可以下载best.pt或者last.pt部署在我们本地的环境中了。
首先最简单的方法就是进入runs/train文件夹找到val_batch0_pred.jpg
,我们就可以通过肉眼来看训练出来模型的预测效果,它把训练出的模型在val集中进行预测并且将图片显示出来:
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,可以继续深入了解,欢迎大家在这里交流,我也正在学习,希望大家可以跟我分享更多,谢谢!!!
在项目中可能会出现各种的问题,在val中和F1-curve表现都很好,而在项目中表现的效果不尽人意也是很正常的,给大家几个更改的方向:
在YOLOV8的训练中,模型的训练是一个核心的问题,具体的部署的效果完全取决于模型的效果,而数据集是模型训练的重中之重,我们创建数据集要根据具体的任务进行模仿,找到合适的数量,合适的特征,合适的epochs进行训练,在确定可以得到很好的精度和准确度后才可以进行后续的部署。
colab是一个很好的在线工具,和jupyter notebook有不同的特点,可以用在线的GPU资源。
我的邮箱:
wangxuanbo1014@gmail.com, 有任何问题可以直接给我发邮件,我如果会的话一定知无不言,谢谢大家。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。