2021-11-10 YOLOX训练最新笔记总结(coco格式)

1. 数据准备

如下图所示,训练图片images的格式尺寸可以不等:
在这里插入图片描述
标签label(.txt)一个文件对应一个txt文件:
在这里插入图片描述
labellmg 标注可以直接导出 .txt文件 一一对应的格式,如图:
在这里插入图片描述
上图换了个任务标签,细节不要在意,意思到就行~
如果是labelme生成的Json文件,like this:
在这里插入图片描述
json转化一下txt:

import json
import os

name2id = {'advertisement': 0}  # 此处为类别id


# name2id = {'person':0,'helmet':1,'Fire extinguisher':2,'Hook':3,'Gas cylinder':4}
#
def convert(img_size, box):
    dw = 1. / (img_size[0])
    dh = 1. / (img_size[1])
    x = (box[0] + box[2]) / 2.0 - 1
    y = (box[1] + box[3]) / 2.0 - 1
    w = box[2] - box[0]
    if w < 0:
        w = box[0] - box[2]
    h = box[3] - box[1]
    if h < 0:
        h = box[1] - box[3]
    x = x * dw
    w = w * dw
    y = y * dh
    h = h * dh
    return (x, y, w, h)


def decode_json(json_floder_path, json_name):
    txt_name = txt_floder_path + json_name[0:-5] + '.txt'   #
    txt_file = open(txt_name, 'w')

    json_path = os.path.join(json_floder_path, json_name)
    data = json.load(open(json_path, 'r', encoding='gb2312'))

    img_w = data['imageWidth']
    img_h = data['imageHeight']

    for i in data['shapes']:

        label_name = i['label']
        if (i['shape_type'] == 'rectangle'):
            x1 = int(i['points'][0][0])
            y1 = int(i['points'][0][1])
            x2 = int(i['points'][1][0])
            y2 = int(i['points'][1][1])

            bb = (x1, y1, x2, y2)
            bbox = convert((img_w, img_h), bb)
            txt_file.write(str(name2id[label_name]) + " " + " ".join([str(a) for a in bbox]) + '\n')


if __name__ == "__main__":

    json_floder_path = 'D:\\advertisement1622+json\\json1615\\'   # json文件夹路径
    txt_floder_path = 'D:\\advertisement1622+json\\txt1615\\'     # txt文件夹路径
    json_names = os.listdir(json_floder_path)
    for json_name in json_names:
        decode_json(json_floder_path, json_name)

生成训练测试验证的总json文件:

"""
YOLO 格式的数据集转化为 COCO 格式的数据集
--root_dir 输入根路径
--save_path 保存文件的名字(没有random_split时使用)
--random_split 有则会随机划分数据集,然后再分别保存为3个文件。
"""

import os
import cv2
import json
from tqdm import tqdm
from sklearn.model_selection import train_test_split
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--root_dir', default='F:\\advertisement1622+json\\advertisementv2\\', type=str,
                    help="root path of images and labels, include ./images and ./labels and classes.txt")
parser.add_argument('--save_path', type=str, default='./train.json',
                    help="if not split the dataset, give a path to a json file")
parser.add_argument('--random_split', action='store_false', help="random split the dataset, default ratio is 8:1:1") # store_false = 8:1:1
arg = parser.parse_args()                                                                                            # store_true =train 全部
# test_image = "F:\\advertisement1622+json\\test2017\\"    # 新建以下三个文件夹
# val_image = "F:\\advertisement1622+json\\val2017\\"
# train_image = "F:\\advertisement1622+json\\train2017\\"

test_image = os.path.join(arg.root_dir, 'test2017')
val_image = os.path.join(arg.root_dir, 'val2017')
train_image = os.path.join(arg.root_dir, 'train2017')
if not os.path.exists(test_image):
    os.makedirs(test_image)
if not os.path.exists(val_image):
    os.makedirs(val_image)
if not os.path.exists(train_image):
    os.makedirs(train_image)



