MMDetection3D学习笔记_整体架构

完整文章转载自OpenMMLab,此仅作个人学习笔记:

带你玩转 3D 检测和分割 (三):有趣的可视化 - OpenMMLab的文章 - 知乎https://zhuanlan.zhihu.com/p/504862433


一、MMDetection3D 整体框架介绍

1.1 总体框架

在这里插入图片描述

1.2点云 3D 检测(包含多模态 3D 检测):

对于点云 3D 检测(多模态 3D 检测),我们继承自 MMDetection 中的 BaseDetector 构建了适用于 3D 检测的 Base3DDetector 。
不同于 SingleStage3DDetector,为了尽可能的复用已有的代码组件,二阶段检测器TwoStage3DDetector 同时继承自 Base3DDetector 和 TwoStageDetector。
而由于多模态任务的特殊性,我们专门为多模态检测方法设计了 MVXTwoStage3DDetector。

在这里插入图片描述

1.3单目3D检测

对于单目 3D 检测考虑到和 2D 检测输入数据的一致性,我们继承自 MMDetection 中的 SingleStageDetector 构建了 SingleStageMono3DDetector,目前所支持的单目 3D 检测算法都是基于该类构建的。
在这里插入图片描述

1.4数据预处理

该部分对应于 tools/create_data.py ,各个数据集预处理脚本位于 tools/data_converter 目录下。由于 3D 数据集的多样性,MMDetection3D 会对数据集做预处理。
在这里插入图片描述

  1. 对所有的任务和场景,我们统一使用数据处理脚本转换后的 pkl 文件,该文件包含数据集的各种信息,包括数据集路径、calib 信息和标注信息等等,从而做到各个数据集内部格式尽可能的统一

  2. 对于点云 (多模态)3D 检测,室内和室外数据集生成的文件是不一样的:
    室外数据集:
    我们会借助 pkl 文件的信息进一步提取 reduced_point_cloudgt_databasereduced_point_cloud仅包含前方视野的点云文件,通常存在于 kitti 数据集处理过程中,因为 kitti 数据集仅包含前方视野的标注;
    gt_database则是将包含在训练数据集的每个 3D 边界框中的点云数据分别提取出来得到的各个物体的点云文件,常用来在数据增强时使用(copy-paste)。

    室内数据集
    由于室内点云较为密集的特点,通常会进行点云的下采样处理,保存在points内。

  3. 对于单目 3D 检测,由于在前面提到,整个模型构建的流程是遵循 2D 检测的,同样的在数据处理的过程中,在生成基本的 pkl 文件后,还需要将其转换为 coco 标注格式的 json 文件,该过程中会对 pkl 的标注信息做相应处理,实际在该任务中,pkl 文件用来提供 data 信息,json 文件提供标注信息

1.5模块抽象

和 MMDetection 一脉相承,整个 MMDetection3D 的模块内部抽象流程也主要包括 PipelineDataParallelModelRunnerHooks

1.5.1 pipeline:

在这里插入图片描述
上图展示了三个比较典型的 3D 检测 pipeline, 流程自上而下分别是:点云 3D 检测多模态 3D 检测单目 3D 检测
从上述的流程可以,pipeline 其实是由一系列的按照插入顺序运行的数据处理模块组成接受数据字典,输出经过处理后的数据字典
1. MMDetection3D 对于点云 3D 检测提供了很多常用的 pipeline 模块,比如GlobalRotScaleTrans(点云的旋转缩放)、PointsRangeFilter / ObjectRangeFilter(限定了点云和物体的范围)、PointShuffle(打乱点云数据);
2. 而对于单目 3D 检测基本就是直接调用 MMDetection 的数据处理模块,比如 Resize (图片缩放)、Normalize (正则化)、Pad (图片填充);
3. 多模态检测则兼用两者
我们可以看到其实这些任务共享了部分的 pipeline 模块,比如 LoadAnnotations3D (标签载入)、RandomFlip3D(会对点云和图片同时进行翻转)、DefaultFormatBundle3D(数据格式化)、Collect3D (选取需要用于训练的数据和标签)。
这些代码都在 mmdet3d/datasets/pipeline 目录下

1.5.2 Model:

1.5.2.1 点云 3D 检测模型

