Skip to content

Commit b56e177

Browse files
authored
adds a bundle config yaml example (#1023)
Signed-off-by: Wenqi Li <[email protected]> ### Description adding another example of yaml config and bundle parsing. ### Checks <!--- Put an `x` in all the boxes that apply, and remove the not applicable items --> - [ ] Notebook runs automatically `./runner [-p <regex_pattern>]` Signed-off-by: Wenqi Li <[email protected]>
1 parent 6194d37 commit b56e177

File tree

4 files changed

+219
-0
lines changed

4 files changed

+219
-0
lines changed

bundle/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# MONAI bundle
22
This folder contains the getting started tutorial and code examples of training / inference for MONAI bundle parser.
33

4+
### [introducing_config](./introducing_config)
5+
A simple example to introduce the MONAI bundle config and parsing.
6+
47
### [spleen segmentation](./spleen_segmentation)
58
A bundle example for volumetric (3D) segmentation of the spleen from CT image.
69

bundle/introducing_config/README.md

+159
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
# An example of how to use the bundle config
2+
3+
```bash
4+
python -m monai.bundle run display --config_file example.yaml
5+
```
6+
7+
By running the command within the same directory of this readme file, an example MedNIST dataset (~60MB) will be downloaded
8+
and a PyTorch-style `Dataset` will be created. The yaml config file also specifies the necessary commands to display the first pair of images in the dataset (shown in the figure).
9+
10+
<div> <img src="../../figures/mednist_config_intro.png"/> </div>
11+
12+
More specifically:
13+
- `python -m monai.bundle run` is the command [provided by the `monai.bundle` module](https://docs.monai.io/en/stable/bundle.html#monai.bundle.run). Apart from `run`, there are other actions available, such as `download` and `init_bundle`.
14+
- `display` is a user-defined component name in the `example.yaml` config file.
15+
- `--config_file example.yaml` specifies the config file describing the workflow, `monai.bundle` module supports both yaml and json formats ([syntax quick ref.](https://docs.monai.io/en/stable/config_syntax.html)).
16+
17+
The rest of the readme file will explain how the yaml config file is parsed in detail.
18+
19+
_Pre-requisites_
20+
21+
Installing MONAI (<https://docs.monai.io/en/stable/installation.html>) and basic knowledge of Python and Pytorch.
22+
23+
## Parsing the `example.yaml`
24+
25+
### Import modules
26+
27+
The bundle parser will first evaluate all the import statements such as `import package` and `from package import mod`.
28+
29+
```yaml
30+
imports:
31+
- $import glob
32+
- $import matplotlib.pyplot as plt
33+
```
34+
35+
These two statements will be evaluated and the imported modules will be available throughout the config file.
36+
By default, the parser imports `monai`'s modules and `import numpy as np` for you, so you don't need to add them in the config file.
37+
38+
### Running the `display` component
39+
40+
After all the import statements are evaluated, the `display` component defined as follows will be evaluated:
41+
42+
```yaml
43+
display:
44+
- _requires_: "@downloading"
45+
- $print("displaying images:")
46+
- $plt.subplot(1,2,1)
47+
- $plt.imshow(@first_pair['f_img'][0], cmap="gray")
48+
- $plt.subplot(1,2,2)
49+
- $plt.imshow(@first_pair['m_img'][0], cmap="gray")
50+
- $plt.show()
51+
```
52+
53+
`_requires_` is a special key for the bundle parsing, it specifies the dependencies of the component. In this case, the `display` component requires the `downloading` component to be executed first.
54+
55+
The rest of the keys are the list of commands to be executed. The bundle parser will evaluate the commands in the order they are defined in the config file.
56+
57+
`$` is the prefix for the commands, it tells the parser to evaluate the following string as a Python expression.
58+
59+
The `@` prefix is used to refer to another component. In this case, the `display` component refers to the output of the `first_pair` component, which is a dictionary containing the first pair of images in the dataset.
60+
At the runtime, the `@first_pair` will be replaced by the output of the `first_pair` component.
61+
62+
### Running the `first_pair` component
63+
64+
```yaml
65+
first_pair: $@preprocessing(@paired_dataset[0])
66+
```
67+
68+
The `first_pair` component is a simple Python expression, it refers to calling the `preprocessing` python instance with the first element of `paired_dataset`, which is a dictionary containing the first pair of images in the dataset.
69+
70+
### Defining the `preprocessing` component
71+
72+
```yaml
73+
preprocessing:
74+
_target_: Compose
75+
transforms:
76+
77+
- _target_: LoadImaged
78+
keys: [f_img, m_img]
79+
image_only: True
80+
81+
- _target_: EnsureChannelFirstd
82+
keys: [f_img, m_img]
83+
84+
- _target_: ScaleIntensityRanged
85+
keys: [f_img, m_img]
86+
a_min: 0.
87+
a_max: 255.
88+
b_min: 0.0
89+
b_max: 1.0
90+
91+
- _target_: RandRotated
92+
keys: [m_img]
93+
range_x: $np.pi/4
94+
prob: 1.0
95+
mode: "bicubic"
96+
keep_size: True
97+
98+
- _target_: RandZoomd
99+
keys: [m_img]
100+
min_zoom: 0.9
101+
max_zoom: 1.1
102+
prob: 1.0
103+
mode: "bicubic"
104+
```
105+
106+
`_target_` is a special key for the bundle parsing, it specifies the class to be instantiated. In this case, the `preprocessing` component is a `Compose` object. `Compose` is resolved to `monai.transforms.Compose` by default, so you don't need to specify the full path.
107+
108+
`transforms` is the first argument to `monai.transforms.Compose`, it specifies the list of transforms to be added to the `Compose` object.
109+
110+
The rest of the keys are the arguments to the transforms. In this case, the `LoadImaged` transform is used to load the images from the file paths, `EnsureChannelFirstd` transform is used to ensure the image data is in channel-first format, `ScaleIntensityRanged` transform is used to scale the image intensity to `[0, 1]`. `RandRotated` transform is used to randomly rotate the moving image, and `RandZoomd` transform is used to randomly zoom the moving image.
111+
112+
113+
_The equivalent Python code of the yaml config file as a comparison_
114+
115+
```py
116+
import glob
117+
import matplotlib.pyplot as plt
118+
import monai
119+
import monai.transforms as mt
120+
import numpy as np
121+
122+
url = "https://github.com/Project-MONAI/MONAI-extra-test-data/releases/download/0.8.1/MedNIST.tar.gz"
123+
monai.apps.utils.download_and_extract(url, './mednist.tar.gz')
124+
125+
dataset_dir = "MedNIST/Hand"
126+
datalist = list(sorted(glob.glob(f"{dataset_dir}/*.jpeg")))
127+
paired_dataset = [{"f_img": item, "m_img": item} for item in datalist]
128+
129+
preprocessing = mt.Compose(
130+
[
131+
mt.LoadImaged(keys=("f_img", "m_img"), image_only=True),
132+
mt.EnsureChannelFirstd(keys=("f_img", "m_img")),
133+
mt.ScaleIntensityRanged(
134+
keys=("f_img", "m_img"), a_min=0.0, a_max=255.0, b_min=0.0, b_max=1.0
135+
),
136+
mt.RandRotated(
137+
keys=["m_img"], range_x=np.pi / 4, prob=1.0, mode="bicubic", keep_size=True
138+
),
139+
mt.RandZoomd(keys=["m_img"], min_zoom=0.9, max_zoom=1.1, prob=1.0, mode="bicubic"),
140+
]
141+
)
142+
143+
first_pair = preprocessing(paired_dataset[0])
144+
print("displaying images:")
145+
plt.subplot(1, 2, 1)
146+
plt.imshow(first_pair["f_img"][0], cmap="gray")
147+
plt.subplot(1, 2, 2)
148+
plt.imshow(first_pair["m_img"][0], cmap="gray")
149+
plt.show()
150+
151+
```
152+
153+
## Topics not covered but possible in the config
154+
155+
- Running customized Python components (made available on the `PYTHONPATH`, more examples [in the model_zoo](https://github.com/Project-MONAI/model-zoo)).
156+
- Overriding the component in `example.yaml` using, for example, `--id=new_value` in the command line.
157+
- Multiple configuration files and cross-file references.
158+
- Replacing in terms of plain texts instead of Python objects ([tutorial](https://github.com/Project-MONAI/tutorials/blob/main/bundle/get_started.ipynb)).
159+
- The debugging mode to investigate the intermediate variables and results.
+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
imports:
3+
- $import glob
4+
- $import matplotlib.pyplot as plt
5+
6+
# download and extract dataset (60MB):
7+
url: "https://github.com/Project-MONAI/MONAI-extra-test-data/releases/download/0.8.1/MedNIST.tar.gz"
8+
downloading: "$monai.apps.utils.download_and_extract(@url, './mednist.tar.gz')"
9+
10+
# construct the input paired data (moving and fixed images)
11+
dataset_dir: "MedNIST/Hand"
12+
datalist: $list(sorted(glob.glob(@dataset_dir + '/*.jpeg')))
13+
paired_dataset: "$[{'f_img': item, 'm_img': item} for item in @datalist]"
14+
15+
# define preprocessing (additional randomization on the moving image)
16+
preprocessing:
17+
_target_: Compose
18+
transforms:
19+
20+
- _target_: LoadImaged
21+
keys: [f_img, m_img]
22+
image_only: True
23+
24+
- _target_: EnsureChannelFirstd
25+
keys: [f_img, m_img]
26+
27+
- _target_: ScaleIntensityRanged
28+
keys: [f_img, m_img]
29+
a_min: 0.
30+
a_max: 255.
31+
b_min: 0.0
32+
b_max: 1.0
33+
34+
- _target_: RandRotated
35+
keys: [m_img]
36+
range_x: $np.pi/4
37+
prob: 1.0
38+
mode: "bicubic"
39+
keep_size: True
40+
41+
- _target_: RandZoomd
42+
keys: [m_img]
43+
min_zoom: 0.9
44+
max_zoom: 1.1
45+
prob: 1.0
46+
mode: "bicubic"
47+
48+
# display the first pair of moving and fixed images
49+
first_pair: $@preprocessing(@paired_dataset[0])
50+
display:
51+
- _requires_: "@downloading"
52+
- $print("displaying images:")
53+
- $plt.subplot(1,2,1)
54+
- $plt.imshow(@first_pair['f_img'][0], cmap="gray")
55+
- $plt.subplot(1,2,2)
56+
- $plt.imshow(@first_pair['m_img'][0], cmap="gray")
57+
- $plt.show()

figures/mednist_config_intro.png

23.2 KB
Loading

0 commit comments

Comments
 (0)