mmlab
MMCV/MMDETECT 架构分析
mmcv 是 mmdet 的主要依赖包。mmcv 的特点是广泛地使用配置文件来规范化模型的构建、训练等。实现这一特性的核心是 mmcv 的 Config 类与 Registry 类。分别定义于 mmcv/utils/config.py 与 mmcv/utils/registry.py 文件中。以下架构分析针对的版本为:
mmcv-full 1.3.9
mmdetection (git commit id: 522eb9ebd7df0944b2a659354f01799895df74ce,版本为2.14~2.15之间)
与许多优秀的开源项目一样,mmlab 的项目也会存在 API 变化的现象,大多数时候 mmlab 会对之前的 API 兼容,但给出警告。对于源码分析而言,这种代码是一种干扰。
安装
源码安装 mmcv-full,可能需要修改 setup.py
# cmd_class = {'build_ext': torch.utils.cpp_extension.BuildExtension}
cmd_class = {'build_ext': torch.utils.cpp_extension.BuildExtension.with_options(use_ninja=False)}随后使用如下命令进行安装
MMCV_WITH_OPS=1 pip install -e . # 开发模式安装
MMCV_WITH_OPS=1 python setup.py install # 安装典型用法(此处补充一个 mmdet 的例子):
dataset = DATASET.build(Config.fromfile("xxx.py"))
model = MODEL.build(Config.fromfile("xxx.py"))
runner = RUNNER.build(Config.fromfile("xxx.py"))mmcv.utils.config.Config 类
动机
这个类的作用是配置的解析,mmlab 的项目通常是直接使用“python”文件作为配置文件的,
mmdetection 内置的模型通常使用配置文件,放置在 mmdetection/configs 文件夹下,
进阶:Config.fromfile 方法的实现细节
注意:可以在配置文件中配置
custom_imports,这样可以不对源码进行修改添加自定义的模型或数据集
mmcv.utils.registry.Registry 类
目的是希望可以使用类似于如下的方式进行统一地初始化模型:
Register 的作用如下,假定 MODELS 为一个 Register 对象,通过对其他的类使用 MODELS.register_module 装饰,在 MODELS 内部维护一个映射表,例如:
而被装饰的类本身没有被进行任何的修改。
简化版:
源码:
2.16.0 版本 mmcv/utils/registry.py:Registry
Registry 的默认 build_func
build_func如上所述,mmcv 1.3.16 版本
此处的 build_func 的默认值为 build_from_cfg(cfg, registry, default_args=None),而这个函数的作用就是利用 cfg 的 "type" 字段取出,其余参数用于创建实例。
mmcv.cnn.MODELS 所使用的 build_func 使用的是如下:
即如果传入参数 cfg 是字典,则使用默认的 build_from_cfg,如果是列表则依次使用默认的 build_from_cfg。
而 mmdetection 2.18.0 的 tools/train.py 中用如下方式调用
的 mmdet/models/builder.py:build_detector 源码如下
备注:在之前的 mmdetection 版本中,最初的 .py 配置文件里 model,train_cfg,test_cfg 是并列的关系。而在此 mmdetection 版本中,后两者被包在前者里面。此处仅仅是为了兼容性,因此实际上等同于调用
因此本质上是调用 DETECTOR.build。
然而,mmdetection 中的迭代器实际上在 mmdet/models/builder.py 被一起定义了,其 build_func 直接沿用了 mmcv.cnn.MODELS
而 mmdetection 2.18.0 的 tools/train.py 中用如下方式调用
而 mmdet/datasets/builder.py 的 build_dataset 源码为递归方式(如果 cfg 参数中的 "type" 为特殊取值,则特殊处理,这些特殊的类都被注册在 DATASETS 里):
最常用的情况:cfg 本身为字典的列表,则逐个调用
build_dataset后再包一层ConcatDatasetConcatDataset及其他情况基本都假定
cfg.datasets是一个字典的列表
Registry 实例:
mmcv.runner.builder.Runner 类
mmdet/../tools/train.py 脚本源码解析
参见 notebook 里的注解
此脚本为训练脚本,通常利用这个脚本训练模型
兼容性:在 mmdet 之前的版本里,配置文件中通常按这种方式组织
但在此版本的 mmdet 现在的版本里,推荐用这种方式组织
真正复杂的逻辑发生在
运行实例:Yolov3
下面具体介绍一个模型,启动方式为:
而简化版的配置文件为(将配置文件的继承关系展平了):
因此,运行时,首先会执行到以下代码构建模型
而这行代码最终会执行的类似于:
而 YOLOV3 类是按如下方式定义的:
所以实际上只需理解 SingleStageDetector,BaseDetector,BaseModule 这三个类的逻辑即可。
首先,SingleStageDetector.__init__ 函数会依次调用
前面已经提到,伪代码如下,因此最终都回到了 build_model_from_cfg 函数的调用:
FP16 训练
使用方法:配置文件顶级位置加上即可
实现原理如下:
pytorch>=1.6.0 且配置 fp16 参数,此时的
Fp16OptimizerHook的before_run函数已经事先将模型的fp16_enabled设置为True, 在每轮迭代时,@auto_fp16装饰器内部首先将输入转为 fp16,然后在torch.cuda.amp.autocast下运行模型,此时无所谓输入是 fp16 还是 fp32,皆可正常运行。pytorch<1.6.0 且配置 fp16 参数, 此时的
Fp16OptimizerHook的before_run函数已经事先将模型转为fp16,在每轮迭代时,@auto_fp16装饰器内部会将输入转换为 fp16,因此模型能正常运行不配置 fp16 参数时,将不会使用
Fp16OptimizerHook,因此模型将不会被设置fp16_enabled=True,因此@auto_fp16将不会对输入做任何变换,即此时该装饰器完全无效
为理解原理,关键代码如下:
图解:

更详细的代码如下(待整理)
一些相对独立的底层代码
mmcv/runner/base_module.py:BaseModule
mmcv 中类似于 torch.nn.Module 的东西,完整源代码(注释有所修改)如下,可以发现本质上只是给 nn.Module 增加了个 init_weights 方法。
以下是一些继承 `mmcv/runner/base_
mmdet/models/detectors/base.py:BaseDetector
mask 标注
mmdet/core/mask/structures.py:PolygonMasks
通常一个物体的标注文件格式类似于:
mmdet/core/mask/structures.py:NitMapMasks
待续
记录
mmdetction 2.16.0
configs/_base_/schedules 里的区别只在于
一个把配置文件打印出来的工具
tools/train.py 可以同时支持分布式与非分布式的启动方式
分布式启动的脚本如下(tools/dist_train.sh):
直接单卡启动最简的启动方式为
以分布式的方式启动时,train.py脚本中存在以下语句,不知道是否写的太死
mmcv 1.3.16
mmocr 0.5.0
KIEDataset.__getitem__: (before pipeline)
Tricks and Discussion and Have Fun
为什么叫 mmdetection?
参考知乎,因为 mmlab 开源项目起源于香港中文大学的多媒体实验室,多媒体(multi-media)
字典
图像读取与变换
mmdetction 使用 opencv 进行图像的读取,变换。对于变换,借用了一些 albumentation 包(针对的是 opencv 格式的数据)的函数。但在进行完图像增强后,会将 BGR 格式转为 RGB 格式进行 Normalize。这是为了和 Torchvision 的预训练模型对齐。例如下面的配置:
MMDeploy 学习记录
实验准备: 使用anaconda管理环境, 操作系统为Windows 10, 显卡为NVIDIA GeForce GTX 1650(4G显存)
其余信息
使用预编译的包: 从mmdeploy-release下载并安装
Last updated
Was this helpful?