YOLO5-v5.0训练自定义数据集(完整教程)

目录

labelimg制作自己训练数据集

labelimg安装

数据准备

数据标记

自己训练数据集转化为训练集和测试集

YOLOv5训练自己数据集

项目下载

数据、预训练权重准备

模型训练

推理测试

labelimg制作自己训练数据集

labelimg安装

在window系统中的安装,在Anaconda Prompt输入以下的命令:

pip install labelimg -i https://pypi.tuna.tsinghua.edu.cn/simple

数据准备

新建VOC2007,在该文件下再新建3个文件JPEGImages、Annotations、predefined_classes.txt(非必须),最好按照一样方式命名,方便后面操作;
JPEGImages:  存放需要打标签的图片;
Annotations:  存放标注的标签文件;
predefined_classes.txt:  定义自己要标注的所有类别(定义类别比较多的时候,最好创建一个这样的txt文件来存放类别);

数据标记

在Anaconda Prompt输入:labelimg,打开标注工具

:打开单张要标记的图片;

:要标注图片的文件夹;

:这个按键可以说明我们标注的标签为voc格式,点击可以换成yolo或者createML格式。

:选择画目标窗口;

我们选用VOC格式,将标注好的文件放在Annotations文件下面

自己训练数据集转化为训练集和测试集

一般目标检测的数据集资源标签的格式都是VOC:xml格式,而yolov5训练所需要的文件格式是yolo:txt格式,则需要对xml格式的标签文件转换为txt文件。同时训练自己的yolov5检测模型的时候,数据集需要划分为训练集和验证集。文件格式:新建文件夹VOCdevkit,将上述VOC2007文件放入该文件夹下;运行代码如下-文件格式一样就不需要改动
TRAIN_RATIO = 80:训练集与验证集比例80%,自己可改

import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
import random
from shutil import copyfile
# 自己标注的类型
classes=["mouse"]
#训练集与验证集比例80%,自己可改
TRAIN_RATIO = 80


def clear_hidden_files(path):
    dir_list = os.listdir(path)
    for i in dir_list:
        abspath = os.path.join(os.path.abspath(path), i)
        if os.path.isfile(abspath):
            if i.startswith("._"):
                os.remove(abspath)
        else:
            clear_hidden_files(abspath)


def convert(size, box):
    dw = 1. / size[0]
    dh = 1. / 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)


def convert_annotation(image_id):
    in_file = open('VOCdevkit/VOC2007/Annotations/%s.xml' % image_id)
    out_file = open('VOCdevkit/VOC2007/YOLOLabels/%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
        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))
        bb = convert((w, h), b)
        out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
    in_file.close()
    out_file.close()


wd = os.getcwd()
wd = os.getcwd()
data_base_dir = os.path.join(wd, "VOCdevkit/")
if not os.path.isdir(data_base_dir):
    os.mkdir(data_base_dir)
work_sapce_dir = os.path.join(data_base_dir, "VOC2007/")
if not os.path.isdir(work_sapce_dir):
    os.mkdir(work_sapce_dir)
annotation_dir = os.path.join(work_sapce_dir, "Annotations/")
if not os.path.isdir(annotation_dir):
    os.mkdir(annotation_dir)
clear_hidden_files(annotation_dir)
image_dir = os.path.join(work_sapce_dir, "JPEGImages/")
if not os.path.isdir(image_dir):
    os.mkdir(image_dir)
clear_hidden_files(image_dir)
yolo_labels_dir = os.path.join(work_sapce_dir, "YOLOLabels/")
if not os.path.isdir(yolo_labels_dir):
    os.mkdir(yolo_labels_dir)
clear_hidden_files(yolo_labels_dir)
yolov5_images_dir = os.path.join(data_base_dir, "images/")
if not os.path.isdir(yolov5_images_dir):
    os.mkdir(yolov5_images_dir)
clear_hidden_files(yolov5_images_dir)
yolov5_labels_dir = os.path.join(data_base_dir, "labels/")
if not os.path.isdir(yolov5_labels_dir):
    os.mkdir(yolov5_labels_dir)
clear_hidden_files(yolov5_labels_dir)
yolov5_images_train_dir = os.path.join(yolov5_images_dir, "train/")
if not os.path.isdir(yolov5_images_train_dir):
    os.mkdir(yolov5_images_train_dir)
