Skip to content

Commit 489d105

Browse files
Add nnUNet segmentation application and dependencies
Signed-off-by: Simone Bendazzoli <[email protected]>
1 parent 104c4e7 commit 489d105

File tree

5 files changed

+114
-14
lines changed

5 files changed

+114
-14
lines changed

examples/apps/ai_spleen_nnunet_seg_app/app.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,28 +22,32 @@
2222
from monai.deploy.operators.dicom_seg_writer_operator import DICOMSegmentationWriterOperator, SegmentDescription
2323
from monai.deploy.operators.dicom_series_selector_operator import DICOMSeriesSelectorOperator
2424
from monai.deploy.operators.dicom_series_to_volume_operator import DICOMSeriesToVolumeOperator
25-
from monai.deploy.operators.monai_bundle_inference_operator import BundleConfigNames, IOMapping
26-
from monai.deploy.operators.monet_bundle_inference_operator import MONetBundleInferenceOperator
25+
from monai.deploy.operators.monai_bundle_inference_operator import (
26+
BundleConfigNames,
27+
IOMapping,
28+
29+
)
30+
from monai.deploy.operators.monai_nnunet_bundle_inference_operator import MonainnUNetBundleInferenceOperator
2731
from monai.deploy.operators.stl_conversion_operator import STLConversionOperator
2832

2933

3034
# @resource(cpu=1, gpu=1, memory="7Gi")
3135
# pip_packages can be a string that is a path(str) to requirements.txt file or a list of packages.
3236
# The monai pkg is not required by this class, instead by the included operators.
3337
class AISpleennnUNetSegApp(Application):
34-
"""Demonstrates inference with built-in MONet Bundle inference operator with DICOM files as input/output
38+
"""Demonstrates inference with built-in MONAI nnUNet Bundle inference operator with DICOM files as input/output
3539
3640
This application loads a set of DICOM instances, select the appropriate series, converts the series to
37-
3D volume image, performs inference with the built-in MONet Bundle inference operator, including nnUNet resampling, pre-processing
41+
3D volume image, performs inference with the built-in MONAI nnUNet Bundle inference operator, including pre-processing
3842
and post-processing, save the segmentation image in a DICOM Seg OID in an instance file, and optionally the
3943
surface mesh in STL format.
4044
4145
Pertinent nnUNet MONAI Bundle:
4246
<Upload to the MONAI Model Zoo>
4347
4448
Execution Time Estimate:
45-
With a Nvidia RTXA600 48GB GPU, for an input DICOM Series of size 106x415x415 and patches of size 64x192x160, the execution time is around
46-
50 seconds with saving both DICOM Seg and surface mesh STL file.
49+
With a Nvidia RTXA600 48GB GPU, for an input DICOM Series of 139 instances, the execution time is around
50+
75 seconds with saving both DICOM Seg and surface mesh STL file.
4751
"""
4852

4953
def __init__(self, *args, **kwargs):
@@ -83,7 +87,7 @@ def compose(self):
8387

8488
config_names = BundleConfigNames(config_names=["inference"]) # Same as the default
8589

86-
bundle_spleen_seg_op = MONetBundleInferenceOperator(
90+
bundle_spleen_seg_op = MonainnUNetBundleInferenceOperator(
8791
self,
8892
input_mapping=[IOMapping("image", Image, IOType.IN_MEMORY)],
8993
output_mapping=[IOMapping("pred", Image, IOType.IN_MEMORY)],
@@ -158,6 +162,16 @@ def compose(self):
158162
"""
159163

160164
if __name__ == "__main__":
165+
# Creates the app and test it standalone. When running is this mode, please note the following:
166+
# -m <model file>, for model file path
167+
# -i <DICOM folder>, for input DICOM CT series folder
168+
# -o <output folder>, for the output folder, default $PWD/output
169+
# e.g.
170+
# monai-deploy exec app.py -i input -m model/model.ts
171+
#
172+
# export HOLOSCAN_INPUT_PATH=dcm
173+
# export HOLOSCAN_MODEL_PATH=spleen_model/model.ts
174+
# export HOLOSCAN_OUTPUT_PATH="output"
161175
logging.info(f"Begin {__name__}")
162176
AISpleennnUNetSegApp().run()
163177
logging.info(f"End {__name__}")

examples/apps/ai_spleen_nnunet_seg_app/app.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# limitations under the License.
1616
---
1717
application:
18-
title: MONAI Deploy App Package - Spleen MONet Seg Inference
18+
title: MONAI Deploy App Package - Spleen nnUNet Seg Inference
1919
version: 1.0
2020
inputFormats: ["file"]
2121
outputFormats: ["file"]

examples/apps/ai_spleen_nnunet_seg_app/requirements.txt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,5 @@ numpy-stl>=2.12.0
77
trimesh>=3.8.11
88
nibabel>=3.2.1
99
torch>=1.12.0
10-
nvflare
11-
git+https://github.com/SimoneBendazzoli93/dynamic-network-architectures.git
12-
git+https://github.com/SimoneBendazzoli93/MONAI.git@dev
13-
git+https://github.com/SimoneBendazzoli93/nnUNet.git
10+
monai>=1.0.0
11+
nnunetv2>=2.5.1

