Co-DETR训练自己的数据集,环境配置+问题总结

目录

一、Co-DETR环境配置

1、下载Co-DETR

2、安装所需的库

二、训练自己的数据集

1、准备数据集

2、修改配置文件


一、Co-DETR环境配置

Co-DETR官网github仓库地址:https://github.com/Sense-X/Co-DETR

首先需要在一个有pytorch,cuda的环境下进行如下安装,可以采用租用服务器的方法,选择pytorch基础镜像。pytorch版本参考官方给的(见下图),其中python3.8的版本也可。

1、下载Co-DETR

可采用如下命令下载Co-DETR的代码(方法1),但我在拉取时一直没有成功,所以直接在github上将其下载下来再解压使用(方法2)

方法1:

# 拉取github上的代码
git clone https://github.com/Sense-X/Co-DETR.git
# 进入Co-DETR目录
cd Co-DETR

方法2:

2、安装所需的库

(1)安装Co-DETR代码中所依赖的库

pip install -e .

(2)安装mmcv。官方说了他们使用了mmdet和mmcv实现Co-DETR

pip install -U openmim
mim install mmcv-full==1.6.1

注:一定要使用mim install来安装,我最开始直接使用pip install mmcv-full==1.6.1,结果没有成功,使用mim很快就成功了,并且最好安装mmcv-full,mmcv可能后面会出现报错。我的环境里是有mmdet的,如果没有需要使用pip install mmdet==2.25.3。

(3)重新安装低版本yapf,当前yapf版本过高会报错“TypeError: FormatCode() got an unexpected keyword argument ‘verify‘”,参考了另一篇博文(CO-DETR利用coco数据集训练和推理过程_co-detr训练自己的数据集-CSDN博客)给出的方法,发现降低yapf版本即可。

pip install yapf==0.40.1

二、训练自己的数据集

1、准备数据集

首先你需要准备好自己的coco格式数据集,如果之前你的数据集是yolo格式,那就将其转换为coco格式(下面的yolo转换为coco格式的代码是其他博主的,但具体参考的哪篇博文忘记了):

import json
import os
import shutil
import cv2

# info ,license,categories 结构初始化;
# 在train.json,val.json,test.json里面信息是一致的;

# info,license暂时用不到
# info = {
#     "year": 2024,
#     "version": '1.0',
#     "date_created": 2024 - 3 - 29
# }
#
# licenses = {
#     "id": 1,
#     "name": "null",
#     "url": "null",
# }

info = {}
licenses ={}

# 自己的标签类别,跟yolo的数据集类别要对应好;
categories = [
    {
        "id": 0,
        "name": 'Bus',
        "supercategory": 'lines',
    },
    {
        "id": 1,
        "name": 'Bike',
        "supercategory": 'lines',
    },
    {
        "id": 2,
        "name": 'Car',
        "supercategory": 'lines',
    },
    {
        "id": 3,
        "name": 'Pedestrian',
        "supercategory": 'lines',
    },
    {
        "id": 4,
        "name": 'Truck',
        "supercategory": 'lines',
    },
]

# 初始化train,test、valid 数据字典
# info licenses categories 在train和test里面都是一致的;
train_data = {'info': info, 'licenses': licenses, 'categories': categories, 'images': [], 'annotations': []}
test_data = {'info': info, 'licenses': licenses, 'categories': categories, 'images': [], 'annotations': []}
valid_data = {'info': info, 'licenses': licenses, 'categories': categories, 'images': [], 'annotations': []}

