Глубокое обучение — трансферное обучение yolov5, обучение пользовательскому набору данных

алгоритм
  • Пожалуйста, обратите внимание на источник оригинального текста при перепечатке, спасибо:blog.CSDN.net/Pentium cm/Ах…

Глубокое обучение — трансферное обучение yolov5, обучение пользовательскому набору данных

1. Введение

В этой статье рассказывается, как обучить модель обнаружения целей YOLO5 на ваших собственных наборах данных, включая наборы данных в формате VOC и наборы данных в формате coco.

2. Обучение пользовательскому набору данных

Распознавание по умолчанию в коде при обучении yolov5imagesиlabelsДве папки, возьмите изображения в качестве папки входных изображений и метки в качестве папки меток, поэтому независимо от того, какой формат набора данных мы используем, пока мы наконец можем создать эти две папки.

(1) Набор данных формата ЛОС

1. Подготовьте набор данных

Каталог набора данных выглядит следующим образом:

└─cell_phone:		自定义数据集
    ├─Annotations	存放的是数据集标签文件,xml格式
    ├─images		yolov5将此文件夹当作训练图片的输入,直接将 JPEGImages 中的内容放进去
    ├─ImageSets		数据集的划分文件
    │  └─Main
    ├─JPEGImages	存放的是数据集图片
    └─labels		yolov5将此文件夹当作训练的标注文件夹

В отличие от формата данных VOC по умолчанию, мы создали новыйimagesиlabelsпапку, изображения напрямую копируют в нее изображения из JPEGImages. labels в качестве папки для последующего сохранения файлов этикеток. Созданный каталог показан ниже:

在这里插入图片描述

2. Разделите набор данных

Создайте файлы разделения в ImageSets/Main/, train.txt, val.txt, trainval.txt, test.txt. Код для разделения набора данных выглядит следующим образом: непосредственно выполните следующий код для создания четырех файлов train.txt, val.txt, trainval.txt, test.txt в ImageSets/Main

#!/usr/bin/env python
# encoding: utf-8
'''
@Author  : pentiumCM
@Email   : 842679178@qq.com
@Software: PyCharm
@File    : make_txt.py
@Time    : 2020/11/25 16:51
@desc	 : 划分数据集 ——
            生成:trainval.txt,train.txt,val.txt,test.txt
            为ImageSets文件夹下面Main子文件夹中的训练集+验证集、训练集、验证集、测试集的划分
'''

import os
import random


def ds_partition(annotation_filepath, ds_divide_save__path):
    """
    数据集划分:训练集,验证集,测试集,在ImageSets/Main/生成 train.txt,val.txt,trainval.txt,test.txt
    :param annotation_filepath: 标注文件的路径 Annotations
    :param ds_divide_save__path:   数据集划分保存的路径 ImageSets/Main/
    :return:
    """
    if not os.path.exists(ds_divide_save__path):
        os.mkdir(ds_divide_save__path)

    # train_percent:训练集占(训练集+验证集)的比例
    train_percent = 0.8

    # trainval_percent:(训练集+验证集)占总数据集的比例。测试集所占比例为:1-trainval_percent
    trainval_percent = 1

    temp_xml = os.listdir(annotation_filepath)
    total_xml = []
    for xml in temp_xml:
        if xml.endswith(".xml"):
            total_xml.append(xml)

    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)

    print("train and val size", tv)
    print("traub suze", tr)
    ftrainval = open(os.path.join(ds_divide_save__path, 'trainval.txt'), 'w')
    ftest = open(os.path.join(ds_divide_save__path, 'test.txt'), 'w')
    ftrain = open(os.path.join(ds_divide_save__path, 'train.txt'), 'w')
    fval = open(os.path.join(ds_divide_save__path, 'val.txt'), 'w')

    for i in list:
        name = total_xml[i][:-4] + '\n'
        if i in trainval:
            ftrainval.write(name)
            if i in train:
                ftrain.write(name)
            else:
                fval.write(name)
        else:
            ftest.write(name)

    ftrainval.close()
    ftrain.close()
    fval.close()
    ftest.close()