def train_test_val_split(img_paths, ratio_train=0.889, ratio_test=0.1, ratio_val=0.001,):
    # 这里可以修改数据集划分的比例。
    assert int(ratio_train + ratio_test + ratio_val) == 1
    train_img, middle_img = train_test_split(img_paths, test_size=1 - ratio_train, random_state=233)
    ratio = ratio_val / (1 - ratio_train)
    val_img, test_img = train_test_split(middle_img, test_size=ratio, random_state=233)
    print("NUMS of train:val:test = {}:{}:{}".format(len(train_img), len(val_img), len(test_img)))
    return train_img, val_img, test_img


def yolo2coco(root_path, random_split):
    originLabelsDir = os.path.join(root_path, 'labels')
    originImagesDir = os.path.join(root_path, 'images')
    with open(os.path.join(root_path, 'classes.txt')) as f:
        classes = f.read().strip().split()
    # images dir name
    indexes = os.listdir(originImagesDir)

    if random_split:
        # 用于保存所有数据的图片信息和标注信息
        train_dataset = {'categories': [], 'annotations': [], 'images': []}
        val_dataset = {'categories': [], 'annotations': [], 'images': []}
        test_dataset = {'categories': [], 'annotations': [], 'images': []}

        # 建立类别标签和数字id的对应关系, 类别id从0开始。
        for i, cls in enumerate(classes, 0):
            train_dataset['categories'].append({'id': i, 'name': cls, 'supercategory': 'mark'})
            val_dataset['categories'].append({'id': i, 'name': cls, 'supercategory': 'mark'})
            test_dataset['categories'].append({'id': i, 'name': cls, 'supercategory': 'mark'})
        train_img, val_img, test_img = train_test_val_split(indexes, 0.899, 0.1, 0.001)  # 这里可以修改数据集划分的比例。
    else:
        dataset = {'categories': [], 'annotations': [], 'images': []}
        for i, cls in enumerate(classes, 0):
            dataset['categories'].append({'id': i, 'name': cls, 'supercategory': 'mark'})

    # 标注的id
    ann_id_cnt = 0
    for k, index in enumerate(tqdm(indexes)):
        # 支持 png jpg 格式的图片。
        txtFile = index.replace('images', 'txt').replace('.jpg', '.txt').replace('.png', '.txt')
        # 读取图像的宽和高
        im = cv2.imread(os.path.join(root_path, 'images/') + index)
        height, width, _ = im.shape
        # index = index.replace('.png', '.jpg')
        if random_split:
            # 切换dataset的引用对象,从而划分数据集
            if index in train_img:
                dataset = train_dataset
                cv2.imwrite(train_image + os.sep + index, im)
                # print(train_image + os.sep + index)
            elif index in val_img:
                dataset = val_dataset
                cv2.imwrite(val_image + os.sep + index, im)
                # print(val_image + os.sep + index)
            elif index in test_img:
                dataset = test_dataset
                cv2.imwrite(test_image + os.sep + index, im)
                # print(test_image + os.sep + index)
        # 添加图像的信息
        dataset['images'].append({'file_name': index,
                                  'id': k,
                                  'width': width,
                                  'height': height})
        if not os.path.exists(os.path.join(originLabelsDir, txtFile)):
            # 如没标签,跳过,只保留图片信息。
            continue
        with open(os.path.join(originLabelsDir, txtFile), 'r') as fr:
            labelList = fr.readlines()
            for label in labelList:
                label = label.strip().split()
                x = float(label[1])
                y = float(label[2])
                w = float(label[3])
                h = float(label[4])

                # convert x,y,w,h to x1,y1,x2,y2
                H, W, _ = im.shape
                x1 = (x - w / 2) * W
                y1 = (y - h / 2) * H
                x2 = (x + w / 2) * W
                y2 = (y + h / 2) * H
                # 标签序号从0开始计算, coco2017数据集标号混乱,不管它了。
                cls_id = int(label[0])
                width = max(0, x2 - x1)
                height = max(0, y2 - y1)
                dataset['annotations'].append({
                    'area': width * height,
                    'bbox': [x1, y1, width, height],
                    'category_id': cls_id,
                    'id': ann_id_cnt,
                    'image_id': k,
                    'iscrowd': 0,
                    # mask, 矩形是从左上角点按顺时针的四个顶点
                    'segmentation': [[x1, y1, x2, y1, x2, y2, x1, y2]]
                })
                ann_id_cnt += 1

    # 保存结果
    folder = os.path.join(root_path, 'annotations')
    if not os.path.exists(folder):
        os.makedirs(folder)
    if random_split:
        for phase in ['instances_train2017', 'instances_val2017', 'instances_test2017']:
            json_name = os.path.join(root_path, 'annotations/{}.json'.format(phase))
            with open(json_name, 'w') as f:
                if phase == 'instances_train2017':
                    json.dump(train_dataset, f)
                elif phase == 'instances_val2017':
                    json.dump(val_dataset, f)
                elif phase == 'instances_test2017':
                    json.dump(test_dataset, f)
            print('Save annotation to {}'.format(json_name))
    else:
        json_name = os.path.join(root_path, 'annotations/{}'.format(arg.save_path))
        with open(json_name, 'w') as f:
            json.dump(dataset, f)
            print('Save annotation to {}'.format(json_name))


