Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
3c9d2d1
3482 Build component instance from dictionary config (#3518)
Nic-Ma Jan 6, 2022
b5509a5
Merge branch 'dev' into 3482-mmar-mvp
Nic-Ma Jan 17, 2022
85f6797
[DLMED] add ConfigResolver ConfigComponent
Nic-Ma Jan 19, 2022
b7d08d8
Merge branch 'dev' into 3482-mmar-mvp
Nic-Ma Jan 19, 2022
ba629b3
[DLMED] add to doc
Nic-Ma Jan 19, 2022
da2a4bc
[DLMED] add details unit tests for ConfigComponent
Nic-Ma Jan 24, 2022
7e07e76
[DLMED] add unit tests for ConfigResolver
Nic-Ma Jan 24, 2022
c579c59
[DLMED] add details unit tests for ConfigParser, ConfigResolver
Nic-Ma Jan 24, 2022
9a3c38b
Merge branch 'dev' into 3482-mmar-mvp
Nic-Ma Jan 24, 2022
9283623
[DLMED] fix typo
Nic-Ma Jan 24, 2022
d4ebe57
[DLMED] add details doc-strings
Nic-Ma Jan 24, 2022
5776301
[DLMED] fix typo
Nic-Ma Jan 24, 2022
8cc4d3e
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 24, 2022
0f66ad8
[DLMED] update to dependencies
Nic-Ma Jan 24, 2022
9d38e44
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 24, 2022
5646b0a
[DLMED] add circle dependency check
Nic-Ma Jan 24, 2022
d154750
Merge branch 'dev' into 3482-mmar-mvp
Nic-Ma Jan 24, 2022
cfb2bdd
[DLMED] fix flake8 error
Nic-Ma Jan 24, 2022
ff93b76
Merge branch 'dev' into 3482-mmar-mvp
Nic-Ma Jan 24, 2022
55a210e
[DLMED] fix min tests
Nic-Ma Jan 24, 2022
d598be6
[DLMED] fix docs
Nic-Ma Jan 24, 2022
196bcff
Merge branch 'dev' into 3482-mmar-mvp
Nic-Ma Jan 25, 2022
1bee7f1
[DLMED] update according to comments
Nic-Ma Jan 25, 2022
de9710f
Merge branch 'dev' into 3482-mmar-mvp
Nic-Ma Jan 25, 2022
2acd6f8
Merge branch 'dev' into 3482-mmar-mvp
Nic-Ma Jan 26, 2022
bb8b2a7
Merge branch 'dev' into 3482-mmar-mvp
Nic-Ma Jan 26, 2022
3049e28
[DLMED] add scripts logic
Nic-Ma Jan 27, 2022
506b908
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 27, 2022
9d1e716
[DLMED] update to latest
Nic-Ma Feb 16, 2022
80de798
Merge branch 'dev' into 3482-mmar-mvp
Nic-Ma Feb 16, 2022
393887d
[DLMED] update reference resolver
Nic-Ma Feb 17, 2022
b40f3e5
[DLMED] update file names
Nic-Ma Feb 17, 2022
0198f9b
[DLMED] fix ReferenceResolver
Nic-Ma Feb 17, 2022
1ffe52a
[DLMED] update ConfigParser
Nic-Ma Feb 18, 2022
627f7d5
[DLMED] fix unit tests
Nic-Ma Feb 18, 2022
48a1c2a
Merge branch 'dev' into 3482-mmar-mvp
Nic-Ma Feb 18, 2022
fe5997f
Merge branch 'dev' into 3482-mmar-mvp
Nic-Ma Feb 18, 2022
1684c23
[DLMED] update ConfigParse logic
Nic-Ma Feb 18, 2022
23e1fb9
Merge branch 'dev' into 3482-mmar-mvp
Nic-Ma Feb 18, 2022
7d4d60c
[DLMED] add docs
Nic-Ma Feb 18, 2022
9a06ce9
[DLMED] add unit tests
Nic-Ma Feb 18, 2022
b9c26e1
[DLMED] update to latest
Nic-Ma Feb 19, 2022
01fdf0a
[DLMED] resolve conflicts
Nic-Ma Feb 19, 2022
c5c93f8
Merge remote-tracking branch 'origin/dev' into 3482-mmar-mvp
Nic-Ma Feb 19, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions monai/apps/manifest/export.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Copyright (c) MONAI Consortium
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import argparse
import json

import torch
from monai.apps import ConfigParser
from ignite.handlers import Checkpoint
from monai.data import save_net_with_metadata
from monai.networks import convert_to_torchscript


def main():
parser = argparse.ArgumentParser()
parser.add_argument('--weights', '-w', type=str, help='file path of the trained model weights', required=True)
parser.add_argument('--config', '-c', type=str, help='file path of config file that defines network', required=True)
parser.add_argument('--meta', '-e', type=str, help='file path of the meta data')
args = parser.parse_args()

# load config file
with open(args.config) as f:
config_dict = json.load(f)
# load meta data
with open(args.meta) as f:
meta_dict = json.load(f)

net: torch.nn.Module = None
# TODO: parse network definiftion from config file and construct network instance
config_parser = ConfigParser(config_dict)
net = config_parser.get_instance("network")

checkpoint = torch.load(args.weights)
# here we use ignite Checkpoint to support nested weights and be compatible with MONAI CheckpointSaver
Checkpoint.load_objects(to_load={"model": net}, checkpoint=checkpoint)

# convert to TorchScript model and save with meta data
net = convert_to_torchscript(model=net)

save_net_with_metadata(
jit_obj=net,
filename_prefix_or_stream="model.ts",
include_config_vals=False,
append_timestamp=False,
meta_values=meta_dict,
more_extra_files={args.config: json.dumps(config_dict).encode()},
)


if __name__ == '__main__':
main()
68 changes: 68 additions & 0 deletions monai/apps/manifest/inference.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Copyright (c) MONAI Consortium
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import argparse
import json

import torch
from monai.apps import ConfigParser
from monai.data import decollate_batch
from monai.inferers import Inferer
from monai.transforms import Transform
from monai.utils.enums import CommonKeys


def main():
parser = argparse.ArgumentParser()
parser.add_argument('--config', '-c', type=str, help='config file that defines components', required=True)
parser.add_argument('--meta', '-e', type=str, help='file path of the meta data')
parser.add_argument('--override', '-o', type=str, help='config file that override components', required=False)
args = parser.parse_args()

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
configs = {}

# load meta data
with open(args.meta) as f:
configs.update(json.load(f))
# load config file, can override meta data in config
with open(args.config) as f:
configs.update(json.load(f))

model: torch.nn.Module = None
dataloader: torch.utils.data.DataLoader = None
inferer: Inferer = None
postprocessing: Transform = None
# TODO: parse inference config file and construct instances
config_parser = ConfigParser(configs)

# change JSON config content in python code, lazy instantiation
model_conf = config_parser.get_config("model")
model_conf["disabled"] = False
model = config_parser.build(model_conf).to(device)

# instantialize the components immediately
dataloader = config_parser.get_instance("dataloader")
inferer = config_parser.get_instance("inferer")
postprocessing = config_parser.get_instance("postprocessing")

model.eval()
with torch.no_grad():
for d in dataloader:
images = d[CommonKeys.IMAGE].to(device)
# define sliding window size and batch size for windows inference
d[CommonKeys.PRED] = inferer(inputs=images, predictor=model)
# decollate the batch data into a list of dictionaries, then execute postprocessing transforms
[postprocessing(i) for i in decollate_batch(d)]


if __name__ == '__main__':
main()
71 changes: 71 additions & 0 deletions monai/apps/manifest/schema/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://monai.io/mmar_metadata_schema.json",
"title": "metadata",
"description": "metadata that defines the context information for MMAR.",
"type": "object",
"properties": {
"version": {
"description": "version number of this MMAR.",
"type": "string"
},
"monai_version": {
"description": "version number of MONAI used in this MMAR.",
"type": "string"
},
"pytorch_version": {
"description": "version number of PyTorch used in this MMAR.",
"type": "string"
},
"numpy_version": {
"description": "version number of MONAI used in this MMAR.",
"type": "string"
},
"network_data_format": {
"description": "define the input and output data format for network.",
"type": "object",
"properties": {
"inputs": {
"type": "object",
"properties": {
"image": {
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "the data format for `image`."
},
"format": {
"type": "string"
},
"num_channels": {
"type": "integer",
"minimum": 1
},
"spatial_shape": {
"type": "array",
"items": {
"type": "integer",
"minumum": 1
}
},
"dtype": {
"type": "string"
},
"value_range": {
"type": "array",
"items": {
"type": "number",
"unuqueItems": true
}
},
"required": ["num_channels", "spatial_shape", "value_range"]
}
}
}
}
}
},
"required": ["monai_version", "pytorch_version", "network_data_format"]
}
}
60 changes: 60 additions & 0 deletions monai/apps/manifest/verify_network.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Copyright (c) MONAI Consortium
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import argparse
import json