目前点云目标检测按照对点云数据的处理方式,可以分为体素处理方法 (Voxel-based)原始点云处理方法 (Point-based)

  1. 素处理方法 (Voxel-based): 基于体素的模型通常需要 Encoder 来对点云体素化,如 HardVFE 和 PointPillarScatter等,采用的稀疏卷积或者 Pillars 的方法从点云中生成 2D 特征图,然后基本可以套用 2D 检测流程进行 3D 检测
  2. 原始点云处理方法: 基于原始点云模型通常直接采用 3D Backbone (Pointnet / Pointnet++ 等) 提取点的特征,再针对提取到的点云特征采用 RoI 或者 Group 等方式回归 3D bounding box。
    在这里插入图片描述
1.5.2.2 单目 3D 检测模型

单目 3D 检测的输入是图片,输出是 3D bounding box, 所以整体的检测流程和模型组成来说基本和 2D 检测保持一致
在这里插入图片描述

1.5.2.3 多模态 3D 检测模型

多模态的检测模型可以看成 2D 检测模型和点云检测模型的拼接。

1.6 train流程

1.6.1 总体流程:

  1. 训练和验证调用的是 tools/train.py 脚本,先进行 Dataset、Model 等相关类初始化;
  2. 构建了一个 runner,最终模型的训练和验证过程是发生在 runner 内部;
  3. runner 调用了 model 内部的 train_step 和 val_step 函数
    在这里插入图片描述

1.6.2 调用runner中的train_step / val_step

  1. 首先会调用 DataParallel 中的 train_step 或者 val_step ;
  2. 然后调用self.scatter 函数处理 DataContainer 格式数据,使其能够组成 batch,否则程序会报错;
  3. 调用 model 本身的self.module.train_step;
  4. 在不同算法子类中调用 self.forward_train 和 self.forward_test 需要在不同的算法子类中实现,输出是 Loss + 预测结果
  5. 调用 model 中的 _parse_losses 方法,对 loss 进行求和
# 非分布式训练 
#=================== mmcv/parallel/data_parallel.py/MMDataParallel ================== 
def train_step(self, *inputs, **kwargs): 
    if not self.device_ids: 
        inputs, kwargs = self.scatter(inputs, kwargs, [-1]) 
        ***# 此时才是调用 model 本身的 train_step*** 
        return self.module.train_step(*inputs, **kwargs) 
    # 单 gpu 模式 
    inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids) 
    # 此时才是调用 model 本身的 train_step 
    return self.module.train_step(*inputs[0], **kwargs[0]) 
 
# val_step 也是的一样逻辑 
def val_step(self, *inputs, **kwargs): 
    inputs, kwargs = self.scatter(inputs, kwargs, self.device_ids) 
    # 此时才是调用 model 本身的 val_step 
    return self.module.val_step(*inputs[0], **kwargs[0]) 
#=================== mmdet/models/detectors/base.py/BaseDetector ============= 
def train_step(self, data, optimizer): 
    # 调用本类自身的 forward 方法 
    losses = self(**data) 
    # 解析 loss 
    loss, log_vars = self._parse_losses(losses) 
    # 返回字典对象 
    outputs = dict( 
        loss=loss, log_vars=log_vars, num_samples=len(data['img_metas'])) 
    return outputs 
 
#=================== mmdet/models/detectors/base.py/Base3DDetector =========== 
# Base3DDetector 主要是重写了 forward,改变了模型输入数据的类型,可同时传入点云数据和图片数据,从而满足多模态检测的需求 
@auto_fp16(apply_to=('img', 'points')) 
def forward(self, return_loss=True, **kwargs): 
    if return_loss: 
        # 训练模式 
        return self.forward_train(**kwargs) 
    else: 
        # 测试模式 
        return self.forward_test(**kwargs) 


#=================== mmdet/models/detectors/base.py/BaseDetector ================== 
def _parse_losses(self, losses): 
 
    # 返回来的 losses 是一个dict, 我们需要对 loss 进行求和 
    log_vars = OrderedDict() 
    for loss_name, loss_value in losses.items(): 
        if isinstance(loss_value, torch.Tensor): 
            log_vars[loss_name] = loss_value.mean() 
        elif isinstance(loss_value, list): 
            log_vars[loss_name] = sum(_loss.mean() for _loss in loss_value) 
        else: 
            raise TypeError( 
                f'{loss_name} is not a tensor or list of tensors') 
 
    loss = sum(_value for _key, _value in log_vars.items() 
               if 'loss' in _key) 
 
    log_vars['loss'] = loss 
    for loss_name, loss_value in log_vars.items(): 
        # reduce loss when distributed training 
        if dist.is_available() and dist.is_initialized(): 
            loss_value = loss_value.data.clone() 
            dist.all_reduce(loss_value.div_(dist.get_world_size())) 
        log_vars[loss_name] = loss_value.item() 
 
    return loss, log_vars 

