1.准备VOC数据集
将所有数据集图片放入JPEGImages文件夹中,所有的图片对应的xml文件放入Annotations中,ImageSets文件夹中创建Main文件夹,暂时Main文件夹为空。
** 文件夹结构**
VOCdevkit
————VOC2007
————Annotations # 存放图片对应的xml文件,与JPEGImages图片一一对应
————ImageSets
————Main # 存放train.txt和val.txt文件
————JPEGImages # 存放所有图片
2.数据集划分
**在 VOCdevkit 目录下创建
split.py
,运行之后会在Main 文件夹下生成三个个txt文件:**
**
train.txt、val.txt、test.txt
**
split.py
# -*- coding: utf-8 -*-
"""
Author:smile
Date:2022/09/11 10:00
顺序:脚本A1
简介:分训练集、验证集和测试集,按照 8:1:1 的比例来分,训练集8,验证集1,测试集1
"""
import os
import random
import argparse
parser = argparse.ArgumentParser()
# xml文件的地址,根据自己的数据进行修改 xml一般存放在Annotations下
parser.add_argument('--xml_path', default='VOCdevkit/VOC2007/Annotations', type=str, help='input xml label path')
# 数据集的划分,地址选择自己数据下的ImageSets/Main
parser.add_argument('--txt_path', default='VOCdevkit/VOC2007/ImageSets/Main', type=str, help='output txt label path')
opt = parser.parse_args()
train_percent = 0.8 # 训练集所占比例
val_percent = 0.1 # 验证集所占比例
test_persent = 0.1 # 测试集所占比例
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 = list(range(num))
t_train = int(num * train_percent)
t_val = int(num * val_percent)
train = random.sample(list, t_train)
num1 = len(train)
for i in range(num1):
list.remove(train[i])
val_test = [i for i in list if not i in train]
val = random.sample(val_test, t_val)
num2 = len(val)
for i in range(num2):
list.remove(val[i])
file_train = open(txtsavepath + '/train.txt', 'w')
file_val = open(txtsavepath + '/val.txt', 'w')
file_test = open(txtsavepath + '/test.txt', 'w')
for i in train:
name = total_xml[i][:-4] + '\n'
file_train.write(name)
for i in val:
name = total_xml[i][:-4] + '\n'
file_val.write(name)
for i in list:
name = total_xml[i][:-4] + '\n'
file_test.write(name)
file_train.close()
file_val.close()
file_test.close()
3. VOC转YOLO格式
第2步只是把数据集划分了比例,想训练,还要进行这一步。在VOCdevkit目录下创建**
voc_label.py
,点击运行,会在目录下生成新的
labels
**文件夹,把数据集路径导入txt文件,将每个xml标注信息提取转换为了txt格式,每个图像对应一个txt文件。
# -*- coding: utf-8 -*-
import xml.etree.ElementTree as ET
import os
sets = ['train', 'val', 'test'] # 如果你的Main文件夹没有test.txt,就删掉'test'
# classes = ["a", "b"] # 改成自己的类别,VOC数据集有以下20类别
classes = ["aeroplane", 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog',
'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor'] # class names
abs_path = os.getcwd()
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(abs_path + '/VOCdevkit/VOC2007/Annotations/%s.xml' % (image_id), encoding='UTF-8')
out_file = open(abs_path + '/VOCdevkit/VOC2007/labels/%s.txt' % (image_id), 'w')
tree = ET.parse(in_file)
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')
for image_set in sets:
if not os.path.exists(abs_path + '/VOCdevkit/VOC2007/labels/'):
os.makedirs(abs_path + '/VOCdevkit/VOC2007/labels/')
image_ids = open(abs_path + '/VOCdevkit/VOC2007/ImageSets/Main/%s.txt' % (image_set)).read().strip().split()
list_file = open(abs_path + '/VOCdevkit/VOC2007/%s.txt' % (image_set), 'w')
for image_id in image_ids:
list_file.write(abs_path + '/VOCdevkit/VOC2007/JPEGImages/%s.jpg\n' % (image_id)) # 要么自己补全路径,只写一半可能会报错
convert_annotation(image_id)
list_file.close()
运行之后,会在VOC2007目录下生成 **
labels
**文件夹和3个新的.txt文件
其中,新生成的3个的**
train.txt、val.txt、test.txt
**,这正是后面训练需要用的文件。每个txt文件里面存放的图片的文件名全路径:
4.训练准备
1.创建自己数据集的 yaml 文件
找到文件夹 data** , **在data 文件夹中创建自己数据集的 mydata.yaml 文件
**train val test : **三个txt的路径(注意冒号后要有一个空格)
nc : 自己数据集类别个数
**names: **数据集类别名字
2.修改训练 yolov7 的 yaml 文件
在 **cfg/training 文件夹中,选择想要使用的 yaml 文件,将文件中的 nc **改为自己数据集的类别数
3. 修改datasets.py文件
做完以上步骤,若直接开始训练,会报错:
AssertionError: train: No labels in 2007_train.cache. Can not train without labels
解决方法:
找到 ** **
**utils/dataset.py **
文件,搜索框搜索 Define label,将下图红色线处内容修改为’JPEGImages’。原本yolov7 代码这里是’images’,但VOC是把图片保存在JPEGImages下的,所以需要修改方能正确读取图片。
5. 开始训练
训练的时候 train 和 val 数据集都会使用到,验证集 test 在下一步使用
weights : 预训练权重位置
**cfg : **上一部分修改的 yolov7.yaml 文件位置
**data : **上一部分修改的数据集 yaml 文件位置
hyp :训练所需超参数位置,可以不用修改
epochs : 想要训练的轮数
batch-size : 步距,需要显存,过大可能报错
6.使用 test.py
当训练完之后想要使用测试集(test)进行测试的时候,找到 test.py
**weights **: 自己训练完之后生成的权重位置
data : 同训练时使用的一样(自己数据集的 yaml)
task : 改为 test
参考:yolov5训练—VOC数据集划分(训练集、验证集、测试集)和转换YOLO格式_目标检测_下雨天不下雨-DevPress官方社区 (csdn.net)
版权归原作者 I'mFAN 所有, 如有侵权,请联系我们删除。