Skip to content

Commit 8b0953c

Browse files
ppwwyyxxfacebook-github-bot
authored andcommitted
docs about LazyConfig
Summary: fix facebookresearch#3225 Pull Request resolved: fairinternal/detectron2#553 Reviewed By: wat3rBro Differential Revision: D29731838 Pulled By: ppwwyyxx fbshipit-source-id: 69ed27681747cf00a2fa682c245369c3d1ee8945
1 parent 729227f commit 8b0953c

File tree

12 files changed

+203
-34
lines changed

12 files changed

+203
-34
lines changed

MODEL_ZOO.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ You can access these models from code using [detectron2.model_zoo](https://detec
1111
In addition to these official baseline models, you can find more models in [projects/](projects/).
1212

1313
#### How to Read the Tables
14-
* The "Name" column contains a link to the config file. Running `tools/train_net.py --num-gpus 8` with this config file
15-
will reproduce the model.
14+
* The "Name" column contains a link to the config file. Models can be reproduced using `tools/train_net.py` with the corresponding yaml config file,
15+
or `tools/lazyconfig_train_net.py` for python config files.
1616
* Training speed is averaged across the entire training.
1717
We keep updating the speed with latest version of detectron2/pytorch/etc.,
1818
so they might be different from the `metrics` file.

detectron2/config/lazy.py

+9-1
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,11 @@ def load(filename: str, keys: Union[None, str, Tuple[str, ...]] = None):
229229
@staticmethod
230230
def save(cfg, filename: str):
231231
"""
232+
Save a config object to a yaml file.
233+
Note that when the config dictionary contains complex objects (e.g. lambda),
234+
it can't be saved to yaml. In that case we will print an error and
235+
attempt to save to a pkl file instead.
236+
232237
Args:
233238
cfg: an omegaconf config object
234239
filename: yaml file name to save the config file
@@ -311,7 +316,10 @@ def safe_update(cfg, key, value):
311316
@staticmethod
312317
def to_py(cfg, prefix: str = "cfg."):
313318
"""
314-
Convert a config object into its equivalent Python code.
319+
Try to convert a config object into its equivalent Python code.
320+
321+
Note that this is not always possible. So the returned results are mainly
322+
meant to be human-readable, and not meant to be loaded back.
315323
316324
Args:
317325
cfg: an omegaconf config object

detectron2/engine/defaults.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,11 @@ def default_argument_parser(epilog=None):
132132
)
133133
parser.add_argument(
134134
"opts",
135-
help="Modify config options by adding 'KEY VALUE' pairs at the end of the command. "
136-
"See config references at "
137-
"https://detectron2.readthedocs.io/modules/config.html#config-references",
135+
help="""
136+
Modify config options at the end of the command. For Yacs configs, use
137+
space-separated "PATH.KEY VALUE" pairs.
138+
For python-based LazyConfig, use "path.key=value".
139+
""".strip(),
138140
default=None,
139141
nargs=argparse.REMAINDER,
140142
)

detectron2/utils/analysis.py

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"flop_count_operators",
1414
"parameter_count_table",
1515
"parameter_count",
16+
"FlopCountAnalysis",
1617
]
1718

1819
FLOPS_MODE = "flops"

docs/modules/config.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
detectron2.config
1+
detectron2.config
22
=========================
33

44
Related tutorials: :doc:`../tutorials/configs`, :doc:`../tutorials/extend`.
@@ -10,7 +10,7 @@ Related tutorials: :doc:`../tutorials/configs`, :doc:`../tutorials/extend`.
1010
:inherited-members:
1111

1212

13-
Config References
13+
Yaml Config References
1414
-----------------
1515

1616
.. literalinclude:: ../../detectron2/config/defaults.py

docs/tutorials/configs.md

+12-21
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,17 @@
1-
# Configs
1+
# Yacs Configs
22

33
Detectron2 provides a key-value based config system that can be
44
used to obtain standard, common behaviors.
55

