From 7e123ad6d6978bc447f34a33c1809ca230501fe3 Mon Sep 17 00:00:00 2001 From: Zaida Zhou <58739961+zhouzaida@users.noreply.github.com> Date: Fri, 22 Apr 2022 20:45:13 +0800 Subject: [PATCH] [Docs] Refine registry documentation (#186) * [Docs] Refine registry documentation * reslove comments * minor refinement --- docs/zh_cn/tutorials/registry.md | 42 +++++++++++++++++++------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/docs/zh_cn/tutorials/registry.md b/docs/zh_cn/tutorials/registry.md index ced73f25..1e0ff3a2 100644 --- a/docs/zh_cn/tutorials/registry.md +++ b/docs/zh_cn/tutorials/registry.md @@ -262,7 +262,7 @@ class RetinaNet(nn.Module): ![registry](https://user-images.githubusercontent.com/58739961/153880947-1d66ac06-e5ee-448e-8d7d-201e96d1101d.png) -我们可以在 `MMDetection` 中调用 `MMEngine` 中模块。 +我们可以在 `MMDetection` 中调用 `MMEngine` 中的模块。 ```python from mmdet.models import MODELS @@ -278,6 +278,29 @@ model = MODELS.build(cfg=dict(type='Conv2d')) 如果不加前缀,`build` 方法首先查找当前节点是否存在该模块,如果存在则返回该模块,否则会继续向上查找父节点甚至祖先节点直到找到该模块,因此,如果当前节点和父节点存在同一模块并且希望调用父节点的模块,我们需要指定 `scope` 前缀。需要注意的是,向上查找父节点甚至祖先节点的**前提是父节点或者祖先节点的模块已通过某种方式被导入进而完成注册**。例如,在上面这个示例中,之所以没有显示导入父节点 `mmengine` 中的 `MODELS`,是因为通过 `from mmdet.models import MODELS` 间接触发 `mmengine.MODELS` 完成模块的注册。 +上面展示了如何使用子节点注册器构建模块,但有时候我们希望不填加前缀也能在父节点注册器中构建子节点的模块,目的是提供通用的代码,避免下游算法库重复造轮子,该如何实现呢? + +假设 MMEngine 中有一个 `build_model` 函数,该方法用于构建模型。 + +```python +from mmengine.registry import MODELS + +def build_model(cfg): + model = MODELS.build(cfg) +``` + +如果我们希望在 MMDetection 中调用该函数构建 MMDetection 注册的模块,那么我们需要先获取一个 scope_name 为 'mmdet' 的 [DefaultScope](https://mmengine.readthedocs.io/zh/latest/api.html#mmengine.registry.DefaultScope) 实例,该实例全局唯一。 + +```python +from mmengine import build_model +import mmdet.models # 通过 import 的方式将 mmdet 中的模块导入注册器进而完成注册 + +default_scope = DefaultScope.get_instance('my_experiment', scope_name='mmdet') +model = build_model(cfg=dict(type='RetinaNet')) +``` + +获取 `DefaultScope` 实例的目的是使 Registry 的 build 方法会将 DefaultScope 名称(mmdet)注册器节点作为注册器的起点,才能在配置中不填加 mmdet 前缀的情况下在 MMDetection 的注册器节点中找到 RetinaNet 模块,如若不然,程序会报找不到 RetinaNet 错误。 + ### 调用兄弟节点的模块 除了可以调用父节点的模块,也可以调用兄弟节点的模块。 @@ -311,16 +334,7 @@ from mmcls.models import MODELS model = MODELS.build(cfg=dict(type='mmdet.RetinaNet')) ``` -调用非本节点的模块需要指定在 `type` 中指定 `scope` 前缀,如果不想指定,我们可以创建一个全局变量 `default_scope` 并将 `scope_name` 设置为 'mmdet',`Registry` 会将 `scope_name` 对应的 `registry` 作为当前 `Registry` 并调用 `build` 方法。 - -```python -from mmengine.registry import DefaultScope, MODELS - -# 调用注册在 mmdet 中的 RetinaNet -default_scope = DefaultScope.get_instance( - 'my_experiment', scope_name='mmdet') -model = MODELS.build(cfg=dict(type='RetinaNet')) -``` +调用非本节点或父节点的模块需要在 `type` 中指定 `scope` 前缀。 注册器除了支持两层结构,三层甚至更多层结构也是支持的。 @@ -358,10 +372,4 @@ model = MODELS.build(cfg=dict(type='mmcls.ResNet')) from mmcls.models import MODELS # 需要注意前缀的顺序,'detplus.mmdet.ResNet' 是不正确的 model = MODELS.build(cfg=dict(type='mmdet.detplus.MetaNet')) - -# 如果希望默认从 detplus 构建模型,设置可以 default_scope -from mmengine.registry import DefaultScope -default_scope = DefaultScope.get_instance( - 'my_experiment', scope_name='detplus') -model = MODELS.build(cfg=dict(type='MetaNet', default_scope='detplus')) ```