OpenMMLab 模型大联动,MMDet 也能用 MMCls 的网络!

简介: 使用过 OpenMMLab 旗下开源软件,如 mmdet、mmseg 的读者们,一定知道在这些软件中,我们通过配置文件来定义深度学习任务的方方面面,比如模型结构、训练所使用的优化器、数据集等。

使用过 OpenMMLab 旗下开源软件,如 mmdet、mmseg 的读者们,一定知道在这些软件中,我们通过配置文件来定义深度学习任务的方方面面,比如模型结构、训练所使用的优化器、数据集等。


以 Yolo V3 模型结构为例,典型的配置文件是这样的:

model = dict(
    type='YOLOV3',
    backbone=dict(
        type='MobileNetV2',
        out_indices=(2, 4, 6),
        ...),
    neck=dict(
        type='YOLOV3Neck',
        num_scales=3,
        in_channels=[320, 96, 32],
        out_channels=[96, 96, 96]),
    ...
)

可以看到,配置文件虽然使用了 Python 的语法(也支持 json 和 yaml 格式,这里暂且不表),但并不会像我们直接使用 PyTorch 一样,直接 import 相应的模块和类,然后进行类的实例化,而是使用字典来进行配置,使用 type 字段来标示该组件的类型。


这带来了一个问题,如果我想要引用另外一个代码库中注册的模型,该如何用配置文件的方式来实现呢?让我们从一个实际的例子入手。

640.png


1. 在 mmdet 中调用 mmcls 的 backbone



通常,在检测任务中,我们会使用一个主干网络来提取图片的特征。而由于图片特征提取对于各类图像任务是较为通用的需要,因而可以“借用”在分类任务中预训练的主干网络和相应的模型权重。因为分类任务比较简单,故而可以利用庞大的 ImageNet 数据集进行预训练,而在此基础上进一步训练检测网络,既能够提高模型收敛速度,又能够提高精度。


假设现在我们想要使用一个 MMDetection 中没有实现的主干网络进行特征提取,我们当然可以直接在 mmdet 中实现这个主干网络,但如果这个主干网络在分类代码库 MMClassification 中已经实现了,我们是可以直接通过修改配置文件来跨库调用的。比如我们想把上述 Yolo V3 中的主干网络从 MobileNet V2 换成 MobileNet V3,但 mmdet 还没有 Mobilenet V3 的实现,可以使用如下配置:

# 直接继承 yolo v3 的原始配置
_base_ = "./yolov3_mobilenetv2_320_300e_coco.py"
# 因为 mmdet 中没有 import mmcls
# 因而其中的主干网络并不会被注册到管理器中
# 这里我们需要手动用 custom_imports 来指定额外的导入
# 从而注册 mmcls 中的主干网络
custom_imports=dict(imports='mmcls.models', allow_failed_imports=False)
model = dict(
    backbone=dict(
        # 使用 "scope.type" 的语法,指定从 mmcls 中寻找需要的模块
        type='mmcls.MobileNetV3',
        # MobileNet V3 的其他设置
        arch='large',
        out_indices=(5, 11, 14),
        init_cfg=dict(
            type='Pretrained',
            checkpoint='mmcls://mobilenet_v3_large'),
        # 配置文件与继承的配置文件中相同字段的字典,默认会融合
        # 这里使用 `_delete_` 来删除继承的配置文件中的其他配置
        _delete_=True),
    # 主干网络发生变化,其他相应的配置也需要改变
    neck=dict(in_channels=[160, 112, 40])
)


2. 跨代码库调用机制



在 OpenMMLab 的 cfg 模式和 Registry 机制 一文中,我们简要介绍了关于 config 文件和 Registry 的架构和实现。而在这里,我们将从上文中跨仓库调用中涉及的两个关键点,来更进一步地了解 config 和 Registry 一些高级用法和实现。

640.jpg


custom_imports


在 OpenMMLab 的 cfg 模式和 Registry 机制 中,我们提到过类是在何时被注册到 Registry 中的:

通常, 在 import 相应模块时, 都会过一遍相应的定义被装饰对象的代码, 此时装饰器就已经运行了. 例如, 对于 mmdet 的 AnchorGenerator, SSDAnchorGenerator 这些类, 他们是在何时注册到 ANCHOR_GENERATORS 这个 Registry 类实例中的?


在 train.py 执行 from mmdet.core import DistEvalHook, EvalHook 时, 会调用并执行 mmdet/core/__init__.py 中的 from .anchor import *, 进而会调用并执行 mmdet/core/anchor/__init__.py 中的 from .anchor_generator import (AnchorGenerator, LegacyAnchorGenerator, YOLOAnchorGenerator), 从而完成 AnchorGenerator, SSDAnchorGenerator 这些类的注册。


也就是说只要 import 了相应的模块,模块中所有包含的类都会被注册到对应的 Registry 中。


那么问题来了,这些模块是在何时被 import 的呢?答案很简单,就是在我们代码执行的入口程序 tools/train.py 和 tools/test.py 中。以 MMClassification 中的 tools/train.py 为例:

...
from mmcv.runner import get_dist_info, init_dist
...
from mmcls.datasets import build_dataset
from mmcls.models import build_classifier

通过导入 mmcv.runner 包,完成了 mmcv/runner/__init__.py 中一系列执行器、钩子、优化器等类的注册。通过导入 mmcls.datasets 包,完成了mmcls/datasets/__init__.py 中一系列数据集的注册。通过导入mmcls.models 包,完成了mmcls/models/__init__.py中一系列主干网络、颈部头部函数的注册。


