YOLO训练

这篇博客详细介绍了如何训练YOLO模型,包括准备训练数据,如转换Pascal VOC、MSCOCO、ImageNet数据,以及自定义数据的转换。此外,还讨论了配置文件的准备、多GPU训练技巧、训练过程的可视化和模型验证。作者提供了转换脚本和训练过程中的注意事项,如学习率调整和损失曲线的可视化。

准备训练数据

使用darknet训练自己的YOLO模型需要将数据转成darknet需要的格式,每张图片对应一个.txt的label文件,文件格式如下:

<object-class> <x> <y> <width> <height>

object-class是类的索引,后面的4个值都是相对于整张图片的比例。

x是ROI中心的x坐标,y是ROI中心的y坐标,width是ROI的宽,height是ROI的高。

我需要用到Pascal VOC、MSCOCO、ImageNet和自己标记的一些图片。
混用这些数据集有一个严重的问题,有一些需要标记的物体没有被标记。
如ImageNet的200种物体中有iPod并做了标记,而MSCOCO中有一些图片中有iPod却没有标记出来,这会导致模型的精度下降。该问题可以通过对这部分图片重新标记来解决(工作量很大);也可以修改损失函数,对不同数据集的image计算不同的损失,同时针对不同数据集中的数据使用不同的object_scale和noobject_scale。

整合这些数据集首先要准备一个list,list中列出了要识别的物体。
如paul_list.txt

0,ambulance
1,apple
2,automat
3,backpack
4,baggage
5,banana
6,baseball
7,basketball
8,bed
9,bench

转换Pascal VOC

darknet作者提供了voc_label.py脚本来实现该功能,我们只需修改脚本中的classes为我们需要的classes即可,然后在VOCdevkit的父目录执行voc_label.py即可。

classes = ["ambulance", "apple", "automat", "backpack", "baggage", "banana", "baseball", "basketball", "bed","bench"]

转换MSCOCO

查看coco的80种物体有哪些是我们需要的,制作coco_list.txt,格式为,。如:

1,apple
3,backpack
5,banana
8,bed
9,bench

安装MSCOCO提供的python API库,然后执行coco_label.py。
coco_label.py见github。
https://github.com/PaulChongPeng/darknet/blob/master/tools/coco_label.py

执行脚本前需要修改dataDir和classes为自己的COCO数据集路径和coco_list.txt路径

# coding=utf-8
# 使用说明
# 需要先安装coco tools
# git clone https://github.com/pdollar/coco.git
# cd coco/PythonAPI
# make install(可能会缺少相关依赖,根据提示安装依赖即可)
# 执行脚本前需在train2014和val2014目录下分别创建JPEGImages和labels目录,并将原来train2014和val2014目录下的图片移到JPEGImages下
# COCO数据集的filelist目录下会生成图片路径列表
# COCO数据集的子集的labels目录下会生成yolo需要的标注文件


from pycocotools.coco import COCO
import shutil
import os


# 将ROI的坐标转换为yolo需要的坐标
# size是图片的w和h
# box里保存的是ROI的坐标(x,y的最大值和最小值)
# 返回值为ROI中心点相对于图片大小的比例坐标,和ROI的w、h相对于图片大小的比例
def convert(size, box):
    dw = 1. / size[0]
    dh = 1. / size[1]
    x = box[0] + box[2] / 2.0
    y = box[1] + box[3] / 2.0
    w = box[2]
    h = box[3]
    x = x * dw
    w = w * dw
    y = y * dh
    h = h * dh
    return (x, y, w, h)


# 获取所需要的类名和id
# path为类名和id的对应关系列表的地址(标注文件中可能有很多类,我们只加载该path指向文件中的类)
# 返回值是一个字典,键名是类名,键值是id
def get_classes_and_index(path):
    D = {}
    f = open(path)
    for line in f:
        temp = line.rstrip().split(',', 2)
        print("temp[0]:" + temp[0] + "\n")
        print("temp[1]:" + temp[1] + "\n")
        D[temp[1]] = temp[0]
    return D


