# 教程 3:如何增加新数据集 在本教程中,我们将介绍一些有关如何按已支持的数据格式进行数据组织,和组合已有数据集来自定义数据集的方法。 - [通过重组数据来自定义数据集](#%E9%80%9A%E8%BF%87%E9%87%8D%E7%BB%84%E6%95%B0%E6%8D%AE%E6%9D%A5%E8%87%AA%E5%AE%9A%E4%B9%89%E6%95%B0%E6%8D%AE%E9%9B%86) - [将数据集重新组织为现有格式](#%E5%B0%86%E6%95%B0%E6%8D%AE%E9%9B%86%E9%87%8D%E6%96%B0%E7%BB%84%E7%BB%87%E4%B8%BA%E7%8E%B0%E6%9C%89%E6%A0%BC%E5%BC%8F) - [自定义数据集的示例](#%E8%87%AA%E5%AE%9A%E4%B9%89%E6%95%B0%E6%8D%AE%E9%9B%86%E7%9A%84%E7%A4%BA%E4%BE%8B) - [通过组合已有数据集来自定义数据集](#%E9%80%9A%E8%BF%87%E7%BB%84%E5%90%88%E5%B7%B2%E6%9C%89%E6%95%B0%E6%8D%AE%E9%9B%86%E6%9D%A5%E8%87%AA%E5%AE%9A%E4%B9%89%E6%95%B0%E6%8D%AE%E9%9B%86) - [重复数据集](#%E9%87%8D%E5%A4%8D%E6%95%B0%E6%8D%AE%E9%9B%86) ## 通过重组数据来自定义数据集 ### 将数据集重新组织为现有格式 最简单的方法是将数据集转换为现有的数据集格式(RawframeDataset 或 VideoDataset)。 有三种标注文件: - 帧标注(rawframe annotation) 帧数据集(rawframe dataset)标注文件由多行文本组成,每行代表一个样本,每个样本分为三个部分,分别是 `帧(相对)文件夹`(rawframe directory of relative path), `总帧数`(total frames)以及 `标签`(label),通过空格进行划分 示例如下: ``` some/directory-1 163 1 some/directory-2 122 1 some/directory-3 258 2 some/directory-4 234 2 some/directory-5 295 3 some/directory-6 121 3 ``` - 视频标注(video annotation) 视频数据集(video dataset)标注文件由多行文本组成,每行代表一个样本,每个样本分为两个部分,分别是 `文件(相对)路径`(filepath of relative path) 和 `标签`(label),通过空格进行划分 示例如下: ``` some/path/000.mp4 1 some/path/001.mp4 1 some/path/002.mp4 2 some/path/003.mp4 2 some/path/004.mp4 3 some/path/005.mp4 3 ``` - ActivityNet 标注 ActivityNet 数据集的标注文件是一个 json 文件。每个键是一个视频名,其对应的值是这个视频的元数据和注释。 示例如下: ``` { "video1": { "duration_second": 211.53, "duration_frame": 6337, "annotations": [ { "segment": [ 30.025882995319815, 205.2318595943838 ], "label": "Rock climbing" } ], "feature_frame": 6336, "fps": 30.0, "rfps": 29.9579255898 }, "video2": { "duration_second": 26.75, "duration_frame": 647, "annotations": [ { "segment": [ 2.578755070202808, 24.914101404056165 ], "label": "Drinking beer" } ], "feature_frame": 624, "fps": 24.0, "rfps": 24.1869158879 } } ``` 有两种使用自定义数据集的方法: - 在线转换 用户可以通过继承 [BaseDataset](/mmaction/datasets/base.py) 基类编写一个新的数据集类,并重写三个抽象类方法: `load_annotations(self)`,`evaluate(self, results, metrics, logger)` 和 `dump_results(self, results, out)`, 如 [RawframeDataset](/mmaction/datasets/rawframe_dataset.py),[VideoDataset](/mmaction/datasets/video_dataset.py) 或 [ActivityNetDataset](/mmaction/datasets/activitynet_dataset.py)。 - 本地转换 用户可以转换标注文件格式为上述期望的格式,并将其存储为 pickle 或 json 文件,然后便可以应用于 `RawframeDataset`,`VideoDataset` 或 `ActivityNetDataset` 中。 数据预处理后,用户需要进一步修改配置文件以使用数据集。 这里展示了以帧形式使用自定义数据集的例子: 在 `configs/task/method/my_custom_config.py` 下: ```python ... # 数据集设定 dataset_type = 'RawframeDataset' data_root = 'path/to/your/root' data_root_val = 'path/to/your/root_val' ann_file_train = 'data/custom/custom_train_list.txt' ann_file_val = 'data/custom/custom_val_list.txt' ann_file_test = 'data/custom/custom_val_list.txt' ... data = dict( videos_per_gpu=32, workers_per_gpu=2, train=dict( type=dataset_type, ann_file=ann_file_train, ...), val=dict( type=dataset_type, ann_file=ann_file_val, ...), test=dict( type=dataset_type, ann_file=ann_file_test, ...)) ... ``` ### 自定义数据集的示例 假设注释在文本文件中以新格式显示,并且图像文件名具有类似 “img_00005.jpg” 的模板。 那么视频注释将以以下形式存储在文本文件 `annotation.txt` 中。 ``` #文件夹,总帧数,类别 D32_1gwq35E,299,66 -G-5CJ0JkKY,249,254 T4h1bvOd9DA,299,33 4uZ27ivBl00,299,341 0LfESFkfBSw,249,186 -YIsNpBEx6c,299,169 ``` 在 `mmaction/datasets/my_dataset.py` 中创建新数据集加载数据 ```python import copy import os.path as osp import mmcv from .base import BaseDataset from .builder import DATASETS @DATASETS.register_module() class MyDataset(BaseDataset): def __init__(self, ann_file, pipeline, data_prefix=None, test_mode=False, filename_tmpl='img_{:05}.jpg'): super(MyDataset, self).__init__(ann_file, pipeline, test_mode) self.filename_tmpl = filename_tmpl def load_annotations(self): video_infos = [] with open(self.ann_file, 'r') as fin: for line in fin: if line.startswith("directory"): continue frame_dir, total_frames, label = line.split(',') if self.data_prefix is not None: frame_dir = osp.join(self.data_prefix, frame_dir) video_infos.append( dict( frame_dir=frame_dir, total_frames=int(total_frames), label=int(label))) return video_infos def prepare_train_frames(self, idx): results = copy.deepcopy(self.video_infos[idx]) results['filename_tmpl'] = self.filename_tmpl return self.pipeline(results) def prepare_test_frames(self, idx): results = copy.deepcopy(self.video_infos[idx]) results['filename_tmpl'] = self.filename_tmpl return self.pipeline(results) def evaluate(self, results, metrics='top_k_accuracy', topk=(1, 5), logger=None): pass ``` 然后在配置文件中,用户可通过如下修改来使用 `MyDataset`: ```python dataset_A_train = dict( type='MyDataset', ann_file=ann_file_train, pipeline=train_pipeline ) ``` ## 通过组合已有数据集来自定义数据集 MMAction2 还支持组合已有数据集以进行训练。 目前,它支持重复数据集(repeat dataset)。 ### 重复数据集 MMAction2 使用 “RepeatDataset” 作为包装器来重复数据集。例如,假设原始数据集为 “Dataset_A”, 为了重复此数据集,可设置配置如下: ```python dataset_A_train = dict( type='RepeatDataset', times=N, dataset=dict( # 这是 Dataset_A 的原始配置 type='Dataset_A', ... pipeline=train_pipeline ) ) ```