Skip to content

Latest commit

 

History

History
252 lines (202 loc) · 9.87 KB

config_syntax.md

File metadata and controls

252 lines (202 loc) · 9.87 KB

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

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:

{
  "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):

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:

>>> 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))
<class 'monai.networks.nets.basic_unet.BasicUNet'>

or additionally, tune the input parameters then instantiate the component:

>>> 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.

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

"@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.)

"@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

"$print(42)"

Description: $ is a special character to indicate evaluating print(42) at runtime.

"$[i for i in @datalist]"

Description: Create a list at runtime using the values in datalist as input.

"$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

"%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

{
  "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.

{
  "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)
    • "callable" -- return a callable, either as _target_ itself or, if kwargs are provided, as a partial function of functools.partial(_target_, **kwargs). Useful for defining a class or function that will be instantied or called later. User can pre-define some arguments to the _target_ and 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.

Multiple config files

Description: Multiple config files may be specified on the command line. The content of those config files is being merged. When same keys are specifiled in more than one config file, the value associated with the key is being overridden, in the order config files are specified. If the desired behaviour is to merge values from both files, the key in second config file should be prefixed with +. The value types for the merged contents must match and be both of dict or both of list type. dict values will be merged via update(), list values - concatenated via extend(). Here's an example. In this case, "amp" value will be overridden by extra_config.json. imports and preprocessing#transforms lists will be merged. An error would be thrown if the value type in "+imports" is not list:

config.json:

{
    "amp": "$True"
    "imports": [
	"$import torch"
    ],
    "preprocessing": {
        "_target_": "Compose",
        "transforms": [
	  "$@t1",
	  "$@t2"
        ]
    },
}

extra_config.json:

{
    "amp": "$False"
    "+imports": [
	"$from monai.networks import trt_compile"
    ],
    "+preprocessing#transforms": [
        "$@t3"
    ]
}

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:

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:

python -m monai.bundle run -- --help

The support is provided by 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.

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 <module> in the configuration, please make sure there are instructions for the users to install the <module> 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.