dataDir = '/mnt/large4t/pengchong_data/Data/COCO'  # COCO数据集所在的路径
dataType = 'train2014'  # 要转换的COCO数据集的子集名
annFile = '%s/annotations/instances_%s.json' % (dataDir, dataType)  # COCO数据集的标注文件路径
classes = get_classes_and_index('/mnt/large4t/pengchong_data/Tools/Yolo_paul/darknet/data/coco_list.txt')

# labels 目录若不存在,创建labels目录。若存在,则清空目录
if not os.path.exists('%s/%s/labels/' % (dataDir, dataType)):
    os.makedirs('%s/%s/labels/' % (dataDir, dataType))
else:
    shutil.rmtree('%s/%s/labels/' % (dataDir, dataType))
    os.makedirs('%s/%s/labels/' % (dataDir, dataType))

# filelist 目录若不存在,创建filelist目录。
if not os.path.exists('%s/filelist/' % dataDir):
    os.makedirs('%s/filelist/' % dataDir)

coco = COCO(annFile)  # 加载解析标注文件
list_file = open('%s/filelist/%s.txt' % (dataDir, dataType), 'w')  # 数据集的图片list保存路径

imgIds = coco.getImgIds()  # 获取标注文件中所有图片的COCO Img ID
catIds = coco.getCatIds()  # 获取标注文件总所有的物体类别的COCO Cat ID

for imgId in imgIds:
    objCount = 0  # 一个标志位,用来判断该img是否包含我们需要的标注
    print('imgId :%s' % imgId)
    Img = coco.loadImgs(imgId)[0]  # 加载图片信息
    print('Img :%s' % Img)
    filename = Img['file_name']  # 获取图片名
    width = Img['width']  # 获取图片尺寸
    height = Img['height']  # 获取图片尺寸
    print('filename :%s, width :%s ,height :%s' % (filename, width, height))
    annIds = coco.getAnnIds(imgIds=imgId, catIds=catIds, iscrowd=None)  # 获取该图片对应的所有COCO物体类别标注ID
    print('annIds :%s' % annIds)
    for annId in annIds:
        anns = coco.loadAnns(annId)[0]  # 加载标注信息
        catId = anns['category_id']  # 获取该标注对应的物体类别的COCO Cat ID
        cat = coco.loadCats(catId)[0]['name']  # 获取该COCO Cat ID对应的物体种类名
        # print 'anns :%s' % anns
        # print 'catId :%s , cat :%s' % (catId,cat)

        # 如果该类名在我们需要的物体种类列表中,将标注文件转换为YOLO需要的格式
        if cat in classes:
            objCount = objCount + 1
            out_file = open('%s/%s/labels/%s.txt' % (dataDir, dataType, filename[:-4]), 'a')
            cls_id = classes[cat]  # 获取该类物体在yolo训练中的id
            box = anns['bbox']
            size = [width, height]
            bb = convert(size, box)
            out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
            out_file.close()

    if objCount > 0:
        list_file.write('%s/%s/JPEGImages/%s\n' % (dataDir, dataType, filename))

list_file.close()

转换ImageNet

我使用的是ILSVRC2016的数据,查看200种物体中有哪些是我们需要的,然后制作imagenet_list.txt。

需要注意,ImageNet的标注文件中的object name使用的物体的WordNetID,所以imagenet_list.txt中需要使用WordNetID,如:

1,n07739125     
3,n02769748  
5,n07753592   
6,n02799071 
7,n02802426      
9,n02828884 

为了方便获取WordNetID在ImageNet中的物体名词(paul_list.txt中的名词未必和ImageNet中的一致),可以制作一个imagenet_map.txt,如:

1,apple,n07739125     
3,backpack,n02769748  
5,banana,n07753592   
6,baseball,n02799071 
7,basketball,n02802426      
9,bench,n02828884