clear_hidden_files(yolov5_images_train_dir)
yolov5_images_test_dir = os.path.join(yolov5_images_dir, "val/")
if not os.path.isdir(yolov5_images_test_dir):
    os.mkdir(yolov5_images_test_dir)
clear_hidden_files(yolov5_images_test_dir)
yolov5_labels_train_dir = os.path.join(yolov5_labels_dir, "train/")
if not os.path.isdir(yolov5_labels_train_dir):
    os.mkdir(yolov5_labels_train_dir)
clear_hidden_files(yolov5_labels_train_dir)
yolov5_labels_test_dir = os.path.join(yolov5_labels_dir, "val/")
if not os.path.isdir(yolov5_labels_test_dir):
    os.mkdir(yolov5_labels_test_dir)
clear_hidden_files(yolov5_labels_test_dir)

train_file = open(os.path.join(wd, "yolov5_train.txt"), 'w')
test_file = open(os.path.join(wd, "yolov5_val.txt"), 'w')
train_file.close()
test_file.close()
train_file = open(os.path.join(wd, "yolov5_train.txt"), 'a')
test_file = open(os.path.join(wd, "yolov5_val.txt"), 'a')
list_imgs = os.listdir(image_dir)  # list image files
prob = random.randint(1, 100)
print("Probability: %d" % prob)
for i in range(0, len(list_imgs)):
    path = os.path.join(image_dir, list_imgs[i])
    if os.path.isfile(path):
        image_path = image_dir + list_imgs[i]
        voc_path = list_imgs[i]
        (nameWithoutExtention, extention) = os.path.splitext(os.path.basename(image_path))
        (voc_nameWithoutExtention, voc_extention) = os.path.splitext(os.path.basename(voc_path))
        annotation_name = nameWithoutExtention + '.xml'
        annotation_path = os.path.join(annotation_dir, annotation_name)
        label_name = nameWithoutExtention + '.txt'
        label_path = os.path.join(yolo_labels_dir, label_name)
    prob = random.randint(1, 100)
    print("Probability: %d" % prob)
    if (prob < TRAIN_RATIO):  # train dataset
        if os.path.exists(annotation_path):
            train_file.write(image_path + '\n')
            convert_annotation(nameWithoutExtention)  # convert label
            copyfile(image_path, yolov5_images_train_dir + voc_path)
            copyfile(label_path, yolov5_labels_train_dir + label_name)
    else:  # test dataset
        if os.path.exists(annotation_path):
            test_file.write(image_path + '\n')
            convert_annotation(nameWithoutExtention)  # convert label
            copyfile(image_path, yolov5_images_test_dir + voc_path)
            copyfile(label_path, yolov5_labels_test_dir + label_name)
train_file.close()
test_file.close()

YOLOv5训练自己数据集

项目下载

       首先打开yolov5的github的官网GitHub - ultralytics/yolov5 at v5.0:打开的官网界面如下,glenn-jocher开源的yolov5的项目

 打开项目目录如下:

data:主要是存放一些超参数的配置文件(.yaml文件:是用来配置训练集、测试集、验证集的路径,还包括目标检测的种类数和种类的名称);训练自己的数据集的话,那么就需要修改其中的.yaml文件。但是自己的数据集不建议放在这个路径下面,而是建议把数据集放到yolov5项目的同级目录下面。

 models:主要是一些网络构建的配置文件和函数,其中包含了该项目的四个不同的版本,分别为是s、m、l、x。这几个版本的大小。他们的检测测度分别都是从快到慢,但是精确度分别是从低到高。训练自己的数据集的话,就需要修改这里面相对应的yaml文件来训练自己模型。

 utils:放置工具类的函数,里面有loss函数、metrics函数、plots函数等。

weights:放置训练好的权重参数。

detect.py:利用训练好的权重参数进行目标检测,可以进行图像、视频和摄像头的检测。

 train.py:训练自己的数据集的函数。

test.py:测试训练的结果的函数。

requirements.txt:这是一个文本文件,里面写着使用yolov5项目的环境依赖包的一些版本,可以利用该文本导入相应版本的包。