当然,注册不一定仅仅发生在入口程序的最外层,比如在入口程序中没有导入数据处理和增强相关的包,这些类是在执行 build_dataset 时,在 mmcls/datasets/base_dataset.py 中进行的注册。


因此,Registry 的注册其实没有什么魔法,就是单纯地通过在入口程序中导入相应的包,在导入过程中完成的注册。这也就为我们的跨代码库调用带来了第一个问题,入口程序中当然不会导入与自己无关的另外一个库中的包,那怎么注册我们我需要的类呢?修改入口程序当然是一种办法,但 MMCV 中提供了更直接的在配置文件中显式导入自定义包的方法 —— custom_imports。

custom_imports=dict(imports='mmcls.models', allow_failed_imports=False)

只要在配置文件中加入这么一行,MMCV 在解析配置文件时,会自动调用 mmcv.import_modules_from_strings 函数,借助 Python 内置的 importlib 库中的 import_module 函数,进而完成对应的一系列类的注册。


Regsitry 中的 scope


在上文的例子中,我们看到,在跨仓库调用 MMClassification 的主干网络时,使用了一种特殊的写法,也就是 type='mmcls.MobileNetV3',既然我们都已经通过 custom_imports实现了 MMClassification 中主干网络的注册,为什么还要在使用时注明 mmcls. 呢?这就涉及到了 Registry 的 scope 机制。


Scope 机制的引入,是为了解决一个基础的问题,即类型的冲突,MMDetection 注册了一个 MobileNetV2,MMClassification 也注册了一个 MobileNetV2,到底用哪一个呢?MMCV 中给出的要求十分简单,禁止同一个 Regsitry 中注册两个相同名字的类。进一步地,每一个代码库在注册自己的模型时,都会注册到代码库自己的 Regsitry 中,而不是注册到 MMCV 统一的 Registry 中,从而避免与其他代码库产生冲突。


与此同时,虽然每个代码库都是注册到自己的 Registry 中,这些 Registry 却又不是独立的,而是以 MMCV 中某个统一的 Registry 为父 Regsitry,从而形成如图所示的树状结构。

640.png

通过 scope 这一机制,我们避免了不同代码库之间重复注册产生的冲突,同时使用 scope 来指定 type 具体在哪一个 Registry 中,也使得跨代码库的调用更加显式和清晰


文章来源:公众号【OpenMMLab】

2021-11-23 19:52

目录
相关文章
|
2月前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于BP神经网络的苦瓜生长含水量预测模型matlab仿真
本项目展示了基于BP神经网络的苦瓜生长含水量预测模型,通过温度(T)、风速(v)、模型厚度(h)等输入特征,预测苦瓜的含水量。采用Matlab2022a开发,核心代码附带中文注释及操作视频。模型利用BP神经网络的非线性映射能力,对试验数据进行训练,实现对未知样本含水量变化规律的预测,为干燥过程的理论研究提供支持。
|
1月前
|
存储 网络协议 安全
30 道初级网络工程师面试题,涵盖 OSI 模型、TCP/IP 协议栈、IP 地址、子网掩码、VLAN、STP、DHCP、DNS、防火墙、NAT、VPN 等基础知识和技术,帮助小白们充分准备面试,顺利踏入职场
本文精选了 30 道初级网络工程师面试题,涵盖 OSI 模型、TCP/IP 协议栈、IP 地址、子网掩码、VLAN、STP、DHCP、DNS、防火墙、NAT、VPN 等基础知识和技术,帮助小白们充分准备面试,顺利踏入职场。
83 2
|
1月前
|
运维 网络协议 算法
7 层 OSI 参考模型:详解网络通信的层次结构
7 层 OSI 参考模型:详解网络通信的层次结构
85 1
|
2月前
|
网络协议 前端开发 Java
网络协议与IO模型
网络协议与IO模型
106 4
网络协议与IO模型
|
2月前
|
机器学习/深度学习 网络架构 计算机视觉
目标检测笔记(一):不同模型的网络架构介绍和代码
这篇文章介绍了ShuffleNetV2网络架构及其代码实现,包括模型结构、代码细节和不同版本的模型。ShuffleNetV2是一个高效的卷积神经网络,适用于深度学习中的目标检测任务。
92 1
目标检测笔记(一):不同模型的网络架构介绍和代码
|
1月前
|
网络协议 算法 网络性能优化
计算机网络常见面试题(一):TCP/IP五层模型、TCP三次握手、四次挥手,TCP传输可靠性保障、ARQ协议
计算机网络常见面试题(一):TCP/IP五层模型、应用层常见的协议、TCP与UDP的区别,TCP三次握手、四次挥手,TCP传输可靠性保障、ARQ协议、ARP协议
|
1月前
|
机器学习/深度学习 人工智能 算法
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型
车辆车型识别,使用Python作为主要编程语言,通过收集多种车辆车型图像数据集,然后基于TensorFlow搭建卷积网络算法模型,并对数据集进行训练,最后得到一个识别精度较高的模型文件。再基于Django搭建web网页端操作界面,实现用户上传一张车辆图片识别其类型。
82 0
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型
|
2月前
|
缓存 Java Linux
硬核图解网络IO模型!
硬核图解网络IO模型!
|
2月前
|
机器学习/深度学习 编解码 算法
【深度学习】经典的深度学习模型-01 开山之作:CNN卷积神经网络LeNet-5
【深度学习】经典的深度学习模型-01 开山之作:CNN卷积神经网络LeNet-5
47 0
|
2月前
|
存储 分布式计算 负载均衡