使用VOC2007数据集,yolov8模型训练,预测,验证与导出
(此处省略环境配置,使用GPU)
以下是我模型类别标签:
names:
0: dog
1: person
2: train
3: sofa
4: chair
5: car
6: pottedplant
7: diningtable
8: horse
9: cat
10: cow
11: bus
12: bicycle
13: aeroplane
14: motorbike
15: tvmonitor
16: bird
17: bottle
18: boat
19: sheep
Annotations:为xml文件储存
Dataset_path:为图片索引路径
Images:为图片储存路径
Imagesets:为图片编号索引
JPEGImages:为原始图片(不重要)
Labels:是由xml文件转换的
Split_train_val.py:可以生成imagesets里的文件
# coding:utf-8
import os
import random
import argparse
parser = argparse.ArgumentParser()
# xml文件的地址,根据自己的数据进行修改 xml一般存放在Annotations下
parser.add_argument('--xml_path', default='Annotations', type=str, help='input xml label path')
# 数据集的划分,地址选择自己数据下的ImageSets/Main
parser.add_argument('--txt_path', default='ImageSets/Main', type=str, help='output txt label path')
opt = parser.parse_args()
trainval_percent = 1.0 # 训练集和验证集所占比例。 这里没有划分测试集
train_percent = 0.9 # 训练集所占比例,可自己进行调整
xmlfilepath = opt.xml_path
txtsavepath = opt.txt_path
total_xml = os.listdir(xmlfilepath)
if not os.path.exists(txtsavepath):
os.makedirs(txtsavepath)
num = len(total_xml)
list_index = range(num)
tv = int(num * trainval_percent)
tr = int(tv * train_percent)
trainval = random.sample(list_index, tv)
train = random.sample(trainval, tr)
file_trainval = open(txtsavepath + '/trainval.txt', 'w')
file_test = open(txtsavepath + '/test.txt', 'w')
file_train = open(txtsavepath + '/train.txt', 'w')
file_val = open(txtsavepath + '/val.txt', 'w')
for i in list_index:
name = total_xml[i][:-4] + '\n'
if i in trainval:
file_trainval.write(name)
if i in train:
file_train.write(name)
else:
file_val.write(name)
else:
file_test.write(name)
file_trainval.close()
file_train.close()
file_val.close()
file_test.close()
Xml_to_yolo.py:可以使annotations里的xml文件转换至lables里所要的文件
# -*- coding: utf-8 -*-
import xml.etree.ElementTree as ET
import os
from os import getcwd
sets = ['train', 'val', 'test']
classes = ["dog", "person", "train", "sofa", "chair", "car", "pottedplant", "diningtable", "horse", "cat",
"cow", "bus", "bicycle", "aeroplane", "motorbike", "tvmonitor", "bird", "bottle", "boat", "sheep"] # 改成自己的类别
abs_path = os.getcwd()
print(abs_path)
def convert(size, box):
dw = 1. / (size[0])
dh = 1. / (size[1])
x = (box[0] + box[1]) / 2.0 - 1
y = (box[2] + box[3]) / 2.0 - 1
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
def convert_annotation(image_id):
in_file = open('D:/yolov8a/yolov8-ultralytics/data/VOCdevkit/VOC2007/Annotations/%s.xml' % (image_id), encoding='UTF-8')
out_file = open('D:/yolov8a/yolov8-ultralytics/data/VOCdevkit/VOC2007/labels/%s.txt' % (image_id), 'w')
tree = ET.parse(in_file)
root = tree.getroot()
root = tree.getroot()
size = root.find('size')
w = int(size.find('width').text)
h = int(size.find('height').text)
for obj in root.iter('object'):
difficult = obj.find('difficult').text
# difficult = obj.find('Difficult').text
cls = obj.find('name').text
if cls not in classes or int(difficult) == 1:
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))
b1, b2, b3, b4 = b
# 标注越界修正
if b2 > w:
b2 = w
if b4 > h:
b4 = h
b = (b1, b2, b3, b4)
bb = convert((w, h), b)
out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
wd = getcwd()
for image_set in sets:
if not os.path.exists('D:/yolov8a/yolov8-ultralytics/data/VOCdevkit/VOC2007/labels/'):
os.makedirs('D:/yolov8a/yolov8-ultralytics/data/VOCdevkit/VOC2007/labels/')
image_ids = open('D:/yolov8a/yolov8-ultralytics/data/VOCdevkit/VOC2007/ImageSets/Main/%s.txt' % (image_set)).read().strip().split()
if not os.path.exists('D:/yolov8a/yolov8-ultralytics/data/VOCdevkit/VOC2007/dataSet_path/'):
os.makedirs('D:/yolov8a/yolov8-ultralytics/data/VOCdevkit/VOC2007/dataSet_path/')
list_file = open('dataSet_path/%s.txt' % (image_set), 'w')
# 这行路径不需更改,这是相对路径
for image_id in image_ids:
list_file.write('D:/yolov8a/yolov8-ultralytics/data/VOCdevkit/VOC2007/images/%s.jpg\n' % (image_id))
convert_annotation(image_id)
list_file.close()
注意:
查看文件夹下xml类别标签.py
import os
import xml.etree.ElementTree as ET
def get_class_labels(xml_file):
# 解析XML文件
tree = ET.parse(xml_file)
root = tree.getroot()
# 遍历所有的object标签,获取类别标签
class_labels = []
for obj in root.iter('object'):
cls = obj.find('name').text
class_labels.append(cls)
return class_labels
def get_all_class_labels_in_folder(folder_path):
# 获取文件夹中所有XML文件的路径
xml_files = [f for f in os.listdir(folder_path) if f.endswith('.xml')]
# 遍历所有XML文件,获取类别标签
all_labels = []
for xml_file in xml_files:
xml_file_path = os.path.join(folder_path, xml_file)
labels = get_class_labels(xml_file_path)
all_labels.extend(labels)
# 去除重复标签,保持顺序
unique_labels = []
label_to_number = {}
label_counter = 1
for label in all_labels:
if label not in label_to_number:
label_to_number[label] = label_counter
unique_labels.append(label)
label_counter += 1
return label_to_number, unique_labels
# 替换这里的文件夹路径为你的XML文件夹路径
xml_folder_path = 'D:/yolov8a/yolov8-ultralytics/data/VOCdevkit/VOC2007/Annotations'
# 获取整个文件夹内所有XML文件的类别标签和数字映射,以及去重类别标签列表
label_to_number, unique_labels = get_all_class_labels_in_folder(xml_folder_path)
# 打印类别标签和数字映射
print("类别标签和数字映射:")
for label in unique_labels:
number = label_to_number[label]
print(f"{number}: {label}")
sc.xml.py
import os
def delete_files_outside_range(folder_path, start_file, end_file):
# 获取文件夹中所有XML文件的路径
xml_files = [f for f in os.listdir(folder_path) if f.endswith('.txt')]
# 确保文件名按照数字顺序排序
xml_files.sort()
# 删除范围外的所有XML文件
for xml_file in xml_files:
if xml_file < start_file or xml_file > end_file:
xml_file_path = os.path.join(folder_path, xml_file)
os.remove(xml_file_path)
# 替换这里的文件夹路径为你的XML文件夹路径
xml_folder_path = 'D:\yolov8a\yolov8-ultralytics\data\VOCdevkit\VOC2007\labels'
# 定义删除范围,从 "000001.xml" 到 "002008.xml"
start_file = '000001.txt'
end_file = '002008.txt'
# 删除范围外的所有XML文件
delete_files_outside_range(xml_folder_path, start_file, end_file)
然后是coco128-seg.yaml文件
train: D:\yolov8a\yolov8-ultralytics\data\VOCdevkit\VOC2007\images
val: D:\yolov8a\yolov8-ultralytics\data\VOCdevkit\VOC2007\images
# Classes
names:
0: dog
1: person
2: train
3: sofa
4: chair
5: car
6: pottedplant
7: diningtable
8: horse
9: cat
10: cow
11: bus
12: bicycle
13: aeroplane
14: motorbike
15: tvmonitor
16: bird
17: bottle
18: boat
19: sheep
此文件需要自己创建 name为类别标签
Yolov8n.pt 不需要下载,跑模型时会自动下载
Yolov8s-seg.yaml 文件配置
nc: 20 # number of classes
depth_multiple: 0.33 # scales module repeats
width_multiple: 0.50 # scales convolution channels
# YOLOv8.0s 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.0s 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, Segment, [nc, 32, 256]] # Detect(P3, P4, P5)
只需要改一个参数 nc = 你的类别标签个数
然后就可以开始训练过程
模型训练命令:
yolo detect train data=D:\yolov8a\yolov8-ultralytics\data\coco128-seg.yaml model=D:\yolov8a\yolov8-ultralytics\weights\yolov8n.pt epochs=10 imgsz=640 device=0
模型的预测:
yolo predict model=D:\yolov8a\yolov8-ultralytics\runs\detect\train4\weights\best.pt source=此处给你想要预测图片的绝对路径 imgsz=640
预测结果一样也会在runs/detect/predict 文件夹下
模型的验证:
yolo val model=D:\yolov8a\yolov8-ultralytics\runs\detect\train4\weights\best.pt data=D:\yolov8a\yolov8-ultralytics\data\coco128-seg.yaml batch=1 imgsz=640
模型的导出:
yolo export model=D:\yolov8a\yolov8-ultralytics\runs\detect\train4\weights\best.pt format=onnx
可打开网页Netron打开文件详细查看模型结构