if __name__ == '__main__':
    # 自定义数据集文件夹的名称
    dataset_name = r'./cell_phone/'
    annotation_filepath = dataset_name + 'Annotations/'
    divide_save_path = dataset_name + 'ImageSets/Main/'

    ds_partition(annotation_filepath, divide_save_path)

3. Обработайте результаты аннотации

Аннотации VOC преобразуются в результаты аннотаций yolo. Аннотация VOC хранится в файле xml, а правила для VOC, соответствующие полю метки, таковы:xmin ymin xmax ymaxАннотация yolo хранится в текстовом файле, а правила для yolo, соответствующие полю метки, таковы:class center_x center_y width height

Код преобразования выглядит следующим образом, после выполнения кода он будет сгенерированlablesпапка сtest.txt、train.txt、val.txtдокумент:

  • Метки сохраняют результат разбора ЛОС в йоло.
  • Остальные три текстовых файла представляют собой абсолютные пути к изображениям в соответствующих наборах данных.
#!/usr/bin/env python
# encoding: utf-8
'''
@Author  : pentiumCM
@Email   : 842679178@qq.com
@Software: PyCharm
@File    : voc2yolo_label.py
@Time    : 2020/11/25 16:54
@desc	 : 类别文件格式转换 ——
            把数据集标注格式转换成yolo_txt格式,即将每个xml标注提取bbox信息为txt格式
'''

import xml.etree.ElementTree as ET
import os

sets = ['train', 'test', 'val']

# 改成自己训练所需要的类
classes = ['cell phone']


def convert(size, box):
    """
    将 VOC 的标注转为 yolo的标注,即 xyxy -> xywh
    :param size: 图片尺寸
    :param box: 标注框(xyxy)
    :return:
    """
    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(annotation_filepath, label_dir, image_id):
    """
    VOC 标注的结果转为 yolo 数据集的标注结果
    :param annotation_filepath: VOC标注文件夹路径
    :param label_dir: 解析成 yolo 标注文件夹的路径
    :param image_id: 文件名
    :return:
    """
    in_file = open(annotation_filepath + '%s.xml' % (image_id))
    out_file = open(label_dir + '%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')


if __name__ == '__main__':

    # 当前文件的绝对路径
    abs_path = os.getcwd() + '/'

    # 自定义数据集文件夹的名称
    dataset_name = 'cell_phone'

    # VOC数据集标注文件
    annotation_filepath = dataset_name + '/Annotations/'

    # 数据集划分文件
    txtfile_dir = dataset_name + '/ImageSets/Main/'

    # coco训练图像输入的文件夹
    image_dir = dataset_name + '/images/'

    # 标注文件解析之后的文件夹路径
    label_dir = dataset_name + '/labels/'

    if not os.path.exists(label_dir):
        os.makedirs(label_dir)

    for image_set in sets:

        txtfile = txtfile_dir + '%s.txt' % (image_set)

        image_ids = open(txtfile).read().strip().split()
        list_file = open(dataset_name + '/%s.txt' % (image_set), 'w')
        for image_id in image_ids:
            list_file.write((abs_path + image_dir + '%s.jpg\n' % (image_id)).replace('\\', '/'))
            convert_annotation(annotation_filepath, label_dir, image_id)
        list_file.close()

Содержимое файла метки в папке меток после разбора показано на следующем рисунке, каждая строка соответствует окну метки, первое значение строки соответствует номеру категории, а последние четыре значения соответствуют координатам центральной точки, а также ширину и высоту поля метки (нормализованные) от 1 до значения от 0 до 1).

在这里插入图片描述

Содержимое файлов test.txt, train.txt и val.txt показано на рисунке ниже, это пути к картинкам в каждом наборе данных:

在这里插入图片描述

4. Создайте файл конфигурации набора данных

Нам нужно создать новый файл конфигурации yaml, соответствующий нашему пользовательскому набору данных VOC, например, vocds.yaml, основное содержимое:

  • train, val — это путь к txt-файлу, сгенерированному на шаге 3.
  • nc: количество категорий (+1 не требуется)
  • имена: название категории

Содержимое файла yaml выглядит следующим образом:

