(七)mmdetection源码解读:训练数据加载流程之pipeline(一)

一、数据集处理流程

首先通过官方文档流程图了解据预处理和数据增强整个流程:
mmdetection数据预处理和数据增强都在pipeline过程中实现,下面这张图来自mmdetection官方文档,因为版本不同具体内容会稍有差别:
mmdetection官方文档

1、LoadImageFromFile

img:当前图像
img_shape:resize、crop后的图片大小
ori_shape:原始图片大小

2、LoadAnnotations

gt_bboxes:数据集标注中给出的目标物体对应的边界框
gt_bboxes_ignore:数据集标注中给出的需要忽略的目标物体对应的边界框
gt_labels:数据集标注中给出的目标物体对应的label

3、Resize

更多Resize细节参考下面链接
https://zhuanlan.zhihu.com/p/381117525
img_scale=(512, 512), keep_ratio=True
img_scale缩放之后图像的最终尺度,keep_ratio保持宽高比(scale、scale_factor表示的缩放比例系数)
注意:当 keep_ratio 设置为 False 时候,输入的 img_scale 含义是 w,h, 输出尺度就是预设的输入尺度。当 keep_ratio 设置为 True 时候,输入的 img_scale 不区分 h,w,而是 min 和 max,输出会在保证宽高比不变的情况下,最大程度接近 [min(img_scale), max(img_scale)] 范围。

4、RandomFlip

flip_ratio:反转概率。direction:‘horizontal’, ‘vertical’, ‘diagonal’. Default: ‘horizontal’:翻转方向

5、Normalize

mean (sequence): Mean values of 3 channels.:均值
std (sequence): Std values of 3 channels.:方差
to_rgb (bool): Whether to convert the image from BGR to RGB,default is true.:是否BGR 转 RGB

6、Pad

size (tuple, optional):填充图像到指定大小
size_divisor (int, optional):填充图像到可以整除size_divisor
pad_to_square (bool): Whether to pad the image into a square.填充图像到正方形

填充图像到指定大小,填充图像到尺寸可以除开

7、DefaultFormatBundle

定义在formating.py中,这一步就是把img、bboxes、labels转换为tensor,再转换为DataContainer。

8、Collect

定义在formating.py中,把一些标注信息插入到results[‘img_metas’]

二、代码中pipeline调用过程

然后,介绍pipeline处理数据过程中代码的一些细节问题:
1、数据实例化的过程中,数据父类CustomDataset初始化函数中会实例化Compose去构建pipeline

@DATASETS.register_module()
class CustomDataset(Dataset):
    def __init__():
        self.pipeline = Compose(pipeline)
@PIPELINES.register_module()
class Compose:
    def __init__(self, transforms):
           transform = build_from_cfg(transform, PIPELINES)

2、按照pipeline去处理数据

#从配置文件看出train_pipeline 包含LoadImageFromFile、LoadAnnotations、Resize、RandomFlip、Normalize、
#Pad、DefaultFormatBundle、Collect九大步骤
#Compose 的__init__函数把九个步骤添加到  self.transforms中
#__call__函数 按照处理流程对数据进行变换
@PIPELINES.register_module()

class Compose:
    def __init__(self, transforms):
        assert isinstance(transforms, collections.abc.Sequence)
        self.transforms = []
        for transform in transforms:
            if isinstance(transform, dict):
                transform = build_from_cfg(transform, PIPELINES)
                self.transforms.append(transform)
            elif callable(transform):
                self.transforms.append(transform)
            else:
                raise TypeError('transform must be callable or a dict')
	def __call__(self, data):
			for t in self.transforms:
			     data = t(data)
			     if data is None:
			         return None
		 return data

#在epoch_based_runner.py
def run(self, data_loaders, workflow, max_epochs=None, **kwargs):
	    epoch_runner(data_loaders[i], **kwargs)
def train(self, data_loader, **kwargs):
		for i, data_batch in enumerate(self.data_loader):#这里调用的 CustomDataset类的__getitem__方法

self.pipeline被调用的位置如下

    def prepare_train_img(self, idx):

        img_info = self.data_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)

三、python中的 __call__和 __getitem__方法

3.1 __call__方法

在Python中,函数其实是一个对象,一个类实例也可以变成一个可调用对象,只需要实现一个特殊方法__call__().Compose类实现了方法__call__,self.pipeline(results)实际上执行的是Compose类方法__call_

@DATASETS.register_module()
class CustomDataset(Dataset):
    def __init__(self):
        self.pipeline = Compose(pipeline)
    def prepare_train_img(self, idx):
#什么时候调用的 __call__
        return self.pipeline(results)#这里调用的 __call__方法

3.1 __getitem__方法

python 中的 __getitem__方法,常见的两种写法
形式一: getitem(self, index) 一般用来迭代序列(常见序列如:列表、元组、字符串),或者求序列中的索引为 index 处的值。
形式二: getitem(self, key) 一般用来迭代映射(常见映射如:字典),或者求映射中的键为 key 出的值。


@DATASETS.register_module()
class CustomDataset(Dataset):
    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
 #下面伪代码
cc=CustomDataset()
b=cc[1]# 会自动调用 __getitem__方法

最后区分一下下面的概念:
Epoch 使用训练集的全部数据对模型进行一次完整的训练,被称为“一代训练”或者“一轮训练”
Batch 使用训练集中的一小部分样本对模型权重进行一次反向传播的参数更新,这一小部分样本被称为“一批数据”
Iteration 使用一个Batch数据对模型进行一次参数更新的过程,被称之为“一次训练”
(1)batchsize:批大小。在深度学习中,一般采用SGD训练,即每次训练在训练集中取batchsize个样本训练;
(2)iteration:1个iteration等于使用batchsize个样本训练一次;
(3)epoch:1个epoch等于使用训练集中的全部样本训练一次,通俗的讲epoch的值就是整个数据集被轮几次。

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值