import torch
from monai.apps import ConfigParser
from monai.utils.type_conversion import get_equivalent_dtype


def main():
parser = argparse.ArgumentParser()
parser.add_argument('--config', '-c', type=str, help='config file that defines components', required=True)
parser.add_argument('--meta', '-e', type=str, help='file path of the meta data')
args = parser.parse_args()

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
configs = {}

# load meta data
with open(args.meta) as f:
configs.update(json.load(f))
# load config file, can override meta data in config
with open(args.config) as f:
configs.update(json.load(f))

model: torch.nn.Module = None
# TODO: parse inference config file and construct instances
config_parser = ConfigParser(configs)

model = config_parser.get_instance("model")
input_channels = config_parser.get_config("network_data_format#inputs#image#num_channels")
input_spatial_shape = tuple(config_parser.get_config("network_data_format#inputs#image#spatial_shape"))
dtype = config_parser.get_config("network_data_format#inputs#image#dtype")
dtype = get_equivalent_dtype(dtype, data_type=torch.Tensor)

output_channels = config_parser.get_config("network_data_format#outputs#pred#num_channels")
output_spatial_shape = tuple(config_parser.get_config("network_data_format#outputs#pred#spatial_shape"))

model.eval()
with torch.no_grad():
test_data = torch.rand(*(input_channels, *input_spatial_shape), dtype=dtype, device=device)
output = model(test_data)
if output.shape[0] != output_channels:
raise ValueError(f"channel number of output data doesn't match expection: {output_channels}.")
if output.shape[1:] != output_spatial_shape:
raise ValueError(f"spatial shape of output data doesn't match expection: {output_spatial_shape}.")


if __name__ == '__main__':
main()
35 changes: 0 additions & 35 deletions tests/test_component_locator.py

This file was deleted.

99 changes: 0 additions & 99 deletions tests/test_config_item.py

This file was deleted.