制作imagenet_list.txt和imagenet_map.txt需要知道WordNetID和名词间的映射关系,有两个办法。

离线版:

从ImageNet下载words.txt(WordNetID和名词间的映射)和gloss.txt(WordNetID对应的名词的定义),然后查询。如果没有梯子,国内访问ImageNet龟速,文件被我备份在GitHub。
https://github.com/PaulChongPeng/darknet/blob/32dddd8509de4bf57cad0aa330160d57d33d0c66/data/words.txt
https://github.com/PaulChongPeng/darknet/blob/32dddd8509de4bf57cad0aa330160d57d33d0c66/data/gloss.txt

在线版:

访问 http://image-net.org/challenges/LSVRC/2015/browse-det-synsets 。请自备梯子,不然慢的令人发指。

点击需要查询的名词,如Volleyball,会跳转到对应的网页,我们需要的是网页地址后的wnid。如 http://imagenet.stanford.edu/synset?wnid=n04540053

制作好list后,将imagenet_to_yolo.py放在ILSVRC2016/bject_detection/ILSVRC目录下,并将Data文件夹重命名为JPEGImages(因为darknet找图片对应的标记文件是直接替换JPEGImages为labels,图片后缀名替换为txt)。修改classes为自己的list路径后直接运行脚本即可。

imagenet_to_yolo.py 我放在了GitHub上:

https://github.com/PaulChongPeng/darknet/blob/master/tools/imagenet_to_yolo.py

# coding=utf-8

# 使用说明
# 将该文件放在ILSVRC2016/bject_detection/ILSVRC目录下,并将Data文件夹重命名为JPEGImages
# 执行该工具,Lists目录下会生成图片路径列表
# labels目录下会生成yolo需要的标注文件

import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
import shutil


# 获取所有包含标注文件的的目录路径
def get_dirs():
    dirs = ['DET/train/ILSVRC2014_train_0006', 'DET/train/ILSVRC2014_train_0005', 'DET/train/ILSVRC2014_train_0004',
            'DET/train/ILSVRC2014_train_0003', 'DET/train/ILSVRC2014_train_0002', 'DET/train/ILSVRC2014_train_0001',
            'DET/train/ILSVRC2014_train_0000', 'DET/val']
    dirs_2013 = os.listdir('JPEGImages/DET/train/ILSVRC2013_train/')
    for dir_2013 in dirs_2013:
        dirs.append('DET/train/ILSVRC2013_train/' + dir_2013)
    return dirs


# 获取所需要的类名和id
# path为类名和id的对应关系列表的地址(标注文件中可能有很多类,我们只加载该path指向文件中的类)
# 返回值是一个字典,键名是类名,键值是id
def get_classes_and_index(path):
    D = {}
    f = open(path)
    for line in f:
        temp = line.rstrip().split(',', 2)
        D[temp[1]] = temp[0]
    return D


# 将ROI的坐标转换为yolo需要的坐标
# size是图片的w和h
# box里保存的是ROI的坐标(x,y的最大值和最小值)
# 返回值为ROI中心点相对于图片大小的比例坐标,和ROI的w、h相对于图片大小的比例
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)


# 将labelImg 生成的xml文件转换为yolo需要的txt文件
# image_dir 图片所在的目录的路径
# image_id图片名
def convert_annotation(image_dir, image_id):
    in_file = open('Annotations/%s/%s.xml' % (image_dir, image_id))
    obj_num = 0  # 一个标志位,用来判断该img是否包含我们需要的标注
    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'):
        cls = obj.find('name').text
        if cls not in classes:
            continue
        obj_num = obj_num + 1
        if obj_num == 1:
            out_file = open('labels/%s/%s.txt' % (image_dir, image_id), 'w')
        cls_id = classes[cls]  # 获取该类物体在yolo训练中的id
        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 obj_num > 0:
        list_file = open('Lists/%s.txt' % image_dir.split('/')[-1], 'a')  # 数据集的图片list保存路径
        list_file.write('%s/JPEGImages/%s/%s.JPEG\n' % (wd, image_dir, image_id))
        list_file.close()