# image_path 对应yolo的图像路径,比如images/train;
# label_path 对应yolo的label路径,比如labels/train 跟images要对应;
def yolo_covert_coco_format(image_path, label_path):
    images = []
    annotations = []
    for index, img_file in enumerate(os.listdir(image_path)):
        if img_file.endswith('.png'):
            image_info = {}
            img = cv2.imread(os.path.join(image_path, img_file))
            height, width, channel = img.shape
            image_info['id'] = index
            image_info['file_name'] = img_file
            image_info['width'], image_info['height'] = width, height
        else:
            continue
        if image_info != {}:
            images.append(image_info)
        # 处理label信息-------
        label_file = os.path.join(label_path, img_file.replace('.png', '.txt'))
        file_size = os.path.getsize(label_file)
        with open(label_file, 'r') as f:
            if file_size == 0:
                info_annotation = {}
                info_annotation["category_id"] = None  # 类别的id
                info_annotation['bbox'] = []  ## bbox的坐标
                info_annotation['area'] = None  ###area
                info_annotation['image_id'] = index  # bbox的id
                info_annotation['id'] = index * 100  # bbox的id
                # cv2.imwrite(f"./temp/{info_annotation['id']}.png", img_copy)
                info_annotation['segmentation'] = [[]]  # 四个点的坐标
                info_annotation['iscrowd'] = 0  # 单例
                annotations.append(info_annotation)
            else:
                for idx, line in enumerate(f.readlines()):
                    info_annotation = {}
                    class_num, xs, ys, ws, hs = line.strip().split(' ')
                    class_id, xc, yc, w, h = int(class_num), float(xs), float(ys), float(ws), float(hs)
                    xmin = (xc - w / 2) * width
                    ymin = (yc - h / 2) * height
                    xmax = (xc + w / 2) * width
                    ymax = (yc + h / 2) * height
                    bbox_w = int(width * w)
                    bbox_h = int(height * h)

                    info_annotation["category_id"] = class_id  # 类别的id
                    info_annotation['bbox'] = [xmin, ymin, bbox_w, bbox_h]  ## bbox的坐标
                    info_annotation['area'] = bbox_h * bbox_w  ###area
                    info_annotation['image_id'] = index  # bbox的id
                    info_annotation['id'] = index * 100 + idx  # bbox的id
                    # cv2.imwrite(f"./temp/{info_annotation['id']}.png", img_copy)
                    info_annotation['segmentation'] = [[xmin, ymin, xmax, ymin, xmax, ymax, xmin, ymax]]  # 四个点的坐标
                    info_annotation['iscrowd'] = 0  # 单例
                    annotations.append(info_annotation)
    return images, annotations


# key == train,test,val
# 对应要生成的json文件,比如instances_train.json,instances_test.json,instances_val.json
# 只是为了不重复写代码。。。。。
def gen_json_file(yolo_data_path, coco_format_path, key):
    # json path
    json_path = os.path.join(coco_format_path, f'annotations/instances_{key}2017.json')
    dst_path = os.path.join(coco_format_path, f'{key}')
    if not os.path.exists(os.path.dirname(json_path)):
        os.makedirs(os.path.dirname(json_path), exist_ok=True)
    data_path = os.path.join(yolo_data_path, f'images/{key}')
    label_path = os.path.join(yolo_data_path, f'labels/{key}')
    images, anns = yolo_covert_coco_format(data_path, label_path)
    if key == 'train':
        train_data['images'] = images
        train_data['annotations'] = anns
        with open(json_path, 'w') as f:
            json.dump(train_data, f, indent=2)
        # shutil.copy(data_path,'')
    elif key == 'test':
        test_data['images'] = images
        test_data['annotations'] = anns
        with open(json_path, 'w') as f:
            json.dump(test_data, f, indent=2)
    elif key == 'val':
        valid_data['images'] = images
        valid_data['annotations'] = anns
        with open(json_path, 'w') as f:
            json.dump(valid_data, f, indent=2)
    else:
        print(f'key is {key}')
    print(f'generate {key} json success!')
    return


if __name__ == '__main__':
    yolo_data_path = "your yolo datapath"
    coco_format_path = "your save coco datapath"
    gen_json_file(yolo_data_path, coco_format_path, key='train')
    # gen_json_file(yolo_data_path, coco_format_path, key='val')
    # gen_json_file(yolo_data_path, coco_format_path, key='test')

yolo格式的目录层级为:

yolo

——images

————train

————test

——labels

————train

————test

coco格式的目录层级为:

coco

 ——annotations

————instances_train2017.json

————instances_val2017.json

——train2017

——val2017

2、修改配置文件

(1)下载权重文件

可以直接去github官网下载,点进model,里面会有几个模型权重,我下载了co_dino_5scale_swin_large_3x_coco.pth这个权重文件。

(2)修改配置文件

在这个目录下Co-DETR/projects/configs/co_dino/co_dino_5scale_swin_large_3x_coco.py找到这个模型权重的配置文件,一般和模型权重的名字相同。

打开这个文件会发现它很短(见下图),base的其它文件:

我们又找到它base的这个文件 :

发现通过这样一层层修改参数比较麻烦,所以我们可以利用下述命令先生成一个config文件,在这个config文件上进行修改,这个文件具有所有的参数设置。

# projects/configs/co_dino/co_dino_5scale_swin_large_3x_coco.py这个就是刚官方的config文件,运行后生成的config文件就在output
python tools/train.py projects/configs/co_dino/co_dino_5scale_swin_large_3x_coco.py --work_dir output

然后点开这个文件对里面的参数进行修改,重点修改如下参数:

data_root改成自己存放数据集的路径,最开始是'data/coco/'

load_from第(1)步下载的权重文件:

在Swin-Transformer的github官网(GitHub - microsoft/Swin-Transformer: This is an official implementation for "Swin Transformer: Hierarchical Vision Transformer using Shifted Windows".)下载这个权重:

就是如下这个权重: 

 注:一定要注意!!!这里需要导入两个模型权重文件,一个是“load_from”参数:导入的是co_dino_5scale_swin_large_3x_coco.pth模型权重,是Co-DINO模型在COCO数据集上训练后得到的模型;另一个是“pretrained”参数(有两处需要修改):导入的是swin_large_patch4_window12_384_22k.pth模型权重。

因为我在训练自己的模型时,load_from参数为None,pretrained参数为co_dino_5scale_swin_large_3x_coco.pth,导致训练过程中评估结果全为0,更改过后才变正常,如下图。


下面这些参数根据需要更改,num_classes类别数(在config文件内有3处需要更改,可直接搜索num_classes将其改为自定义数据集的类别数,默认是80)。

lr学习率,max_epochs迭代轮数,work_dir结果保存路径。

samples_per_gpu(每个 GPU 上每次迭代所处理的样本数量)和workers_per_gpu(每个 GPU 所分配的数据加载线程数)两个参数(这两个参数可能就是我们平时训练模型的batch_size,因为在这个config文件内没有直接找到batch_size参数,感觉就是这两个参数控制的) 。

eg.若你有 4 个 GPU,samples_per_gpu设置为 8,那么总的批量大小就是 4 × 8 = 32。

eg.若你有 4 个 GPU,workers_per_gpu设置为 2,那么总共会使用 4 × 2 = 8 个线程来进行数据加载。


此外,还需要对COCO数据类型的一些参数进行更改,改为自定义数据集的类别,更改文件包括:

(1)Co-DETR/mmdet/datasets/coco.py,更改如下图。将其改为自定义数据集的类别名称,以及对应类别数的PALETTE颜色。

注:这里也出现了一个问题,我在训练模型时,最开始是将原有的COCO数据集默认的CLASSES和PALETTE直接注释了,然后在下面重写的自定义的数据类别,但训练时模型并没有将我更改后的CLASSES读入,导致LOSS全为0,后面我直接将默认的删除掉,才解决了这个问题,这里我也比较疑惑?

(2) Co-DETR/mmdet/core/evaluation/class_names.py,更改如下图。找到coco_classes,同样将其改为自己的类别,这里我就是直接注释掉上面默认的,在下面接着写的就没有问题,但上面不知道为什么有那个问题。


根据上述的修改,模型就可以按如下命令训练起来了:

python tools/train.py 你保存的config文件的位置
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值