数据、预训练权重准备

1、修改数据配置文件 :一个是data目录下的相应的yaml文件,一个是model目录文件下的相应的yaml文件。 修改data目录下:voc.yaml文件,将该文件复制一份,将复制的文件重命名,最好和项目相关,mouse.yaml。

注意:注释download,不然会报错;names:类别为英文,不识别中文;路径最好放绝对路径,不容易报错;

 

 2、修改模型配置文件:models目录下的yolov5s.yaml文件中的相应参数。将yolov5s.yaml文件复制一份,然后将其重命名yolov5_mouse.yaml。
  打开yolov5_mouse.yaml文件只需要修改如图中的数字

 

3、预训练权重下载网址:https://github.com/ultralytics/yolov5/releases,将yolo5s.pt放在weights文件夹下;

模型训练

train.py文件模型的主要参数解析如下所示:

  • weights:初始化的权重文件的路径地址
  • cfg:模型yaml文件的路径地址
  • data:数据yaml文件的路径地址
  • hyp:超参数文件路径地址
  • epochs:训练轮次
  • batch-size:喂入批次文件的多少
  • img-size:输入图片尺寸
  • rect:是否采用矩形训练,默认False
  • resume:接着打断训练上次的结果接着训练
  • nosave:不保存模型,默认False
  •  notest:不进行test,默认False
  • noautoanchor:不自动调整anchor,默认False
  • volve:是否进行超参数进化,默认False
  • bucket:谷歌云盘bucket,一般不会用到
  • cache-images:是否提前缓存图片到内存,以加快训练速度,默认False
  • image-weights:使用加权图像选择进行训练
  • device:训练的设备,cpu;0(表示一个gpu设备cuda:0);0,1,2,3(多个gpu设备)
  • multi-scale:是否进行多尺度训练,默认False
  • single-cls:数据集是否只有一个类别,默认False
  • adam:是否使用adam优化器
  • ync-bn:是否使用跨卡同步BN,在DDP模式使用
  • local_rank:DDP参数,请勿修改
  • workers:最大工作核心数
  •  project:训练模型的保存位置
  • name:模型保存的目录名称
  • exist-ok:模型目录是否存在,不存在就创建

这几个参数就必须要修改的参数:

  parser.add_argument('--weights', type=str, default='weights/yolov5s.pt', help='initial weights path')
  parser.add_argument('--cfg', type=str, default='models/yolov5s_mouse.yaml', help='models/yolov5s_gps.yaml')
  parser.add_argument('--data', type=str, default='data/mouse.yaml', help='data.yaml path')

epochs、batch-size可以根据自身的数据来设置,运行train.py进行模型训练;

推理测试

数据训练好之后,就会在主目录下产生一个run文件夹,在run/train/exp/weights目录下会产生两个权重文件,一个是最后一轮的权重文件,一个是最好的权重文件

主目录下的detect.py,参数解析如下:

  • weights:权重的路径地址
  • source:测试数据,可以是图片/视频路径,也可以是'0'(电脑自带摄像头),也可以是rtsp等视频流
  • output:网络预测之后的图片/视频的保存路径
  • img-size:网络输入图片大小
  • conf-thres:置信度阈值
  • iou-thres:做nms的iou阈值
  • device:是用GPU还是CPU做推理
  • view-img:是否展示预测之后的图片/视频,默认False
  • save-txt:是否将预测的框坐标以txt文件形式保存,默认False
  • classes:设置只保留某一部分类别,形如0或者0 2 3
  • agnostic-nms:进行nms是否也去除不同类别之间的框,默认False
  • augment:推理的时候进行多尺度,翻转等操作(TTA)推理
  • update:如果为True,则对所有模型进行strip_optimizer操作,去除pt文件中的优化器等信息,默认为False
  • project:推理的结果保存在runs/detect目录下

修改主函数的这两处,运行detect.py;

parser.add_argument('--weights', nargs='+', type=str, default='runs/train/exp/weights/best.pt', help='model.pt path(s)')
parser.add_argument('--source', type=str, default='127.jpg', help='source') 

运行过程一些报错问题可看我另外一个博客

猜你喜欢

转载自blog.csdn.net/qq_31807039/article/details/130761433
今日推荐