目录
PaddleDetection是一个基于PaddlePaddle的目标检测端到端开发套件,可用于版面分析等通过视觉特征进行检测、分类、(分割)、 关键点检测的任务( 2D关键点检测),配合clas完成 属性识别等


数据准备
数据处理模块
PaddleDetection的数据处理模块的所有代码逻辑在ppdet/data/
中,数据处理模块用于加载数据并将其转换成适用于物体检测模型的训练、评估、推理所需要的格式。 数据处理模块的主要构成如下架构所示:
ppdet/data/
├── reader.py # 基于Dataloader封装的Reader模块
├── source # 数据源管理模块
│ ├── dataset.py # 定义数据源基类,各类数据集继承于此
│ ├── coco.py # COCO数据集解析与格式化数据
│ ├── voc.py # Pascal VOC数据集解析与格式化数据
│ ├── widerface.py # WIDER-FACE数据集解析与格式化数据
│ ├── category.py # 相关数据集的类别信息
├── transform # 数据预处理模块
│ ├── batch_operators.py # 定义各类基于批量数据的预处理算子
│ ├── op_helper.py # 预处理算子的辅助函数
│ ├── operators.py # 定义各类基于单张图片的预处理算子
│ ├── gridmask_utils.py # GridMask数据增强函数
│ ├── autoaugment_utils.py # AutoAugment辅助函数
├── shm_utils.py # 用于使用共享内存的辅助函数
数据源管理模块-source
- 基类DetDataSet
数据集定义在source
目录下,其中dataset.py
中定义了数据集的基类DetDataSet
, 所有的数据集均继承于基类,DetDataset
基类里定义了如下等方法:
当一个数据集类继承自DetDataSet
,那么它只需要实现parse_dataset
函数即可。parse_dataset根据数据集设置的数据集根路径dataset_dir
,图片文件夹image_dir
, 标注文件路径anno_path
取出所有的样本,并将其保存在一个列表roidbs
中,每一个列表中的元素为一个样本xxx_rec(比如coco_rec或者voc_rec),用dict表示,dict中包含样本的image, gt_bbox, gt_class等字段。COCO和Pascal-VOC数据集中的xxx_rec的数据结构定义如下:
xxx_rec = {
'im_file': im_fname, # 一张图像的完整路径
'im_id': np.array([img_id]), # 一张图像的ID序号
'h': im_h, # 图像高度
'w': im_w, # 图像宽度
'is_crowd': is_crowd, # 是否是群落对象, 默认为0 (VOC中无此字段)
'gt_class': gt_class, # 标注框标签名称的ID序号
'gt_bbox': gt_bbox, # 标注框坐标(xmin, ymin, xmax, ymax)
'gt_poly': gt_poly, # 分割掩码,此字段只在coco_rec中出现,默认为None
'difficult': difficult # 是否是困难样本,此字段只在voc_rec中出现,默认为0
}
xxx_rec中的内容也可以通过DetDataSet的data_fields参数来控制,即可以过滤掉一些不需要的字段,但大多数情况下不需要修改,按照configs/datasets
中的默认配置即可。
此外,在parse_dataset函数中,保存了类别名到id的映射的一个字典cname2cid
。在coco数据集中,会利用COCO API从标注文件中加载数据集的类别名,并设置此字典。在voc数据集中,如果设置use_default_label=False
,将从label_list.txt
中读取类别列表,反之将使用voc默认的类别列表。
数据预处理模块-transform
数据增强算子
PaddleDetection中支持了种类丰富的数据增强算子,有单图像数据增强算子与批数据增强算子两种方式,您可选取合适的算子组合使用。单图像数据增强算子定义在transform/operators.py
中,已支持的单图像数据增强算子详见下表:
批数据增强算子定义在transform/batch_operators.py
中, 目前支持的算子列表如下:
几点说明:
- 数据增强算子的输入为sample或者samples,每一个sample对应上文所说的
DetDataSet
输出的roidbs中的一个样本,如coco_rec或者voc_rec - 单图像数据增强算子(Mixup, Cutmix等除外)也可用于批数据处理中。但是,单图像处理算子和批图像处理算子仍有一些差异,以RandomResize和BatchRandomResize为例,RandomResize会将一个Batch中的每张图片进行随机缩放,但是每一张图像Resize之后的形状不尽相同,BatchRandomResize则会将一个Batch中的所有图片随机缩放到相同的形状。
- 除BatchRandomResize外,定义在
transform/batch_operators.py
的批数据增强算子接收的输入图像均为CHW形式,所以使用这些批数据增强算子�前请先使用Permute进行处理。如果用到Gt2xxxTarget算子,需要将其放置在靠后的位置。NormalizeBox算子建议放置在Gt2xxxTarget之前。将这些限制条件总结下来,推荐的预处理算子的顺序为
- XXX: {
}
- ...
- BatchRandomResize: {
...} # 如果不需要,可以移除,如果需要,放置在Permute之前
- Permute: {
} # 必须项
- NormalizeBox: {
} # 如果需要,建议放在Gt2XXXTarget之前
- PadBatch: {
...} # 如果不需要可移除,如果需要,建议放置在Permute之后
- Gt2XXXTarget: {
...} # 建议与PadBatch放置在最后的位置
自定义数据增强算子
如果需要自定义数据增强算子,那么您需要了解下数据增强算子的相关逻辑。数据增强算子基类为定义在transform/operators.py
中的BaseOperator
类,单图像数据增强算子与批数据增强算子均继承自这个基类。完整定义参考源码,以下代码显示了BaseOperator
类的关键函数: apply和__call__方法
class BaseOperator(object):
...
def apply(self, sample, context=None):
return sample
def __call__(self, sample, context=None):
if isinstance(sample, Sequence):
for i in range(len(sample)):
sample[i] = self.apply(sample[i], context)
else:
sample = self.apply(sample, context)
return sample
__call__方法为BaseOperator
的调用入口,接收一个sample(单图像)或者多个sample(多图像)作为输入,并调用apply函数对一个或者多个sample进行处理。大多数情况下,你只需要继承BaseOperator
重写apply方法或者重写__call__方法即可,如下所示,定义了一个XXXOp继承自BaseOperator,并注册:
@register_op
class XXXOp(BaseOperator):
def __init__(self,...):
super(XXXImage, self).__init__()
...
# 大多数情况下只需要重写apply方法
def apply(self, sample, context=None):
...
省略对输入的sample具体操作
...
return sample
# 如果有需要,可以重写__call__方法,如Mixup, Gt2XXXTarget等
# def __call__(self, sample, context=None):
# ...
# 省略对输入的sample具体操作
# ...
# return sample
大多数情况下,只需要重写apply方法即可,如transform/operators.py
中除Mixup和Cutmix外的预处理算子。对于批处理的情况一般需要重写__call__方法,如transform/batch_operators.py
的预处理算子。
Reader
Reader相关的类定义在reader.py
, 其中定义了BaseDataLoader
类。BaseDataLoader
在paddle.io.DataLoader
的基础上封装了一层,其具备paddle.io.DataLoader
的所有功能,并能够实现不同模型对于DetDataset
的不同需求,如可以通过对Reader进行设置,以控制DetDataset支持Mixup, Cutmix等操作。除此之外,数据预处理算子通过Compose
类和BatchCompose
类组合起来分别传入DetDataset
和paddle.io.DataLoader
中。 所有的Reader类都继承自BaseDataLoader
类,具体可参见源码。
相关配置及运行
Dataset、Reader配置
- Dataset配置
关于Dataset的配置文件存在于configs/datasets
文件夹。比如COCO数据集的配置文件如下:
metric: COCO # 目前支持COCO, VOC, OID, WiderFace等评估标准
num_classes: 80 # num_classes数据集的类别数,不包含背景类
TrainDataset:
!COCODataSet
image_dir: train2017 # 训练集的图片所在文件相对于dataset_dir的路径
anno_path: annotations/instances_train2017.json # 训练集的标注文件相对于dataset_dir的路径
dataset_dir: dataset/coco #数据集所在路径,相对于PaddleDetection路径
data_fields: ['image', 'gt_bbox', 'gt_class', 'is_crowd'] # 控制dataset输出的sample所包含的字段,注意此为TrainDataset独有的且必须配置的字段
EvalDataset:
!COCODataSet
image_dir: val2017 # 验证集的图片所在文件夹相对于dataset_dir的路径
anno_path: annotations/instances_val2017.json # 验证集的标注文件相对于dataset_dir的路径
dataset_dir: dataset/coco # 数据集所在路径,相对于PaddleDetection路径
TestDataset:
!ImageFolder
anno_path: annotations/instances_val2017.json # 标注文件所在路径,仅用于读取数据集的类别信息,支持json和txt格式
dataset_dir: dataset/coco # 数据集所在路径,若添加了此行,则`anno_path`路径为`dataset_dir/anno_path`,若此行不设置或去掉此行,则`anno_path`路径即为`anno_path`
在PaddleDetection的yml配置文件中,使用!
直接序列化模块实例(可以是函数,实例等),上述的配置文件均使用Dataset进行了序列化。
注意: 请运行前自行仔细检查数据集的配置路径,在训练或验证时如果TrainDataset和EvalDataset的路径配置有误,会提示自动下载数据集。若使用自定义数据集,在推理时如果TestDataset路径配置有误,会提示使用默认COCO数据集的类别信息
- Reader配置
不同模型专用的Reader定义在每一个模型的文件夹下,如yolov3的Reader配置文件定义在configs/yolov3/_base_/yolov3_reader.yml
。一个Reader的示例配置如下:
worker_num: 2
TrainReader:
sample_transforms:
- Decode: