Skip to content

Commit 264b9e4

Browse files
Add "properties_path" in BundleWorkflow (#7542)
Fixes #7541 ### Types of changes <!--- Put an `x` in all the boxes that apply, and remove the not applicable items --> - [x] Non-breaking change (fix or new feature that would not break existing functionality). - [ ] Breaking change (fix or new feature that would cause existing functionality to change). - [ ] New tests added to cover the changes. - [ ] Integration tests passed locally by running `./runtests.sh -f -u --net --coverage`. - [ ] Quick tests passed locally by running `./runtests.sh --quick --unittests --disttests`. - [ ] In-line docstrings updated. - [ ] Documentation updated, tested `make html` command in the `docs/` folder. --------- Signed-off-by: YunLiu <55491388+KumoLiu@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent c885100 commit 264b9e4

File tree

4 files changed

+112
-4
lines changed

4 files changed

+112
-4
lines changed

monai/bundle/workflows.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
from __future__ import annotations
1313

14+
import json
1415
import os
1516
import sys
1617
import time
@@ -24,6 +25,7 @@
2425
from monai.bundle.config_parser import ConfigParser
2526
from monai.bundle.properties import InferProperties, MetaProperties, TrainProperties
2627
from monai.bundle.utils import DEFAULT_EXP_MGMT_SETTINGS, EXPR_KEY, ID_REF_KEY, ID_SEP_KEY
28+
from monai.config import PathLike
2729
from monai.utils import BundleProperty, BundlePropertyConfig, deprecated_arg, deprecated_arg_default, ensure_tuple
2830

2931
__all__ = ["BundleWorkflow", "ConfigWorkflow"]
@@ -46,6 +48,7 @@ class BundleWorkflow(ABC):
4648
or "infer", "inference", "eval", "evaluation" for a inference workflow,
4749
other unsupported string will raise a ValueError.
4850
default to `None` for common workflow.
51+
properties_path: the path to the JSON file of properties.
4952
meta_file: filepath of the metadata file, if this is a list of file paths, their contents will be merged in order.
5053
logging_file: config file for `logging` module in the program. for more details:
5154
https://docs.python.org/3/library/logging.config.html#logging.config.fileConfig.
@@ -66,6 +69,7 @@ def __init__(
6669
self,
6770
workflow_type: str | None = None,
6871
workflow: str | None = None,
72+
properties_path: PathLike | None = None,
6973
meta_file: str | Sequence[str] | None = None,
7074
logging_file: str | None = None,
7175
):
@@ -92,15 +96,24 @@ def __init__(
9296
meta_file = None
9397

9498
workflow_type = workflow if workflow is not None else workflow_type
95-
if workflow_type is None:
99+
if workflow_type is None and properties_path is None:
96100
self.properties = copy(MetaProperties)
97101
self.workflow_type = None
98102
self.meta_file = meta_file
99103
return
100-
if workflow_type.lower() in self.supported_train_type:
104+
if properties_path is not None:
105+
properties_path = Path(properties_path)
106+
if not properties_path.is_file():
107+
raise ValueError(f"Property file {properties_path} does not exist.")
108+
with open(properties_path) as json_file:
109+
self.properties = json.load(json_file)
110+
self.workflow_type = None
111+
self.meta_file = meta_file
112+
return
113+
if workflow_type.lower() in self.supported_train_type: # type: ignore[union-attr]
101114
self.properties = {**TrainProperties, **MetaProperties}
102115
self.workflow_type = "train"
103-
elif workflow_type.lower() in self.supported_infer_type:
116+
elif workflow_type.lower() in self.supported_infer_type: # type: ignore[union-attr]
104117
self.properties = {**InferProperties, **MetaProperties}
105118
self.workflow_type = "infer"
106119
else:
@@ -247,6 +260,7 @@ class ConfigWorkflow(BundleWorkflow):
247260
or "infer", "inference", "eval", "evaluation" for a inference workflow,
248261
other unsupported string will raise a ValueError.
249262
default to `None` for common workflow.
263+
properties_path: the path to the JSON file of properties.
250264
override: id-value pairs to override or add the corresponding config content.
251265
e.g. ``--net#input_chns 42``, ``--net %/data/other.json#net_arg``
252266
@@ -271,6 +285,7 @@ def __init__(
271285
tracking: str | dict | None = None,
272286
workflow_type: str | None = None,
273287
workflow: str | None = None,
288+
properties_path: PathLike | None = None,
274289
**override: Any,
275290
) -> None:
276291
workflow_type = workflow if workflow is not None else workflow_type
@@ -289,7 +304,7 @@ def __init__(
289304
else:
290305
config_root_path = Path("configs")
291306
meta_file = str(config_root_path / "metadata.json") if meta_file is None else meta_file
292-
super().__init__(workflow_type=workflow_type, meta_file=meta_file)
307+
super().__init__(workflow_type=workflow_type, meta_file=meta_file, properties_path=properties_path)
293308
self.config_root_path = config_root_path
294309
logging_file = str(self.config_root_path / "logging.conf") if logging_file is None else logging_file
295310
if logging_file is not None:

tests/test_bundle_workflow.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,16 @@ def test_inference_config(self, config_file):
105105
)
106106
self._test_inferer(inferer)
107107

108+
# test property path
109+
inferer = ConfigWorkflow(
110+
config_file=config_file,
111+
properties_path=os.path.join(os.path.dirname(__file__), "testing_data", "fl_infer_properties.json"),
112+
logging_file=os.path.join(os.path.dirname(__file__), "testing_data", "logging.conf"),
113+
**override,
114+
)
115+
self._test_inferer(inferer)
116+
self.assertEqual(inferer.workflow_type, None)
117+
108118
@parameterized.expand([TEST_CASE_3])
109119
def test_train_config(self, config_file):
110120
# test standard MONAI model-zoo config workflow

tests/test_regularization.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,15 @@
1616
import torch
1717

1818
from monai.transforms import CutMix, CutMixd, CutOut, MixUp, MixUpd
19+
from monai.utils import set_determinism
1920

2021

2122
class TestMixup(unittest.TestCase):
23+
def setUp(self) -> None:
24+
set_determinism(seed=0)
25+
26+
def tearDown(self) -> None:
27+
set_determinism(None)
2228

2329
def test_mixup(self):
2430
for dims in [2, 3]:
@@ -53,6 +59,11 @@ def test_mixupd(self):
5359

5460

5561
class TestCutMix(unittest.TestCase):
62+
def setUp(self) -> None:
63+
set_determinism(seed=0)
64+
65+
def tearDown(self) -> None:
66+
set_determinism(None)
5667

5768
def test_cutmix(self):
5869
for dims in [2, 3]:
@@ -78,6 +89,11 @@ def test_cutmixd(self):
7889

7990

8091
class TestCutOut(unittest.TestCase):
92+
def setUp(self) -> None:
93+
set_determinism(seed=0)
94+
95+
def tearDown(self) -> None:
96+
set_determinism(None)
8197

8298
def test_cutout(self):
8399
for dims in [2, 3]:
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
{
2+
"bundle_root": {
3+
"description": "root path of the bundle.",
4+
"required": true,
5+
"id": "bundle_root"
6+
},
7+
"device": {
8+
"description": "target device to execute the bundle workflow.",
9+
"required": true,
10+
"id": "device"
11+
},
12+
"dataset_dir": {
13+
"description": "directory path of the dataset.",
14+
"required": true,
15+
"id": "dataset_dir"
16+
},
17+
"dataset": {
18+
"description": "PyTorch dataset object for the inference / evaluation logic.",
19+
"required": true,
20+
"id": "dataset"
21+
},
22+
"evaluator": {
23+
"description": "inference / evaluation workflow engine.",
24+
"required": true,
25+
"id": "evaluator"
26+
},
27+
"network_def": {
28+
"description": "network module for the inference.",
29+
"required": true,
30+
"id": "network_def"
31+
},
32+
"inferer": {
33+
"description": "MONAI Inferer object to execute the model computation in inference.",
34+
"required": true,
35+
"id": "inferer"
36+
},
37+
"dataset_data": {
38+
"description": "data source for the inference / evaluation dataset.",
39+
"required": false,
40+
"id": "dataset::data",
41+
"refer_id": null
42+
},
43+
"handlers": {
44+
"description": "event-handlers for the inference / evaluation logic.",
45+
"required": false,
46+
"id": "handlers",
47+
"refer_id": "evaluator::val_handlers"
48+
},
49+
"preprocessing": {
50+
"description": "preprocessing for the input data.",
51+
"required": false,
52+
"id": "preprocessing",
53+
"refer_id": "dataset::transform"
54+
},
55+
"postprocessing": {
56+
"description": "postprocessing for the model output data.",
57+
"required": false,
58+
"id": "postprocessing",
59+
"refer_id": "evaluator::postprocessing"
60+
},
61+
"key_metric": {
62+
"description": "the key metric during evaluation.",
63+
"required": false,
64+
"id": "key_metric",
65+
"refer_id": "evaluator::key_val_metric"
66+
}
67+
}

0 commit comments

Comments
 (0)