# train2017 and val2017 data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/]
#train2017: ../VOC/images/train2017/  # 16551 images
#val2017: ../VOC/images/val2017/  # 4952 images

train: F:/develop_code/python/yolo/yolov5/v5.0/yolov5/data/cell_phone/train.txt
val: F:/develop_code/python/yolo/yolov5/v5.0/yolov5/data/cell_phone/val.txt


# number of classes:数据集的类别数
nc: 1

# class names
names: ['cell phone']

5. Файл конфигурации пользовательской модели

Какую модель вы хотите обучить, измените соответствующий файл model.yaml. Например, модель предварительного обучения, которую мы используем, — это yolov5s, нам нужно изменить соответствующий файл конфигурации, я напрямую копирую соответствующий файл конфигурации, изменяю количество категорий, предсказанных моделью, количество категорий — это количество классов в наш пользовательский набор данных, другое место не изменено

在这里插入图片描述

6. Изменить параметры тренировки

Измените параметры обучения train.py:

--data: соответствует 'data/cell_phone.yaml'

--cfg: соответствует предварительно обученному файлу конфигурации модели, 'models/cell_phone.yaml'

--weights: файл весов предварительно обученной модели, такой как yolov5s.pt

--epochs, --batch-size: Зависит от конфигурации видеокарты вашего компьютера.Если она слишком велика, будет сообщено о нехватке видеопамяти.

7. Начать обучение

  • Обычно выполняется непосредственно:python train.py, ты сможешь. Но если вы используете терминал для подключения к серверу для обучения, лучше всего использовать:nohup python train.py > train_nub.log 2>&1 &, преимущество в том, что когда мы отключаемся от сервера, обучение будет продолжать выполняться в фоновом режиме, а не в терминале.

  • .cache: Во время обучения будет создан файл кеша, чтобы прервать процесс обучения и продолжить обучение в следующий раз. (также, если бы мы переписали обучение, нам нужно было бы очистить файл, чтобы предотвратить помехи от последних результатов обучения)

  • Результаты обучения модели находятся в корневом каталогеrunsв папке

  • Скриншот тренировочного процесса:

    在这里插入图片描述

8. Оценка производительности

Оценка производительности модели:

# 模型测试:
python test.py  --data ./data/vocds.yaml --weights runs/train/exp5/weights/best.pt --augment

(2) набор данных о кокосе

  1. Подготовьте набор данных Подготовьте папку с набором данных coco, код для набора данных и yolov5тот же уровень, структура каталогов выглядит следующим образом:

    ├─coco:			数据集根目录
    │  ├─images:		数据集图片
    │  │  ├─train2017:	训练集
    │  │  └─val2017:	验证集
    │  └─labels:		数据集标签
    │      ├─train2017
    │      └─val2017
    └─yolov5:			yolov5源代码,(数据集和源代码同级)
    
  2. Новый файл конфигурации набора данных yaml Мы создаем новый файл coco_custom.yaml со следующим содержимым:

    # train2017 and val2017 data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/]
    train: ../coco/images/train2017/
    
    val: ../coco/images/val2017/
    
    # number of classes
    nc: 2
    
    # class names
    names: ['person_legal', 'person_illegal']
    
  3. Измените файл конфигурации предварительно обученной модели.

  4. Измените параметры обучения train.py.

  5. начать обучение

  6. Оценка производительности модели

Приведенное выше содержание совпадает с шагами в предыдущем разделе и не будет повторяться здесь.

3. Анализ результатов обучения

yolov5 будет генерировать каталог expi в каталоге выполнения каждый раз, когда поезд завершается (i представляет количество сгенерированных результатов, первое обучение завершается для генерации exp0, второе генерируется exp1... и так далее) Результаты визуального обучения будут сохранены в каталоге expi: путаница_matrix.png (матрица путаницы), F1_curve.png (кривая F1), P_curve.png (кривая P), R_curve.png (кривая R), PR_curve.png (кривая PR). ), result.png, results.txt и тренировочные веса (last.pt и best.pt); параметры кратко описаны ниже:

  • результат.png:

использованная литература