if __name__ == "__main__":
    root_path = arg.root_dir
    assert os.path.exists(root_path)
    random_split = arg.random_split
    print("Loading data from ", root_path, "\nWhether to split the data:", random_split)
    yolo2coco(root_path, random_split)

自动生成annotations文件夹和里面的train/val/test.json训练图片、验证、测试图片的文件夹
在这里插入图片描述

在这里插入图片描述

最后上传的是以下数据文件:
在这里插入图片描述

2.训练开始

2.1 修改文件1.yolox_s.py 修改网络宽度和深度、数据集的位置、种类等参数

./exps/example/custom/yolox_s.py

在这里插入图片描述
其中yolox所用的depth和width要和模型大小(S\M\L) ./exps/default/yolox_s.py(yolox_m.py/yolox_l.py) 保持一致,like this:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2 修改文件 2.yolox_base.py 同样修改类别、网络宽度和深度等参数

./yolox/exp/yolox_base.py

在这里插入图片描述

2.3 修改文件 3.coco_classes.py 改成自己的类别,记得类别之后打“,”逗号,不然会报错

./yolox/data/datasets/coco_classes.py

在这里插入图片描述

在这里插入图片描述

3.训练起来:

终端执行:

python train.py -f exps/example/custom/yolox_s.py -d 2 -b 16 --fp16 -o -c yolox_s.pth --cache

like this:
请添加图片描述
请添加图片描述
注意!!!!# 遇到的一些坑和问题:
1.直接pip install loguru会报错,用清华镜像安装就没有问题了
pip install loguru -i http://pypi.tuna.tsinghua.edu.cn/simple/ --trusted-host pypi.tuna.tsinghua.edu.cn 请添加图片描述
请添加图片描述

2.AssertionError错误
终端开始训练输入:python train.py -f exps/example/custom/yolox_s.py -d 2 -b 16 --fp16 -o -c yolox_m.pth [--cache]
会出现报错 但是之前不会。
训练的代码在train.py 中,首先对训练的参数进行解析,然后调用get_exp(args.exp_file, args.name) 获取exp,调用exp.merge(args.opts)并merge训练参数,然后启动训练,报错如下:

Traceback (most recent call last):
  File "train.py", line 122, in <module>
    exp.merge(args.opts)
  File "/home/jovyan/YOLOX-main/yolox/exp/base_exp.py", line 64, in merge
    assert len(cfg_list) % 2 == 0
AssertionError

代码终端训练改成:

python train.py -f exps/example/custom/yolox_s.py -d 2 -b 16 --fp16 -o -c yolox_s.pth --cache

去掉[–cache]外面的括号,然后正常开始训练~
请添加图片描述

版权声明:本文为CSDN博主「blue_lala」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44245653/article/details/121144231

blue_lala

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

cocoapi+coco20i

下载cocoapi git clone https://github.com/cocodataset/cocoapi.git 进入文件夹 cd cocoapi/PythonAPI 安装 python setup.py build_ext --i