# MONAI Bundle Configuration The `monai.bundle` module supports building Python-based workflows via structured configurations. The main benefits are threefold: - it provides good readability and usability by separating system parameter settings from the Python code. - it describes workflow at a relatively high level and allows for different low-level implementations. - learning paradigms at a higher level such as federated learning and AutoML can be decoupled from the component details. Content: - [A basic example](#a-basic-example) - [Syntax examples explained](#syntax-examples-explained) - [`@` to reference Python objects in configurations](#to-reference-python-objects-in-configurations) - [`$` to evaluate as Python expressions](#to-evaluate-as-python-expressions) - [`%` to textually replace configuration elements](#to-textually-replace-configuration-elements) - [`_target_` (`_disabled_`, `_desc_`, `_requires_`, `_mode_`) to instantiate a Python object](#instantiate-a-python-object) - [The command line interface](#the-command-line-interface) - [Recommendations](#recommendations) ## A basic example Components as part of a workflow can be specified using `JSON` or `YAML` syntax, for example, a network architecture definition could be stored in a `demo_config.json` file with the following content: ```json { "demo_net": { "_target_": "monai.networks.nets.BasicUNet", "spatial_dims": 3, "in_channels": 1, "out_channels": 2, "features": [16, 16, 32, 32, 64, 64] } } ``` or alternatively, in `YAML` format (`demo_config.yaml`): ```yaml demo_net: _target_: monai.networks.nets.BasicUNet spatial_dims: 3 in_channels: 1 out_channels: 2 features: [16, 16, 32, 32, 64, 64] ``` The configuration parser can instantiate the component as a Python object: ```py >>> from monai.bundle import ConfigParser >>> config = ConfigParser() >>> config.read_config("demo_config.json") >>> net = config.get_parsed_content("demo_net", instantiate=True) BasicUNet features: (16, 16, 32, 32, 64, 64). >>> print(type(net)) ``` or additionally, tune the input parameters then instantiate the component: ```py >>> config["demo_net"]["features"] = [32, 32, 32, 64, 64, 64] >>> net = config.get_parsed_content("demo_net", instantiate=True) BasicUNet features: (32, 32, 32, 64, 64, 64). ``` For more details on the `ConfigParser` API, please see [`monai.bundle.ConfigParser`](https://docs.monai.io/en/latest/bundle.html#config-parser). ## Syntax examples explained A few characters and keywords are interpreted beyond the plain texts, here are examples of the syntax: ### To reference Python objects in configurations ```json "@preprocessing::transforms::keys" ``` _Description:_ `@` character indicates a reference to another configuration value defined at `preprocessing::transforms::keys`. where `::` indicates a sub-structure of this configuration file. (`#` is a synonym for `::`, `preprocessing#transforms#keys` refers to the same object.) ```json "@preprocessing::1" ``` _Description:_ `1` is referencing as an integer, which is used to index (zero-based indexing) the `preprocessing` sub-structure. Relative reference is supported by starting the reference with `#`. For example, `@#A` is to use `A` at the same config structure level, and `@##A` refers to `A` at one level above. ### To evaluate as Python expressions ```json "$print(42)" ``` _Description:_ `$` is a special character to indicate evaluating `print(42)` at runtime. ```json "$[i for i in @datalist]" ``` _Description:_ Create a list at runtime using the values in `datalist` as input. ```json "$from torchvision.models import resnet18" ``` _Description:_ `$` followed by an import statement is handled slightly differently from the Python expressions. The imported module `resnet18` will be available as a global variable to the other configuration sections. This is to simplify the use of external modules in the configuration. The config expressions may use `@` to reference other config items. For example, in `$lambda x: x + @a + @b`, `@a` and `@b` are references to other Python objects and are made available to the anonymous function as 'globals'. It's therefore possible to modify the Python objects within an expression, for example, `$lambda x: @my_list.pop() + x` will pop the last element from `@my_list` and add it to `x`. ### To textually replace configuration elements ```json "%demo_config.json::demo_net::in_channels" ``` _Description:_ `%` character indicates a macro to replace the current configuration element with the texts at `demo_net::in_channels` in the `demo_config.json` file. The replacement is done before instantiating or evaluating the components. ### Instantiate a Python object ```json { "demo_name":{ "_target_": "my.python.module.Class", "args1": "string", "args2": 42} } ``` _Description:_ This dictionary defines an object with a reference name `demo_name`, with an instantiable type specified at `_target_` and with input arguments `args1` and `args2`. This dictionary will be instantiated as a Pytorch object at runtime. `_target_` is a required key by monai bundle syntax for the Python object name. `args1` and `args2` should be compatible with the Python object to instantiate. ```json { "component_name": { "_target_": "my.module.Class", "_desc_": "this is a customized class which also triggers 'cudnn_opt' reference", "_requires_": "@cudnn_opt", "_disabled_": "true", "_mode_": "default"} } ``` _Description:_ `_requires_`, `_disabled_`, `_desc_`, and `_mode_` are optional keys. - `_requires_` specifies references (string starts with `@`) or Python expression that will be evaluated/instantiated before `_target_` object is instantiated. It is useful when the component does not explicitly depend on the other ConfigItems via its arguments, but requires the dependencies to be instantiated/evaluated beforehand. - `_disabled_` specifies a flag to indicate whether to skip the instantiation. - `_desc_` can be used for providing free text descriptions. - `_mode_` specifies the operating mode when the component is instantiated or the callable is called. it currently supports the following values: - `"default"` (default) -- return the return value of ``_target_(**kwargs)`` - `"partial"` -- return a partial function of ``functools.partial(_target_, **kwargs)`` (this is often useful when some portion of the full set of arguments are supplied to the ``_target_``, and the user wants to call it with additional arguments later). - `"debug"` -- execute with debug prompt and return the return value of ``pdb.runcall(_target_, **kwargs)``, see also [`pdb.runcall`](https://docs.python.org/3/library/pdb.html#pdb.runcall). ## The command line interface In addition to the Pythonic APIs, a few command line interfaces (CLI) are provided to interact with the bundle. The primary usage is: ```bash python -m monai.bundle COMMANDS ``` where `COMMANDS` is one of the following: `run`, `verify_metadata`, `ckpt_export`, ... (please see `python -m monai.bundle --help` for a list of available options). The CLI supports flexible use cases, such as overriding configs at runtime and predefining arguments in a file. To display a usage page for a command, for example `run`: ```bash python -m monai.bundle run -- --help ``` The support is provided by [Python Fire](https://github.com/google/python-fire), please make sure the optional dependency is installed, for example, using `pip install monai[fire]` or `pip install fire`. Details on the CLI argument parsing is provided in the [Python Fire Guide](https://github.com/google/python-fire/blob/master/docs/guide.md#argument-parsing). ## Recommendations - Both `YAML` and `JSON` are supported, but the advanced features of these formats are not supported. - Using meaningful names for the configuration elements can improve the readability. - While it is possible to build complex configurations with the bundle syntax, simple structures with sparse uses of expressions or references are preferred. - For `$import ` in the configuration, please make sure there are instructions for the users to install the `` if it is not a (optional) dependency of MONAI. - As `#`, `::`, and `$` might be interpreted differently by the `shell` or `CLI` tools, may need to add escape characters or quotes for them in the command line, like: `"\$torch.device('cuda:1')"`, `"'train_part#trainer'"`. - For more details and examples, please see [the tutorials](https://github.com/Project-MONAI/tutorials/tree/main/bundle).