def test_url_download_bundle(self, bundle_files, bundle_name, url, hash_val): with skip_if_downloading_fails(): # download a single file from url, also use `args_file` with tempfile.TemporaryDirectory() as tempdir: def_args = { "name": bundle_name, "bundle_dir": tempdir, "url": "" } def_args_file = os.path.join(tempdir, "def_args.json") parser = ConfigParser() parser.export_config_file(config=def_args, filepath=def_args_file) cmd = [ "coverage", "run", "-m", "monai.bundle", "download", "--args_file", def_args_file ] cmd += ["--url", url] subprocess.check_call(cmd) for file in bundle_files: file_path = os.path.join(tempdir, bundle_name, file) self.assertTrue(os.path.exists(file_path)) if file == "network.json": self.assertTrue( check_hash(filepath=file_path, val=hash_val))
def test_verify(self, meta_file, config_file): with tempfile.TemporaryDirectory() as tempdir: def_args = { "meta_file": "will be replaced by `meta_file` arg", "p": 2 } def_args_file = os.path.join(tempdir, "def_args.json") ConfigParser.export_config_file(config=def_args, filepath=def_args_file) cmd = [ "coverage", "run", "-m", "monai.bundle", "verify_net_in_out", "network_def", "--meta_file" ] cmd += [ meta_file, "--config_file", config_file, "-n", "4", "--any", "16", "--args_file", def_args_file ] cmd += [ "--_meta_#network_data_format#inputs#image#spatial_shape", "[16,'*','2**p*n']" ] test_env = os.environ.copy() print(f"CUDA_VISIBLE_DEVICES in {__file__}", test_env.get("CUDA_VISIBLE_DEVICES")) subprocess.check_call(cmd, env=test_env)
def test_relative_id(self, config): parser = ConfigParser(config=config) for id in config: item = parser.get_parsed_content(id=id) if isinstance(item, int): self.assertEqual(item, 1) if isinstance(item, dict): self.assertEqual(str(item), str({"key": 1, "value1": 2, "value2": 2, "value3": [3, 4, 4, 105]}))
def test_verify(self, meta_file, schema_file): with tempfile.TemporaryDirectory() as tempdir: def_args = {"meta_file": "will be replaced by `meta_file` arg"} def_args_file = os.path.join(tempdir, "def_args.json") ConfigParser.export_config_file(config=def_args, filepath=def_args_file) cmd = ["coverage", "run", "-m", "monai.bundle", "verify_metadata", "--meta_file", meta_file] cmd += ["--filepath", schema_file, "--hash_val", self.config["hash_val"], "--args_file", def_args_file] subprocess.check_call(cmd)
def test_lambda_reference(self): configs = { "patch_size": [8, 8], "transform": {"_target_": "Lambda", "func": "$lambda x: x.reshape((1, *@patch_size))"}, } parser = ConfigParser(config=configs) trans = parser.get_parsed_content(id="transform") result = trans(np.ones(64)) self.assertTupleEqual(result.shape, (1, 8, 8))
def test_function(self, config): parser = ConfigParser(config=config, globals={"TestClass": TestClass}) for id in config: func = parser.get_parsed_content(id=id) self.assertTrue(id in parser.ref_resolver.resolved_content) if id == "error_func": with self.assertRaises(TypeError): func(1, 2) continue self.assertEqual(func(1, 2), 3)
def test_list_expressions(self): config = { "transform": { "_target_": "Compose", "transforms": [{"_target_": "RandScaleIntensity", "factors": 0.5, "prob": 1.0}], }, "training": ["$monai.utils.set_determinism(seed=123)", "$@transform(np.asarray([1, 2]))"], } parser = ConfigParser(config=config) parser.get_parsed_content("training", lazy=True, instantiate=True, eval_expr=True) np.testing.assert_allclose(parser.get_parsed_content("training#1", lazy=True), [0.7942, 1.5885], atol=1e-4)
def test_shape(self, config_file, expected_shape): test_image = np.random.rand(*expected_shape) tempdir = self.data_dir filename = os.path.join(tempdir, "image.nii") nib.save(nib.Nifti1Image(test_image, np.eye(4)), filename) # generate default args in a JSON file logging_conf = os.path.join(os.path.dirname(__file__), "testing_data", "logging.conf") def_args = {"config_file": "will be replaced by `config_file` arg", "logging_file": logging_conf} def_args_file = os.path.join(tempdir, "def_args.json") ConfigParser.export_config_file(config=def_args, filepath=def_args_file) meta = {"datalist": [{"image": filename}], "output_dir": tempdir, "window": (96, 96, 96)} # test YAML file meta_file = os.path.join(tempdir, "meta.yaml") ConfigParser.export_config_file(config=meta, filepath=meta_file, fmt="yaml") # test override with file, up case postfix overridefile1 = os.path.join(tempdir, "override1.JSON") with open(overridefile1, "w") as f: # test override with part of the overriding file json.dump({"move_net": "$@network_def.to(@device)"}, f) os.makedirs(os.path.join(tempdir, "jsons"), exist_ok=True) overridefile2 = os.path.join(tempdir, "jsons/override2.JSON") with open(overridefile2, "w") as f: # test override with the whole overriding file json.dump("Dataset", f) saver = LoadImage(image_only=True) if sys.platform == "win32": override = "--network $@network_def.to(@device) --dataset#_target_ Dataset" else: override = f"--network %{overridefile1}#move_net --dataset#_target_ %{overridefile2}" # test with `monai.bundle` as CLI entry directly cmd = f"-m monai.bundle run evaluator --postprocessing#transforms#2#output_postfix seg {override}" la = ["coverage", "run"] + cmd.split(" ") + ["--meta_file", meta_file] + ["--config_file", config_file] test_env = os.environ.copy() print(f"CUDA_VISIBLE_DEVICES in {__file__}", test_env.get("CUDA_VISIBLE_DEVICES")) subprocess.check_call(la + ["--args_file", def_args_file], env=test_env) self.assertTupleEqual(saver(os.path.join(tempdir, "image", "image_seg.nii.gz")).shape, expected_shape) # here test the script with `google fire` tool as CLI cmd = "-m fire monai.bundle.scripts run --runner_id evaluator" cmd += f" --evaluator#amp False {override}" la = ["coverage", "run"] + cmd.split(" ") + ["--meta_file", meta_file] + ["--config_file", config_file] subprocess.check_call(la, env=test_env) self.assertTupleEqual(saver(os.path.join(tempdir, "image", "image_trans.nii.gz")).shape, expected_shape)
def test_export(self, key_in_ckpt): meta_file = os.path.join(os.path.dirname(__file__), "testing_data", "metadata.json") config_file = os.path.join(os.path.dirname(__file__), "testing_data", "inference.json") with tempfile.TemporaryDirectory() as tempdir: def_args = {"meta_file": "will be replaced by `meta_file` arg"} def_args_file = os.path.join(tempdir, "def_args.json") ckpt_file = os.path.join(tempdir, "model.pt") ts_file = os.path.join(tempdir, "model.ts") parser = ConfigParser() parser.export_config_file(config=def_args, filepath=def_args_file) parser.read_config(config_file) net = parser.get_parsed_content("network_def") save_state(src=net if key_in_ckpt == "" else {key_in_ckpt: net}, path=ckpt_file) cmd = [ "coverage", "run", "-m", "monai.bundle", "ckpt_export", "network_def", "--filepath", ts_file ] cmd += [ "--meta_file", meta_file, "--config_file", config_file, "--ckpt_file", ckpt_file ] cmd += ["--key_in_ckpt", key_in_ckpt, "--args_file", def_args_file] subprocess.check_call(cmd) self.assertTrue(os.path.exists(ts_file))
def test_macro_replace(self): with tempfile.TemporaryDirectory() as tempdir: another_file = os.path.join(tempdir, "another.json") ConfigParser.export_config_file(config={"E": 4}, filepath=another_file) # test macro with id, relative id, and macro in another file config = {"A": {"B": 1, "C": 2}, "D": [3, "%A#B", "%#0", f"%{another_file}#E"]} parser = ConfigParser(config=config) parser.resolve_macro_and_relative_ids() self.assertEqual(str(parser.get()), str({"A": {"B": 1, "C": 2}, "D": [3, 1, 3, 4]}))
def test_parse(self, config, expected_ids, output_types): parser = ConfigParser(config=config, globals={"monai": "monai"}) # test lazy instantiation with original config content parser["transform"]["transforms"][0]["keys"] = "label1" trans = parser.get_parsed_content(id="transform#transforms#0") self.assertEqual(trans.keys[0], "label1") # test re-use the parsed content or not with the `lazy` option self.assertEqual(trans, parser.get_parsed_content(id="transform#transforms#0")) self.assertEqual(trans, parser.get_parsed_content(id="transform#transforms#0", lazy=True)) self.assertNotEqual(trans, parser.get_parsed_content(id="transform#transforms#0", lazy=False)) # test nested id parser["transform#transforms#0#keys"] = "label2" self.assertEqual(parser.get_parsed_content(id="transform#transforms#0").keys[0], "label2") for id, cls in zip(expected_ids, output_types): self.assertTrue(isinstance(parser.get_parsed_content(id), cls)) # test root content root = parser.get_parsed_content(id="") for v, cls in zip(root.values(), [Compose, Dataset, DataLoader]): self.assertTrue(isinstance(v, cls)) # test default value self.assertEqual(parser.get_parsed_content(id="abc", default=ConfigItem(12345, "abc")), 12345)
def test_config_content(self): test_config = {"preprocessing": [{"_target_": "LoadImage"}], "dataset": {"_target_": "Dataset"}} parser = ConfigParser(config=test_config) # test `get`, `set`, `__getitem__`, `__setitem__` self.assertEqual(str(parser.get()), str(test_config)) parser.set(config=test_config) self.assertListEqual(parser["preprocessing"], test_config["preprocessing"]) parser["dataset"] = {"_target_": "CacheDataset"} self.assertEqual(parser["dataset"]["_target_"], "CacheDataset") # test nested ids parser["dataset#_target_"] = "Dataset" self.assertEqual(parser["dataset#_target_"], "Dataset") parser.update({"dataset#_target_1": "Dataset1"}) self.assertEqual(parser["dataset#_target_1"], "Dataset1") # test int id parser.set(["test1", "test2", "test3"]) parser[1] = "test4" self.assertEqual(parser[1], "test4")
def test_contains(self): empty_parser = ConfigParser({}) empty_parser.parse() parser = ConfigParser({"value": 1, "entry": "string content"}) parser.parse() with self.subTest("Testing empty parser"): self.assertFalse("something" in empty_parser) with self.subTest("Testing with keys"): self.assertTrue("value" in parser) self.assertFalse("value1" in parser) self.assertTrue("entry" in parser) self.assertFalse("entr" in parser)
def test_allow_missing_reference(self, config): default = ReferenceResolver.allow_missing_reference ReferenceResolver.allow_missing_reference = True parser = ConfigParser(config=config) for id in config: item = parser.get_parsed_content(id=id) if id in ("A", "B"): self.assertEqual(item, 1) elif id == "C": self.assertEqual(item, "@D") elif id == "E": self.assertEqual(item, "test@F") # restore the default value ReferenceResolver.allow_missing_reference = default with self.assertRaises(ValueError): parser.parse() parser.get_parsed_content(id="E")
def test_transforms(self, case_id): set_determinism(2022) config = ConfigParser() config.read_config(TEST_CASES) config["input_keys"] = keys test_case = config.get_parsed_content(id=case_id, instantiate=True) # transform instance dataset = CacheDataset(self.files, transform=test_case) loader = DataLoader(dataset, batch_size=3, shuffle=True) for x in loader: self.assertIsInstance(x[keys[0]], MetaTensor) self.assertIsInstance(x[keys[1]], MetaTensor) out = decollate_batch(x) # decollate every batch should work # test forward patches loaded = out[0] self.assertEqual(len(loaded), len(keys)) img, seg = loaded[keys[0]], loaded[keys[1]] expected = config.get_parsed_content(id=f"{case_id}_answer", instantiate=True) # expected results self.assertEqual(expected["load_shape"], list(x[keys[0]].shape)) assert_allclose(expected["affine"], img.affine, type_test=False, atol=TINY_DIFF, rtol=TINY_DIFF) assert_allclose(expected["affine"], seg.affine, type_test=False, atol=TINY_DIFF, rtol=TINY_DIFF) test_cls = [type(x).__name__ for x in test_case.transforms] tracked_cls = [x[TraceKeys.CLASS_NAME] for x in img.applied_operations] self.assertTrue(len(tracked_cls) <= len(test_cls)) # tracked items should be no more than the compose items. with tempfile.TemporaryDirectory() as tempdir: # test writer SaveImageD(keys, resample=False, output_dir=tempdir, output_postfix=case_id)(loaded) # test inverse inv = InvertD(keys, orig_keys=keys, transform=test_case, nearest_interp=True) out = inv(loaded) img, seg = out[keys[0]], out[keys[1]] assert_allclose(expected["inv_affine"], img.affine, type_test=False, atol=TINY_DIFF, rtol=TINY_DIFF) assert_allclose(expected["inv_affine"], seg.affine, type_test=False, atol=TINY_DIFF, rtol=TINY_DIFF) self.assertFalse(img.applied_operations) self.assertFalse(seg.applied_operations) assert_allclose(expected["inv_shape"], img.shape, type_test=False, atol=TINY_DIFF, rtol=TINY_DIFF) assert_allclose(expected["inv_shape"], seg.shape, type_test=False, atol=TINY_DIFF, rtol=TINY_DIFF) with tempfile.TemporaryDirectory() as tempdir: # test writer SaveImageD(keys, resample=False, output_dir=tempdir, output_postfix=case_id)(out) seg_file = os.path.join(tempdir, key_1, f"{key_1}_{case_id}.nii.gz") segout = nib.load(seg_file).get_fdata() segin = nib.load(FILE_PATH_1).get_fdata() ndiff = np.sum(np.abs(segout - segin) > 0) total = np.prod(segout.shape) self.assertTrue(ndiff / total < 0.4, f"{ndiff / total}")
def test_parse(self, config, expected_ids, output_types): parser = ConfigParser(config=config, globals={"monai": "monai"}) # test lazy instantiation with original config content parser["transform"]["transforms"][0]["keys"] = "label1" self.assertEqual( parser.get_parsed_content(id="transform#transforms#0").keys[0], "label1") # test nested id parser["transform#transforms#0#keys"] = "label2" self.assertEqual( parser.get_parsed_content(id="transform#transforms#0").keys[0], "label2") for id, cls in zip(expected_ids, output_types): self.assertTrue(isinstance(parser.get_parsed_content(id), cls)) # test root content root = parser.get_parsed_content(id="") for v, cls in zip(root.values(), [Compose, Dataset, DataLoader]): self.assertTrue(isinstance(v, cls))
def test_error_instance(self): config = {"transform": {"_target_": "Compose", "transforms_wrong_key": []}} parser = ConfigParser(config=config) with self.assertRaises(RuntimeError): parser.get_parsed_content("transform", instantiate=True, eval_expr=True)