YYOLOV5训练自己的数据集

简介: YOLOV5训练自己的数据集

1、简介

本文主要详细对YOLOV5网络训练自己的数据集进行讲解,从基础网络下载,到训练自己的数据集,详细的对操作过程进行讲解,适合小白学习以及老手回顾。


2、YOLOV5网络下载

2.1 网络查找

首先点击项目地址:YOLOV5

2.2 版本选择

1.点击tags进行版本选择,如下图所示:



2.选择所需的版本,本次以V6.1版本进行介绍,如下图所示:



3.返回主页进行下载,如下图所示:



在主界面可以看到以及切换到V6.1版本,接着进行下载,如下图所示:



3 环境搭建

将下载好的网络打开,找到requirements.txt文件点击打开,如下图所示:


cc71250d68e6e267ee9dbfc4ab5f1ea2.png


接着按照requirements.txt文件要求在终端输入pip install -r requirements.txt,进行各个包搭建,如下图所示:



接着选择detect.py运行,如下所示:



从报错可知需要进行yolov5s.pt进行下载,下载链接如下:

链接:https://pan.baidu.com/s/1dbALmj7AWUQsVz6GZL9Kiw

提取码:gp2w

将下载好的yolov5s.pt文件拽入总文件夹下,在此运行detect.py,可以进行检测,如下所示:



4 训练集准备

在主目录下新建文件夹VOCData,如下所示:



接着在VOCData文件夹下新建Annotations、images文件夹,如下所示:


3458bca06d074da7361120ae850e3408.png


images文件夹中存放JPG图片,如下所示:


e40fd53deaf233bb52898a38593950d4.png


在images文件夹中建立classes.txt 定义自己要标注的所有类别,如下图所示:


74002c5e102ec09496be4a59fb409de3.png

46b25ecc74372a9805d93467aca854a7.png


Annotations :存放标注的标签文件。


5 labelImg标注图片

图片标注点击:利用labelimg制作自己的数据集。


6划分训练集、验证集、测试集

6.1、在VOCData目录下创建程序 split_train_val.py ,如下图所示:


运行代码如下所示:

# 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()

运行完毕后,会生成 ImagesSets\Main 文件夹,并且Main文件夹下会生成四个子文件如下图所示:



6.2在VOCData目录下创建程序 xml_to_yolo.py 并运行

新建文件如下图所示:



文件代码如下所示:

# -*- coding: utf-8 -*-
import xml.etree.ElementTree as ET
import os
from os import getcwd
sets = ['train', 'val', 'test']
classes = ["windows"]  # 改成自己的类别
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:/Test/Desktop/Desktop/TSET/v5mobilenetsmall/yolov5-master/VOCData/%s.xml' % (image_id), encoding='UTF-8')
    out_file = open('D:/Test/Desktop/Desktop/TSET/v5mobilenetsmall/yolov5-master/VOCData/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')
wd = getcwd()
for image_set in sets:
    if not os.path.exists('D:/Test/Desktop/Desktop/TSET/v5mobilenetsmall/yolov5-master/VOCData/labels/'):
        os.makedirs('D:/Test/Desktop/Desktop/TSET/v5mobilenetsmall/yolov5-master/VOCData/labels/')
    image_ids = open('D:/Test/Desktop/Desktop/TSET/v5mobilenetsmall/yolov5-master/VOCData/ImageSets/Main/%s.txt' % (image_set)).read().strip().split()
    if not os.path.exists('D:/Test/Desktop/Desktop/TSET/v5mobilenetsmall/yolov5-master/VOCData/dataSet_path/'):
        os.makedirs('D:/Test/Desktop/Desktop/TSET/v5mobilenetsmall/yolov5-master/VOCData/dataSet_path/')
    list_file = open('dataSet_path/%s.txt' % (image_set), 'w')
    # 这行路径不需更改,这是相对路径
    for image_id in image_ids:
        list_file.write('D:/Test/Desktop/Desktop/TSET/v5mobilenetsmall/yolov5-master/VOCData/images/%s.jpg\n' % (image_id))
        convert_annotation(image_id)
    list_file.close()


第七行类别需要修改自己的类别,如下图所示:


1f5316a4fd23def4708b610dca02a854.png


第27、28、57、58、59、61、62、67行改成自己的绝对路径如下图所示:


5a39a9e9503fa3aee5cc5c0270b6b697.png


如果本身有的数据集就是yolo格式,那么可以使用如下代码进行yolo转xml:

from xml.dom.minidom import Document
import os
import cv2
# def makexml(txtPath, xmlPath, picPath):  # txt所在文件夹路径,xml文件保存路径,图片所在文件夹路径
def makexml(images, Annotations, xmlPath):  # txt所在文件夹路径,xml文件保存路径,图片所在文件夹路径
    """此函数用于将yolo格式txt标注文件转换为voc格式xml标注文件
    在自己的标注图片文件夹下建三个子文件夹,分别命名为picture、txt、xml
    """
    dic = {'0': "boat",  # 创建字典用来对类型进行转换
           '1': "cat",  # 此处的字典要与自己的classes.txt文件中的类对应,且顺序要一致
           }
    files = os.listdir(txtPath)
    for i, name in enumerate(files):
        xmlBuilder = Document()
        annotation = xmlBuilder.createElement("annotation")  # 创建annotation标签
        xmlBuilder.appendChild(annotation)
        txtFile = open(txtPath + name)
        txtList = txtFile.readlines()
        img = cv2.imread(picPath + name[0:-4] + ".jpg")
        Pheight, Pwidth, Pdepth = img.shape
        folder = xmlBuilder.createElement("folder")  # folder标签
        foldercontent = xmlBuilder.createTextNode("driving_annotation_dataset")
        folder.appendChild(foldercontent)
        annotation.appendChild(folder)  # folder标签结束
        filename = xmlBuilder.createElement("filename")  # filename标签
        filenamecontent = xmlBuilder.createTextNode(name[0:-4] + ".jpg")
        filename.appendChild(filenamecontent)
        annotation.appendChild(filename)  # filename标签结束
        size = xmlBuilder.createElement("size")  # size标签
        width = xmlBuilder.createElement("width")  # size子标签width
        widthcontent = xmlBuilder.createTextNode(str(Pwidth))
        width.appendChild(widthcontent)
        size.appendChild(width)  # size子标签width结束
        height = xmlBuilder.createElement("height")  # size子标签height
        heightcontent = xmlBuilder.createTextNode(str(Pheight))
        height.appendChild(heightcontent)
        size.appendChild(height)  # size子标签height结束
        depth = xmlBuilder.createElement("depth")  # size子标签depth
        depthcontent = xmlBuilder.createTextNode(str(Pdepth))
        depth.appendChild(depthcontent)
        size.appendChild(depth)  # size子标签depth结束
        annotation.appendChild(size)  # size标签结束
        for j in txtList:
            oneline = j.strip().split(" ")
            object = xmlBuilder.createElement("object")  # object 标签
            picname = xmlBuilder.createElement("name")  # name标签
            namecontent = xmlBuilder.createTextNode(dic[oneline[0]])
            picname.appendChild(namecontent)
            object.appendChild(picname)  # name标签结束
            pose = xmlBuilder.createElement("pose")  # pose标签
            posecontent = xmlBuilder.createTextNode("Unspecified")
            pose.appendChild(posecontent)
            object.appendChild(pose)  # pose标签结束
            truncated = xmlBuilder.createElement("truncated")  # truncated标签
            truncatedContent = xmlBuilder.createTextNode("0")
            truncated.appendChild(truncatedContent)
            object.appendChild(truncated)  # truncated标签结束
            difficult = xmlBuilder.createElement("difficult")  # difficult标签
            difficultcontent = xmlBuilder.createTextNode("0")
            difficult.appendChild(difficultcontent)
            object.appendChild(difficult)  # difficult标签结束
            bndbox = xmlBuilder.createElement("bndbox")  # bndbox标签
            xmin = xmlBuilder.createElement("xmin")  # xmin标签
            mathData = int(((float(oneline[1])) * Pwidth + 1) - (float(oneline[3])) * 0.5 * Pwidth)
            xminContent = xmlBuilder.createTextNode(str(mathData))
            xmin.appendChild(xminContent)
            bndbox.appendChild(xmin)  # xmin标签结束
            ymin = xmlBuilder.createElement("ymin")  # ymin标签
            mathData = int(((float(oneline[2])) * Pheight + 1) - (float(oneline[4])) * 0.5 * Pheight)
            yminContent = xmlBuilder.createTextNode(str(mathData))
            ymin.appendChild(yminContent)
            bndbox.appendChild(ymin)  # ymin标签结束
            xmax = xmlBuilder.createElement("xmax")  # xmax标签
            mathData = int(((float(oneline[1])) * Pwidth + 1) + (float(oneline[3])) * 0.5 * Pwidth)
            xmaxContent = xmlBuilder.createTextNode(str(mathData))
            xmax.appendChild(xmaxContent)
            bndbox.appendChild(xmax)  # xmax标签结束
            ymax = xmlBuilder.createElement("ymax")  # ymax标签
            mathData = int(((float(oneline[2])) * Pheight + 1) + (float(oneline[4])) * 0.5 * Pheight)
            ymaxContent = xmlBuilder.createTextNode(str(mathData))
            ymax.appendChild(ymaxContent)
            bndbox.appendChild(ymax)  # ymax标签结束
            object.appendChild(bndbox)  # bndbox标签结束
            annotation.appendChild(object)  # object标签结束
        f = open(xmlPath + name[0:-4] + ".xml", 'w')
        xmlBuilder.writexml(f, indent='\t', newl='\n', addindent='\t', encoding='utf-8')
        f.close()