def IsSubString(SubStrList, Str):
    flag = True
    for substr in SubStrList:
        if not (substr in Str):
            flag = False

    return flag


# 获取FindPath路径下指定格式(FlagStr)的文件名(不包含后缀名)列表
def GetFileList(FindPath, FlagS
### YOLO 模型训练方法 YOLO(You Only Look Once)是一种流行的实时目标检测模型,它在单次前向传播中完成目标检测任务,具有速度快、精度高的特点。YOLO 模型的训练方法主要包括以下几个步骤: #### 数据准备 在训练 YOLO 模型之前,首先需要准备好数据集。数据集通常包括图像和对应的标签文件。标签文件通常以 `.txt` 格式存储,每个文件对应一张图像,包含目标物体的类别和边界框信息(通常是归一化的坐标)。为了方便训练,通常需要将数据集划分为训练集、验证集和测试集。训练集用于模型训练,验证集用于调整超参数和评估模型性能,测试集用于最终评估模型的泛化能力。 在数据准备过程中,还需要创建一个 `data.yaml` 文件来指定数据集的路径和类别信息。例如: ```yaml path: E:/Model/yolo11/data # dataset root dir train: train/images # train images (relative to 'path') val: val/images # val images (relative to 'path') test: test/images # test images (relative to 'path') # Classes nc: 2 # number of classes names: ['head', 'body'] # class names ``` [^4] #### 模型加载与预训练 YOLO 模型通常从预训练模型开始训练,这样可以利用预训练模型的特征提取能力,加快收敛速度并提高模型性能。例如,可以使用以下代码加载预训练YOLO 模型: ```python model = YOLO("yolo11s.pt") # load a pretrained model (recommended for training) ``` [^3] #### 训练配置 在训练 YOLO 模型时,需要设置一些关键的超参数,例如训练轮数(epochs)、图像大小(imgsz)、批量大小(batch size)等。这些超参数可以通过命令行参数或代码中的字典传递给训练函数。例如,可以使用以下代码启动训练过程: ```python # Train the model results = model.train(data="yolo.yaml", epochs=100, imgsz=640) ``` [^3] #### 分布式训练 为了加速训练过程并扩展到更大的数据集,可以使用分布式训练技术。分布式训练可以在GPU 上并行训练模型,从而显著提高训练速度。分布式训练的配置通常包括环境搭建、代码修改以及数据并行的实现。具体步骤可能包括安装必要的库、配置 GPU 环境、修改代码以支持 GPU 训练等。[^1] #### 训练技巧 在训练 YOLO 模型时,还可以采用一些实用的训练技巧来提高训练效率和模型性能。这些技巧包括但不限于: - **数据增强**:通过随机变换(如旋转、翻转、缩放等)来增加数据的样性,提高模型的泛化能力。 - **学习率调整**:使用学习率衰减策略(如余弦退火、阶梯式衰减等)来优化模型的收敛速度。 - **早停机制**:当验证集上的性能不再提升时,提前停止训练,避免过拟合。 - **权重初始化**:使用合适的权重初始化方法(如 He 初始化、Xavier 初始化等)来加速模型的收敛。 这些技巧不仅适用于 YOLO 模型,也适用于其他深度学习模型。[^2] #### 模型评估与调优 在训练过程中,需要定期评估模型在验证集上的性能,并根据评估结果调整超参数。常用的评估指标包括平均精度(mAP)、召回率(Recall)、精确率(Precision)等。通过不断调整超参数(如学习率、批量大小、正则化系数等),可以进一步优化模型的性能。 #### 模型保存与部署 训练完成后,可以将模型保存为文件,以便后续使用或部署。YOLO 模型通常保存为 `.pt` 或 `.pth` 文件格式。保存模型后,可以将其部署到生产环境中进行目标检测任务。 ###
评论 65
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值