registry.md 7.17 KB
Newer Older
1
2
3
4
5
## Registry

MMCV implements [registry](https://github.com/open-mmlab/mmcv/blob/master/mmcv/utils/registry.py) to manage different modules that share similar functionalities, e.g., backbones, head, and necks, in detectors.
Most projects in OpenMMLab use registry to manage modules of datasets and models, such as [MMDetection](https://github.com/open-mmlab/mmdetection), [MMDetection3D](https://github.com/open-mmlab/mmdetection3d), [MMClassification](https://github.com/open-mmlab/mmclassification), [MMEditing](https://github.com/open-mmlab/mmediting), etc.

6
7
8
9
```{note}
In v1.5.1 and later, the Registry supports registering functions and calling them.
```

10
11
### What is registry

12
13
14
In MMCV, registry can be regarded as a mapping that maps a class or function to a string.
These classes or functions contained by a single registry usually have similar APIs but implement different algorithms or support different datasets.
With the registry, users can find the class or function through its corresponding string, and instantiate the corresponding module or call the function to obtain the result according to needs.
15
One typical example is the config systems in most OpenMMLab projects, which use the registry to create hooks, runners, models, and datasets, through configs.
16
The API reference could be found [here](https://mmcv.readthedocs.io/en/latest/api.html?highlight=registry#mmcv.utils.Registry).
17
18
19

To manage your modules in the codebase by `Registry`, there are three steps as below.

Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
20
21
22
23
1. Create a build method (optional, in most cases you can just use the default one).
2. Create a registry.
3. Use this registry to manage the modules.

24
`build_func` argument of `Registry` is to customize how to instantiate the class instance or how to call the function to obtain the result, the default one is `build_from_cfg` implemented [here](https://mmcv.readthedocs.io/en/latest/api.html?highlight=registry#mmcv.utils.build_from_cfg).
25
26
27
28
29
30
31

### A Simple Example

Here we show a simple example of using registry to manage modules in a package.
You can find more practical examples in OpenMMLab projects.

Assuming we want to implement a series of Dataset Converter for converting different formats of data to the expected data format.
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
32
We create a directory as a package named `converters`.
33
34
35
36
37
In the package, we first create a file to implement builders, named `converters/builder.py`, as below

```python
from mmcv.utils import Registry
# create a registry for converters
38
CONVERTERS = Registry('converters')
39
40
```

41
Then we can implement different converters that is class or function in the package. For example, implement `Converter1` in `converters/converter1.py`, and `converter2` in `converters/converter2.py`.
42
43
44
45
46

```python

from .builder import CONVERTERS

Wenwei Zhang's avatar
Wenwei Zhang committed
47
# use the registry to manage the module
48
49
50
51
52
53
@CONVERTERS.register_module()
class Converter1(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b
```
54

55
56
57
58
59
60
61
62
63
64
```python
# converter2.py
from .builder import CONVERTERS
from .converter1 import Converter1

# 使用注册器管理模块
@CONVERTERS.register_module()
def converter2(a, b)
    return Converter1(a, b)
```
65

66
The key step to use registry for managing the modules is to register the implemented module into the registry `CONVERTERS` through
67
`@CONVERTERS.register_module()` when you are creating the module. By this way, a mapping between a string and the class (function) is built and maintained by `CONVERTERS` as below
Wenwei Zhang's avatar
Wenwei Zhang committed
68
69
70

```python
'Converter1' -> <class 'Converter1'>
71
'converter2' -> <function 'converter2'>
Wenwei Zhang's avatar
Wenwei Zhang committed
72
```
73

Zaida Zhou's avatar
Zaida Zhou committed
74
75
76
77
```{note}
The registry mechanism will be triggered only when the file where the module is located is imported.
So you need to import that file somewhere. More details can be found at https://github.com/open-mmlab/mmdetection/issues/5974.
```
Wenwei Zhang's avatar
Wenwei Zhang committed
78

79
80
81
If the module is successfully registered, you can use this converter through configs as

```python
82
83
84
85
86
converter1_cfg = dict(type='Converter1', a=a_value, b=b_value)
converter2_cfg = dict(type='converter2', a=a_value, b=b_value)
converter1 = CONVERTERS.build(converter1_cfg)
# returns the calling result
result = CONVERTERS.build(converter2_cfg)
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
87
88
```

Zaida Zhou's avatar
Zaida Zhou committed
89
### Customize Build Function
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109

Suppose we would like to customize how `converters` are built, we could implement a customized `build_func` and pass it into the registry.

```python
from mmcv.utils import Registry

# create a build function
def build_converter(cfg, registry, *args, **kwargs):
    cfg_ = cfg.copy()
    converter_type = cfg_.pop('type')
    if converter_type not in registry:
        raise KeyError(f'Unrecognized converter type {converter_type}')
    else:
        converter_cls = registry.get(converter_type)

    converter = converter_cls(*args, **kwargs, **cfg_)
    return converter

# create a registry for converters and pass ``build_converter`` function
CONVERTERS = Registry('converter', build_func=build_converter)
110
```
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
111

Zaida Zhou's avatar
Zaida Zhou committed
112
113
```{note}
In this example, we demonstrate how to use the `build_func` argument to customize the way to build a class instance.
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
114
The functionality is similar to the default `build_from_cfg`. In most cases, default one would be sufficient.
115
`build_model_from_cfg` is also implemented to build PyTorch module in `nn.Sequential`, you may directly use them instead of implementing by yourself.
Zaida Zhou's avatar
Zaida Zhou committed
116
```
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
117

Zaida Zhou's avatar
Zaida Zhou committed
118
### Hierarchy Registry
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
119
120
121
122
123
124
125
126
127
128
129
130
131

You could also build modules from more than one OpenMMLab frameworks, e.g. you could use all backbones in [MMClassification](https://github.com/open-mmlab/mmclassification) for object detectors in [MMDetection](https://github.com/open-mmlab/mmdetection), you may also combine an object detection model in [MMDetection](https://github.com/open-mmlab/mmdetection) and semantic segmentation model in [MMSegmentation](https://github.com/open-mmlab/mmsegmentation).

All `MODELS` registries of downstream codebases are children registries of MMCV's `MODELS` registry.
Basically, there are two ways to build a module from child or sibling registries.

1. Build from children registries.

   For example:

   In MMDetection we define:

   ```python
132
133
134
   from mmengine.registry import Registry
   from mmengine.registry import MODELS as MMENGINE_MODELS
   MODELS = Registry('model', parent=MMENGINE_MODELS)
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
135
136
137
138
139
140
141
142
143
144

   @MODELS.register_module()
   class NetA(nn.Module):
       def forward(self, x):
           return x
   ```

   In MMClassification we define:

   ```python
145
146
147
   from mmengine.registry import Registry
   from mmengine.registry import MODELS as MMENGINE_MODELS
   MODELS = Registry('model', parent=MMENGINE_MODELS)
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175

   @MODELS.register_module()
   class NetB(nn.Module):
       def forward(self, x):
           return x + 1
   ```

   We could build two net in either MMDetection or MMClassification by:

   ```python
   from mmdet.models import MODELS
   net_a = MODELS.build(cfg=dict(type='NetA'))
   net_b = MODELS.build(cfg=dict(type='mmcls.NetB'))
   ```

   or

   ```python
   from mmcls.models import MODELS
   net_a = MODELS.build(cfg=dict(type='mmdet.NetA'))
   net_b = MODELS.build(cfg=dict(type='NetB'))
   ```

2. Build from parent registry.

   The shared `MODELS` registry in MMCV is the parent registry for all downstream codebases (root registry):

   ```python
176
177
178
   from mmengine.registry import MODELS as MMENGINE_MODELS
   net_a = MMENGINE_MODELS.build(cfg=dict(type='mmdet.NetA'))
   net_b = MMENGINE_MODELS.build(cfg=dict(type='mmcls.NetB'))
Jerry Jiarui XU's avatar
Jerry Jiarui XU committed
179
   ```