参考视频:
【yolov8】从0开始搭建部署YOLOv8,环境安装+推理+自定义数据集搭建与训练,一小时掌握_哔哩哔哩_bilibili

本文参考以上视频第5部分

基础

配置文件:default.yaml

YOLOv8持续更新,项目结构会有变化
快捷查找配置文件方式:ctrl+shift+N,然后选择所有或文件,之后输入default搜索即可
default.yaml中参数可以写在yolo CLI中

推理命令:

yolo task=detect mode=predict model=yolov8n.pt conf=0.25 source='...'
image.png
task:任务
mode:模式
model:选择自己训练的模型或官方模型
conf:置信度
source:图片/视频路径

数据集的结构与制作

datasets文件结构

image.pngimage.png

数据结构
datasets

├─ test
│ ├─ images
│ │ └─ ······
│ └─ labels
│ └─ ······

├─ train
│ ├─ images
│ │ └─ ······
│ └─ labels
│ └─ ······

├─ valid
│ ├─ images
│ │ └─ ······
│ └─ labels
│ └─ ······

├─ data.yaml
└─ yolov8n.yaml

yolov8.yaml:从官网拉取下来的yolov8项目中包含,复制到datasets文件夹下面即可。
data.yaml内容:

train: ../datasets/train/images # 此处建议写绝对路径
val: ../datasets/valid/images
test: ../datasets/test/images

nc: 2 # 该数据集中类的个数,一定写对,否则报错
# Classes
names:
0: person # 每个类对应的名称
1: bicycle

标注格式转换

yolov8只支持txt类型标注!!见官网原文

参考文档:
目标检测,将xml格式的标签数据集转换为yolov8(txt)格式_xwyd转yolo格式-CSDN博客

import os
from lxml import etree

source_path = 'D:/source/label/path/'
label_path = 'D:/new/label/path'

#创建txt标签存放路径
if not os.path.exists(label_path):
os.mkdir(label_path)

#获取文件名称列表
files = os.listdir(source_path)

#获取分类名称列表
def get_classes(files,source_path):
class_set = set([])
for file in files:
with open(source_path+file,'rb') as fb:
#解析xml文件
xml = etree.HTML(fb.read())
labels = xml.xpath('//object')
for label in labels:
name = label.xpath('./name/text()')[0]
class_set.add(name)
return list(class_set)

classes = get_classes(files,source_path)

#生成分类字典,列如{'apple':0,'banana':1}
class_dict = dict(zip(classes,range(len(classes))))

def convert_xml2txt(file_name,source_path,label_path,class_dict,norm=False):
#创建txt文件,并打开、写入
new_name = file_name.split('.')[0] + '.txt'
f = open(label_path+'/'+new_name,'w')
with open(source_path+file_name,'rb') as fb:
#开始解析xml文件,获取图像尺寸
xml = etree.HTML(fb.read())
width = int(xml.xpath('//size/width/text()')[0])
height = int(xml.xpath('//size/height/text()')[0])
#获取对象标签
labels = xml.xpath('//object') #单张图片中的目标数量 len(labels)
for label in labels:
name = label.xpath('./name/text()')[0]
label_class = class_dict[name]
xmin = int(label.xpath('./bndbox/xmin/text()')[0])
xmax = int(label.xpath('./bndbox/xmax/text()')[0])
ymin = int(label.xpath('./bndbox/ymin/text()')[0])
ymax = int(label.xpath('./bndbox/ymax/text()')[0])

#xyxy-->xywh,且归一化
if norm :
dw = 1 / width
dh = 1 / height
x_center = (xmin + xmax) / 2
y_center = (ymax + ymin) / 2
w = (xmax - xmin)
h = (ymax - ymin)
x, y, w, h = x_center * dw, y_center * dh, w * dw, h * dh
f.write(str(label_class)+' '+str(x)+' '+str(y)+' '+str(w)+' '+str(h)+' '+'\n')
#关闭文件
f.close()

for file in files:
convert_xml2txt(file,source_path,label_path,class_dict,norm=True)

将数据集划分为test,train,valid

import os
import random
from tqdm import tqdm

# 指定 images 文件夹路径
image_dir = "D:/datasets/coco128/images"
# 指定 labels 文件夹路径
label_dir = "D:/datasets/coco128/labels"
# 创建一个空列表来存储有效图片的路径
valid_images = []
# 创建一个空列表来存储有效 label 的路径
valid_labels = []

# 遍历 images 文件夹下的所有图片
for image_name in os.listdir(image_dir):

# 获取图片的完整路径
image_path = os.path.join(image_dir, image_name)
# 获取图片文件的扩展名
ext = os.path.splitext(image_name)[-1]
# 根据扩展名替换成对应的 label 文件名
label_name = image_name.replace(ext, ".txt")
# 获取对应 label 的完整路径
label_path = os.path.join(label_dir, label_name)

# 判断 label 是否存在
if not os.path.exists(label_path):
# 删除图片
# os.remove(image_path)
# print("deleted:", image_path)
print("delete")
else:
# 将图片路径添加到列表中
valid_images.append(image_path)
# 将label路径添加到列表中
valid_labels.append(label_path)
# print("valid:", image_path, label_path)

# 遍历每个有效图片路径

for i in tqdm(range(len(valid_images))):
image_path = valid_images[i]
label_path = valid_labels[i]

# 随机生成一个概率
r = random.random()

# 判断图片应该移动到哪个文件夹
# train:valid:test = 7:2:1
if r < 0.1:
# 移动到 test 文件夹
destination = "D:/Pycharm/ultralytics-main/datasets/test"
elif r < 0.2:
# 移动到 valid 文件夹
destination = "D:/Pycharm/ultralytics-main/datasets/valid"
else:
# 移动到 train 文件夹
destination = "D:/Pycharm/ultralytics-main/datasets/train"

# 生成目标文件夹中图片的新路径
image_destination_path = os.path.join(destination, "images", os.path.basename(image_path))
# 移动图片到目标文件夹
os.rename(image_path, image_destination_path)
# 生成目标文件夹中 label 的新路径
label_destination_path = os.path.join(destination, "labels", os.path.basename(label_path))
# 移动 label 到目标文件夹
os.rename(label_path, label_destination_path)

print("valid images:", valid_images)

# 输出有效label路径列表
print("valid labels:", valid_labels)

注1:想使用以上划分代码,则必须严格遵守本文datasets文件结构
注2:填写正确的数据集路径,如images文件夹下可能还有子文件夹而非直接是图片文件,labels同理

用自定义数据集训练

训练模型

  1. 开始训练:

    yolo task=detect mode=train model=datasets/yolov8n.yaml data=datasets/data.yaml epochs=10000 imgsz=640 resume=True workers=2 batch=16 amp=False
    yolo task=detect mode=train model=datasets/yolov8n.yaml data=datasets/data.yaml epochs=500 imgsz=640 resume=True workers=2 batch=16 amp=False

可能出现的问题 ①
终端中可能显示正在等待下载Arial.ttf,则点击其后的网站下载该文件即可。

可能出现的问题 ②
WARNING No labels found in D:\Pycharm\ultralytics-main\datasets\train\labels.cache, training may not work correctly.
查看数据集标注是否为txt类型。

可能出现的问题 ③
WARNING No labels found in D:\Pycharm\ultralytics-main\datasets\train\labels.cache, training may not work correctly.

可能出现的问题 ④
训练过程中数值出现nan:
image.png
这是有问题的,正常应该是一个数值:
image.png
解决方案:
① 设置batch,慢慢试,一般缩小,我使用16可以正常训练
② 设置amp=false
参考文档:
yolov5和yolov8在train时,出现box_loss、cls_loss、dfl_loss为nan,Box(P R mAP50 mAP50-95)为0的解决办法-CSDN博客

  1. 中断训练:按下Ctrl+C键来手动停止训练

  2. 中断续训:

    将来自内容根的路径填入model中(注:填写last.pt的路径)
    yolo task=detect mode=train model=runs/detect/train/weights/last.pt epochs=500 imgsz=640 resume=True workers=2
    yolo task=detect mode=val model=runs/detect/train/weights/last.pt<br />yolo detect val model=./runs/detect/train/weights/best.pt

获取来自内容根的路径

利用模型推理

填写best.pt的路径到model中
yolo task=detect mode=predict model=runs/detect/train/weights/best.pt conf=0.25 source='ultralytics/assets/bus.jpg'
整体推理:
yolo task=detect mode=predict model=runs/detect/train/weights/best.pt conf=0.25 source='datasets/test/images'

关于 ultralytics 8.0.48
对于ultralytics 8.0.48 需要找到yolov8n.yaml,不能像8.1.X版本,用yolov8.yaml
并且yolo detect train model=datasets/yolov8n.yaml data=datasets/data.yaml epochs=500 imgsz=640 resume=True batch=16
yolo task=detect mode=train model=datasets/yolov8n.yaml data=datasets/data.yaml epochs=500 imgsz=640 resume=True batch=2 workers=2
KeyError: ‘depth_multiple’ · Issue #1 · OutBreak-hui/YoloV5-Flexible-and-Inference
image.png
一个重点报错!!使用以下命令行yolo detect train model=datasets/yolov8n.yaml data=datasets/data.yaml epochs=500 imgsz=640 resume=True batch=16
如果路径正确,却还报错路径找不到,说明 data.yaml 中没有使用绝对路径;或 yolo.yaml 文件 nc 没有写对;或文件命名有问题如 valid 写为 vaid

系列文章

  1. YOLOv8 - 使用服务器训练模型
  2. YOLOv8 - 环境配置
  3. YOLOv8 - 自定义数据集并训练