monai/deploy/operators/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
IOMapping
2626
ModelInfo
2727
MonaiBundleInferenceOperator
28-
MONetBundleInferenceOperator
28+
MonainnUNetBundleInferenceOperator
2929
MonaiSegInferenceOperator
3030
PNGConverterOperator
3131
PublisherOperator
@@ -48,8 +48,8 @@
4848
from .dicom_utils import EquipmentInfo, ModelInfo, random_with_n_digits, save_dcm_file, write_common_modules
4949
from .inference_operator import InferenceOperator
5050
from .monai_bundle_inference_operator import BundleConfigNames, IOMapping, MonaiBundleInferenceOperator
51+
from .monai_nnunet_bundle_inference_operator import MonainnUNetBundleInferenceOperator
5152
from .monai_seg_inference_operator import MonaiSegInferenceOperator
52-
from .monet_bundle_inference_operator import MONetBundleInferenceOperator
5353
from .nii_data_loader_operator import NiftiDataLoader
5454
from .png_converter_operator import PNGConverterOperator
5555
from .publisher_operator import PublisherOperator
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# Copyright 2002 MONAI Consortium
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
# Unless required by applicable law or agreed to in writing, software
7+
# distributed under the License is distributed on an "AS IS" BASIS,
8+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9+
# See the License for the specific language governing permissions and
10+
# limitations under the License.
11+
12+
from monai.deploy.operators.monai_bundle_inference_operator import MonaiBundleInferenceOperator, get_bundle_config
13+
from monai.deploy.utils.importutil import optional_import
14+
from typing import Any, Dict, Tuple, Union
15+
from monai.deploy.core import Image
16+
from pathlib import Path
17+
MONAI_UTILS = "monai.utils"
18+
nibabel, _ = optional_import("nibabel", "3.2.1")
19+
torch, _ = optional_import("torch", "1.10.2")
20+
21+
NdarrayOrTensor, _ = optional_import("monai.config", name="NdarrayOrTensor")
22+
MetaTensor, _ = optional_import("monai.data.meta_tensor", name="MetaTensor")
23+
PostFix, _ = optional_import("monai.utils.enums", name="PostFix") # For the default meta_key_postfix
24+
first, _ = optional_import("monai.utils.misc", name="first")
25+
ensure_tuple, _ = optional_import(MONAI_UTILS, name="ensure_tuple")
26+
convert_to_dst_type, _ = optional_import(MONAI_UTILS, name="convert_to_dst_type")
27+
Key, _ = optional_import(MONAI_UTILS, name="ImageMetaKey")
28+
MetaKeys, _ = optional_import(MONAI_UTILS, name="MetaKeys")
29+
SpaceKeys, _ = optional_import(MONAI_UTILS, name="SpaceKeys")
30+
Compose_, _ = optional_import("monai.transforms", name="Compose")
31+
ConfigParser_, _ = optional_import("monai.bundle", name="ConfigParser")
32+
MapTransform_, _ = optional_import("monai.transforms", name="MapTransform")
33+
SimpleInferer, _ = optional_import("monai.inferers", name="SimpleInferer")
34+
35+
Compose: Any = Compose_
36+
MapTransform: Any = MapTransform_
37+
ConfigParser: Any = ConfigParser_
38+
__all__ = ["MonainnUNetBundleInferenceOperator"]
39+
40+
41+
class MonainnUNetBundleInferenceOperator(MonaiBundleInferenceOperator):
42+
"""
43+
A specialized operator for performing inference using the MONAI nnUNet bundle.
44+
This operator extends the `MonaiBundleInferenceOperator` to support nnUNet-specific
45+
configurations and prediction logic. It initializes the nnUNet predictor and provides
46+
a method for performing inference on input data.
47+
48+
Attributes
49+
----------
50+
_nnunet_predictor : torch.nn.Module
51+
The nnUNet predictor module used for inference.
52+
53+
Methods
54+
-------
55+
_init_config(config_names)
56+
Initializes the configuration for the nnUNet bundle, including parsing the bundle
57+
configuration and setting up the nnUNet predictor.
58+
predict(data, *args, **kwargs)
59+
Performs inference on the input data using the nnUNet predictor.
60+
"""
61+
62+
def __init__(
63+
self,
64+
*args,
65+
**kwargs,
66+
):
67+
68+
69+
super().__init__(*args, **kwargs)
70+
71+
self._nnunet_predictor : torch.nn.Module = None
72+
73+
74+
def _init_config(self, config_names):
75+
76+
super()._init_config(config_names)
77+
parser = get_bundle_config(str(self._bundle_path), config_names)
78+
parser['bundle_root'] = str(Path(self._bundle_path).parent.parent.parent)
79+
self._parser = parser
80+
81+
self._nnunet_predictor = parser.get_parsed_content("network_def")
82+
83+
def predict(self, data: Any, *args, **kwargs) -> Union[Image, Any, Tuple[Any, ...], Dict[Any, Any]]:
84+
"""Predicts output using the inferer."""
85+
86+
self._nnunet_predictor.predictor.network = self._model_network
87+
#os.environ['nnUNet_def_n_proc'] = "1"
88+
return self._nnunet_predictor(torch.unsqueeze(data, 0))

0 commit comments

Comments
 (0)