if __name__ == "__main__":
    picPath = "D:/Desktop/TSET/v5-6.1/VOCData/images/"  # 图片所在文件夹路径,后面的/一定要带上
    txtPath = "D:/Desktop/TSET/v5-6.1/VOCData/Annotations/"  # txt所在文件夹路径,后面的/一定要带上
    xmlPath = "D:/Desktop/TSET/v5-6.1/VOCData/xmlPath/"  # xml文件保存路径,后面的/一定要带上
    makexml(images, Annotations, xmlPath)


仅仅需要在下方三个路径进行修改即可:


7aba5a55555b77dc75bc9da0029a3ed7.png


接着将生成的xml文件复制到Annotations文件夹下:


7396101ab625a536bfcae61217dcd5e2.png

f156233cbdb7d7600811c6f6f783e433.png


7 文件配置

7.1在data目录下新建一个XX.yaml文件

分别对训练集、验证集路径进行设置以及类别个数、名称进行修改,如下所示:



代码如下所示:

train: D:/Desktop/TSET/v5-6.1/VOCData/dataSet_path/train.txt #训练集
val: D:/Desktop/TSET/v5-6.1/VOCData/dataSet_path/val.txt    #验证集
# number of classes
nc: 1 # 类别个数
# class names
names: ["windows"]  # 类别


7.2聚类获得先验框

检查一下是否有下图文件(低版本是没有的,没有的需要自行手动获取)



接着选中下图的yolov5s.yaml文件对类别个数进行修改,如下图所示:



接着在models文件下将yolov5s.yaml文件复制重命名windows,如下所示:



8开始训练

点击train.py文件仅仅需要对下图参数进行修改:



接着对训练轮数进行设置,如下所示:



运行后,会发现下图错误:



说明虚拟内存不足,utils路径下找到datasets.py这个文件,将119行num_workers=0,如下所示:


963ffa1cb8272c76ae2191fa224c5c54.png


接着遇到RuntimeError: result type Float can't be cast to the desired output type __int64问题,如下所示:


b6437cbce19ea67c5b562620f9478c9e.png


loss.py在utils文件夹下,ctrl+f搜索gain,找到gain = torch.ones(7, device=targets.device),将其修改为gain = torch.ones(7, device=targets.device).long(),问题解决


bf0cf779af7d434fab9ee7a7b34693c6.png


接着点击运行,开始训练,如下图所示:


70574061fc78e724074231d8964b4ef2.png


9 启用tensorbord查看参数

首先打开pycharm的命令控制终端,输入如下命令:

tensorboard --logdir=runs/train


接着将得到得网址复制,如下图所示:



点击网址,就会跳转到浏览器中,如下图所示:



上文如有错误,恳请给位大佬指正。

相关文章
|
存储 机器学习/深度学习 算法
MMDetection3d对KITT数据集的训练与评估介绍
MMDetection3d对KITT数据集的训练与评估介绍
1958 0
MMDetection3d对KITT数据集的训练与评估介绍
|
3月前
|
Python
模型训练
【8月更文挑战第20天】模型训练。
49 0
|
2月前
|
人工智能 自动驾驶 数据库
领域大模型的训练需要什么数据?
领域大模型的训练需要什么数据?
113 0
|
3月前
|
计算机视觉
数据集介绍
【8月更文挑战第9天】数据集介绍。
97 1
|
4月前
|
机器学习/深度学习 数据采集 存储
数据集
【7月更文挑战第10天】数据集
191 1
|
机器学习/深度学习 前端开发 测试技术
数据集相关知识
数据集相关知识
299 0
每日训练(五)
每日训练五,题目来源:牛客、力扣
每日训练(五)
|
算法 搜索推荐
每日训练(二)
每日训练(二),题目来源:力扣,PTA。
每日训练(二)