6-
Detectron2's config system uses YAML and [yacs](https://github.com/rbgirshick/yacs).
7-
In addition to the [basic operations](../modules/config.html#detectron2.config.CfgNode)
8-
that access and update a config, we provide the following extra functionalities:
9-
10-
1. The config can have `_BASE_: base.yaml` field, which will load a base config first.
11-
Values in the base config will be overwritten in sub-configs, if there are any conflicts.
12-
We provided several base configs for standard model architectures.
13-
2. We provide config versioning, for backward compatibility.
14-
If your config file is versioned with a config line like `VERSION: 2`,
15-
detectron2 will still recognize it even if we change some keys in the future.
16-
17-
Config file is a very limited language.
18-
We do not expect all features in detectron2 to be available through configs.
6+
This system uses YAML and [yacs](https://github.com/rbgirshick/yacs).
7+
Yaml is a very limited language,
8+
so we do not expect all features in detectron2 to be available through configs.
199
If you need something that's not available in the config space,
2010
please write code using detectron2's API.
2111

12+
With the introduction of a more powerful [LazyConfig system](lazyconfigs.md),
13+
we no longer add functionality / new keys to the Yacs/Yaml-based config system.
14+
2215
### Basic Usage
2316

2417
Some basic usage of the `CfgNode` object is shown here. See more in [documentation](../modules/config.html#detectron2.config.CfgNode).
@@ -32,6 +25,11 @@ cfg.merge_from_list(["MODEL.WEIGHTS", "weights.pth"]) # can also load values f
3225
print(cfg.dump()) # print formatted configs
3326
```
3427

28+
In addition to the basic Yaml syntax, the config file can
29+
define a `_BASE_: base.yaml` field, which will load a base config file first.
30+
Values in the base config will be overwritten in sub-configs, if there are any conflicts.
31+
We provided several base configs for standard model architectures.
32+
3533
Many builtin tools in detectron2 accept command line config overwrite:
3634
Key-value pairs provided in the command line will overwrite the existing values in the config file.
3735
For example, [demo.py](../../demo/demo.py) can be used with
@@ -43,7 +41,6 @@ For example, [demo.py](../../demo/demo.py) can be used with
4341
To see a list of available configs in detectron2 and what they mean,
4442
check [Config References](../modules/config.html#config-references)
4543

46-
4744
### Configs in Projects
4845

4946
A project that lives outside the detectron2 library may define its own configs, which will need to be added
@@ -61,9 +58,3 @@ add_pointrend_config(cfg) # add pointrend's default config
6158
to share common parts between configs.
6259

6360
2. Keep the configs you write simple: don't include keys that do not affect the experimental setting.
64-
65-
3. Keep a version number in your configs (or the base config), e.g., `VERSION: 2`,
66-
for backward compatibility.
67-
We print a warning when reading a config without version number.
68-
The official configs do not include version number because they are meant to
69-
be always up-to-date.

docs/tutorials/extend.md

+8-3
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,17 @@ which is a challenge for any research engineering project of a significant size:
1515
In detectron2, there are two types of interfaces that address this tension together:
1616

1717
1. Functions and classes that take a config (`cfg`) argument
18+
created from a yaml file
1819
(sometimes with few extra arguments).
1920

2021
Such functions and classes implement
21-
the "standard default" behavior: it will read what it needs from the
22+
the "standard default" behavior: it will read what it needs from a given
2223
config and do the "standard" thing.
23-
Users only need to load a given config and pass it around, without having to worry about
24+
Users only need to load an expert-made config and pass it around, without having to worry about
2425
which arguments are used and what they all mean.
2526

27+
See [Yacs Configs](configs.md) for a detailed tutorial.
28+
2629
2. Functions and classes that have well-defined explicit arguments.
2730

2831
Each of these is a small building block of the entire system.
@@ -33,6 +36,8 @@ In detectron2, there are two types of interfaces that address this tension toget
3336
When you need to implement something not supported by the "standard defaults"
3437
included in detectron2, these well-defined components can be reused.
3538

39+
The [LazyConfig system](lazyconfigs.md) relies on such functions and classes.
40+
3641
3. A few functions and classes are implemented with the
3742
[@configurable](../modules/config.html#detectron2.config.configurable)
3843
decorator - they can be called with either a config, or with explicit arguments, or a mixture of both.
@@ -42,7 +47,7 @@ In detectron2, there are two types of interfaces that address this tension toget
4247

4348
1. Config-only:
4449
```python
45-
# load proper config file, then
50+
# load proper yaml config file, then
4651
model = build_model(cfg)
4752
```
4853

docs/tutorials/index.rst

+1
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ Tutorials
1616
training
1717
evaluation
1818
configs
19+
lazyconfigs
1920
deployment

docs/tutorials/lazyconfig.jpg

64.1 KB
Loading

docs/tutorials/lazyconfigs.md

+158
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# Lazy Configs
2+
3+
The traditional yacs-based config system provides basic, standard functionalities.
4+
However, it does not offer enough flexibility for many new projects.
5+
We develop an alternative, non-intrusive config system that can be used with
6+
detectron2 or potentially any other complex projects.
7+
8+
## Python Syntax
9+
10+
Our config objects are still dictionaries. Instead of using Yaml to define dictionaries,
11+
we create dictionaries in Python directly. This gives users the following power that
12+
doesn't exist in Yaml:
13+
14+
* Easily manipulate the dictionary (addition & deletion) using Python.
15+
* Write simple arithmetics or call simple functions.
16+
* Use more data types / objects.
17+
* Import / compose other config files, using the familiar Python import syntax.
18+
19+
A Python config file can be loaded like this:
20+
```python
21+
# config.py:
22+
a = dict(x=1, y=2, z=dict(xx=1))
23+
b = dict(x=3, y=4)
24+
25+
# my_code.py:
26+
from detectron2.config import LazyConfig
27+
cfg = LazyConfig.load("path/to/config.py") # an omegaconf dictionary
28+
assert cfg.a.z.xx == 1
29+
```
30+
31+
After `LazyConfig.load`, `cfg` will be a dictionary that contains all dictionaries
32+
defined in the global scope of the config file. Note that:
33+
* All dictionaries are turned to an [omegaconf](https://omegaconf.readthedocs.io/)
34+
config object during loading. This enables access to omegaconf features,
35+
such as its [access syntax](https://omegaconf.readthedocs.io/en/2.1_branch/usage.html#access-and-manipulation)
36+
and [interoplation](https://omegaconf.readthedocs.io/en/2.1_branch/usage.html#variable-interpolation).
37+
* Absolute imports in `config.py` works the same as in regular Python.
38+
* Relative imports can only import dictionaries from config files.
39+
They are simply a syntax sugar for [LazyConfig.load_rel](../modules/config.html#detectron2.config.LazyConfig.load_rel).
40+
They can load Python files at relative path without requiring `__init__.py`.
41+
42+
## Recursive Instantiation
43+
44+
The LazyConfig system heavily uses recursive instantiation, which is a pattern that
45+
uses a dictionary to describe a
46+
call to a function/class. The dictionary consists of:
47+
48+
1. A "\_target\_" key which contains path to the callable, such as "module.submodule.class_name".
49+
2. Other keys that represent arguments to pass to the callable. Arguments themselves can be defined
50+
using recursive instantiation.
51+
52+
We provide a helper function [LazyCall](../modules/config.html#detectron2.config.LazyCall) that helps create such dictionaries.
53+
The following code using `LazyCall`
54+
```python
55+
from detectron2.config import LazyCall as L
56+
from my_app import Trainer, Optimizer
57+
cfg = L(Trainer)(
58+
optimizer=L(Optimizer)(
59+
lr=0.01,
60+
algo="SGD"
61+
)
62+
)
63+
```
64+
creates a dictionary like this:
65+
```
66+
cfg = {
67+
"_target_": "my_app.Trainer",
68+
"optimizer": {
69+
"_target_": "my_app.Optimizer",
70+
"lr": 0.01, "algo": "SGD"
71+
}
72+
}
73+
```
74+
75+
By representing objects using such dictionaries, a general
76+
[instantiate](../modules/config.html#detectron2.config.instantiate)
77+
function can turn them into actual objects, i.e.:
78+
```python
79+
from detectron2.config import instantiate
80+
trainer = instantiate(cfg)
81+
# equivalent to:
82+
# from my_app import Trainer, Optimizer
83+
# trainer = Trainer(optimizer=Optimizer(lr=0.01, algo="SGD"))
84+
```
85+
86+
This pattern is powerful enough to describe very complex objects, e.g.:
87+
88+
<details>
89+
<summary>
90+
A Full Mask R-CNN described in recursive instantiation (click to expand)
91+
</summary>
92+
93+
```eval_rst
94+
.. literalinclude:: ../../configs/common/models/mask_rcnn_fpn.py
95+
:language: python
96+
:linenos:
97+
```
98+
99+
</details>
100+
101+
There are also objects or logic that cannot be described simply by a dictionary,
102+
such as reused objects or method calls. They may require some refactoring
103+
to work with recursive instantiation.
104+
105+
## Using Model Zoo LazyConfigs
106+
107+
We provide some configs in the model zoo using the LazyConfig system, for example:
108+
109+
* [common baselines](../../configs/common/).
110+
* [new Mask R-CNN baselines](../../configs/new_baselines/)
111+
112+
After installing detectron2, they can be loaded by the model zoo API
113+
[model_zoo.get_config](../modules/model_zoo.html#detectron2.model_zoo.get_config).
114+
115+
Our model zoo configs follow some simple conventions, e.g.
116+
`cfg.model` defines a model object, `cfg.dataloader.{train,test}` defines dataloader objects,
117+
and `cfg.train` contains training options in key-value form.
118+
We provide a reference training script
119+
[tools/lazyconfig_train_net.py](../../tools/lazyconfig_train_net.py),
120+
that can train/eval our model zoo configs.
121+
It also shows how to support command line value overrides.
122+
123+
Nevertheless, you are free to define any custom structure for your project and use it
124+
with your own scripts.
125+
126+
To demonstrate the power and flexibility of the new system, we show that
127+
[a simple config file](../../configs/Misc/torchvision_imagenet_R_50.py)
128+
can let detectron2 train an ImageNet classification model from torchvision, even though
129+
detectron2 contains no features about ImageNet classification.
130+
This can serve as a reference for using detectron2 in other deep learning tasks.
131+
132+
## Summary
133+
134+
By using recursive instantiation to create objects,
135+
we avoid passing a giant config to many places, because `cfg` is only passed to `instantiate`.
136+
This has the following benefits:
137+
138+
* It's __non-intrusive__: objects to be constructed are config-agnostic, regular Python
139+
functions/classes.
140+
They can even live in other libraries. For example,
141+
`{"_target_": "torch.nn.Conv2d", "in_channels": 10, "out_channels": 10, "kernel_size": 1}`
142+
defines a conv layer.
143+
* __Clarity__ of what function/classes will be called, and what arguments they use.
144+
* `cfg` doesn't need pre-defined keys and structures. It's valid as long as it translates to valid
145+
code. This gives a lot more __flexibility__.
146+
* You can still pass huge dictionaries as arguments, just like the old way.
147+
148+
Putting recursive instantiation together with the Python config file syntax, the config file
149+
looks a lot like the code that will be executed:
150+
151+
![img](./lazyconfig.jpg)
152+
153+
However, the config file just defines dictionaries, which can be easily manipulated further
154+
by composition or overrides.
155+
The corresponding code will only be executed
156+
later when `instantiate` is called. In some way,
157+
in config files we're writing "editable code" that will be "lazily executed" later when needed.
158+
That's why we call this system "LazyConfig".

docs/tutorials/models.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Use Models
22

3-
Models (and their sub-models) in detectron2 are built by
3+
## Build Models from Yacs Config
4+
From a yacs config object,
5+
models (and their sub-models) can be built by
46
functions such as `build_model`, `build_backbone`, `build_roi_heads`:
57
```python
68
from detectron2.modeling import build_model

docs/tutorials/training.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ It includes the following two instantiations:
2222
provides a minimal training loop for single-cost single-optimizer single-data-source training, with nothing else.
2323
Other tasks (checkpointing, logging, etc) can be implemented using
2424
[the hook system](../modules/engine.html#detectron2.engine.HookBase).
25-
* [DefaultTrainer](../modules/engine.html#detectron2.engine.defaults.DefaultTrainer) is a `SimpleTrainer` initialized from a config, used by
25+
* [DefaultTrainer](../modules/engine.html#detectron2.engine.defaults.DefaultTrainer) is a `SimpleTrainer` initialized from a
26+
yacs config, used by
2627
[tools/train_net.py](../../tools/train_net.py) and many scripts.
2728
It includes more standard default behaviors that one might want to opt in,
2829
including default configurations for optimizer, learning rate schedule,

0 commit comments

Comments
 (0)