最早一直想把mmdetection吃掉,但是一只拖延没有搞定。趁着近期休息,mmlab官方也举办了一个mmlab-challenge(https://openmmlab.com/competitions/algorithm-2021)复现论文的比赛,报名准备督促自己学习一下mmTask的框架。最终决定从mmsegmentation(https://github.com/open-mmlab/mmsegmentation)切入,记录一下过程中的问题。
首先建议大家学习的话直接从最新版的代码看起,时间隔的久的话代码变化还蛮大的。比如我最早是从CVPR2021-SETR的code(https://github.com/fudan-zvg/SETR)入手的,后来又看最新的code发现变化蛮大的(主要隔了估计也有快1年了...)。而且像cvpr这种顶会的论文复现code一般都会在最新版集成进去。再退一步,某一篇论文也只是一个你看code的切入点,因为你看完之后发现mmlab的code模块化很明显,不同的paper之间只有少量文件不同。

1 如何PR(Pull Request)

感受了一波contributer的感觉2333

1.1 【干货贴】手把手教你给 OpenMMLab 提 PR

1. 复刻 OpenMMLab 原代码库,点击 GitHub 页面右上角的 Fork 按钮即可
2. 克隆复刻的代码库到本地
    git clone git@github.com:XXX/mmcv.git

3. 添加原代码库为上游代码库
    git remote add upstream git@github.com:open-mmlab/mmcv

4. 拉取最新的原代码库的主分支
    git pull upstream master

5. 新建并检出一个新的分支,进行开发
    git checkout –b branchname
    # 写code
    git add [files]
    git commit -m 'messages'

6. 推送到复刻的代码库
    git push -u origin branchname

7. 创建一个 PR
    code部分有个Compare & pull request

8. 创建 PR 时,可以关联给相关人员进行 review
    点击create pull request

9. 关联相关的 issue 和 PR
10. 根据 reviewer 的意见修改代码,并推送修改
11. PR 合并之后删除该分支
    git branch –d branchname # 删除本地分支
    git push origin --delete branchname # 删除远程分支

1.2 提交PR中遇到的问题

遇到的一个基础问题就是代码风格问题,每个项目都有自己的格式,commit&push前尽量自行统一格式,免得pr之后对方还要就格式问题耽误时间。

格式的话repr中一般已经定义好了,在‘.pre-commit-config.yaml’这个文件中,我们需要安装pre-commit这个东西来实现commit前根据这个config文件来check code的style是否和repr要求的一样。

# After you clone the repository, you will need to install initialize pre-commit hook.
pip install -U pre-commit

# From the repository folder
pre-commit install

reference:https://github.com/open-mmlab/mmsegmentation/blob/master/.github/CONTRIBUTING.md

ps:在实际使用时pre-commit构建环境的时候出现了一些bug(‘fake_gem__-0.0.0.gem’,‘gem’,‘build’啥啥乱七八糟的),总结下来好像就是没有安装ruby,>=2.4版本的。本来apt install ruby-full就能直接安装的,但是貌似我修改了源之后最新版就是2.3,很蛋疼,还要自己添加新的源来下载更新版本的ruby,参考:https://www.brightbox.com/blog/2017/01/13/ruby-2-4-ubuntu-packages/

$ sudo apt-add-repository ppa:brightbox/ruby-ng
$ sudo apt-get update
$ sudo apt-get install ruby2.4 ruby2.4-dev
$ ruby -v
ruby 2.4.10p364 (2020-03-31 revision 67879) [x86_64-linux-gnu]

2 Train code

2.1 overview

先上代码结构,训练时主要使用时用到configsmmsegtoolsmmcv

configs---- 其中configs保存了不同论文的不同实验的各种配置,包括模型,数据集,优化器,等等之类的。以configs/setr/setr_mla_512x512_160k_b8_ade20k为例:

_base_ = []其中是一些默认设置,_base_是一个configs目录下的一个文件夹。

下边的配置是用于覆盖默认配置的。如optimizer中paramwise_cfg = dict(custom_keys={'head': dict(lr_mult=10.)})意思就是模型结构中名字包含‘head’子字符串的module对应的parameters的学习率要在基础学习率的基础上*10.,也就是0.001*10 = 0.01。

图1

mmseg---- 其中mmseg主要包含了用于初始化dataset和model的类文件,训练文件(apis/train.py,训练部分的pipeline)还有一些其他辅助类的文件(log之类的)。

tools---- tools就是分布式训练的command(dist_train.sh)和训练的pipeline(train.py)。

mmcv---- mmcv是提供基础功能的。主要会用到mmcv/runner和mmcv/utils,runner中包含真正训练时的code(是按照iteration还是epoch之类的,有对应实现的类,前边两个train.py是更外层的pipeline code)

注:mmcv里这两个也是mmlab各种库的精髓,一个是runner中通过Hook类来操作训练中更微观的步骤(比如学习率更新,优化,模型保存,写入log之类的操作,如下图2),这些hook都有专门的类来实现,类中有对应的函数(‘before_train_iter’,‘after_train_iter’),在runner.train中串联调用(所有的hooks都存在了一个list中,self.call_hook依次调用对应函数)来实现训练过程(Hook类会被insert一个priority优先级参数来控制hook list的顺序,也就是执行顺序,其实一般是按照加入的顺序来的)。

图2

图3

另外一个就是mmcv/utils/registry.py中Registry的使用。训练中所有的模块几乎都是通过Registry来实现的。Registry可以将strings映射到真实的classes(如type“ResNet”到class ResNet

方式是通过在定义ResNet时候就通过@MODELS.register_module()来统一管理了,相当于我手里有个小本本,我的库里有什么模型都有记录,你想要啥,你在config中写好type,我帮你找,初始化出来返还给你。mm系列的的model,dataset,optimizer包括hook都是通过这种形式实现的,也都有对应Registry类实例:MODELS,DATASETS,OPTIMIZERS,HOOKS等。

图4

注:mmcv是应该装到本地的,是mm系列的基础库。但是我看代码的电脑windows缺编译器装不上这个,所以干脆下载下来放在目录中了)

# 待续。。。。。。

2.2 mmcv模块

作为open-mmlab主库,还是值得记录一下的。

 

 2.2.1 utils

2.2.1.1 config.py

·class ConfigDict(Dict): 继承自addict中的Dict(which继承自python的dict),是对python dict的一种用法上的改进。

·def add_args(parser, cfg, prefix=''): 在parser中添加argument

·class Config:A facility for config and config files. (一堆静态函数。。。)

# 在def __init__(self, cfg_dict=None, cfg_text=None, filename=None):中定义了三个attr
super(Config, self).__setattr__('_cfg_dict', ConfigDict(cfg_dict))
super(Config, self).__setattr__('_filename', filename)
super(Config, self).__setattr__('_text', text)

·class DictAction(Action): 继承自argparse中的Action。细节用到再补。

2.2.1.2 registry.py

·def build_from_cfg(cfg, registry, default_args=None):

"""Build a module from config dict.

Args:
    cfg (dict): Config dict. It should at least contain the key "type".
    registry (:obj:`Registry`): The registry to search the type from.
    default_args (dict, optional): Default initialization arguments.

Returns:
    object: The constructed object.
""" 

 cfg中包含type和一些类实例化时的参数,通过type结合register去寻找对应的类,再用cfg剩余的args初始化这个类并返回。

·class Registry:

A registry to map strings to classes.

2.3 mmseg模块

segmentation task specific的库

  • __init__.py用来检查mmcv的版本是不是compatible,以及定义目录下外放的函数。
  • version.py记录mmseg版本之类的信息。

2.3.1 apis

2.3.1.4 train.py

初始化seed的函数(set_random_seed);

以及mmseg的基础训练文件(build data_loaders、optimizer、给model套分布式壳子;构建runner(from mmcv)、register train和validation的hooks);

2.3.2 core

2.3.3 datasets

2.3.4 models

2.3.4.1 builder.py

BACKBONES = Registry('backbone')
NECKS     = Registry('neck')
HEADS     = Registry('head')
LOSSES    = Registry('loss')
SEGMENTORS= Registry('segmentor')

· def build(cfg, registry, default_args=None):

调用mmcv.utils.registry.py中的build_from_cfg函数构建nn module。

· build是基本函数,服务于以下:

def build_backbone(cfg):
    """Build backbone."""
    return build(cfg, BACKBONES)
def build_neck(cfg):
    """Build neck."""
    return build(cfg, NECKS)
def build_head(cfg):
    """Build head."""
    return build(cfg, HEADS)
def build_loss(cfg):
    """Build loss."""
    return build(cfg, LOSSES)
def build_segmentor(cfg, train_cfg=None, test_cfg=None):
    """Build segmentor."""
    return build(cfg, SEGMENTORS, dict(train_cfg=train_cfg, test_cfg=test_cfg))
 
 

2.3.5 ops

2.3.6 utils

2.4 tools

一些训练测试脚本文件之类的。

 

2.4.1 dist_train.sh

2.4.2 train.py

使用mmcv中完备的config管理工具记录当前实验的配置信息至log中。

build segmentor。build datasets。

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