1.7 test流程

在这里插入图片描述

二、第一层整体抽象

在总体把握了整个 MMDetection 框架训练和测试流程后,下个层次是每个模块内部抽象流程,主要包括 PipelineDataParallelModelRunnerHooks
在这里插入图片描述

三、第二层模块抽象

3.1 pipeline

Pipeline 都可以划分为如下部分:

图片和标签加载,通常用的类是 LoadImageFromFile 和 LoadAnnotations
数据前处理,例如统一 Resize
数据增强,典型的例如各种图片几何变换等,这部分是训练流程特有,测试阶段一般不采用(多尺度测试采用其他实现方式)
数据收集,例如 Collect
在 MMDetection 框架中,图片和标签加载和数据后处理流程一般是固定的,用户主要可能修改的是数据增强步骤,目前已经接入了第三方增强库 Albumentations,可以按照示例代码轻松构建属于你自己的数据增强 Pipeline。
在这里插入图片描述

3.2 DataParallel 和 Model

DataParallel
在 MMDetection 中 DataLoader 输出的内容不是 pytorch 能处理的标准格式,还包括了 DataContainer 对象,该对象的作用是包装不同类型的对象使之能按需组成 batch。故需要在 DataParallel 中自行处理。
Model:

在这里插入图片描述

3.3 Runner 和 Hooks

任何一个目标检测算法,都需要包括优化器、学习率设置、权重保存等等组件才能构成完整训练流程,而这些组件是通用的。为了方便 OpenMMLab 体系下的所有框架复用,在 MMCV 框架中引入了 Runner 类来统一管理训练和验证流程,并且通过 Hooks 机制以一种非常灵活、解耦的方式来实现丰富扩展功能。
在这里插入图片描述

四、第三层代码抽象

4.1 训练和测试整体代码抽象流程

在这里插入图片描述
上图为训练和验证的和具体代码相关的整体抽象流程,对应到代码上,其核心代码如下

#=================== tools/train.py ==================
# 1.初始化配置
cfg = Config.fromfile(args.config)

# 2.判断是否为分布式训练模式

# 3.初始化 logger
logger = get_root_logger(log_file=log_file, log_level=cfg.log_level)

# 4.收集运行环境并且打印,方便排查硬件和软件相关问题
env_info_dict = collect_env()

# 5.初始化 model
model = build_detector(cfg.model, ...)

# 6.初始化 datasets

#=================== mmdet/apis/train.py ==================
# 1.初始化 data_loaders ,内部会初始化 GroupSampler
data_loader = DataLoader(dataset,...)

# 2.基于是否使用分布式训练,初始化对应的 DataParallel
if distributed:
  model = MMDistributedDataParallel(...)
else:
  model = MMDataParallel(...)

# 3.初始化 runner
runner = EpochBasedRunner(...)

# 4.注册必备 hook
runner.register_training_hooks(cfg.lr_config, optimizer_config,
                               cfg.checkpoint_config, cfg.log_config,
                               cfg.get('momentum_config', None))

# 5.如果需要 val,则还需要注册 EvalHook           
runner.register_hook(eval_hook(val_dataloader, **eval_cfg))

# 6.注册用户自定义 hook
runner.register_hook(hook, priority=priority)

# 7.权重恢复和加载
if cfg.resume_from:
    runner.resume(cfg.resume_from)
elif cfg.load_from:
    runner.load_checkpoint(cfg.load_from)

# 8.运行,开始训练
runner.run(data_loaders, cfg.workflow, cfg.total_epochs)

五、Head 流程

目前 MMDetection 中 Head 模块主要是按照 stage 来划分,主要包括2个 package:

  1. dense_heads
    1.1.anchor-free
    1.2 anchor-based
    1.3 其他(YOLOHead 等,为重写部分)
  2. roi_heads
    one-stage: 包含1
    two-stage: 包含1和2

每个算法的 Head 子类一般不会重写上述方法,但是每个 Head 子类都会重写 forward 和 loss 方法,其中 forward 方法用于运行 head 网络部分输出分类回归分支的特征图而 loss 方法接收 forward 输出,并且结合 label 计算 loss
在这里插入图片描述


持续学习共同进步

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值