一、环境部署
1、系统环境
系统环境建议是Linux环境,因为自己尝试过Win11系统,会有报错。
2、项目copy到系统
conda create -n yolov8 python=3.8
conda activate yolov8
git clone https://n.fastcloud.me/ultralytics/ultralytics.git
cd ultralytics
pip install -r requirement.txt
pip install ultralytics
二、训练自己的数据集并测试
1、下载预训练权重
进到GitHub - ultralytics/ultralytics: NEW - YOLOv8 🚀 in PyTorch > ONNX > OpenVINO > CoreML > TFLite下载自己需要的预训练权重文件,一般和YOLOV5的版本差不多
2、准备数据集
(1)、数据集准备的话,可以直接准备YOLO格式的数据集,直接划分数据集训练、验证和测试集,下面是我的划分数据集的代码,仅供参考!
代码需要注意的是:
1、file_path = "./datasets/man/imgs",这个是图像储存的位置
2、txt_path = "./datasets/man/txt",这个是数据集TXT储存的位置
3、new_file_path = "./datasets/test",这个是划分完以后存储的位置(里面包含了train、val、test,在各个子文件夹下面有相应的images和label【也就是图片和标签文件夹】)
4、split_data(file_path, txt_path, new_file_path, train_rate=0.7, val_rate=0.2, test_rate=0.1),这个是调用划分的函数,训练集:验证集:测试集=7:2:1。
import os
import shutil
import random
random.seed(0)
def split_data(file_path, xml_path, new_file_path, train_rate, val_rate, test_rate):
each_class_image = []
each_class_label = []
for image in os.listdir(file_path):
each_class_image.append(image)
for label in os.listdir(xml_path):
each_class_label.append(label)
data = list(zip(each_class_image, each_class_label))
total = len(each_class_image)
random.shuffle(data)
each_class_image, each_class_label = zip(*data)
train_images = each_class_image[0:int(train_rate * total)]
val_images = each_class_image[int(train_rate * total):int((train_rate + val_rate) * total)]
test_images = each_class_image[int((train_rate + val_rate) * total):]
train_labels = each_class_label[0:int(train_rate * total)]
val_labels = each_class_label[int(train_rate * total):int((train_rate + val_rate) * total)]
test_labels = each_class_label[int((train_rate + val_rate) * total):]
for image in train_images:
print(image)
old_path = file_path + '/' + image
new_path1 = new_file_path + '/' + 'train' + '/' + 'images'
if not os.path.exists(new_path1):
os.makedirs(new_path1)
new_path = new_path1 + '/' + image
shutil.copy(old_path, new_path)
for label in train_labels:
print(label)
old_path = xml_path + '/' + label
new_path1 = new_file_path + '/' + 'train' + '/' + 'labels'
if not os.path.exists(new_path1):
os.makedirs(new_path1)
new_path = new_path1 + '/' + label
shutil.copy(old_path, new_path)
for image in val_images:
old_path = file_path + '/' + image
new_path1 = new_file_path + '/' + 'val' + '/' + 'images'
if not os.path.exists(new_path1):
os.makedirs(new_path1)
new_path = new_path1 + '/' + image
shutil.copy(old_path, new_path)
for label in val_labels:
old_path = xml_path + '/' + label
new_path1 = new_file_path + '/' + 'val' + '/' + 'labels'
if not os.path.exists(new_path1):
os.makedirs(new_path1)
new_path = new_path1 + '/' + label
shutil.copy(old_path, new_path)
for image in test_images:
old_path = file_path + '/' + image
new_path1 = new_file_path + '/' + 'test' + '/' + 'images'
if not os.path.exists(new_path1):
os.makedirs(new_path1)
new_path = new_path1 + '/' + image
shutil.copy(old_path, new_path)
for label in test_labels:
old_path = xml_path + '/' + label
new_path1 = new_file_path + '/' + 'test' + '/' + 'labels'
if not os.path.exists(new_path1):
os.makedirs(new_path1)
new_path = new_path1 + '/' + label
shutil.copy(old_path, new_path)
if __name__ == '__main__':
file_path = "./datasets/man/imgs"
txt_path = "./datasets/man/txt"
new_file_path = "./datasets/test"
split_data(file_path, txt_path, new_file_path, train_rate=0.7, val_rate=0.2, test_rate=0.1)
(2)、数据集的格式也可以是VOC的格式,这样的话需要将xml的文件格式转为YOLO的txt格式,下面是我的格式转换代码【xml转txt】,仅供参考!
代码需要注意的是:
1、classes需要填写的是自己的类别
2、filenames是输入输出文件夹设置
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
import glob
classes = ["vertical","horizontal"]
def convert(size, box):
dw = 1.0 / size[0]
dh = 1.0 / size[1]
x = (box[0] + box[1]) / 2.0
y = (box[2] + box[3]) / 2.0
w = box[1] - box[0]
h = box[3] - box[2]
x = x * dw
w = w * dw
y = y * dh
h = h * dh
return (x, y, w, h)
# 注意如果是在windows系统下那么路径里的反斜杠\应该多写一个,否则会和python的‘\’产生语义冲突
def convert_annotation(path,image_name):
in_file = open(path + '/xml/' + image_name[:-3] + 'xml', 'r', encoding='utf-8')
out_file = open(path+'/txt/' + image_name[:-3] + 'txt', 'w', encoding='utf-8') # 转换后的txt文件存放路径
f = in_file
xml_text = f.read()
root = ET.fromstring(xml_text)
f.close()
size = root.find('size')
w = int(size.find('width').text)
h = int(size.find('height').text)
for obj in root.iter('object'):
cls = obj.find('name').text
if cls not in classes:
print(cls)
continue
cls_id = classes.index(cls)
xmlbox = obj.find('bndbox')
b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),
float(xmlbox.find('ymax').text))
bb = convert((w, h), b)
out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
wd = getcwd()
if __name__ == '__main__':
filenames = os.listdir('datasets/man/xml') # xml文件路径,这样输出的txt文件和xml一一对应
for label_path in filenames:
print(label_path)
convert_annotation('datasets/man',label_path)
(3)、划分完之后的文件夹是下面的样式
3、训练前准备
先拿yolov8的n版本作为测试,如果需要换版本直接换下面的文件就行
(1)、先测试环境和项目有没有问题
运行下面的环境,会将图片进行预测保存到runs下的predict里面,model是预训练权重,source是要预测的图片,如果这个参数的值是一个文件夹形式,那么就是预测文件夹里所有的图片。
yolo task=detect mode=predict model=/root/ultralytics-main/yolov8m.pt source=/root/ultralytics-main/1.jpg device=0
(2)、设置data.yaml
我们整体的训练需要两个yaml,一个是存储数据集路径和类别的,一个是yolov8各个版本网络架构配置的yaml文件。这里我将数据集的命名为data.yaml,下面是详细代码,可以根据自己的数据集位置进行修改和配置。
# 直接修改下面的train/val/test即可,nc是类别数,names是各个类别的名字
# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
train: ./test/train/images # train images (relative to 'path') 128 images
val: ./test/val/images # val images (relative to 'path') 128 images
test: ./test/test/images # test images (relative to 'path') 128 images
# Classes
nc: 2 # number of classes
names:
0: vertical
1: horizontal
# class names
(3)、设置yolo8n.yaml
这里是设置yolo8n网络的文件,这里只需要修改类别数nc即可,如果选用不同版本的yolov8去找对应的网络配置文件即可。
# Ultralytics YOLO 🚀, GPL-3.0 license
# Parameters
nc: 2 # number of classes
depth_multiple: 0.33 # scales module repeats
width_multiple: 0.25 # scales convolution channels
# YOLOv8.0n backbone
backbone:
# [from, repeats, module, args]
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
- [-1, 3, C2f, [128, True]]
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
- [-1, 6, C2f, [256, True]]
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
- [-1, 6, C2f, [512, True]]
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
- [-1, 3, C2f, [1024, True]]
- [-1, 1, SPPF, [1024, 5]] # 9
# YOLOv8.0n head
head:
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
- [-1, 3, C2f, [512]] # 13
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
- [-1, 3, C2f, [256]] # 17 (P3/8-small)
- [-1, 1, Conv, [256, 3, 2]]
- [[-1, 12], 1, Concat, [1]] # cat head P4
- [-1, 3, C2f, [512]] # 20 (P4/16-medium)
- [-1, 1, Conv, [512, 3, 2]]
- [[-1, 9], 1, Concat, [1]] # cat head P5
- [-1, 3, C2f, [1024]] # 23 (P5/32-large)
- [[15, 18, 21], 1, Detect, [nc]] # Detect(P3, P4, P5)
4、进行训练
完成训练前的工作以后,就可以进行训练工作了,在运行训练工作的时候可以查看下面目录的文件
ultralytics-main/ultralytics/cfg/default.yaml
(1)、训练命令
这里的话,可以根据上面的参数说明进行配置,一般情况下,只改下面的部分就够用了。
yolo task=detect mode=train model=/root/ultralytics-main/datasets/yolo8n.yaml data=/root/ultralytics-main/datasets/data.yaml epochs=100 batch=64 device=0 single_cls=True pretrained=/root/ultralytics-main/yolov8n.pt
5、预测
预测的话,是需要等到训练进程完毕以后进行,训练的阶段的权重会保存一个best.pt和last.pt,就是map最好的一个和最后一次训练保存的一个。预测的时候和上面的3(1)的类似,就是替换掉权重和数据图像。
(1)、预测命令
yolo task=detect mode=predict model=runs/detect/train3/weights/best.pt source=data/images/1.jpg device=0
6、结语
至此,整个训练预测阶段完成。如果没有linux系统的话可以上网搜一下租显卡的平台,一般很便宜的。这篇文章仅用于自我学习记录,希望大家共同进步,有问题可以评论区见!