天天看点

【mmdetection实践】(一)构建自己的数据集理论知识实践

文章目录

  • 理论知识
    • 按照COCO数据集的格式
    • 定义自己的Dataset
  • 实践

理论知识

按照官网所说,构建自己的数据集有两种方法,自己的数据时COCO数据集的格式或者自己定义个数据集的格式。

按照COCO数据集的格式

这种方式要求数据按照COCO数据集的格式组织,COCO数据集的详细解释参考另一篇博客,主要是annotations中的json文件的内容需要注意。

接下来我们看一下mmdetection是如何调用数据集的,首先看一下训练的config文件中对数据集的定义部分:其中定义了dataset_type时COCODataset的类型,然后定义了COCO数据集的位置,train_pipeline定义了读取图片过程中的操作(包括读取,归一化,增广),data定义了train、val、test的具体位置。

# ./configs/faster_rcnn_r50_fpn_1x.py
# dataset settings

# dataset settings
dataset_type = 'CocoDataset'
data_root = './data/coco/'
img_norm_cfg = dict(
    mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)
train_pipeline = [
    dict(type='LoadImageFromFile'),
    dict(type='LoadAnnotations', with_bbox=True),
    dict(type='Resize', img_scale=(1333, 800), keep_ratio=True),
    dict(type='RandomFlip', flip_ratio=0.5),
    dict(type='Normalize', **img_norm_cfg),
    dict(type='Pad', size_divisor=32),
    dict(type='DefaultFormatBundle'),
    dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels']),
]
test_pipeline = [
    dict(type='LoadImageFromFile'),
    dict(
        type='MultiScaleFlipAug',
        img_scale=(1333, 800),
        flip=False,
        transforms=[
            dict(type='Resize', keep_ratio=True),
            dict(type='RandomFlip'),
            dict(type='Normalize', **img_norm_cfg),
            dict(type='Pad', size_divisor=32),
            dict(type='ImageToTensor', keys=['img']),
            dict(type='Collect', keys=['img']),
        ])
]
data = dict(
    imgs_per_gpu=2,
    workers_per_gpu=2,
    train=dict(
        type=dataset_type,
        ann_file=data_root + 'annotations/instances_train2017.json',
        img_prefix=data_root + 'train2017/',
        pipeline=train_pipeline),
    val=dict(
        type=dataset_type,
        ann_file=data_root + 'annotations/instances_val2017.json',
        img_prefix=data_root + 'val2017/',
        pipeline=test_pipeline),
    test=dict(
        type=dataset_type,
        ann_file=data_root + 'annotations/instances_val2017.json',
        img_prefix=data_root + 'val2017/',
        pipeline=test_pipeline))
           

然后看一下COCODataset的定义:对外可调用的函数只有load_annotations和get_ann_info两个

# ./mmdnet/datasets/coco.py

class CocoDataset(CustomDataset):
	def load_annotations(self, ann_file):  # 用于初始化CocoDataset的,主要初始化算imgs的位置,imgs和annotations的关联关系等
		...
	def get_ann_info(self, idx):  # 用于在train/val/test中调取annotations
		...
	
           

然后看一下在训练中时如何调用的,COCODatset继承CustomDatset,在train过程中调用的时CustomDataset的函数:

# ./mmdnet/datasets/custom.py

class CustomDataset(Dataset):

    def __init__(...):
        ...
        # load annotations (and proposals)
        self.img_infos = self.load_annotations(self.ann_file)
        ...
        # processing pipeline
        self.pipeline = Compose(pipeline)

    def __getitem__(self, idx):
       if self.test_mode:
           return self.prepare_test_img(idx)
       while True:
           data = self.prepare_train_img(idx)
           if data is None:
               idx = self._rand_another(idx)
               continue
           return data

    def prepare_train_img(self, idx):
        img_info = self.img_infos[idx]
        ann_info = self.get_ann_info(idx)
        results = dict(img_info=img_info, ann_info=ann_info)
        if self.proposals is not None:
            results['proposals'] = self.proposals[idx]
        self.pre_pipeline(results)
        return self.pipeline(results)
           

可以从上面代码中看出:

  • 在Dataset的init中确实时使用load_annotations进行初始化
  • __getitem__函数是重载Dataset的,就是在train过程中加载data和target的,其中用了prepare_train_img
  • prepare_train_img使用了get_ann_info函数来加载target

定义自己的Dataset

在GETTING_START.md中出现

“You can write a new Dataset class inherited from CustomDataset, and overwrite two methods load_annotations(self, ann_file) and get_ann_info(self, idx), like CocoDataset and VOCDataset.”

根据上述代码,可以看到CustomDataset中使用load_annotations初始化dataset,使用get_ann_info加载target,所以继承CustomDataset需要定义这两个函数,就可以完成自己Dataset的定义。

实践

本次实践采用第一种方法,定义一个自己的COCODataset。在网上的另一篇博客【干货】mmdetection使用coco格式的CrowdHuman数据集进行训练及测试(附调参过程)是直接修改了COCODataset,以至于出现很多错误,这种方法并不是官方推荐的。需要修改的文件如下:

1、在./mmdet/datasets/目录下新建一个.py用于定义自己的Dataset,如myDataset.py,按照官方教程定义即可

from .coco import CocoDataset
from .registry import DATASETS


@DATASETS.register_module
class MyDataset(CocoDataset):  # 继承CocoDataset,使用CocoDataset的初始化和加载函数,这里只需要自己定义本数据集中包含的类别
    CLASSES = ("pos",)  # 本数据集只包含1类,叫做pos
           

2、在./mmdet/datasets/__init__.py中加入自己定义的数据集

from .builder import build_dataset
from .cityscapes import CityscapesDataset
from .coco import CocoDataset
from .custom import CustomDataset
from .dataset_wrappers import ConcatDataset, RepeatDataset
from .loader import DistributedGroupSampler, GroupSampler, build_dataloader
from .registry import DATASETS
from .voc import VOCDataset
from .wider_face import WIDERFaceDataset
from .xml_style import XMLDataset
from .myDataset import MyDataset  # 添加

__all__ = [
    'CustomDataset', 'XMLDataset', 'CocoDataset', 'VOCDataset',
    'CityscapesDataset', 'GroupSampler', 'DistributedGroupSampler',
    'build_dataloader', 'ConcatDataset', 'RepeatDataset', 'WIDERFaceDataset',
    'DATASETS', 'build_dataset', 'MyDataset'  # 添加
]
           

3、修改config文件中的dataset有关项

# dataset settings
dataset_type = 'myDataset'  # 添加
           

至此,构建自己的数据集全部完成,并且能在训练中进行调用!!!

另外在转数据集的过程中,尤其要关注annotations中文件的生成,其中踩坑过程详见【mmdetection采坑记录】(一)将自己的数据转成COCO数据集的格式

继续阅读