精华内容
下载资源
问答
  • yolov5训练自己数据

    千次阅读 2021-01-08 12:20:24
    yolov5训练自己数据集 项目地址:https://github.com/ultralytics/yolov5 环境:Windows pytorch-gpu==1.6.0 ** 一、数据集准备** ├── data │ ├── Annotations 进行 detection 任务时的标签文件,xml 形式,...

    yolov5训练自己数据集

    项目地址:https://github.com/ultralytics/yolov5
    环境:Windows pytorch-gpu==1.6.0

    ** 一、数据集准备**

    ├── data
    │   ├── Annotations  进行 detection 任务时的标签文件,xml 形式,文件名与图片名一一对应
    │   ├── images  存放 .jpg 格式的图片文件
    │   ├── ImageSets  存放的是分类和检测的数据集分割文件,包含train.txt, val.txt,trainval.txt,test.txt
    │   ├── labels  存放label标注信息的txt文件,与图片一一对应
    
    ├── ImageSets(train,val,test建议按照8:1:1比例划分)
    │   ├── train.txt  写着用于训练的图片名称
    │   ├── val.txt  写着用于验证的图片名称
    │   ├── trainval.txt  train与val的合集
    │   ├── test.txt  写着用于测试的图片名称
    
    

    1.ImageSets 下文件的生成
    运行我的data文件夹下的makeTxt.py文件。生成如图所示data/ImageSets下四个文件。

    文件内容如图所示:
    在这里插入图片描述
    makeTxt.py完整代码如下:

    import os
    import random
    
    trainval_percent = 0.1# 训练集和验证集所占比例,剩下的0.2是测试集比例
    train_percent = 0.9# 训练集所占比例
    xmlfilepath = './Annotations'
    txtsavepath = './ImageSets'
    total_xml = os.listdir(xmlfilepath)
    num = len(total_xml)
    list = range(num)
    tv = int(num * trainval_percent)
    tr = int(tv * train_percent)
    trainval = random.sample(list, tv)
    train = random.sample(trainval, tr)
    ftrainval = open('./ImageSets/trainval.txt', 'w') #只包含名称,没有后缀和路径
    ftest = open('./ImageSets/test.txt', 'w')
    ftrain = open('./ImageSets/train.txt', 'w')
    fval = open('./ImageSets/val.txt', 'w')
    
    for i in list:
        name = total_xml[i][:-4] + '\n'
        if i in trainval:
            ftrainval.write(name)
            if i in train:
                ftest.write(name)
            else:
                fval.write(name)
        else:
            ftrain.write(name)
    ftrainval.close()
    ftrain.close()
    fval.close()
    ftest.close()
    

    运行voc_label.py文件,将图片数据集标注后的xml文件中的标注信息读取出来并写入txt文件,运行后在labels文件夹中出现所有图片数据集的标注信息,并在data目录下生成三个txt文件。
    在这里插入图片描述

    # xml解析包 在labels中存放txt格式的标签信息
    import xml.etree.ElementTree as ET
    import pickle
    import os
    # os.listdir() 方法用于返回指定的文件夹包含的文件或文件夹的名字的列表
    from os import listdir, getcwd
    from os.path import join
    
    
    sets = ['train', 'test', 'val']
    classes = ['jyz', 'xcxj', 'fzc', 'nc','jyz_gz','fzc_gz']
    
    
    # 进行归一化操作
    def convert(size, box): # size:(原图w,原图h) , box:(xmin,xmax,ymin,ymax)
        dw = 1./size[0]     # 1/w
        dh = 1./size[1]     # 1/h
        x = (box[0] + box[1])/2.0   # 物体在图中的中心点x坐标
        y = (box[2] + box[3])/2.0   # 物体在图中的中心点y坐标
        w = box[1] - box[0]         # 物体实际像素宽度
        h = box[3] - box[2]         # 物体实际像素高度
        x = x*dw    # 物体中心点x的坐标比(相当于 x/原图w)
        w = w*dw    # 物体宽度的宽度比(相当于 w/原图w)
        y = y*dh    # 物体中心点y的坐标比(相当于 y/原图h)
        h = h*dh    # 物体宽度的宽度比(相当于 h/原图h)
        return (x, y, w, h)    # 返回 相对于原图的物体中心点的x坐标比,y坐标比,宽度比,高度比,取值范围[0-1]
    
    
    # year ='2012', 对应图片的id(文件名)
    def convert_annotation(image_id):
        '''
        将对应文件名的xml文件转化为label文件,xml文件包含了对应的bunding框以及图片长款大小等信息,
        通过对其解析,然后进行归一化最终读到label文件中去,也就是说
        一张图片文件对应一个xml文件,然后通过解析和归一化,能够将对应的信息保存到唯一一个label文件中去
        labal文件中的格式:calss x y w h  同时,一张图片对应的类别有多个,所以对应的bunding的信息也有多个
        '''
        # 对应的通过year 找到相应的文件夹,并且打开相应image_id的xml文件,其对应bund文件
        in_file = open('./Annotations/%s.xml' % (image_id), encoding='utf-8')
        # 准备在对应的image_id 中写入对应的label,分别为
        # <object-class> <x> <y> <width> <height>
        out_file = open('./labels/%s.txt' % (image_id), 'w', encoding='utf-8')
        # 解析xml文件
        tree = ET.parse(in_file)
        # 获得对应的键值对
        root = tree.getroot()
        # 获得图片的尺寸大小
        size = root.find('size')
        # 获得宽
        w = int(size.find('width').text)
        # 获得高
        h = int(size.find('height').text)
        # 遍历目标obj
        for obj in root.iter('object'):
            # 获得difficult ??
            difficult = obj.find('difficult').text
            # 获得类别 =string 类型
            cls = obj.find('name').text
            # 如果类别不是对应在我们预定好的class文件中,或difficult==1则跳过
            if cls not in classes or int(difficult) == 1:
                continue
            # 通过类别名称找到id
            cls_id = classes.index(cls)
            # 找到bndbox 对象
            xmlbox = obj.find('bndbox')
            # 获取对应的bndbox的数组 = ['xmin','xmax','ymin','ymax']
            b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),
                 float(xmlbox.find('ymax').text))
            print(image_id, cls, b)
            # 带入进行归一化操作
            # w = 宽, h = 高, b= bndbox的数组 = ['xmin','xmax','ymin','ymax']
            bb = convert((w, h), b)
            # bb 对应的是归一化后的(x,y,w,h)
            # 生成 calss x y w h 在label文件中
            out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
    
    
    # 返回当前工作目录
    wd = getcwd()
    print(wd)
    
    
    for image_set in sets:
        '''
        对所有的文件数据集进行遍历
        做了两个工作:
        1.讲所有图片文件都遍历一遍,并且将其所有的全路径都写在对应的txt文件中去,方便定位
        2.同时对所有的图片文件进行解析和转化,将其对应的bundingbox 以及类别的信息全部解析写到label 文件中去
             最后再通过直接读取文件,就能找到对应的label 信息
        '''
        # 先找labels文件夹如果不存在则创建
        if not os.path.exists('./labels/'):
            os.makedirs('./labels/')
        # 读取在ImageSets/Main 中的train、test..等文件的内容
        # 包含对应的文件名称
        image_ids = open('./ImageSets/%s.txt' % (image_set)).read().strip().split()
        # 打开对应的2012_train.txt 文件对其进行写入准备
        list_file = open('./%s.txt' % (image_set), 'w')
        # 将对应的文件_id以及全路径写进去并换行
        for image_id in image_ids:
            list_file.write('./images/%s.jpg\n' % (image_id))
            # 调用  year = 年份  image_id = 对应的文件名_id
            convert_annotation(image_id)
        # 关闭文件`在这里插入代码片`
        list_file.close()
    

    二、模型训练和检测
    1.在data目录下,复制一份coco.yaml文件并将其重命名为my.yaml,放在data目录下,并对cat.yaml中的参数进行配置。

    #修改训练集、验证集和测试集txt路径
    train: data/train.txt  # 118287 images
    val: data/val.txt  # 5000 images
    test: data/test.txt  # 20288 of 40670 images, submit to https://competitions.codalab.org/competitions/20794
    # 修改类别数
    nc: 6
    
    # 修改类名
    names: ['jyz', 'xcxj', 'fzc', 'nc','jyz_gz','fzc_gz']
    

    2.修改models目录下的yolov5s.yaml文件。这里可以根据自己选择的模型大小修改对应文件。

    nc: 6   #nc:类别数,你的类别有多少就填写多少。从1开始算起,不是0-14这样算。
    #顺便一提, 下面两个参数可控制网络结构,不需修改,与模型大小已经对应。
    depth_multiple: 0.33  # 控制模型的深度,假设yolov5l中有三个Bottleneck,那yolov5s中就只有一个Bottleneck。
    width_multiple: 0.50  # 控制卷积核的个数设置为0.5,Focus就变成[32, 3],Conv就变成[64, 3, 2]。以此类推,卷积核的个数都变成了设置的一半。
    

    3.训练参数修改 train.py,也可在终端通过命令进行指定参数。注意修改以下几个参数。运行train.py

    parser.add_argument('--weights', type=str, default='yolov5s.pt', help='initial weights path')
    parser.add_argument('--cfg', type=str, default='models/yolov5s.yaml', help='model.yaml path')
    #自己的yaml文件
    parser.add_argument('--data', type=str, default='data/my.yaml', help='data.yaml path')
    parser.add_argument('--epochs', type=int, default=300)
    #爆显存的话调小一点
    parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs')
    parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='[train, test] image sizes')
    # 训练的设备,cpu;0(表示一个gpu设备cuda:0);0,1,2,3(多个gpu设备)。值为空时,训练时默认使用计算机自带的显卡或CPU
    parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
    # dataloader的最大worker数量。这里我记得报错,可以将workers修改为0.
    parser.add_argument('--workers', type=int, default=4, help='maximum number of dataloader workers')
    
    

    可视化:进入环境
    tensorboard --logdir runs
    根据提示打开浏览器http://localhost:6006/
    4.检测需要修改的参数,一般修改的以下几个参数,然后运行detect.py。

    # 选用训练的权重
    parser.add_argument('--weights', nargs='+', type=str, default='runs/train/exp/weights/best.pt', help='model.pt path(s)')
    # source=0表示摄像头实时检测,也可输入视频路径
    parser.add_argument('--source', type=str, default='inference/videos/jyz.mp4', help='source') 
    # 网络输入图片大小
    parser.add_argument('--view-img', action='store_true', help='display results')
    # 是否将检测的框坐标以txt文件形式保存,默认False,当需要报存时,可修改路径default="inference/output"
    parser.add_argument('--save-txt', action='store_true', help='save results to *.txt')
    # 设置只保留某一部分类别,添加语句default=[0,1,2]等id。
    parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --class 0, or --class 0 2 3')
    

    三、pytorch转onnx
    1.官方自带的export.py,选择模型

    python models/export.py --weights weights/yolov5s.pt --img 640 --batch 1
    

    2.根据错误提示pip install coremltools、packaging。然后继续运行1的命令
    3.此时 weights下出现三个文件 :onnx、mlmodel、torchscript
    4.使用神经网络Netron,出现网络结构图。

    import netron
    netron.start('yolov5s.onnx')
    

    5 . pt模型转为了onnx模型,可以说已经脱离了pytorch了,但是转ncnn还需要对模型做一个Simplifier操作,因为转出的onnx模型还有许多冗余,这在ncnn里也是不支持的,避免转ncnn时各种报错安装简化 打开weights简化

    python -m onnxsim yolov5s.onnx yolov5s_sim.onnx 
    

    四、 遇到的问题
    1.路径一定不要包含中文,不让opencv报错。如果必须要读中文的话,读取路径那里添加一句话:

    img = cv2.imdecode(np.fromfile(img_path, dtype=np.uint8), -1)
    

    2.batch-size要根据自己显存调节,不然会报错。

    展开全文
  • YoloV5训练本地数据问题解决:AssertionError: train: No labels in 2007_train.cache. Can not train without labels背景解决方法 背景 在实现YoloV5训练本地数据时遇到了一个关于标签没有读取的问题,无法进行训练...

    YoloV5训练本地数据问题解决:AssertionError: train: No labels in 2007_train.cache. Can not train without labels

    问题1

    在实现YoloV5训练本地数据时遇到了一个关于标签没有读取的问题,无法进行训练,在寻找了多个实验方法之后发现此博文有相似的错误,进而参考其解决方法顺利解决,在此做一下记录。

    Q1解决方法

    打开dataset.py文件,使用快捷键Ctrl+F使用搜索框搜索define label
    在这里插入图片描述

    按照正常的VOC标注之后图片应该时保存在JPEGImages文件夹下的,但是根据源码则是读取的images里的图片,因此需要将images改为JPEGImages,这样就能正常读取了。

    问题2

    在运行的时候出现了这个问题RuntimeError: shape ‘[16, 3, 85, 52, 80]’ is invalid for input of size 17971,其实此类问题的本质是输入的数据维度与需要的维度不一致导致的,因此最大的可能性就是你的数据的设置出现了问题(因为网络本身的结构是没有问题的),这个时候就要去检查下你这行代码出现的地方,把相对应的数据输出再与自己想要的进行对比就能发现你的数据错误。

    Q2解决方法:

    我的错误是因为配置文件里的nc,即类别的数量搞错了,与我的数据不符合,因此报错。解决方法就是找到你的对应的data配置文件,把nc改成你对应的数据集的类别数量即可。

    展开全文
  • yolov5训练自己数据集的时候遇见坑

    千次阅读 2020-08-18 15:33:46
    讲解详细,但是我自己忽略了一个细节,就是将xml文件转成txt文件的代码中 classes = ["b"] # 输入缺陷名称,必须与xml标注名称一致 这块名字并没有跟我自己的xml文件一致,造成生成的txt文件是空文件, ...

    1.mac系统文件夹内会有一个默认文件das_store在遍历文件的收会造成多出来这个文件,造成其他地方的错误;

    2.按照https://www.freesion.com/article/60871062184/这个教程配置文件。讲解详细,但是我自己忽略了一个细节,就是将xml文件转成txt文件的代码中     classes = ["b"] # 输入缺陷名称,必须与xml标注名称一致  这块名字并没有跟我自己的xml文件一致,造成生成的txt文件是空文件,

    展开全文
  • YOLOv5训练自己数据集(超详细完整版)

    万次阅读 多人点赞 2020-10-16 11:38:18
    一.Requirements 本教程所用环境:代码版本V3.0... 准备自己数据集(VOC格式) 1.在yolov5目录下创建paper_data文件夹(名字可以自定义),目录结构如下,将之前labelImg标注好的xml文件和图片放到对应目录下 paper_

    一.Requirements

    本教程所用环境:代码版本V3.0,源码下载地址:https://github.com/ultralytics/yolov5.git
    Pytorch:1.6.0
    Cuda:10.1
    Python:3.7
    官方要求Python>=3.8 and PyTorch>=1.6.
    通过git clone https://github.com/ultralytics/yolov5.git将YOLOv5源码下载到本地,创建好虚拟环境,并通过pip install -r requirements.txt安装依赖包。

    二. 准备自己的数据集(VOC格式)

    1.在yolov5目录下创建paper_data文件夹(名字可以自定义),目录结构如下,将之前labelImg标注好的xml文件和图片放到对应目录下
    paper_data
    …images # 存放图片
    …Annotations # 存放图片对应的xml文件
    …ImageSets/Main #之后会在Main文件夹内自动生成train.txt,val.txt,test.txt和trainval.txt四个文件,存放训练集、验证集、测试集图片的名字(无后缀.jpg)
    示例如下:
    paper_data文件夹下内容如下:
    在这里插入图片描述
    Annotations文件夹下面为xml文件(标注工具采用labelImage),内容如下:
    在这里插入图片描述
    images为VOC数据集格式中的JPEGImages,内容如下:
    在这里插入图片描述
    ImageSets文件夹下面有个Main子文件夹,其下面存放训练集、验证集、测试集的划分,通过脚本生成,可以创建一个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()
    

    运行代码后,在Main文件夹下生成下面四个txt文档:
    在这里插入图片描述
    2.接下来准备labels,把数据集格式转换成yolo_txt格式,即将每个xml标注提取bbox信息为txt格式(这种数据集格式成为yolo_txt格式),每个图像对应一个txt文件,文件每一行为一个目标的信息,包括class, x_center, y_center, width, height格式。格式如下:
    在这里插入图片描述
    参考如下(https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data#2-create-labels):
    在这里插入图片描述

    创建voc_label.py文件,将训练集、验证集、测试集生成label标签(训练中要用到),同时将数据集路径导入txt文件中,代码内容如下:

    # -*- coding: utf-8 -*-
    import xml.etree.ElementTree as ET
    import os
    from os import getcwd
    
    sets = ['train', 'val', 'test']
    classes = ["a", "b"]   # 改成自己的类别
    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('/home/trainingai/zyang/yolov5/paper_data/Annotations/%s.xml' % (image_id), encoding='UTF-8')
        out_file = open('/home/trainingai/zyang/yolov5/paper_data/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('/home/trainingai/zyang/yolov5/paper_data/labels/'):
            os.makedirs('/home/trainingai/zyang/yolov5/paper_data/labels/')
        image_ids = open('/home/trainingai/zyang/yolov5/paper_data/ImageSets/Main/%s.txt' % (image_set)).read().strip().split()
        list_file = open('paper_data/%s.txt' % (image_set), 'w')
        for image_id in image_ids:
            list_file.write(abs_path + '/paper_data/images/%s.jpg\n' % (image_id))
            convert_annotation(image_id)
        list_file.close()
    

    运行后会生成如下labels文件夹和三个包含数据集的txt文件,其中labels中为不同图像的标注文件,train.txt等txt文件为划分后图像所在位置的绝对路径,如train.txt就含有所有训练集图像的绝对路径。
    运行voc_label.py时报错“ZeroDivisionError: float division by zero”的原因是:标注文件中存在width为0或者height为0的数据,检查修改后可解决。
    在这里插入图片描述
    三个txt文件里面的内容如下:
    在这里插入图片描述
    3.配置文件
    1)数据集的配置
    在yolov5目录下的data文件夹下新建一个ab.yaml文件(可以自定义命名),用来存放训练集和验证集的划分文件(train.txt和val.txt),这两个文件是通过运行voc_label.py代码生成的,然后是目标的类别数目和具体类别列表,ab.yaml内容如下:
    在这里插入图片描述
    疑问:ab.yaml文件中train和val通过train.txt和val.txt指定,我在训练时报错(别人没有报错,很费解!评论中有人遇到一样的报错,给出解决方法是:发现冒号后面需要加空格,否则会被认为是字符串而不是字典,可以试一下),于是我参照官网上data/coco128.yaml的形式指定train和val,内容如下:
    在这里插入图片描述
    2)编辑模型的配置文件
    2-1) 聚类得出先验框(可选)(聚类重新生成anchors运行时间较长)
    最新版的yolov5,它会自动kmeans算出anchors
    如下图所示:
    在这里插入图片描述

    kmeans.py代码内容如下:

    import numpy as np
    
    def iou(box, clusters):
        """
        Calculates the Intersection over Union (IoU) between a box and k clusters.
        :param box: tuple or array, shifted to the origin (i. e. width and height)
        :param clusters: numpy array of shape (k, 2) where k is the number of clusters
        :return: numpy array of shape (k, 0) where k is the number of clusters
        """
        x = np.minimum(clusters[:, 0], box[0])
        y = np.minimum(clusters[:, 1], box[1])
        if np.count_nonzero(x == 0) > 0 or np.count_nonzero(y == 0) > 0:
            raise ValueError("Box has no area")                 # 如果报这个错,可以把这行改成pass即可
    
        intersection = x * y
        box_area = box[0] * box[1]
        cluster_area = clusters[:, 0] * clusters[:, 1]
    
        iou_ = intersection / (box_area + cluster_area - intersection)
    
        return iou_
    
    def avg_iou(boxes, clusters):
        """
        Calculates the average Intersection over Union (IoU) between a numpy array of boxes and k clusters.
        :param boxes: numpy array of shape (r, 2), where r is the number of rows
        :param clusters: numpy array of shape (k, 2) where k is the number of clusters
        :return: average IoU as a single float
        """
        return np.mean([np.max(iou(boxes[i], clusters)) for i in range(boxes.shape[0])])
    
    def translate_boxes(boxes):
        """
        Translates all the boxes to the origin.
        :param boxes: numpy array of shape (r, 4)
        :return: numpy array of shape (r, 2)
        """
        new_boxes = boxes.copy()
        for row in range(new_boxes.shape[0]):
            new_boxes[row][2] = np.abs(new_boxes[row][2] - new_boxes[row][0])
            new_boxes[row][3] = np.abs(new_boxes[row][3] - new_boxes[row][1])
        return np.delete(new_boxes, [0, 1], axis=1)
    
    
    def kmeans(boxes, k, dist=np.median):
        """
        Calculates k-means clustering with the Intersection over Union (IoU) metric.
        :param boxes: numpy array of shape (r, 2), where r is the number of rows
        :param k: number of clusters
        :param dist: distance function
        :return: numpy array of shape (k, 2)
        """
        rows = boxes.shape[0]
    
        distances = np.empty((rows, k))
        last_clusters = np.zeros((rows,))
    
        np.random.seed()
    
        # the Forgy method will fail if the whole array contains the same rows
        clusters = boxes[np.random.choice(rows, k, replace=False)]
    
        while True:
            for row in range(rows):
                distances[row] = 1 - iou(boxes[row], clusters)
    
            nearest_clusters = np.argmin(distances, axis=1)
    
            if (last_clusters == nearest_clusters).all():
                break
    
            for cluster in range(k):
                clusters[cluster] = dist(boxes[nearest_clusters == cluster], axis=0)
    
            last_clusters = nearest_clusters
    
        return clusters
    
    if __name__ == '__main__':
        a = np.array([[1, 2, 3, 4], [5, 7, 6, 8]])
        print(translate_boxes(a))
    

    聚类生成新anchors的文件clauculate_anchors.py,代码内容如下:

    # -*- coding: utf-8 -*-
    # 根据标签文件求先验框
    
    import os
    import numpy as np
    import xml.etree.cElementTree as et
    from kmeans import kmeans, avg_iou
    
    FILE_ROOT = "/home/trainingai/zyang/yolov5/paper_data/"     # 根路径
    ANNOTATION_ROOT = "Annotations"  # 数据集标签文件夹路径
    ANNOTATION_PATH = FILE_ROOT + ANNOTATION_ROOT
    
    ANCHORS_TXT_PATH = "/home/trainingai/zyang/yolov5/data/anchors.txt"
    
    CLUSTERS = 9
    CLASS_NAMES = ['a', 'b']
    
    def load_data(anno_dir, class_names):
        xml_names = os.listdir(anno_dir)
        boxes = []
        for xml_name in xml_names:
            xml_pth = os.path.join(anno_dir, xml_name)
            tree = et.parse(xml_pth)
    
            width = float(tree.findtext("./size/width"))
            height = float(tree.findtext("./size/height"))
    
            for obj in tree.findall("./object"):
                cls_name = obj.findtext("name")
                if cls_name in class_names:
                    xmin = float(obj.findtext("bndbox/xmin")) / width
                    ymin = float(obj.findtext("bndbox/ymin")) / height
                    xmax = float(obj.findtext("bndbox/xmax")) / width
                    ymax = float(obj.findtext("bndbox/ymax")) / height
    
                    box = [xmax - xmin, ymax - ymin]
                    boxes.append(box)
                else:
                    continue
        return np.array(boxes)
    
    if __name__ == '__main__':
    
        anchors_txt = open(ANCHORS_TXT_PATH, "w")
    
        train_boxes = load_data(ANNOTATION_PATH, CLASS_NAMES)
        count = 1
        best_accuracy = 0
        best_anchors = []
        best_ratios = []
    
        for i in range(10):      ##### 可以修改,不要太大,否则时间很长
            anchors_tmp = []
            clusters = kmeans(train_boxes, k=CLUSTERS)
            idx = clusters[:, 0].argsort()
            clusters = clusters[idx]
            # print(clusters)
    
            for j in range(CLUSTERS):
                anchor = [round(clusters[j][0] * 640, 2), round(clusters[j][1] * 640, 2)]
                anchors_tmp.append(anchor)
                print(f"Anchors:{anchor}")
    
            temp_accuracy = avg_iou(train_boxes, clusters) * 100
            print("Train_Accuracy:{:.2f}%".format(temp_accuracy))
    
            ratios = np.around(clusters[:, 0] / clusters[:, 1], decimals=2).tolist()
            ratios.sort()
            print("Ratios:{}".format(ratios))
            print(20 * "*" + " {} ".format(count) + 20 * "*")
    
            count += 1
    
            if temp_accuracy > best_accuracy:
                best_accuracy = temp_accuracy
                best_anchors = anchors_tmp
                best_ratios = ratios
    
        anchors_txt.write("Best Accuracy = " + str(round(best_accuracy, 2)) + '%' + "\r\n")
        anchors_txt.write("Best Anchors = " + str(best_anchors) + "\r\n")
        anchors_txt.write("Best Ratios = " + str(best_ratios))
        anchors_txt.close()
    

    clauculate_anchors.py 内要修改为自己数据集的路径,如下:

    FILE_ROOT = "xxx"    # 根路径
    ANNOTATION_ROOT = "xxx"  # 数据集标签文件夹路径
    ANNOTATION_PATH = FILE_ROOT + ANNOTATION_ROOT
    

    运行clauculate_anchors.py跑完会生成一个文件 anchors.txt,里面有得出的建议先验框anchors,内容如下:
    在这里插入图片描述
    PS: 如果自己动手生成anchors时候报错“ raise ValueError(“Box has no area”)”,可能是标注数据中有的目标物很小很小,可以把kmeans.py中第13行注释掉,改成pass即可解决这个报错。

    2-2) 选择一个你需要的模型
    在yolov5目录下的model文件夹下是模型的配置文件,这边提供s、m、l、x版本,逐渐增大(随着架构的增大,训练时间也是逐渐增大),假设采用yolov5s.yaml,只用修改一个参数,把nc改成自己的类别数;如果anchors是重新生成的,也需要修改,根据anchors.txt 中的 Best Anchors 修改,需要取整(可选) 如下:
    在这里插入图片描述
    至此,自定义数据集已创建完毕,接下来就是训练模型了。
    三.模型训练
    1.下载预训练模型
    源码中在yolov5目录下的weights文件夹下提供了下载四种预训练模型的脚本----download_weights.sh
    执行这个shell脚本就可以下载,这里weights的下载可能因为网络而难以进行,有人分享了百度网盘的下载地址,但是不一定是v3.0版本最新的预训练模型,如果不是v3.0版本最新的预训练模型,在训练时会报错如下:
    在这里插入图片描述
    出现这个问题原因是预训练模型下载的不是最新的,例如V3.0的代码,下载的是V2.0或者V1.0的模型权重就会报错,重新下载最新的模型权重即可解决。我是通过官网源码给的链接翻墙在google云盘上下载的。
    2.训练
    在train.py进行以下几个修改:
    在这里插入图片描述

    以上参数解释如下:
    epochs:指的就是训练过程中整个数据集将被迭代多少次,显卡不行你就调小点。
    batch-size:一次看完多少张图片才进行权重更新,梯度下降的mini-batch,显卡不行你就调小点。
    cfg:存储模型结构的配置文件
    data:存储训练、测试数据的文件
    img-size:输入图片宽高,显卡不行你就调小点。
    rect:进行矩形训练
    resume:恢复最近保存的模型开始训练
    nosave:仅保存最终checkpoint
    notest:仅测试最后的epoch
    evolve:进化超参数
    bucket:gsutil bucket
    cache-images:缓存图像以加快训练速度
    weights:权重文件路径
    name: 重命名results.txt to results_name.txt
    device:cuda device, i.e. 0 or 0,1,2,3 or cpu
    adam:使用adam优化
    multi-scale:多尺度训练,img-size +/- 50%
    single-cls:单类别的训练集
    之后运行训练命令如下:

    python train.py --img 640 --batch 16 --epoch 300 --data data/ab.yaml --cfg models/yolov5s.yaml --weights weights/yolov5s.pt --device '0'     # 0号GPU
    

    根据自己的硬件配置修改参数,训练好的模型会被保存在yolov5目录下的runs/exp0/weights/last.pt和best.pt,详细训练数据保存在runs/exp0/results.txt文件中。
    如果Cuda版本不对(不是>=10.1版本),在调用GPU训练时会报错如下:
    在这里插入图片描述
    3.训练过程可视化
    利用tensorboard可视化训练过程,训练开始会在yolov5目录生成一个runs文件夹,利用tensorboard打开即可查看训练日志,命令如下:

    tensorboard --logdir=runs
    

    在这里插入图片描述
    由于TensorFlow2.0及以上版本现在支持CUDA10.0,还不支持CUDA10.1,因此我在使用TensorFlow2.0以上版本利用tensorboard打开训练日志时报错如下:
    在这里插入图片描述
    于是我改用tensorflow-gpu1.13.1版本的环境,利用tensorboard即可成功打开并查看训练日志,可视化结果如上图。

    至此YOLOv5训练自己的数据集,训练阶段已完毕。
    YOLOv5训练速度更快,准确率更高,个人感觉最大的优势是相比YOLOv3,YOLOv5的模型更加轻量级,同样的数据集训练出来的模型大小是YOLOv3的将近四分之一大小。
    四.模型测试
    评估模型好坏就是在有标注的测试集或者验证集上进行模型效果的评估,在目标检测中最常使用的评估指标为mAP。在test.py文件中指定数据集配置文件和训练结果模型,如下:
    在这里插入图片描述
    通过下面的命令进行模型测试:

    python test.py  --data data/ab.yaml --weights runs/exp1/weights/best.pt --augment
    

    模型测试效果如下:
    在这里插入图片描述
    五.模型推理
    最后,模型在没有标注的数据集上进行推理,在detect.py文件中指定测试图片和测试模型的路径,其他参数(img_size、置信度object confidence threshold、IOU threshold for NMS)可自行修改,如下:
    在这里插入图片描述
    使用下面的命令(该命令中save_txt选项用于生成结果的txt标注文件,不指定则只会生成结果图像),其中,weights使用最满意的训练模型即可,source则提供一个包含所有测试图片的文件夹路径即可。

     python detect.py --weights runs/exp1/weights/best.pt --source inference/images/ --device 0 --save-txt
    

    测试完毕后,每个测试图片会在指定的inference/output输出文件夹中生成结果图片和同名的txt文件,如下:
    在这里插入图片描述
    每个txt会生成一行一个目标的信息,信息包括类别序号、xcenter ycenter w h,后面四个为bbox位置,均为归一化数值,如下图:
    在这里插入图片描述
    在进行模型推理时,无论是加载模型的速度还是对测试图片的推理速度,都能明显感觉到YOLOv5比YOLOv3速度快,尤其是加载模型的速度,因为同样的数据集训练出来的模型YOLOv5更加轻量级,模型大小减小为YOLOv3的将近四分之一。
    至此YOLOv5训练自己的数据集整个过程:制作数据集----模型训练----模型测试----模型推理阶段已全部完成。

    展开全文
  • 项目代码yolov5,官网,项目开源的时间:20200601 自定义数据集: #1 安装环境依赖 ##1.1 克隆项目 git clone https://github.com/ultralytics/yolov5 # clone repo 如果下载比较慢,建议使用下面的镜像下载: ...
  • YOLOV5训练自己数据集(踩坑经验之谈)

    万次阅读 多人点赞 2020-12-19 13:01:54
    这几天也一直在csdn里学习YOLOv3与YOLOv5训练数据集的具体步骤,几经波折终于实现了很好的效果。因此,决定利用闲暇时间,为大家写一篇YOLOv5训练数据集的小白手册,还望大家喜欢!有不同看法或意见欢迎在评论区指出...
  • yolov5训练自己数据

    万次阅读 2020-06-24 00:54:43
    yolov5使用的是yolo格式的标注文件,内容长这样,第一个数是标签的序号,后面四个是坐标。 标注软件依然是labelimg,在使用前将VOC格式转换为YOLO即可 如果有之前标注好的xml文件,可以通过脚本直接转成yolo所需...
  • 使用YOLOv5训练自己数据

    万次阅读 多人点赞 2020-06-17 11:23:32
    使用YOLOv5训练自己数据 新东西出来,总是要试试,这几天使用了yolov5跑了几个模型,特来记录一下心得与坑。 作者给出的教程,可以先浏览一下: link. 源码下载链接: link. 一.环境部署 yolov5基于pytouch,在测试...
  • 【小白CV】手把手教你用YOLOv5训练自己数据集(从环境配置到模型部署)前言:1. 安装Anaconda:2. 创建虚拟环境:3. 安装pytorch:4. 下载源码和安装依赖库:5. 数据标注:5. 数据预处理:6. 下载预训练模型: ...
  • 零基础用yoloV5 训练自己数据

    千次阅读 2020-10-23 14:35:08
    yoloV5 训练自己数据

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 14,412
精华内容 5,764
关键字:

yolov5训练自己的数据