-Currently, `nvcr.io/nvidia/pytorch:22.08-py3` base Docker image is used by [MONAI Application Packager](/developing_with_sdk/packaging_app) by default.
+Currently, `nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu` base Docker image is used by [MONAI Application Packager](/developing_with_sdk/packaging_app) by default for X86-64 in Linux system.
-The image size is large so please pull the image in advance to save time.
+The base image size is large so please pull the image in advance to save time. Note that the container image tag in the following example, e.g. v0.6.0, corresponds to the SDK version.
```bash
-docker pull nvcr.io/nvidia/pytorch:22.08-py3
+docker pull nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu
```
:::
diff --git a/docs/source/getting_started/tutorials/index.md b/docs/source/getting_started/tutorials/index.md
index 3a1d8395..0c21815e 100644
--- a/docs/source/getting_started/tutorials/index.md
+++ b/docs/source/getting_started/tutorials/index.md
@@ -7,7 +7,7 @@
simple_app
mednist_app
monai_bundle_app
-segmentation_app
segmentation_clara-viz_app
multi_model_app
+segmentation_app
```
diff --git a/docs/source/getting_started/tutorials/mednist_app.md b/docs/source/getting_started/tutorials/mednist_app.md
index 8e950b8d..6389da82 100644
--- a/docs/source/getting_started/tutorials/mednist_app.md
+++ b/docs/source/getting_started/tutorials/mednist_app.md
@@ -7,8 +7,6 @@ This tutorial demos the process of packaging up a trained model using MONAI Depl
```bash
# Create a virtual environment with Python 3.8.
# Skip if you are already in a virtual environment.
-# (JupyterLab dropped its support for Python 3.6 since 2021-12-23.
-# See https://github.com/jupyterlab/jupyterlab/pull/11740)
conda create -n mednist python=3.8 pytorch jupyterlab cudatoolkit=11.1 -c pytorch -c conda-forge
conda activate mednist
@@ -71,32 +69,42 @@ pip install monai-deploy-app-sdk
pip install gdown
gdown https://drive.google.com/uc?id=1yJ4P-xMNEfN6lIOq_u6x1eMAq1_MJu-E
-# After downloading mednist_classifier_data.zip from the web browser or using gdown,
+# After downloading mednist_classifier_data.zip from the web browser or using gdown
unzip -o mednist_classifier_data.zip
-# Install necessary packages from the app
-pip install monai Pillow
+# Install necessary packages required by the app
+pip install -r examples/apps/mednist_classifier_monaideploy/requirements.txt
-# Local execution of the app
-python examples/apps/mednist_classifier_monaideploy/mednist_classifier_monaideploy.py -i input/AbdomenCT_007000.jpeg -o output -m classifier.zip
+# Local execution of the app using environment variables for input, output, and model paths
+# instead of command line options, `-i input/AbdomenCT_007000.jpeg -o output -m classifier.zip`
+export HOLOSCAN_INPUT_PATH="input/AbdomenCT_007000.jpeg"
+export HOLOSCAN_MODEL_PATH="classifier.zip"
+export HOLOSCAN_OUTPUT_PATH="output"
+
+python examples/apps/mednist_classifier_monaideploy/mednist_classifier_monaideploy.py
+
+# See the classification result
+cat output/output.json
# Package app (creating MAP docker image) using `-l DEBUG` option to see progress.
# This assumes that nvidia docker is installed in the local machine.
# Please see https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#docker to install nvidia-docker2.
+
+# Need to move the model file to a clean folder as a workaround of an known packaging issue in v0.6
+mkdir -p mednist_model && rm -rf mednist_model/* && cp classifier.zip mednist_model/
+
monai-deploy package examples/apps/mednist_classifier_monaideploy/mednist_classifier_monaideploy.py \
+ --config examples/apps/mednist_classifier_monaideploy/app.yaml \
--tag mednist_app:latest \
- --model classifier.zip \
+ --models mednist_model/classifier.zip \
+ --platform x64-workstation \
-l DEBUG
-# For AMD GPUs, nvidia-docker is not required. Use --base [base image] option to override the docker base image.
-# Please see https://hub.docker.com/r/rocm/pytorch for rocm/pytorch docker images.
-monai-deploy package -b rocm/pytorch:rocm5.4.1_ubuntu20.04_py3.7_pytorch_1.12.1 \
- examples/apps/mednist_classifier_monaideploy/mednist_classifier_monaideploy.py \
- --tag mednist_app:latest \
- --model classifier.zip \
- -l DEBUG
+# Note: for AMD GPUs, nvidia-docker is not required, but the dependency of the App SDK, namely Holoscan SDK
+# has not been tested to work with a ROCM base image.
# Run the app with docker image and input file locally
-monai-deploy run mednist_app:latest input output
+rm -rf output
+monai-deploy run mednist_app-x64-workstation-dgpu-linux-amd64:latest -i input -o output
cat output/output.json
```
diff --git a/docs/source/getting_started/tutorials/monai_bundle_app.md b/docs/source/getting_started/tutorials/monai_bundle_app.md
index 582ba5f4..9a05c34e 100644
--- a/docs/source/getting_started/tutorials/monai_bundle_app.md
+++ b/docs/source/getting_started/tutorials/monai_bundle_app.md
@@ -7,8 +7,6 @@ This tutorial shows how to create an organ segmentation application for a PyTorc
```bash
# Create a virtual environment with Python 3.8.
# Skip if you are already in a virtual environment.
-# (JupyterLab dropped its support for Python 3.6 since 2021-12-23.
-# See https://github.com/jupyterlab/jupyterlab/pull/11740)
conda create -n monai python=3.8 pytorch torchvision jupyterlab cudatoolkit=11.1 -c pytorch -c conda-forge
conda activate monai
@@ -21,13 +19,25 @@ jupyter-lab
```{toctree}
:maxdepth: 4
-../../notebooks/tutorials/06_monai_bundle_app.ipynb
+../../notebooks/tutorials/04_monai_bundle_app.ipynb
+```
+
+```{raw} html
+
+ VIDEO
+
+```
+
+```{raw} html
+
+ VIDEO
+
```
```{raw} html
-
- Download 06_monai_bundle_app.ipynb
+
+ Download 04_monai_bundle_app.ipynb
```
@@ -49,27 +59,40 @@ pip install --upgrade monai-deploy-app-sdk
pip install gdown
gdown https://drive.google.com/uc?id=1Uds8mEvdGNYUuvFpTtCQ8gNU97bAPCaQ
-# After downloading it using gdown, unzip the zip file saved by gdown
+# After downloading it using gdown, unzip the zip file saved by gdown and
+# copy the model file into a folder structure that is required by CLI Packager
+rm -rf dcm
unzip -o ai_spleen_seg_bundle_data.zip
+rm -rf spleen_model && mkdir -p spleen_model && mv model.ts spleen_model && ls spleen_model
# Install necessary packages from the app; note that numpy-stl and trimesh are only
# needed if the application uses the STL Conversion Operator
pip install monai torch pydicom highdicom SimpleITK Pillow nibabel scikit-image numpy-stl trimesh
+# Use env variables for input, output, and model paths for local running of Python application
+export HOLOSCAN_INPUT_PATH=dcm
+export HOLOSCAN_MODEL_PATH=spleen_model/model.ts
+export HOLOSCAN_OUTPUT_PATH="output"
+export HOLOSCAN_LOG_LEVEL=TRACE
+
# Local execution of the app directly or using MONAI Deploy CLI
-python examples/apps/ai_spleen_seg_app/app.py -i dcm/ -o output -m model.ts
-# or alternatively,
-monai-deploy exec ../examples/apps/ai_spleen_seg_app/app.py -i dcm/ -o output -m model.ts
+python examples/apps/ai_spleen_seg_app/app.py
# Package app (creating MAP docker image) using `-l DEBUG` option to see progress.
# This assumes that nvidia docker is installed in the local machine.
# Please see https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#docker to install nvidia-docker2.
-monai-deploy package examples/apps/ai_spleen_seg_app --tag seg_app:latest --model model.ts -l DEBUG
+monai-deploy package examples/apps/ai_spleen_seg_app \
+ --config examples/apps/ai_spleen_seg_app/app.yaml \
+ --tag seg_app:latest \
+ --models spleen_model/model.ts \
+ --platform x64-workstation \
+ -l DEBUG
-# For AMD GPUs, nvidia-docker is not required. Use --base [base image] option to override the docker base image.
-# Please see https://hub.docker.com/r/rocm/pytorch for rocm/pytorch docker images.
-monai-deploy package -b rocm/pytorch:rocm5.4.1_ubuntu20.04_py3.7_pytorch_1.12.1 examples/apps/ai_spleen_seg_app --tag seg_app:latest --model model.ts -l DEBUG
+# Note: for AMD GPUs, nvidia-docker is not required, but the dependency of the App SDK, namely Holoscan SDK
+# has not been tested to work with a ROCM base image.
# Run the app with docker image and input file locally
-monai-deploy run seg_app:latest dcm/ output
+rm -rf output
+monai-deploy run seg_app-x64-workstation-dgpu-linux-amd64:latest -i dcm -o output
+ls -R output
```
diff --git a/docs/source/getting_started/tutorials/multi_model_app.md b/docs/source/getting_started/tutorials/multi_model_app.md
index 307cb6f1..d91629cc 100644
--- a/docs/source/getting_started/tutorials/multi_model_app.md
+++ b/docs/source/getting_started/tutorials/multi_model_app.md
@@ -1,4 +1,4 @@
-# Creating a Segmentation App Consuming a MONAI Bundle
+# Creating a Segmentation App Supporting Multiple Models
This tutorial shows how to create an inference application with multiple models, focusing on model files organization, inferring with named model in the application, and packaging.
@@ -9,8 +9,6 @@ The models used in this example are trained with MONAI, and are packaged in the
```bash
# Create a virtual environment with Python 3.8.
# Skip if you are already in a virtual environment.
-# (JupyterLab dropped its support for Python 3.6 since 2021-12-23.
-# See https://github.com/jupyterlab/jupyterlab/pull/11740)
conda create -n monai python=3.8 pytorch torchvision jupyterlab cudatoolkit=11.1 -c pytorch -c conda-forge
conda activate monai
@@ -23,13 +21,13 @@ jupyter-lab
```{toctree}
:maxdepth: 4
-../../notebooks/tutorials/07_multi_model_app.ipynb
+../../notebooks/tutorials/05_multi_model_app.ipynb
```
```{raw} html
-
- Download 07_multi_model_app.ipynb
+
+ Download 05_multi_model_app.ipynb
```
@@ -50,26 +48,37 @@ pip install gdown
gdown https://drive.google.com/uc?id=1llJ4NGNTjY187RLX4MtlmHYhfGxBNWmd
# After downloading it using gdown, unzip the zip file saved by gdown
+rm -rf dcm && rm -rf multi_models
unzip -o ai_multi_model_bundle_data.zip
# Install necessary packages from the app; note that numpy-stl and trimesh are only
# needed if the application uses the STL Conversion Operator
pip install monai torch pydicom highdicom SimpleITK Pillow nibabel scikit-image numpy-stl trimesh
-# Local execution of the app directly or using MONAI Deploy CLI
-python examples/apps/examples/apps/ai_multi_ai_app/app.py -i dcm/ -o output -m multip_models
-# or alternatively,
-monai-deploy exec ../examples/apps/examples/apps/ai_multi_ai_app/app.py -i dcm/ -o output -m multip_models
+# Use env variables for input, output, and model paths for local running of Python application
+export HOLOSCAN_INPUT_PATH=dcm
+export HOLOSCAN_MODEL_PATH=multi_models
+export HOLOSCAN_OUTPUT_PATH="output"
+export HOLOSCAN_LOG_LEVEL=TRACE
+
+# Local execution of the app directly
+python examples/apps/ai_multi_ai_app/app.py
# Package app (creating MAP docker image) using `-l DEBUG` option to see progress.
# This assumes that nvidia docker is installed in the local machine.
# Please see https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#docker to install nvidia-docker2.
-monai-deploy package -b nvcr.io/nvidia/pytorch:22.08-py3 examples/apps/ai_multi_ai_app --tag multi_model_app:latest --model multi_models -l DEBUG
+monai-deploy package examples/apps/ai_multi_ai_app \
+ --tag multi_model_app:latest \
+ --config examples/apps/ai_multi_ai_app/app.yaml \
+ --models multi_models \
+ --platform x64-workstation \
+ -l DEBUG
-# For AMD GPUs, nvidia-docker is not required. Use --base [base image] option to override the docker base image.
-# Please see https://hub.docker.com/r/rocm/pytorch for rocm/pytorch docker images.
-monai-deploy package -b rocm/pytorch:rocm5.4.1_ubuntu20.04_py3.7_pytorch_1.12.1 examples/apps/ai_multi_ai_app --tag multi_model_app:latest --model multi_models -l DEBUG
+# Note: for AMD GPUs, nvidia-docker is not required, but the dependency of the App SDK, namely Holoscan SDK
+# has not been tested to work with a ROCM base image.
# Run the app with docker image and input file locally
-monai-deploy run multi_model_app:latest dcm/ output
+rm -rf output
+monai-deploy run multi_model_app-x64-workstation-dgpu-linux-amd64:latest -i dcm -o output
+ls -R output
```
diff --git a/docs/source/getting_started/tutorials/segmentation_app.md b/docs/source/getting_started/tutorials/segmentation_app.md
index 49ef72f5..d19147d7 100644
--- a/docs/source/getting_started/tutorials/segmentation_app.md
+++ b/docs/source/getting_started/tutorials/segmentation_app.md
@@ -1,14 +1,14 @@
-# Creating a Segmentation App
+# Creating a Segmentation App with a TorchScript Model
-This tutorial shows how to create an organ segmentation application for a PyTorch model that has been trained with MONAI. Please note that the example code used in the Jupyter Notebook is based on an earlier version of the segmentation application, i.e., not using MONAI Bundle Inference Operator, and the code is not necessarily the same as the latest source code on Github.
+This tutorial shows how to create an organ segmentation application for a PyTorch model that has been trained with MONAI and saved as TorchScript, without necessarily being a MONAI bundle.
+
+Please note that the following steps are for demonstration purpose. The code pulled from GitHub is not the same as that in the actual Jupyter Notebook, which deliberately does not use the MONAI Bundle Inference Operator.
## Setup
```bash
# Create a virtual environment with Python 3.8.
# Skip if you are already in a virtual environment.
-# (JupyterLab dropped its support for Python 3.6 since 2021-12-23.
-# See https://github.com/jupyterlab/jupyterlab/pull/11740)
conda create -n monai python=3.8 pytorch torchvision jupyterlab cudatoolkit=11.1 -c pytorch -c conda-forge
conda activate monai
@@ -24,18 +24,6 @@ jupyter-lab
../../notebooks/tutorials/03_segmentation_app.ipynb
```
-```{raw} html
-
- VIDEO
-
-```
-
-```{raw} html
-
- VIDEO
-
-```
-
```{raw} html
@@ -61,25 +49,40 @@ pip install --upgrade monai-deploy-app-sdk
pip install gdown
gdown https://drive.google.com/uc?id=1Uds8mEvdGNYUuvFpTtCQ8gNU97bAPCaQ
-# After downloading it using gdown, unzip the zip file saved by gdown
+# After downloading it using gdown, unzip the zip file saved by gdown and
+# copy the model file into a folder structure that is required by CLI Packager
+rm -rf dcm
unzip -o ai_spleen_seg_bundle_data.zip
+rm -rf spleen_model && mkdir -p spleen_model && mv model.ts spleen_model && ls spleen_model
# Install necessary packages from the app; note that numpy-stl and trimesh are only
# needed if the application uses the STL Conversion Operator
-pip install monai pydicom highdicom SimpleITK Pillow nibabel scikit-image numpy-stl trimesh
+pip install monai torch pydicom highdicom SimpleITK Pillow nibabel scikit-image numpy-stl trimesh
+
+# Use env variables for input, output, and model paths for local running of Python application
+export HOLOSCAN_INPUT_PATH=dcm
+export HOLOSCAN_MODEL_PATH=spleen_model/model.ts
+export HOLOSCAN_OUTPUT_PATH="output"
+export HOLOSCAN_LOG_LEVEL=TRACE
-# Local execution of the app
-python examples/apps/ai_spleen_seg_app/app.py -i dcm/ -o output -m model.ts
+# Local execution of the app directly or using MONAI Deploy CLI
+python examples/apps/ai_spleen_seg_app/app.py
# Package app (creating MAP docker image) using `-l DEBUG` option to see progress.
# This assumes that nvidia docker is installed in the local machine.
# Please see https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#docker to install nvidia-docker2.
-monai-deploy package examples/apps/ai_spleen_seg_app --tag seg_app:latest --model model.ts -l DEBUG
+monai-deploy package examples/apps/ai_spleen_seg_app \
+ --config examples/apps/ai_spleen_seg_app/app.yaml \
+ --tag seg_app:latest \
+ --models spleen_model/model.ts \
+ --platform x64-workstation \
+ -l DEBUG
-# For AMD GPUs, nvidia-docker is not required. Use --base [base image] option to override the docker base image.
-# Please see https://hub.docker.com/r/rocm/pytorch for rocm/pytorch docker images.
-monai-deploy package -b rocm/pytorch:rocm5.4.1_ubuntu20.04_py3.7_pytorch_1.12.1 examples/apps/ai_spleen_seg_app --tag seg_app:latest --model model.ts -l DEBUG
+# Note: for AMD GPUs, nvidia-docker is not required, but the dependency of the App SDK, namely Holoscan SDK
+# has not been tested to work with a ROCM base image.
# Run the app with docker image and input file locally
-monai-deploy run seg_app:latest dcm/ output
+rm -rf output
+monai-deploy run seg_app-x64-workstation-dgpu-linux-amd64:latest -i dcm -o output
+ls -R output
```
diff --git a/docs/source/getting_started/tutorials/segmentation_clara-viz_app.md b/docs/source/getting_started/tutorials/segmentation_clara-viz_app.md
index 63edda0f..3058d0df 100644
--- a/docs/source/getting_started/tutorials/segmentation_clara-viz_app.md
+++ b/docs/source/getting_started/tutorials/segmentation_clara-viz_app.md
@@ -1,14 +1,12 @@
# Creating a Segmentation App Including Including Visualization with Clara-Viz
-This tutorial shows how to create an organ segmentation application for a PyTorch model that has been trained with MONAI, and visualize the segmentation and input images with Clara Viz integration.
+This tutorial shows how to create an organ segmentation application for a PyTorch model that has been trained with MONAI, and provide interactive visualization of the segmentation and input images with Clara Viz integration.
## Setup
```bash
# Create a virtual environment with Python 3.8.
# Skip if you are already in a virtual environment.
-# (JupyterLab dropped its support for Python 3.6 since 2021-12-23.
-# See https://github.com/jupyterlab/jupyterlab/pull/11740)
conda create -n monai python=3.8 pytorch torchvision jupyterlab cudatoolkit=11.1 -c pytorch -c conda-forge
conda activate monai
diff --git a/docs/source/getting_started/tutorials/simple_app.md b/docs/source/getting_started/tutorials/simple_app.md
index f19f7856..78a62242 100644
--- a/docs/source/getting_started/tutorials/simple_app.md
+++ b/docs/source/getting_started/tutorials/simple_app.md
@@ -1,14 +1,12 @@
-# Creating a simple image processing app
+# Creating a Simple Image Processing App
-This tutorial shows how to develop a simple image processing application can be created with MONAI Deploy App SDK.
+This tutorial shows how a simple image processing application can be created with MONAI Deploy App SDK.
## Setup
```bash
# Create a virtual environment with Python 3.8.
# Skip if you are already in a virtual environment.
-# (JupyterLab dropped its support for Python 3.6 since 2021-12-23.
-# See https://github.com/jupyterlab/jupyterlab/pull/11740)
conda create -n monai python=3.8 pytorch torchvision jupyterlab cudatoolkit=11.1 -c pytorch -c conda-forge
conda activate monai
@@ -49,25 +47,34 @@ cd monai-deploy-app-sdk
# Install monai-deploy-app-sdk package
pip install monai-deploy-app-sdk
-# Install necessary packages from the app
+# Install necessary packages from the app. Can simply run `pip install -r examples/apps/simple_imaging_app/requirements.txt`
pip install scikit-image
+pip install setuptools
-# Local execution of the app
-python examples/apps/simple_imaging_app/app.py -i examples/apps/simple_imaging_app/brain_mr_input.jpg -o output
+# See the input file exists in the default `input`` folder in the current working directory
+ls examples/apps/simple_imaging_app/input/
+
+# Local execution of the app with output file in the `output` folder in the current working directory
+python examples/apps/simple_imaging_app/app.py
# Check the output file
ls output
-# Package app (creating MAP docker image) using `-l DEBUG` option to see progress.
+# Package app (creating MAP docker image) using `-l DEBUG` option to see progress. Note the container image name is postfixed with platform info.
# This assumes that nvidia docker is installed in the local machine.
# Please see https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#docker to install nvidia-docker2.
-monai-deploy package examples/apps/simple_imaging_app -t simple_app:latest -l DEBUG
+monai-deploy package examples/apps/simple_imaging_app -c examples/apps/simple_imaging_app/app.yaml -t simple_app:latest --platform x64-workstation -l DEBUG
+
+# Show the application and package manifest files of the MONAI Application Package
+
+docker images | grep simple_app
+docker run --rm simple_app-x64-workstation-dgpu-linux-amd64:latest show
-# Copy a test input file to 'input' folder
-mkdir -p input && rm -rf input/*
-cp examples/apps/simple_imaging_app/brain_mr_input.jpg input/
+# Run the MAP container image with MONAI Deploy MAP Runner, with a cleaned output folder
+rm -rf output
+monai-deploy run simple_app-x64-workstation-dgpu-linux-amd64:latest -i input -o output
-# Run the app with docker image and input file locally
-monai-deploy run simple_app:latest input output
+# Check the output file
+ls output
```
diff --git a/docs/source/introduction/architecture.md b/docs/source/introduction/architecture.md
index 40422f11..711951a1 100644
--- a/docs/source/introduction/architecture.md
+++ b/docs/source/introduction/architecture.md
@@ -26,18 +26,18 @@ The core development-time concept in the MONAI Deploy App SDK is an inference ap
The user is encouraged to structure the application code in a way that enables reproducibility and debuggability. In contrast, the SDK itself is designed to minimize concerns related to production readiness during development time. Optimally, the user can write idiomatic Python code focusing on the logic itself and the guard rails of the framework enable the code to be production-ready.
-**Application**: An application represents a collection of computational tasks that together accomplish a meaningful goal in the healthcare domain. Typically, an app defines a workflow that reads medical imaging data from disk, processes it in one or more operators (some of which could be AI inference related), and produces output data. User implements an app by subclassing [Application](/modules/_autosummary/monai.deploy.core.Application) class. An app makes use of instances of Operators as stages in the application.
+**Application**: An application represents a collection of computational tasks that together accomplish a meaningful goal in the healthcare domain. Typically, an app defines a workflow that reads medical imaging data from disk, processes it in one or more [operators](/modules/_autosummary/monai.deploy.core.Operator) (some of which could be AI inference related), and produces output data. User implements an app by subclassing [Application](/modules/_autosummary/monai.deploy.core.Application) class. An app makes use of instances of Operators as stages in the application.
-**Graph**: The SDK provides a mechanism to define a directed acyclic graph (through [Graph](/modules/_autosummary/monai.deploy.core.graphs.Graph) class) which can be composed of operators. This acyclic property is important, as it prevents the framework from running into circular dependencies between operators. The graph consists of one or more vertices and edges, with each edge directed from one vertex to another, such that there is no way to start at any vertex and follow a consistently directed sequence of edges that eventually loops back to the same vertex again. Each vertex in the graph represents an Operator. The edge between two operators contains connectivity information.
+**Graph**: The SDK provides a mechanism to define a directed acyclic graph (through [Graph](/modules/graphs) classes) which can be composed of operators. This acyclic property is important, as it prevents the framework from running into circular dependencies between operators. The graph consists of one or more vertices and edges, with each edge directed from one vertex to another, such that there is no way to start at any vertex and follow a consistently directed sequence of edges that eventually loops back to the same vertex again. Each vertex in the graph represents an Operator. The edge between two operators contains connectivity information.
-**Operator**: An operator is the smallest unit of computation. It is implemented by the user by inheriting a class from the [Operator](/modules/_autosummary/monai.deploy.core.Operator). An operator is an element of a MONAI Deploy Application. Each operator is typically designed to perform a specific function/analysis on incoming input data. Common examples of such functions are: reading images from disk, performing image processing, performing AI inference, writing images to disk, etc. The SDK comes with a bundled set of operators.
+**Operator**: An operator is the smallest unit of computation. It is implemented by the user by inheriting a class from the [Operator](/modules/_autosummary/monai.deploy.core.Operator). An operator is an element of a MONAI Deploy Application. Each operator is typically designed to perform a specific function/analysis on incoming input data. Common examples of such functions are: reading images from disk, performing image processing, performing AI inference, writing images to disk, etc. The SDK comes with a bundled set of [operators](/modules/_autosummary/monai.deploy.operators).
+
+**Executor**: An executor in the SDK is an entity that ingests an Application, parses the Directed Acyclic Graph inside it, and executes the operators in the specified order. The SDK has provisions to support multiple types of [Executors](modules/executors) depending on single/multi-process and execution order needs. The same executor executes the application either directly on the host system or in a MAP as a containerized application.
### Run-Time Concepts
The core runtime concepts in the MONAI Deploy App SDK are the MONAI Application Package (MAP) and a MONAI Application Runner (MAR). A key design decision of the SDK is to make the framework runtime-agnostic. The same code should be runnable in various environments, such as on a workstation during development or on a production-ready workflow orchestrator during production.
-**MONAI Application Packager**: Once an application is built using the MONAI App SDK, it can be packaged into a portable [MONAI Application Package (MAP)](https://github.com/Project-MONAI/monai-deploy/blob/main/guidelines/monai-application-package.md). A MAP contains an executable application & provides sufficient information to execute the application as intended. It consists of a single container and metadata that provides additional information about the application. A MAP is self-describing and provides a mechanism for extracting its description. It provides information about its expected inputs such that an external agent is able to determine if the MAP is capable of receiving a workload. The containerized portion of a MAP complies with Open Container Initiative (OCI) format standards. The [MONAI Application Packager](/developing_with_sdk/packaging_app) utility helps developers to package an app written using the SDK into a MAP.
-
-**Executor**: An executor in the SDK is an entity that ingests an Application, parses the Directed Acyclic Graph inside it, and executes the operators in the specified order. The SDK has provisions to support multiple types of Executors depending on single/multi-process and execution order needs.
+**MONAI Application Packager**: Once an application is built using the MONAI App SDK, it can be packaged into a portable [MONAI Application Package (MAP)](https://github.com/Project-MONAI/monai-deploy/blob/main/guidelines/monai-application-package.md). A MAP contains an executable application and provides sufficient information to execute the application as intended. As such, it consists of a single container image with embedded metadata to describe the additional information about the application, along with a mechanism for extracting the contents. For example, it provides information about its expected inputs such that an external agent is able to determine if the MAP is capable of receiving a workload. The MAP container image also complies with [Open Container Initiative (OCI)](https://opencontainers.org/) format standards. To ensure consistency and ease of use, the [MONAI Application Packager](/developing_with_sdk/packaging_app) utility is provided to help developers to package an app written using the SDK into a MAP.
**MONAI Application Runner**: The [MONAI Application Runner (MAR)](/developing_with_sdk/executing_packaged_app_locally) is a command-line utility that allows users to run and test their MONAI Application Package (MAP) locally. MAR is developed to make the running and testing of MAPs locally an easy process for developers by abstracting away the need to understand the internal details of the MAP. MAR allows users to specify input and output paths on the local file system which it maps to the input and output of MAP during execution.
diff --git a/docs/source/introduction/overview.md b/docs/source/introduction/overview.md
index 90900fdd..742f343e 100644
--- a/docs/source/introduction/overview.md
+++ b/docs/source/introduction/overview.md
@@ -5,7 +5,7 @@ The MONAI Deploy Application SDK offers a framework and associated tools to desi
It contains the following elements:
- Pythonic framework for app development
-- A mechanism to package an app in a "MONAI Application Package" (MAP) instance
+- A mechanism to package an app in a "MONAI Application Package" (MAP), a container image that is self-describing
- A mechanism to locally run a MAP via App Runner
- A set of sample applications
- API documentation
@@ -17,9 +17,10 @@ To further accelerate the development of medical imaging AI inference applicatio
- DICOM Segmentation
- DICOM Basic Text Structured Report
- DICOM Encapsulated PDF
- - more are coming
+ - and more to come
:::{note}
+- Starting with release v0.6, the core modules are dependent on the Python SDK of [Nvidia Holoscan](https://docs.nvidia.com/holoscan-sdk/index.html), for its enterprise grade optimized libraries for data processing and AI, and core microservices to run surgical video, ultrasound, medical imaging, and other applications anywhere, from embedded to edge to cloud. A list of its modules are directly exposed through this SDK's namespace, `monai.deploy`. Domain specific operators from previous releases, e.g. DICOM parsing and writing, remain naive to this App SDK, and have been updated to be compatible with the `holoscan` based core modules.
- The software and the imaging AI results generated are for research use only, and per applicable laws and regulations, are not for clinical use.
-- The App SDK, and specifically the DICOM instance writers, rely upon the underlying operating system to provide accurate and consistent time, though have no direct control over how the OS performs time synchronization, e.g. NTP on Ubuntu. For creation of DICOM or HL7 objects that use time, the built-in classes do, and it would also be incumbent on the developer to appropriately use the available system time service and reflect the correct time in those objects properly. Additionally, the DICOM instance generated by the App SDK built-in classes set the Timezone Offset From UTC with the underlying operating system's timezone setting.
+- The App SDK, and specifically the DICOM instance writers, rely upon the underlying operating system to provide accurate and consistent time, and have no direct control over how the OS performs time synchronization, e.g. NTP on Ubuntu. It would be incumbent on the developer to appropriately use the available system time service and reflect the correct time in those objects properly. Additionally, the DICOM instance generated by the App SDK built-in classes set the [Timezone Offset From UTC](https://dicom.nema.org/medical/dicom/2020b/output/chtml/part03/sect_C.12.5.html) with the underlying operating system's timezone setting.
:::
\ No newline at end of file
diff --git a/docs/source/introduction/roadmap.md b/docs/source/introduction/roadmap.md
index fc93da03..bde0bf6b 100644
--- a/docs/source/introduction/roadmap.md
+++ b/docs/source/introduction/roadmap.md
@@ -2,4 +2,4 @@
The first versions of the MONAI Deploy App SDK offer a core framework to build & package healthcare AI apps so that they can be deployed to a production environment.
-We are currently in the process of refining the roadmap for the product based on the community’s input, though it is clear that on the roadmap are more built-in DICOM parsing and DICOM OID generation capabilities to better support IHE AIR profiles , as well as serving model network in a separate process.
+We are currently in the process of refining the roadmap for the product based on the community’s input, though it is clear that on the roadmap are more built-in DICOM parsing and DICOM OID generation capabilities to better support [IHE AIR profiles](https://www.ihe.net/uploadedFiles/Documents/Radiology/IHE_RAD_Suppl_AIR_Rev1-2_TI_2022-07-06.pdf), as well as serving model network in a separate process using [Triton](https://developer.nvidia.com/triton-inference-server).
diff --git a/docs/source/modules/executors.md b/docs/source/modules/executors.md
index 34874bd9..ea3c5e77 100644
--- a/docs/source/modules/executors.md
+++ b/docs/source/modules/executors.md
@@ -1,5 +1,7 @@
# Executors
+Please see Holoscan SDK Python API for classes that are in this module.
+
```{eval-rst}
.. automodule:: monai.deploy.core.executors
:noindex:
diff --git a/docs/source/modules/graphs.md b/docs/source/modules/graphs.md
index 001ff367..d1062293 100644
--- a/docs/source/modules/graphs.md
+++ b/docs/source/modules/graphs.md
@@ -1,5 +1,7 @@
# Graphs
+Please see Holoscan SDK Python API for classes that are in this module.
+
```{eval-rst}
.. automodule:: monai.deploy.core.graphs
:noindex:
diff --git a/docs/source/modules/index.md b/docs/source/modules/index.md
index dc02aa9a..53e460fb 100644
--- a/docs/source/modules/index.md
+++ b/docs/source/modules/index.md
@@ -5,10 +5,10 @@
:maxdepth: 2
core
+conditions
domain_objects
operators
models
-graphs
executors
-datastores
+graphs
```
diff --git a/docs/source/modules/operators.md b/docs/source/modules/operators.md
index ac26cb39..61d8435b 100644
--- a/docs/source/modules/operators.md
+++ b/docs/source/modules/operators.md
@@ -1,5 +1,7 @@
# Operators
+Please also see Holoscan SDK Python API for additional operators that are exposed in this module.
+
```{eval-rst}
.. automodule:: monai.deploy.operators
:noindex:
diff --git a/examples/apps/ai_livertumor_seg_app/__init__.py b/examples/apps/ai_livertumor_seg_app/__init__.py
index 521cb31b..526cee59 100644
--- a/examples/apps/ai_livertumor_seg_app/__init__.py
+++ b/examples/apps/ai_livertumor_seg_app/__init__.py
@@ -1,3 +1,14 @@
+# Copyright 2021-2023 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 os
import sys
diff --git a/examples/apps/ai_livertumor_seg_app/__main__.py b/examples/apps/ai_livertumor_seg_app/__main__.py
index 66210d58..1c645901 100644
--- a/examples/apps/ai_livertumor_seg_app/__main__.py
+++ b/examples/apps/ai_livertumor_seg_app/__main__.py
@@ -1,4 +1,19 @@
+# Copyright 2021-2023 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 logging
+
from app import AILiverTumorApp
if __name__ == "__main__":
- AILiverTumorApp(do_run=True)
+ logging.info(f"Begin {__name__}")
+ AILiverTumorApp().run()
+ logging.info(f"End {__name__}")
diff --git a/examples/apps/ai_livertumor_seg_app/app.py b/examples/apps/ai_livertumor_seg_app/app.py
index 662c5fbb..32707e5c 100644
--- a/examples/apps/ai_livertumor_seg_app/app.py
+++ b/examples/apps/ai_livertumor_seg_app/app.py
@@ -1,4 +1,4 @@
-# Copyright 2021 MONAI Consortium
+# Copyright 2021-2023 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
@@ -10,44 +10,25 @@
# limitations under the License.
import logging
+from pathlib import Path
from livertumor_seg_operator import LiverTumorSegOperator
+from pydicom.sr.codedict import codes # Required for setting SegmentDescription attributes.
-# Required for setting SegmentDescription attributes. Direct import as this is not part of App SDK package.
-from pydicom.sr.codedict import codes
-
-from monai.deploy.core import Application, resource
+from monai.deploy.conditions import CountCondition
+from monai.deploy.core import AppContext, Application
from monai.deploy.operators.dicom_data_loader_operator import DICOMDataLoaderOperator
from monai.deploy.operators.dicom_seg_writer_operator import DICOMSegmentationWriterOperator, SegmentDescription
from monai.deploy.operators.dicom_series_selector_operator import DICOMSeriesSelectorOperator
from monai.deploy.operators.dicom_series_to_volume_operator import DICOMSeriesToVolumeOperator
-from monai.deploy.operators.publisher_operator import PublisherOperator
-
-# This is a sample series selection rule in JSON, simply selecting CT series.
-# If the study has more than 1 CT series, then all of them will be selected.
-# Please see more detail in DICOMSeriesSelectorOperator.
-# For list of string values, e.g. "ImageType": ["PRIMARY", "ORIGINAL"], it is a match if all elements
-# are all in the multi-value attribute of the DICOM series.
+from monai.deploy.operators.stl_conversion_operator import STLConversionOperator
-Sample_Rules_Text = """
-{
- "selections": [
- {
- "name": "CT Series",
- "conditions": {
- "Modality": "(?i)CT",
- "ImageType": ["PRIMARY", "ORIGINAL"],
- "PhotometricInterpretation": "MONOCHROME2"
- }
- }
- ]
-}
-"""
+# This sample example completes the processing of a DICOM series with around 600 instances within 45 seconds,
+# and time reduces to about 23 seconds if the STL generation is disabled,
+# on a desktop with Ubuntu 20.04, 32GB of RAM, and a Nvidia GPU GV100 with 32GB of memory.
-@resource(cpu=1, gpu=1, memory="7Gi")
-# pip_packages can be a string that is a path(str) to requirements.txt file or a list of packages.
-# The MONAI pkg is not required by this class, instead by the included operators.
+# @resource(cpu=1, gpu=1, memory="7Gi")
class AILiverTumorApp(Application):
def __init__(self, *args, **kwargs):
"""Creates an application instance."""
@@ -57,23 +38,35 @@ def __init__(self, *args, **kwargs):
def run(self, *args, **kwargs):
# This method calls the base class to run. Can be omitted if simply calling through.
- self._logger.debug(f"Begin {self.run.__name__}")
+ self._logger.info(f"Begin {self.run.__name__}")
super().run(*args, **kwargs)
- self._logger.debug(f"End {self.run.__name__}")
+ self._logger.info(f"End {self.run.__name__}")
def compose(self):
"""Creates the app specific operators and chain them up in the processing DAG."""
- self._logger.debug(f"Begin {self.compose.__name__}")
+ self._logger.info(f"Begin {self.compose.__name__}")
+ # Use command line options over environment variables to init context.
+ app_context: AppContext = Application.init_app_context(self.argv)
+ app_input_path = Path(app_context.input_path)
+ app_output_path = Path(app_context.output_path)
+ model_path = Path(app_context.model_path)
+
+ self._logger.info(f"App input and output path: {app_input_path}, {app_output_path}")
+
# Creates the custom operator(s) as well as SDK built-in operator(s).
- study_loader_op = DICOMDataLoaderOperator()
- series_selector_op = DICOMSeriesSelectorOperator(rules=Sample_Rules_Text)
- series_to_vol_op = DICOMSeriesToVolumeOperator()
+ study_loader_op = DICOMDataLoaderOperator(
+ self, CountCondition(self, 1), input_folder=app_input_path, name="dcm_loader_op"
+ )
+ series_selector_op = DICOMSeriesSelectorOperator(self, rules=Sample_Rules_Text, name="series_selector_op")
+ series_to_vol_op = DICOMSeriesToVolumeOperator(self, name="series_to_vol_op")
# Model specific inference operator, supporting MONAI transforms.
- liver_tumor_seg_op = LiverTumorSegOperator()
+ liver_tumor_seg_op = LiverTumorSegOperator(self, app_context=app_context, model_path=model_path, name="seg_op")
+ # self, model_path=model_path, output_folder=app_output_path, name="seg_op"
+ # )
- # Create the publisher operator
- publisher_op = PublisherOperator()
+ # Create the surface mesh STL conversion operator
+ stl_op = STLConversionOperator(self, output_file=app_output_path.joinpath("stl/mesh.stl"), name="stl_op")
# Create DICOM Seg writer providing the required segment description for each segment with
# the actual algorithm and the pertinent organ/tissue.
@@ -105,34 +98,52 @@ def compose(self):
),
]
- dicom_seg_writer = DICOMSegmentationWriterOperator(segment_descriptions)
+ dicom_seg_writer = DICOMSegmentationWriterOperator(
+ self, segment_descriptions=segment_descriptions, output_folder=app_output_path, name="dcm_seg_writer_op"
+ )
# Create the processing pipeline, by specifying the source and destination operators, and
# ensuring the output from the former matches the input of the latter, in both name and type.
- self.add_flow(study_loader_op, series_selector_op, {"dicom_study_list": "dicom_study_list"})
+ self.add_flow(study_loader_op, series_selector_op, {("dicom_study_list", "dicom_study_list")})
self.add_flow(
- series_selector_op, series_to_vol_op, {"study_selected_series_list": "study_selected_series_list"}
+ series_selector_op, series_to_vol_op, {("study_selected_series_list", "study_selected_series_list")}
)
- self.add_flow(series_to_vol_op, liver_tumor_seg_op, {"image": "image"})
- # Add the publishing operator to save the input and seg images for Render Server.
- # Note the PublisherOperator has temp impl till a proper rendering module is created.
- self.add_flow(liver_tumor_seg_op, publisher_op, {"saved_images_folder": "saved_images_folder"})
+ self.add_flow(series_to_vol_op, liver_tumor_seg_op, {("image", "image")})
+
# Note below the dicom_seg_writer requires two inputs, each coming from a source operator.
self.add_flow(
- series_selector_op, dicom_seg_writer, {"study_selected_series_list": "study_selected_series_list"}
+ series_selector_op, dicom_seg_writer, {("study_selected_series_list", "study_selected_series_list")}
)
- self.add_flow(liver_tumor_seg_op, dicom_seg_writer, {"seg_image": "seg_image"})
+ self.add_flow(liver_tumor_seg_op, dicom_seg_writer, {("seg_image", "seg_image")})
+
+ # Add the stl mesh operator to save the mesh in stl format.
+ self.add_flow(liver_tumor_seg_op, stl_op, {("seg_image", "image")})
- self._logger.debug(f"End {self.compose.__name__}")
+ self._logger.info(f"End {self.compose.__name__}")
+
+
+# This is a sample series selection rule in JSON, simply selecting CT series.
+# If the study has more than 1 CT series, then all of them will be selected.
+# Please see more detail in DICOMSeriesSelectorOperator.
+# For list of string values, e.g. "ImageType": ["PRIMARY", "ORIGINAL"], it is a match if all elements
+# are all in the multi-value attribute of the DICOM series.
+Sample_Rules_Text = """
+{
+ "selections": [
+ {
+ "name": "CT Series",
+ "conditions": {
+ "Modality": "(?i)CT",
+ "ImageType": ["PRIMARY", "ORIGINAL"],
+ "PhotometricInterpretation": "MONOCHROME2"
+ }
+ }
+ ]
+}
+"""
if __name__ == "__main__":
- # Creates the app and test it standalone. When running is this mode, please note the following:
- # -m , for model file path
- # -i , for input DICOM CT series folder
- # -o , for the output folder, default $PWD/output
- # e.g.
- # python3 app.py -i input -m model/model.ts
- #
- logging.basicConfig(level=logging.DEBUG)
- app_instance = AILiverTumorApp() # Optional params' defaults are fine.
- app_instance.run()
+ # Creates the app and test it standalone.
+ logging.info(f"Begin {__name__}")
+ AILiverTumorApp().run()
+ logging.info(f"End {__name__}")
diff --git a/examples/apps/ai_livertumor_seg_app/livertumor_seg_operator.py b/examples/apps/ai_livertumor_seg_app/livertumor_seg_operator.py
index ef96de36..db646827 100644
--- a/examples/apps/ai_livertumor_seg_app/livertumor_seg_operator.py
+++ b/examples/apps/ai_livertumor_seg_app/livertumor_seg_operator.py
@@ -1,4 +1,4 @@
-# Copyright 2021 MONAI Consortium
+# Copyright 2021-2023 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
@@ -10,11 +10,9 @@
# limitations under the License.
import logging
+from pathlib import Path
-from numpy import uint8
-
-import monai.deploy.core as md
-from monai.deploy.core import DataPath, ExecutionContext, Image, InputContext, IOType, Operator, OutputContext
+from monai.deploy.core import AppContext, ConditionType, Fragment, Operator, OperatorSpec
from monai.deploy.operators.monai_seg_inference_operator import InfererType, InMemImageReader, MonaiSegInferenceOperator
from monai.transforms import (
Activationsd,
@@ -24,99 +22,132 @@
EnsureChannelFirstd,
Invertd,
LoadImaged,
- SaveImaged,
ScaleIntensityRanged,
Spacingd,
)
+# from monai.transforms import SaveImaged # If saving input and seg images uding inference is needed.
+# from numpy import uint8 # Needed if SaveImaged is enabled
+
-@md.input("image", Image, IOType.IN_MEMORY)
-@md.output("seg_image", Image, IOType.IN_MEMORY)
-@md.output("saved_images_folder", DataPath, IOType.DISK)
-@md.env(pip_packages=["monai>=1.0.0", "torch>=1.5", "numpy>=1.21", "nibabel"])
class LiverTumorSegOperator(Operator):
"""Performs liver and tumor segmentation using a DL model with an image converted from a DICOM CT series.
- The model used in this application is from NVIDIA, publicly available at
- https://ngc.nvidia.com/catalog/models/nvidia:med:clara_pt_liver_and_tumor_ct_segmentation
-
- Described in the downloaded model package, also called Medical Model Archive (MMAR), are the pre and post
- transforms before and after inference, and are using MONAI SDK transforms. As such, these transforms are
- simply ported to this operator, with changing SegmentationSaver handler to SaveImageD post transform.
+ The model used in this application is from NVIDIA, and includes configurations for both the pre and post
+ transforms as well as inferer. The MONAI Core transforms are used, as such, these transforms are
+ simply ported to this operator.
- This operator makes use of the App SDK MonaiSegInferenceOperator in a compsition approach.
+ This operator makes use of the App SDK MonaiSegInferenceOperator in a composition approach.
It creates the pre-transforms as well as post-transforms with MONAI dictionary based transforms.
Note that the App SDK InMemImageReader, derived from MONAI ImageReader, is passed to LoadImaged.
This derived reader is needed to parse the in memory image object, and return the expected data structure.
- Loading of the model, and predicting using in-proc PyTorch inference is done by MonaiSegInferenceOperator.
+ Loading of the model, and predicting using the in-proc PyTorch inference is done by MonaiSegInferenceOperator.
+
+ Named Input:
+ image: Image object.
+
+ Named Outputs:
+ seg_image: Image object of the segmentation object.
+ saved_images_folder: Path to the folder with intermediate image output, not requiring a downstream receiver.
"""
- def __init__(self):
+ DEFAULT_OUTPUT_FOLDER = Path.cwd() / "output/saved_images_folder"
+
+ def __init__(
+ self,
+ fragment: Fragment,
+ *args,
+ app_context: AppContext,
+ model_path: Path,
+ output_folder: Path = DEFAULT_OUTPUT_FOLDER,
+ **kwargs,
+ ):
self.logger = logging.getLogger("{}.{}".format(__name__, type(self).__name__))
- super().__init__()
self._input_dataset_key = "image"
self._pred_dataset_key = "pred"
- def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
- input_image = op_input.get("image")
+ self.model_path = model_path
+ self.output_folder = output_folder
+ self.output_folder.mkdir(parents=True, exist_ok=True)
+ self.app_context = app_context
+ self.input_name_image = "image"
+ self.output_name_seg = "seg_image"
+ self.output_name_saved_images_folder = "saved_images_folder"
+
+ # Call the base class __init__() last.
+ # Also, the base class has an attribute called fragment for storing the fragment object
+ super().__init__(fragment, *args, **kwargs)
+
+ def setup(self, spec: OperatorSpec):
+ spec.input(self.input_name_image)
+ spec.output(self.output_name_seg)
+ spec.output(self.output_name_saved_images_folder).condition(
+ ConditionType.NONE
+ ) # Output not requiring a receiver
+
+ def compute(self, op_input, op_output, context):
+ input_image = op_input.receive(self.input_name_image)
if not input_image:
raise ValueError("Input image is not found.")
- # Get the output path from the execution context for saving file(s) to app output.
- # Without using this path, operator would be saving files to its designated path, e.g.
- # $PWD/.monai_workdir/operators/6048d75a-5de1-45b9-8bd1-2252f88827f2/0/output
- op_output_folder_name = DataPath("saved_images_folder")
- op_output.set(op_output_folder_name, "saved_images_folder")
- op_output_folder_path = op_output.get("saved_images_folder").path
- op_output_folder_path.mkdir(parents=True, exist_ok=True)
- print(f"Operator output folder path: {op_output_folder_path}")
-
# This operator gets an in-memory Image object, so a specialized ImageReader is needed.
_reader = InMemImageReader(input_image)
- # In this example, the input image, once loaded at the beginning of the pre-transforms, is
- # saved on disk, so is the segmentation prediction image at the end of the post-transform.
+
+ # In this example, the input image, once loaded at the beginning of the pre-transforms, can
+ # be saved on disk, so can the segmentation prediction image at the end of the post-transform.
# They are both saved in the same subfolder of the application output folder, with names
- # distinguished by postfix. They can also be save in different subfolder if need be.
+ # distinguished by the postfix. They can also be saved in different subfolder if need be.
# These images files can then be packaged for rendering.
- pre_transforms = self.pre_process(_reader, op_output_folder_path)
- post_transforms = self.post_process(pre_transforms, op_output_folder_path)
+ # In the code below, saving of the image files are disabled to save 10 seconds if nii, and 20 if nii.gz
+ pre_transforms = self.pre_process(_reader, str(self.output_folder))
+ post_transforms = self.post_process(pre_transforms, str(self.output_folder))
# Delegates inference and saving output to the built-in operator.
infer_operator = MonaiSegInferenceOperator(
- (
+ self.fragment,
+ roi_size=(
160,
160,
160,
),
- pre_transforms,
- post_transforms,
+ pre_transforms=pre_transforms,
+ post_transforms=post_transforms,
overlap=0.6,
+ app_context=self.app_context,
model_name="",
inferer=InfererType.SLIDING_WINDOW,
sw_batch_size=4,
+ model_path=self.model_path,
+ name="monai_seg_inference_op",
)
- # Setting the keys used in the dictironary based transforms may change.
+ # Setting the keys used in the dictionary based transforms
infer_operator.input_dataset_key = self._input_dataset_key
infer_operator.pred_dataset_key = self._pred_dataset_key
- # Now let the built-in operator handles the work with the I/O spec and execution context.
- infer_operator.compute(op_input, op_output, context)
+ # Now emit data to the output ports of this operator
+ op_output.emit(infer_operator.compute_impl(input_image, context), self.output_name_seg)
+ op_output.emit(self.output_folder, self.output_name_saved_images_folder)
def pre_process(self, img_reader, out_dir: str = "./input_images") -> Compose:
"""Composes transforms for preprocessing input before predicting on a model."""
+ Path(out_dir).mkdir(parents=True, exist_ok=True)
+
my_key = self._input_dataset_key
return Compose(
[
LoadImaged(keys=my_key, reader=img_reader),
EnsureChannelFirstd(keys=my_key),
- SaveImaged(
- keys=my_key,
- output_dir=out_dir,
- output_postfix="",
- resample=False,
- ),
+ # The SaveImaged transform can be commented out to save 5 seconds.
+ # Uncompress NIfTI file, nii, is used favoring speed over size, but can be changed to nii.gz
+ # SaveImaged(
+ # keys=my_key,
+ # output_dir=out_dir,
+ # output_postfix="",
+ # resample=False,
+ # output_ext=".nii",
+ # ),
Spacingd(keys=my_key, pixdim=(1.0, 1.0, 1.0), mode=("bilinear"), align_corners=True),
ScaleIntensityRanged(my_key, a_min=-21, a_max=189, b_min=0.0, b_max=1.0, clip=True),
CropForegroundd(my_key, source_key=my_key),
@@ -126,6 +157,8 @@ def pre_process(self, img_reader, out_dir: str = "./input_images") -> Compose:
def post_process(self, pre_transforms: Compose, out_dir: str = "./prediction_output") -> Compose:
"""Composes transforms for postprocessing the prediction results."""
+ Path(out_dir).mkdir(parents=True, exist_ok=True)
+
pred_key = self._pred_dataset_key
return Compose(
[
@@ -134,6 +167,15 @@ def post_process(self, pre_transforms: Compose, out_dir: str = "./prediction_out
Invertd(
keys=pred_key, transform=pre_transforms, orig_keys=self._input_dataset_key, nearest_interp=True
),
- SaveImaged(keys=pred_key, output_dir=out_dir, output_postfix="seg", output_dtype=uint8, resample=False),
+ # The SaveImaged transform can be commented out to save 5 seconds.
+ # Uncompress NIfTI file, nii, is used favoring speed over size, but can be changed to nii.gz
+ # SaveImaged(
+ # keys=pred_key,
+ # output_dir=out_dir,
+ # output_postfix="seg",
+ # output_dtype=uint8,
+ # resample=False,
+ # output_ext=".nii",
+ # ),
]
)
diff --git a/examples/apps/ai_multi_ai_app/__main__.py b/examples/apps/ai_multi_ai_app/__main__.py
index 412a8ca1..0d1c6005 100644
--- a/examples/apps/ai_multi_ai_app/__main__.py
+++ b/examples/apps/ai_multi_ai_app/__main__.py
@@ -1,4 +1,8 @@
+import logging
+
from app import App
if __name__ == "__main__":
- App(do_run=True)
+ logging.info(f"Begin {__name__}")
+ App().run()
+ logging.info(f"End {__name__}")
diff --git a/examples/apps/ai_multi_ai_app/app.py b/examples/apps/ai_multi_ai_app/app.py
index e6ea0a7e..a47f111e 100644
--- a/examples/apps/ai_multi_ai_app/app.py
+++ b/examples/apps/ai_multi_ai_app/app.py
@@ -1,4 +1,4 @@
-# Copyright 2021-2022 MONAI Consortium
+# Copyright 2021-2023 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
@@ -10,12 +10,13 @@
# limitations under the License.
import logging
+from pathlib import Path
# Required for setting SegmentDescription attributes. Direct import as this is not part of App SDK package.
from pydicom.sr.codedict import codes
-import monai.deploy.core as md
-from monai.deploy.core import Application, resource
+from monai.deploy.conditions import CountCondition
+from monai.deploy.core import AppContext, Application
from monai.deploy.core.domain import Image
from monai.deploy.core.io_type import IOType
from monai.deploy.operators.dicom_data_loader_operator import DICOMDataLoaderOperator
@@ -29,13 +30,8 @@
)
-@resource(cpu=1, gpu=1, memory="7Gi")
-# Enforcing torch>=1.12.0 because one of the Bundles/TorchScripts, Pancreas CT Seg, was created
-# with this version, and would fail to jit.load with lower version of torch.
-# The Bundle Inference Operator as of now only requires torch>=1.10.2, and does not yet dynamically
-# parse the MONAI bundle to get the required pip package or ver on initialization, hence it does not set
-# its own @env decorator accordingly when the app is being packaged into a MONAI Package.
-@md.env(pip_packages=["torch>=1.12.0"])
+# @resource(cpu=1, gpu=1, memory="7Gi")
+# @md.env(pip_packages=["torch>=1.12.0"])
# pip_packages can be a string that is a path(str) to requirements.txt file or a list of packages.
# The monai pkg is not required by this class, instead by the included operators.
class App(Application):
@@ -63,9 +59,15 @@ class App(Application):
Note:
1. The TorchScript files of MONAI Bundles can be downloaded from MONAI Model Zoo, at
https://github.com/Project-MONAI/model-zoo/tree/dev/models
+ https://github.com/Project-MONAI/model-zoo/tree/dev/models/spleen_ct_segmentation, v0.3.2
+ https://github.com/Project-MONAI/model-zoo/tree/dev/models/pancreas_ct_dints_segmentation, v0.3.8
2. The input DICOM instances are from a DICOM Series of CT Abdomen, similar to the ones
used in the Spleen Segmentation example
3. This example is purely for technical demonstration, not for clinical use
+
+ Execution Time Estimate:
+ With a Nvidia GV100 32GB GPU, the execution time is around 87 seconds for an input DICOM series of 204 instances,
+ and 167 second for a series of 515 instances.
"""
def __init__(self, *args, **kwargs):
@@ -84,40 +86,50 @@ def compose(self):
logging.info(f"Begin {self.compose.__name__}")
+ # Use command line options over environment variables to init context.
+ app_context: AppContext = Application.init_app_context(self.argv)
+ app_input_path = Path(app_context.input_path)
+ app_output_path = Path(app_context.output_path)
+
# Create the custom operator(s) as well as SDK built-in operator(s).
- study_loader_op = DICOMDataLoaderOperator()
- series_selector_op = DICOMSeriesSelectorOperator(Sample_Rules_Text)
- series_to_vol_op = DICOMSeriesToVolumeOperator()
+ study_loader_op = DICOMDataLoaderOperator(
+ self, CountCondition(self, 1), input_folder=app_input_path, name="study_loader_op"
+ )
+ series_selector_op = DICOMSeriesSelectorOperator(self, rules=Sample_Rules_Text, name="series_selector_op")
+ series_to_vol_op = DICOMSeriesToVolumeOperator(self, name="series_to_vol_op")
# Create the inference operator that supports MONAI Bundle and automates the inference.
# The IOMapping labels match the input and prediction keys in the pre and post processing.
- # The model_name is optional when the app has only one model.
- # The bundle_path argument optionally can be set to an accessible bundle file path in the dev
- # environment, so when the app is packaged into a MAP, the operator can complete the bundle parsing
- # during init to provide the optional packages info, parsed from the bundle, to the packager
- # for it to install the packages in the MAP docker image.
- # Setting output IOType to DISK only works only for leaf operators, not the case in this example.
- # When multiple models/bundles are supported, create an inference operator for each.
+ # The model_name needs to be provided as this is a multi-model application and each inference
+ # operator need to rely on the name to access the named loaded model network.
+ # create an inference operator for each.
#
# Pertinent MONAI Bundle:
# https://github.com/Project-MONAI/model-zoo/tree/dev/models/spleen_ct_segmentation, v0.3.2
- # https://github.com/Project-MONAI/model-zoo/tree/dev/models/pancreas_ct_dints_segmentation, v0.3
+ # https://github.com/Project-MONAI/model-zoo/tree/dev/models/pancreas_ct_dints_segmentation, v0.3.8
config_names = BundleConfigNames(config_names=["inference"]) # Same as the default
# This is the inference operator for the spleen_model bundle. Note the model name.
bundle_spleen_seg_op = MonaiBundleInferenceOperator(
+ self,
input_mapping=[IOMapping("image", Image, IOType.IN_MEMORY)],
output_mapping=[IOMapping("pred", Image, IOType.IN_MEMORY)],
+ app_context=app_context,
bundle_config_names=config_names,
model_name="spleen_ct",
+ name="bundle_spleen_seg_op",
)
# This is the inference operator for the pancreas_ct_dints bundle. Note the model name.
bundle_pancreas_seg_op = MonaiBundleInferenceOperator(
+ self,
input_mapping=[IOMapping("image", Image, IOType.IN_MEMORY)],
output_mapping=[IOMapping("pred", Image, IOType.IN_MEMORY)],
+ app_context=app_context,
+ bundle_config_names=config_names,
model_name="pancreas_ct_dints",
+ name="bundle_pancreas_seg_op",
)
# Create DICOM Seg writer providing the required segment description for each segment with
@@ -141,24 +153,44 @@ def compose(self):
custom_tags_spleen = {"SeriesDescription": "AI Spleen Seg for research use only. Not for clinical use."}
dicom_seg_writer_spleen = DICOMSegmentationWriterOperator(
- segment_descriptions=seg_descriptions_spleen, custom_tags=custom_tags_spleen
+ self,
+ segment_descriptions=seg_descriptions_spleen,
+ custom_tags=custom_tags_spleen,
+ output_folder=app_output_path,
+ name="dicom_seg_writer_spleen",
)
# Description for the Pancreas seg, and the seg writer obj
+ _algorithm_name = "Pancreas CT DiNTS segmentation from CT image"
+ _algorithm_family = codes.DCM.ArtificialIntelligence
+ _algorithm_version = "0.3.8"
+
seg_descriptions_pancreas = [
SegmentDescription(
segment_label="Pancreas",
segmented_property_category=codes.SCT.Organ,
segmented_property_type=codes.SCT.Pancreas,
- algorithm_name="volumetric (3D) segmentation of the pancreas from CT image",
- algorithm_family=codes.DCM.ArtificialIntelligence,
- algorithm_version="0.3.0",
- )
+ algorithm_name=_algorithm_name,
+ algorithm_family=_algorithm_family,
+ algorithm_version=_algorithm_version,
+ ),
+ SegmentDescription(
+ segment_label="Tumor",
+ segmented_property_category=codes.SCT.Tumor,
+ segmented_property_type=codes.SCT.Tumor,
+ algorithm_name=_algorithm_name,
+ algorithm_family=_algorithm_family,
+ algorithm_version=_algorithm_version,
+ ),
]
custom_tags_pancreas = {"SeriesDescription": "AI Pancreas Seg for research use only. Not for clinical use."}
dicom_seg_writer_pancreas = DICOMSegmentationWriterOperator(
- segment_descriptions=seg_descriptions_pancreas, custom_tags=custom_tags_pancreas
+ self,
+ segment_descriptions=seg_descriptions_pancreas,
+ custom_tags=custom_tags_pancreas,
+ output_folder=app_output_path,
+ name="dicom_seg_writer_pancreas",
)
# NOTE: Sharp eyed readers can already see that the above instantiation of object can be simply parameterized.
@@ -166,29 +198,31 @@ def compose(self):
# Create the processing pipeline, by specifying the upstream and downstream operators, and
# ensuring the output from the former matches the input of the latter, in both name and type.
- self.add_flow(study_loader_op, series_selector_op, {"dicom_study_list": "dicom_study_list"})
+ self.add_flow(study_loader_op, series_selector_op, {("dicom_study_list", "dicom_study_list")})
self.add_flow(
- series_selector_op, series_to_vol_op, {"study_selected_series_list": "study_selected_series_list"}
+ series_selector_op, series_to_vol_op, {("study_selected_series_list", "study_selected_series_list")}
)
# Feed the input image to all inference operators
- self.add_flow(series_to_vol_op, bundle_spleen_seg_op, {"image": "image"})
+ self.add_flow(series_to_vol_op, bundle_spleen_seg_op, {("image", "image")})
# The Pancreas CT Seg bundle requires PyTorch 1.12.0 to avoid failure to load.
- self.add_flow(series_to_vol_op, bundle_pancreas_seg_op, {"image": "image"})
+ self.add_flow(series_to_vol_op, bundle_pancreas_seg_op, {("image", "image")})
# Create DICOM Seg for one of the inference output
# Note below the dicom_seg_writer requires two inputs, each coming from a upstream operator.
self.add_flow(
- series_selector_op, dicom_seg_writer_spleen, {"study_selected_series_list": "study_selected_series_list"}
+ series_selector_op, dicom_seg_writer_spleen, {("study_selected_series_list", "study_selected_series_list")}
)
- self.add_flow(bundle_spleen_seg_op, dicom_seg_writer_spleen, {"pred": "seg_image"})
+ self.add_flow(bundle_spleen_seg_op, dicom_seg_writer_spleen, {("pred", "seg_image")})
# Create DICOM Seg for one of the inference output
# Note below the dicom_seg_writer requires two inputs, each coming from a upstream operator.
self.add_flow(
- series_selector_op, dicom_seg_writer_pancreas, {"study_selected_series_list": "study_selected_series_list"}
+ series_selector_op,
+ dicom_seg_writer_pancreas,
+ {("study_selected_series_list", "study_selected_series_list")},
)
- self.add_flow(bundle_pancreas_seg_op, dicom_seg_writer_pancreas, {"pred": "seg_image"})
+ self.add_flow(bundle_pancreas_seg_op, dicom_seg_writer_pancreas, {("pred", "seg_image")})
logging.info(f"End {self.compose.__name__}")
@@ -219,5 +253,6 @@ def compose(self):
# e.g.
# monai-deploy exec app.py -i input -m model/model.ts
#
- logging.basicConfig(level=logging.DEBUG)
- app_instance = App(do_run=True)
+ logging.info(f"Begin {__name__}")
+ App().run()
+ logging.info(f"End {__name__}")
diff --git a/monai/deploy/core/graphs/__init__.py b/examples/apps/ai_multi_ai_app/app.yaml
similarity index 56%
rename from monai/deploy/core/graphs/__init__.py
rename to examples/apps/ai_multi_ai_app/app.yaml
index 52e4c395..93387e1c 100644
--- a/monai/deploy/core/graphs/__init__.py
+++ b/examples/apps/ai_multi_ai_app/app.yaml
@@ -1,22 +1,27 @@
-# Copyright 2021 MONAI Consortium
+%YAML 1.2
+# SPDX-FileCopyrightText: Copyright (c) 2022-2023 MONAI. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0
+#
# 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
+#
+# 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.
-"""
-.. autosummary::
- :toctree: _autosummary
+---
+application:
+ title: MONAI Deploy App Package - Multi Model App
+ version: 1.0
+ inputFormats: ["file"]
+ outputFormats: ["file"]
- GraphFactory
- Graph
- NetworkXGraph
-"""
-
-from .factory import GraphFactory
-from .graph import Graph
-from .nx_digraph import NetworkXGraph
+resources:
+ cpu: 1
+ gpu: 1
+ memory: 1Gi
+ gpuMemory: 10Gi
diff --git a/examples/apps/ai_multi_ai_app/requirements.txt b/examples/apps/ai_multi_ai_app/requirements.txt
new file mode 100644
index 00000000..a122292f
--- /dev/null
+++ b/examples/apps/ai_multi_ai_app/requirements.txt
@@ -0,0 +1,10 @@
+scikit-image>=0.17.2
+pydicom>=2.3.0
+highdicom>=0.18.2
+SimpleITK>=2.0.0
+Pillow>=8.0.0
+numpy-stl>=2.12.0
+trimesh>=3.8.11
+nibabel>=3.2.1
+torch>=1.12.0
+monai>=1.0.0
\ No newline at end of file
diff --git a/examples/apps/ai_pancrea_seg_app/__init__.py b/examples/apps/ai_pancrea_seg_app/__init__.py
deleted file mode 100644
index 521cb31b..00000000
--- a/examples/apps/ai_pancrea_seg_app/__init__.py
+++ /dev/null
@@ -1,7 +0,0 @@
-import os
-import sys
-
-_current_dir = os.path.abspath(os.path.dirname(__file__))
-if sys.path and os.path.abspath(sys.path[0]) != _current_dir:
- sys.path.insert(0, _current_dir)
-del _current_dir
diff --git a/examples/apps/ai_pancrea_seg_app/__main__.py b/examples/apps/ai_pancrea_seg_app/__main__.py
deleted file mode 100644
index 0fb27c9e..00000000
--- a/examples/apps/ai_pancrea_seg_app/__main__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-from app import AIPancreasSegApp
-
-if __name__ == "__main__":
- AIPancreasSegApp(do_run=True)
diff --git a/monai/deploy/cli/__init__.py b/examples/apps/ai_pancreas_seg_app/__init__.py
similarity index 94%
rename from monai/deploy/cli/__init__.py
rename to examples/apps/ai_pancreas_seg_app/__init__.py
index 26c54045..526cee59 100644
--- a/monai/deploy/cli/__init__.py
+++ b/examples/apps/ai_pancreas_seg_app/__init__.py
@@ -1,4 +1,4 @@
-# Copyright 2021 MONAI Consortium
+# Copyright 2021-2023 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
diff --git a/monai/deploy/cli/__main__.py b/examples/apps/ai_pancreas_seg_app/__main__.py
similarity index 75%
rename from monai/deploy/cli/__main__.py
rename to examples/apps/ai_pancreas_seg_app/__main__.py
index d1152497..243614f7 100644
--- a/monai/deploy/cli/__main__.py
+++ b/examples/apps/ai_pancreas_seg_app/__main__.py
@@ -1,4 +1,4 @@
-# Copyright 2021 MONAI Consortium
+# Copyright 2021-2023 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
@@ -9,8 +9,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import logging
-from main import main # type: ignore # for pytype
+from app import AIPancreasSegApp
if __name__ == "__main__":
- main()
+ logging.info(f"Begin {__name__}")
+ AIPancreasSegApp().run()
+ logging.info(f"End {__name__}")
diff --git a/examples/apps/ai_pancrea_seg_app/app.py b/examples/apps/ai_pancreas_seg_app/app.py
similarity index 58%
rename from examples/apps/ai_pancrea_seg_app/app.py
rename to examples/apps/ai_pancreas_seg_app/app.py
index 48e37397..f5878eff 100644
--- a/examples/apps/ai_pancrea_seg_app/app.py
+++ b/examples/apps/ai_pancreas_seg_app/app.py
@@ -1,4 +1,4 @@
-# Copyright 2021-2022 MONAI Consortium
+# Copyright 2021-2023 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
@@ -10,12 +10,13 @@
# limitations under the License.
import logging
+from pathlib import Path
# Required for setting SegmentDescription attributes. Direct import as this is not part of App SDK package.
from pydicom.sr.codedict import codes
-import monai.deploy.core as md
-from monai.deploy.core import Application, resource
+from monai.deploy.conditions import CountCondition
+from monai.deploy.core import AppContext, Application
from monai.deploy.core.domain import Image
from monai.deploy.core.io_type import IOType
from monai.deploy.operators.dicom_data_loader_operator import DICOMDataLoaderOperator
@@ -28,12 +29,29 @@
MonaiBundleInferenceOperator,
)
+# from monai.deploy.operators.stl_conversion_operator import STLConversionOperator # uncomment if need be used
-@resource(cpu=1, gpu=1, memory="7Gi")
-@md.env(pip_packages=["torch>=1.12.0"])
+
+# @resource(cpu=1, gpu=1, memory="7Gi")
+# @md.env(pip_packages=["torch>=1.12.0"])
# pip_packages can be a string that is a path(str) to requirements.txt file or a list of packages.
# The monai pkg is not required by this class, instead by the included operators.
class AIPancreasSegApp(Application):
+ """Demonstrates inference with built-in MONAI Bundle inference operator with DICOM files as input/output
+
+ This application loads a set of DICOM instances, select the appropriate series, converts the series to
+ 3D volume image, performs inference with the built-in MONAI Bundle inference operator, including pre-processing
+ and post-processing, saves the segmentation image in a DICOM Seg OID in an instance file, and optionally the
+ surface mesh in STL format.
+
+ Pertinent MONAI Bundle:
+ https://github.com/Project-MONAI/model-zoo/tree/dev/models/pancreas_ct_dints_segmentation
+
+ Execution Time Estimate:
+ With a Nvidia GV100 32GB GPU, the execution time is around 80 seconds for an input DICOM series of 204 instances,
+ and 160 second for a series of 515 instances.
+ """
+
def __init__(self, *args, **kwargs):
"""Creates an application instance."""
self._logger = logging.getLogger("{}.{}".format(__name__, type(self).__name__))
@@ -50,10 +68,17 @@ def compose(self):
logging.info(f"Begin {self.compose.__name__}")
+ # Use command line options over environment variables to init context.
+ app_context: AppContext = Application.init_app_context(self.argv)
+ app_input_path = Path(app_context.input_path)
+ app_output_path = Path(app_context.output_path)
+
# Create the custom operator(s) as well as SDK built-in operator(s).
- study_loader_op = DICOMDataLoaderOperator()
- series_selector_op = DICOMSeriesSelectorOperator(Sample_Rules_Text)
- series_to_vol_op = DICOMSeriesToVolumeOperator()
+ study_loader_op = DICOMDataLoaderOperator(
+ self, CountCondition(self, 1), input_folder=app_input_path, name="study_loader_op"
+ )
+ series_selector_op = DICOMSeriesSelectorOperator(self, rules=Sample_Rules_Text, name="series_selector_op")
+ series_to_vol_op = DICOMSeriesToVolumeOperator(self, name="series_to_vol_op")
# Create the inference operator that supports MONAI Bundle and automates the inference.
# The IOMapping labels match the input and prediction keys in the pre and post processing.
@@ -62,54 +87,72 @@ def compose(self):
# environment, so when the app is packaged into a MAP, the operator can complete the bundle parsing
# during init to provide the optional packages info, parsed from the bundle, to the packager
# for it to install the packages in the MAP docker image.
- # Setting output IOType to DISK only works only for leaf operators, not the case in this example.
- #
- # Pertinent MONAI Bundle:
- # https://github.com/Project-MONAI/model-zoo/tree/dev/models/spleen_ct_segmentation
- bundle_spleen_seg_op = MonaiBundleInferenceOperator(
+ config_names = BundleConfigNames(config_names=["inference"]) # Same as the default
+ bundle_seg_op = MonaiBundleInferenceOperator(
+ self,
input_mapping=[IOMapping("image", Image, IOType.IN_MEMORY)],
output_mapping=[IOMapping("pred", Image, IOType.IN_MEMORY)],
- bundle_config_names=BundleConfigNames(config_names=["inference"]), # Same as the default
+ app_context=app_context,
+ bundle_config_names=config_names,
+ name="bundle_seg_op",
)
# Create DICOM Seg writer providing the required segment description for each segment with
# the actual algorithm and the pertinent organ/tissue. The segment_label, algorithm_name,
# and algorithm_version are of DICOM VR LO type, limited to 64 chars.
# https://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_6.2.html
+ _algorithm_name = "Pancreas CT DiNTS segmentation from CT image"
+ _algorithm_family = codes.DCM.ArtificialIntelligence
+ _algorithm_version = "0.3.8"
+
segment_descriptions = [
SegmentDescription(
segment_label="Pancreas",
segmented_property_category=codes.SCT.Organ,
segmented_property_type=codes.SCT.Pancreas,
- algorithm_name="volumetric (3D) segmentation of the pancreas from CT image",
- algorithm_family=codes.DCM.ArtificialIntelligence,
- algorithm_version="0.3.0",
- )
+ algorithm_name=_algorithm_name,
+ algorithm_family=_algorithm_family,
+ algorithm_version=_algorithm_version,
+ ),
+ SegmentDescription(
+ segment_label="Tumor",
+ segmented_property_category=codes.SCT.Tumor,
+ segmented_property_type=codes.SCT.Tumor,
+ algorithm_name=_algorithm_name,
+ algorithm_family=_algorithm_family,
+ algorithm_version=_algorithm_version,
+ ),
]
custom_tags = {"SeriesDescription": "AI generated Seg for research use only. Not for clinical use."}
dicom_seg_writer = DICOMSegmentationWriterOperator(
- segment_descriptions=segment_descriptions, custom_tags=custom_tags
+ self,
+ segment_descriptions=segment_descriptions,
+ custom_tags=custom_tags,
+ output_folder=app_output_path,
+ name="dicom_seg_writer",
)
# Create the processing pipeline, by specifying the source and destination operators, and
# ensuring the output from the former matches the input of the latter, in both name and type.
- self.add_flow(study_loader_op, series_selector_op, {"dicom_study_list": "dicom_study_list"})
+ self.add_flow(study_loader_op, series_selector_op, {("dicom_study_list", "dicom_study_list")})
self.add_flow(
- series_selector_op, series_to_vol_op, {"study_selected_series_list": "study_selected_series_list"}
+ series_selector_op, series_to_vol_op, {("study_selected_series_list", "study_selected_series_list")}
)
- self.add_flow(series_to_vol_op, bundle_spleen_seg_op, {"image": "image"})
+ self.add_flow(series_to_vol_op, bundle_seg_op, {("image", "image")})
# Note below the dicom_seg_writer requires two inputs, each coming from a source operator.
self.add_flow(
- series_selector_op, dicom_seg_writer, {"study_selected_series_list": "study_selected_series_list"}
+ series_selector_op, dicom_seg_writer, {("study_selected_series_list", "study_selected_series_list")}
)
- self.add_flow(bundle_spleen_seg_op, dicom_seg_writer, {"pred": "seg_image"})
+ self.add_flow(bundle_seg_op, dicom_seg_writer, {("pred", "seg_image")})
# Create the surface mesh STL conversion operator and add it to the app execution flow, if needed, by
# uncommenting the following couple lines.
- # stl_conversion_op = STLConversionOperator(output_file="stl/spleen.stl")
- # self.add_flow(bundle_spleen_seg_op, stl_conversion_op, {"pred": "image"})
+ # stl_conversion_op = STLConversionOperator(
+ # self, output_file=app_output_path.joinpath("stl/spleen.stl"), name="stl_conversion_op"
+ # )
+ # self.add_flow(bundle_seg_op, stl_conversion_op, {("pred", "image")})
logging.info(f"End {self.compose.__name__}")
@@ -140,5 +183,6 @@ def compose(self):
# e.g.
# monai-deploy exec app.py -i input -m model/model.ts
#
- logging.basicConfig(level=logging.DEBUG)
- app_instance = AIPancreasSegApp(do_run=True)
+ logging.info(f"Begin {__name__}")
+ AIPancreasSegApp().run()
+ logging.info(f"End {__name__}")
diff --git a/examples/apps/ai_spleen_seg_app/__init__.py b/examples/apps/ai_spleen_seg_app/__init__.py
index 521cb31b..526cee59 100644
--- a/examples/apps/ai_spleen_seg_app/__init__.py
+++ b/examples/apps/ai_spleen_seg_app/__init__.py
@@ -1,3 +1,14 @@
+# Copyright 2021-2023 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 os
import sys
diff --git a/examples/apps/ai_spleen_seg_app/__main__.py b/examples/apps/ai_spleen_seg_app/__main__.py
index 273444f9..2d67f364 100644
--- a/examples/apps/ai_spleen_seg_app/__main__.py
+++ b/examples/apps/ai_spleen_seg_app/__main__.py
@@ -1,4 +1,19 @@
+# Copyright 2021-2023 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 logging
+
from app import AISpleenSegApp
if __name__ == "__main__":
- AISpleenSegApp(do_run=True)
+ logging.info(f"Begin {__name__}")
+ AISpleenSegApp().run()
+ logging.info(f"End {__name__}")
diff --git a/examples/apps/ai_spleen_seg_app/app.py b/examples/apps/ai_spleen_seg_app/app.py
index f267f114..1ca5b1fd 100644
--- a/examples/apps/ai_spleen_seg_app/app.py
+++ b/examples/apps/ai_spleen_seg_app/app.py
@@ -1,4 +1,4 @@
-# Copyright 2021-2022 MONAI Consortium
+# Copyright 2021-2023 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
@@ -10,11 +10,13 @@
# limitations under the License.
import logging
+from pathlib import Path
# Required for setting SegmentDescription attributes. Direct import as this is not part of App SDK package.
from pydicom.sr.codedict import codes
-from monai.deploy.core import Application, resource
+from monai.deploy.conditions import CountCondition
+from monai.deploy.core import AppContext, Application
from monai.deploy.core.domain import Image
from monai.deploy.core.io_type import IOType
from monai.deploy.operators.dicom_data_loader_operator import DICOMDataLoaderOperator
@@ -26,12 +28,28 @@
IOMapping,
MonaiBundleInferenceOperator,
)
+from monai.deploy.operators.stl_conversion_operator import STLConversionOperator
-@resource(cpu=1, gpu=1, memory="7Gi")
+# @resource(cpu=1, gpu=1, memory="7Gi")
# pip_packages can be a string that is a path(str) to requirements.txt file or a list of packages.
# The monai pkg is not required by this class, instead by the included operators.
class AISpleenSegApp(Application):
+ """Demonstrates inference with built-in MONAI Bundle inference operator with DICOM files as input/output
+
+ This application loads a set of DICOM instances, select the appropriate series, converts the series to
+ 3D volume image, performs inference with the built-in MONAI Bundle inference operator, including pre-processing
+ and post-processing, save the segmentation image in a DICOM Seg OID in an instance file, and optionally the
+ surface mesh in STL format.
+
+ Pertinent MONAI Bundle:
+ https://github.com/Project-MONAI/model-zoo/tree/dev/models/spleen_ct_segmentation
+
+ Execution Time Estimate:
+ With a Nvidia GV100 32GB GPU, for an input DICOM Series of 515 instances, the execution time is around
+ 25 seconds with saving both DICOM Seg and surface mesh STL file, and 15 seconds with DICOM Seg only.
+ """
+
def __init__(self, *args, **kwargs):
"""Creates an application instance."""
self._logger = logging.getLogger("{}.{}".format(__name__, type(self).__name__))
@@ -48,29 +66,34 @@ def compose(self):
logging.info(f"Begin {self.compose.__name__}")
+ # Use Commandline options over environment variables to init context.
+ app_context: AppContext = Application.init_app_context(self.argv)
+ app_input_path = Path(app_context.input_path)
+ app_output_path = Path(app_context.output_path)
+
# Create the custom operator(s) as well as SDK built-in operator(s).
- study_loader_op = DICOMDataLoaderOperator()
- series_selector_op = DICOMSeriesSelectorOperator(Sample_Rules_Text)
- series_to_vol_op = DICOMSeriesToVolumeOperator()
+ study_loader_op = DICOMDataLoaderOperator(
+ self, CountCondition(self, 1), input_folder=app_input_path, name="study_loader_op"
+ )
+ series_selector_op = DICOMSeriesSelectorOperator(self, rules=Sample_Rules_Text, name="series_selector_op")
+ series_to_vol_op = DICOMSeriesToVolumeOperator(self, name="series_to_vol_op")
# Create the inference operator that supports MONAI Bundle and automates the inference.
# The IOMapping labels match the input and prediction keys in the pre and post processing.
# The model_name is optional when the app has only one model.
# The bundle_path argument optionally can be set to an accessible bundle file path in the dev
# environment, so when the app is packaged into a MAP, the operator can complete the bundle parsing
- # during init to provide the optional packages info, parsed from the bundle, to the packager
- # for it to install the packages in the MAP docker image.
- # Setting output IOType to DISK only works only for leaf operators, not the case in this example.
- #
- # Pertinent MONAI Bundle:
- # https://github.com/Project-MONAI/model-zoo/tree/dev/models/spleen_ct_segmentation
+ # during init.
config_names = BundleConfigNames(config_names=["inference"]) # Same as the default
bundle_spleen_seg_op = MonaiBundleInferenceOperator(
+ self,
input_mapping=[IOMapping("image", Image, IOType.IN_MEMORY)],
output_mapping=[IOMapping("pred", Image, IOType.IN_MEMORY)],
+ app_context=app_context,
bundle_config_names=config_names,
+ name="bundle_spleen_seg_op",
)
# Create DICOM Seg writer providing the required segment description for each segment with
@@ -84,32 +107,38 @@ def compose(self):
segmented_property_type=codes.SCT.Spleen,
algorithm_name="volumetric (3D) segmentation of the spleen from CT image",
algorithm_family=codes.DCM.ArtificialIntelligence,
- algorithm_version="0.1.0",
+ algorithm_version="0.3.2",
)
]
custom_tags = {"SeriesDescription": "AI generated Seg, not for clinical use."}
dicom_seg_writer = DICOMSegmentationWriterOperator(
- segment_descriptions=segment_descriptions, custom_tags=custom_tags
+ self,
+ segment_descriptions=segment_descriptions,
+ custom_tags=custom_tags,
+ output_folder=app_output_path,
+ name="dicom_seg_writer",
)
# Create the processing pipeline, by specifying the source and destination operators, and
# ensuring the output from the former matches the input of the latter, in both name and type.
- self.add_flow(study_loader_op, series_selector_op, {"dicom_study_list": "dicom_study_list"})
+ self.add_flow(study_loader_op, series_selector_op, {("dicom_study_list", "dicom_study_list")})
self.add_flow(
- series_selector_op, series_to_vol_op, {"study_selected_series_list": "study_selected_series_list"}
+ series_selector_op, series_to_vol_op, {("study_selected_series_list", "study_selected_series_list")}
)
- self.add_flow(series_to_vol_op, bundle_spleen_seg_op, {"image": "image"})
+ self.add_flow(series_to_vol_op, bundle_spleen_seg_op, {("image", "image")})
# Note below the dicom_seg_writer requires two inputs, each coming from a source operator.
self.add_flow(
- series_selector_op, dicom_seg_writer, {"study_selected_series_list": "study_selected_series_list"}
+ series_selector_op, dicom_seg_writer, {("study_selected_series_list", "study_selected_series_list")}
)
- self.add_flow(bundle_spleen_seg_op, dicom_seg_writer, {"pred": "seg_image"})
+ self.add_flow(bundle_spleen_seg_op, dicom_seg_writer, {("pred", "seg_image")})
# Create the surface mesh STL conversion operator and add it to the app execution flow, if needed, by
# uncommenting the following couple lines.
- # stl_conversion_op = STLConversionOperator(output_file="stl/spleen.stl")
- # self.add_flow(bundle_spleen_seg_op, stl_conversion_op, {"pred": "image"})
+ stl_conversion_op = STLConversionOperator(
+ self, output_file=app_output_path.joinpath("stl/spleen.stl"), name="stl_conversion_op"
+ )
+ self.add_flow(bundle_spleen_seg_op, stl_conversion_op, {("pred", "image")})
logging.info(f"End {self.compose.__name__}")
@@ -140,5 +169,6 @@ def compose(self):
# e.g.
# monai-deploy exec app.py -i input -m model/model.ts
#
- logging.basicConfig(level=logging.DEBUG)
- app_instance = AISpleenSegApp(do_run=True)
+ logging.info(f"Begin {__name__}")
+ AISpleenSegApp().run()
+ logging.info(f"End {__name__}")
diff --git a/examples/apps/ai_spleen_seg_app/app.yaml b/examples/apps/ai_spleen_seg_app/app.yaml
new file mode 100644
index 00000000..390ce7ee
--- /dev/null
+++ b/examples/apps/ai_spleen_seg_app/app.yaml
@@ -0,0 +1,27 @@
+%YAML 1.2
+# SPDX-FileCopyrightText: Copyright (c) 2022-2023 MONAI. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0
+#
+# 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.
+---
+application:
+ title: MONAI Deploy App Package - Spleen Seg Inference
+ version: 1.0
+ inputFormats: ["file"]
+ outputFormats: ["file"]
+
+resources:
+ cpu: 1
+ gpu: 1
+ memory: 1Gi
+ gpuMemory: 7Gi
diff --git a/examples/apps/ai_spleen_seg_app/requirements.txt b/examples/apps/ai_spleen_seg_app/requirements.txt
new file mode 100644
index 00000000..a122292f
--- /dev/null
+++ b/examples/apps/ai_spleen_seg_app/requirements.txt
@@ -0,0 +1,10 @@
+scikit-image>=0.17.2
+pydicom>=2.3.0
+highdicom>=0.18.2
+SimpleITK>=2.0.0
+Pillow>=8.0.0
+numpy-stl>=2.12.0
+trimesh>=3.8.11
+nibabel>=3.2.1
+torch>=1.12.0
+monai>=1.0.0
\ No newline at end of file
diff --git a/examples/apps/ai_unetr_seg_app/__main__.py b/examples/apps/ai_unetr_seg_app/__main__.py
index 504a0a74..431acd70 100644
--- a/examples/apps/ai_unetr_seg_app/__main__.py
+++ b/examples/apps/ai_unetr_seg_app/__main__.py
@@ -1,55 +1,8 @@
import logging
-import shutil
-import traceback
-from pathlib import Path
-from typing import List
from app import AIUnetrSegApp
if __name__ == "__main__":
- logging.basicConfig(level=logging.DEBUG)
- # This main function is an example to show how a batch of input can be processed.
- # It assumes that in the app input folder there are a number of subfolders, each
- # containing a discrete input to be processed. Each discrete payload can have
- # multiple DICOM instances file, optionally organized in its own folder structure.
- # The application object is first created, and on its init the model network is
- # loaded as well as pre and post processing transforms. This app object is then
- # run multiple times, each time with a single discrete payload.
-
- app = AIUnetrSegApp(do_run=False)
-
- # Preserve the application top level input and output folder path, as the path
- # in the context may change on each run if the I/O arguments are passed in.
- app_input_path = Path(app.context.input_path)
- app_output_path = Path(app.context.output_path)
-
- # Get subfolders in the input path, assume each one contains a discrete payload
- input_dirs = [path for path in app_input_path.iterdir() if path.is_dir()]
-
- # Set the output path for each run under the app's output path, and do run
- work_dirs: List[str] = [] # strings resprenting folder path
- for idx, dir in enumerate(input_dirs):
- try:
- output_path = app_output_path / f"{dir.name}_output"
- # Note: the work_dir should be mapped to the host drive when used in
- # a container for better performance.
- work_dir = f".unetr_app_workdir{idx}"
- work_dirs.extend(work_dir)
-
- logging.info(f"Start processing input in: {dir} with results in: {output_path}")
-
- # Run app with specific input and output path.
- # Passing in the input and output do have the side effect of changing
- # app context. This side effect will likely be eliminated in later releases.
- app.run(input=dir, output=output_path, workdir=work_dir)
-
- logging.info(f"Completed processing input in: {dir} with results in: {output_path}")
- except Exception as ex:
- logging.error(f"Failed processing input in {dir}, due to: {ex}\n")
- traceback.print_exc()
- finally:
- # Remove the workdir; alternatively do this later, if storage space is not a concern.
- shutil.rmtree(work_dir, ignore_errors=True)
-
- # Alternative. Explicitly remove the working dirs at the end of main.
- # [shutil.rmtree(work_dir, ignore_errors=True) for work_dir in work_dirs]
+ logging.info(f"Begin {__name__}")
+ AIUnetrSegApp().run()
+ logging.info(f"End {__name__}")
diff --git a/examples/apps/ai_unetr_seg_app/app.py b/examples/apps/ai_unetr_seg_app/app.py
index cfca9b46..7a399828 100644
--- a/examples/apps/ai_unetr_seg_app/app.py
+++ b/examples/apps/ai_unetr_seg_app/app.py
@@ -1,4 +1,4 @@
-# Copyright 2021 MONAI Consortium
+# Copyright 2021-2023 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
@@ -10,24 +10,25 @@
# limitations under the License.
import logging
-from typing import List
+from pathlib import Path
-# Required for setting SegmentDescription attributes. Direct import as this is not part of App SDK package.
-from pydicom.sr.codedict import codes
+from pydicom.sr.codedict import codes # Required for setting SegmentDescription attributes.
from unetr_seg_operator import UnetrSegOperator
-from monai.deploy.core import Application, resource
+from monai.deploy.conditions import CountCondition
+from monai.deploy.core import AppContext, Application
from monai.deploy.operators.dicom_data_loader_operator import DICOMDataLoaderOperator
from monai.deploy.operators.dicom_seg_writer_operator import DICOMSegmentationWriterOperator, SegmentDescription
from monai.deploy.operators.dicom_series_selector_operator import DICOMSeriesSelectorOperator
from monai.deploy.operators.dicom_series_to_volume_operator import DICOMSeriesToVolumeOperator
-from monai.deploy.operators.publisher_operator import PublisherOperator
from monai.deploy.operators.stl_conversion_operator import STLConversionOperator
+# This sample example completes the processing of a DICOM series with around 300 instances within 43 seconds,
+# 39 if not saving intermediate image file, and 28 seconds if the STL generation is also disabled,
+# on a desktop with Ubuntu 20.04, 32GB of RAM, and a Nvidia GPU GV100 with 32GB of memory.
-@resource(cpu=1, gpu=1, memory="7Gi")
-# pip_packages can be a string that is a path(str) to requirements.txt file or a list of packages.
-# The MONAI pkg is not required by this class, instead by the included operators.
+
+# @resource(cpu=1, gpu=1, memory="7Gi")
class AIUnetrSegApp(Application):
def __init__(self, *args, **kwargs):
"""Creates an application instance."""
@@ -37,25 +38,37 @@ def __init__(self, *args, **kwargs):
def run(self, *args, **kwargs):
# This method calls the base class to run. Can be omitted if simply calling through.
- self._logger.debug(f"Begin {self.run.__name__}")
+ self._logger.info(f"Begin {self.run.__name__}")
super().run(*args, **kwargs)
- self._logger.debug(f"End {self.run.__name__}")
+ self._logger.info(f"End {self.run.__name__}")
def compose(self):
"""Creates the app specific operators and chain them up in the processing DAG."""
- self._logger.debug(f"Begin {self.compose.__name__}")
+ self._logger.info(f"Begin {self.compose.__name__}")
+ # Use command line options over environment variables to init context.
+ app_context: AppContext = Application.init_app_context(self.argv)
+ app_input_path = Path(app_context.input_path)
+ app_output_path = Path(app_context.output_path)
+ model_path = Path(app_context.model_path)
+
+ self._logger.info(f"App input and output path: {app_input_path}, {app_output_path}")
+
# Creates the custom operator(s) as well as SDK built-in operator(s).
- study_loader_op = DICOMDataLoaderOperator()
- series_selector_op = DICOMSeriesSelectorOperator()
- series_to_vol_op = DICOMSeriesToVolumeOperator()
+ study_loader_op = DICOMDataLoaderOperator(
+ self, CountCondition(self, 1), input_folder=app_input_path, name="dcm_loader_op"
+ )
+ series_selector_op = DICOMSeriesSelectorOperator(self, rules=Sample_Rules_Text, name="series_selector_op")
+ series_to_vol_op = DICOMSeriesToVolumeOperator(self, name="series_to_vol_op")
# Model specific inference operator, supporting MONAI transforms.
- unetr_seg_op = UnetrSegOperator()
- # Create the publisher operator
- publisher_op = PublisherOperator()
+ seg_op = UnetrSegOperator(self, app_context=app_context, model_path=model_path, name="seg_op")
+
# Create the surface mesh STL conversion operator, for all segments
stl_conversion_op = STLConversionOperator(
- output_file="stl/multi-organs.stl", keep_largest_connected_component=False
+ self,
+ output_file=app_output_path.joinpath("stl/mesh.stl"),
+ keep_largest_connected_component=False,
+ name="stl_op",
)
# Create DICOM Seg writer providing the required segment description for each segment with
@@ -100,29 +113,48 @@ def compose(self):
for organ in organs
]
- dicom_seg_writer = DICOMSegmentationWriterOperator(segment_descriptions)
+ dicom_seg_writer = DICOMSegmentationWriterOperator(
+ self, segment_descriptions=segment_descriptions, output_folder=app_output_path, name="dcm_seg_writer_op"
+ )
# Create the processing pipeline, by specifying the source and destination operators, and
# ensuring the output from the former matches the input of the latter, in both name and type.
- self.add_flow(study_loader_op, series_selector_op, {"dicom_study_list": "dicom_study_list"})
+ self.add_flow(study_loader_op, series_selector_op, {("dicom_study_list", "dicom_study_list")})
self.add_flow(
- series_selector_op, series_to_vol_op, {"study_selected_series_list": "study_selected_series_list"}
+ series_selector_op, series_to_vol_op, {("study_selected_series_list", "study_selected_series_list")}
)
- self.add_flow(series_to_vol_op, unetr_seg_op, {"image": "image"})
- self.add_flow(unetr_seg_op, stl_conversion_op, {"seg_image": "image"})
-
- # Add the publishing operator to save the input and seg images for Render Server.
- # Note the PublisherOperator has temp impl till a proper rendering module is created.
- self.add_flow(unetr_seg_op, publisher_op, {"saved_images_folder": "saved_images_folder"})
+ self.add_flow(series_to_vol_op, seg_op, {("image", "image")})
+ self.add_flow(seg_op, stl_conversion_op, {("seg_image", "image")})
# Note below the dicom_seg_writer requires two inputs, each coming from a source operator.
self.add_flow(
- series_selector_op, dicom_seg_writer, {"study_selected_series_list": "study_selected_series_list"}
+ series_selector_op, dicom_seg_writer, {("study_selected_series_list", "study_selected_series_list")}
)
- self.add_flow(unetr_seg_op, dicom_seg_writer, {"seg_image": "seg_image"})
-
- self._logger.debug(f"End {self.compose.__name__}")
-
+ self.add_flow(seg_op, dicom_seg_writer, {("seg_image", "seg_image")})
+
+ self._logger.info(f"End {self.compose.__name__}")
+
+
+# This is a sample series selection rule in JSON, simply selecting CT series.
+# If the study has more than 1 CT series, then all of them will be selected.
+# Please see more detail in DICOMSeriesSelectorOperator.
+# For list of string values, e.g. "ImageType": ["PRIMARY", "ORIGINAL"], it is a match if all elements
+# are all in the multi-value attribute of the DICOM series.
+
+Sample_Rules_Text = """
+{
+ "selections": [
+ {
+ "name": "CT Series",
+ "conditions": {
+ "Modality": "(?i)CT",
+ "ImageType": ["PRIMARY", "ORIGINAL"],
+ "PhotometricInterpretation": "MONOCHROME2"
+ }
+ }
+ ]
+}
+"""
if __name__ == "__main__":
# Creates the app and test it standalone. When running is this mode, please note the following:
@@ -132,53 +164,7 @@ def compose(self):
# e.g.
# python3 app.py -i input -m model/model.ts
#
- import shutil
- import traceback
- from pathlib import Path
-
- logging.basicConfig(level=logging.DEBUG)
- # This main function is an example to show how a batch of input can be processed.
- # It assumes that in the app input folder there are a number of subfolders, each
- # containing a discrete input to be processed. Each discrete payload can have
- # multiple DICOM instances file, optionally organized in its own folder structure.
- # The application object is first created, and on its init the model network is
- # loaded as well as pre and post processing transforms. This app object is then
- # run multiple times, each time with a single discrete payload.
-
- app = AIUnetrSegApp(do_run=False)
-
- # Preserve the application top level input and output folder path, as the path
- # in the context may change on each run if the I/O arguments are passed in.
- app_input_path = Path(app.context.input_path)
- app_output_path = Path(app.context.output_path)
-
- # Get subfolders in the input path, assume each one contains a discrete payload
- input_dirs = [path for path in app_input_path.iterdir() if path.is_dir()]
-
- # Set the output path for each run under the app's output path, and do run
- work_dirs: List[str] = [] # strings resprenting folder path
- for idx, dir in enumerate(input_dirs):
- try:
- output_path = app_output_path / f"{dir.name}_output"
- # Note: the work_dir should be mapped to the host drive when used in
- # a container for better performance.
- work_dir = f".unetr_app_workdir{idx}"
- work_dirs.extend(work_dir)
-
- logging.info(f"Start processing input in: {dir} with results in: {output_path}")
-
- # Run app with specific input and output path.
- # Passing in the input and output do have the side effect of changing
- # app context. This side effect will likely be eliminated in later releases.
- app.run(input=dir, output=output_path, workdir=work_dir)
-
- logging.info(f"Completed processing input in: {dir} with results in: {output_path}")
- except Exception as ex:
- logging.error(f"Failed processing input in {dir}, due to: {ex}\n")
- traceback.print_exc()
- finally:
- # Remove the workdir; alternatively do this later, if storage space is not a concern.
- shutil.rmtree(work_dir, ignore_errors=True)
-
- # Alternative. Explicitly remove the working dirs at the end of main.
- # [shutil.rmtree(work_dir, ignore_errors=True) for work_dir in work_dirs]
+
+ logging.info(f"Begin {__name__}")
+ AIUnetrSegApp().run()
+ logging.info(f"End {__name__}")
diff --git a/examples/apps/ai_unetr_seg_app/unetr_seg_operator.py b/examples/apps/ai_unetr_seg_app/unetr_seg_operator.py
index 3f036503..d368459a 100644
--- a/examples/apps/ai_unetr_seg_app/unetr_seg_operator.py
+++ b/examples/apps/ai_unetr_seg_app/unetr_seg_operator.py
@@ -1,4 +1,4 @@
-# Copyright 2021 MONAI Consortium
+# Copyright 2021-2023 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
@@ -10,11 +10,11 @@
# limitations under the License.
import logging
+from pathlib import Path
from numpy import uint8
-import monai.deploy.core as md
-from monai.deploy.core import DataPath, ExecutionContext, Image, InputContext, IOType, Operator, OutputContext
+from monai.deploy.core import AppContext, ConditionType, Fragment, Operator, OperatorSpec
from monai.deploy.operators.monai_seg_inference_operator import InMemImageReader, MonaiSegInferenceOperator
from monai.transforms import (
Activationsd,
@@ -31,81 +31,116 @@
)
-@md.input("image", Image, IOType.IN_MEMORY)
-@md.output("seg_image", Image, IOType.IN_MEMORY)
-@md.output("saved_images_folder", DataPath, IOType.DISK)
-@md.env(pip_packages=["monai>=0.8.1", "torch>=1.5", "numpy>=1.21", "nibabel"])
+# @md.env(pip_packages=["monai>=0.8.1", "torch>=1.5", "numpy>=1.21", "nibabel"])
class UnetrSegOperator(Operator):
"""Performs multi-organ segmentation using UNETR model with an image converted from a DICOM CT series.
- This operator makes use of the App SDK MonaiSegInferenceOperator in a compsition approach.
+ Named Input:
+ image: Image object.
+
+ Named Outputs:
+ seg_image: Image object of the segmentation object.
+ saved_images_folder: Path to the folder with intermediate image output, not requiring a downstream receiver.
+
+ The model used in this application is published in MONAI Model Zoo,
+ https://github.com/Project-MONAI/model-zoo/tree/dev/models/swin_unetr_btcv_segmentation
+
+ This operator makes use of the App SDK MonaiSegInferenceOperator in a composition approach.
It creates the pre-transforms as well as post-transforms with MONAI dictionary based transforms.
Note that the App SDK InMemImageReader, derived from MONAI ImageReader, is passed to LoadImaged.
This derived reader is needed to parse the in memory image object, and return the expected data structure.
- Loading of the model, and predicting using in-proc PyTorch inference is done by MonaiSegInferenceOperator.
+ Loading of the model, and predicting using the in-proc PyTorch inference is done by MonaiSegInferenceOperator.
"""
- def __init__(self):
+ DEFAULT_OUTPUT_FOLDER = Path.cwd() / "output/saved_images_folder"
+
+ def __init__(
+ self,
+ frament: Fragment,
+ *args,
+ app_context: AppContext,
+ model_path: Path,
+ output_folder: Path = DEFAULT_OUTPUT_FOLDER,
+ **kwargs,
+ ):
self.logger = logging.getLogger("{}.{}".format(__name__, type(self).__name__))
- super().__init__()
+
self._input_dataset_key = "image"
self._pred_dataset_key = "pred"
- def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
- input_image = op_input.get("image")
+ self.model_path = model_path
+ self.output_folder = output_folder
+ self.output_folder.mkdir(parents=True, exist_ok=True)
+ self.fragement = frament # Cache and later pass the Fragment/Application to contained operator(s)
+ self.app_context = app_context
+ self.input_name_image = "image"
+ self.output_name_seg = "seg_image"
+ self.output_name_saved_images_folder = "saved_images_folder"
+
+ super().__init__(frament, *args, **kwargs)
+
+ def setup(self, spec: OperatorSpec):
+ spec.input(self.input_name_image)
+ spec.output(self.output_name_seg)
+ spec.output(self.output_name_saved_images_folder).condition(ConditionType.NONE) # Output not needing a receiver
+
+ def compute(self, op_input, op_output, context):
+ input_image = op_input.receive(self.input_name_image)
if not input_image:
raise ValueError("Input image is not found.")
- # Get the output path from the execution context for saving file(s) to app output.
- # Without using this path, operator would be saving files to its designated path, e.g.
- # $PWD/.monai_workdir/operators/6048d75a-5de1-45b9-8bd1-2252f88827f2/0/output
- op_output_folder_name = DataPath("saved_images_folder")
- op_output.set(op_output_folder_name, "saved_images_folder")
- op_output_folder_path = op_output.get("saved_images_folder").path
- op_output_folder_path.mkdir(parents=True, exist_ok=True)
- print(f"Operator output folder path: {op_output_folder_path}")
-
# This operator gets an in-memory Image object, so a specialized ImageReader is needed.
_reader = InMemImageReader(input_image)
+
# In this example, the input image, once loaded at the beginning of the pre-transforms, is
# saved on disk, so is the segmentation prediction image at the end of the post-transform.
# They are both saved in the same subfolder of the application output folder, with names
# distinguished by postfix. They can also be save in different subfolder if need be.
# These images files can then be packaged for rendering.
- pre_transforms = self.pre_process(_reader, op_output_folder_path)
- post_transforms = self.post_process(pre_transforms, op_output_folder_path)
+ pre_transforms = self.pre_process(_reader, str(self.output_folder))
+ post_transforms = self.post_process(pre_transforms, str(self.output_folder))
# Delegates inference and saving output to the built-in operator.
infer_operator = MonaiSegInferenceOperator(
- (
+ self.fragement,
+ roi_size=(
96,
96,
96,
),
- pre_transforms,
- post_transforms,
+ pre_transforms=pre_transforms,
+ post_transforms=post_transforms,
+ overlap=0.5,
+ app_context=self.app_context,
+ model_path=self.model_path,
)
- # Setting the keys used in the dictironary based transforms may change.
+ # Setting the keys used in the dictionary based transforms
infer_operator.input_dataset_key = self._input_dataset_key
infer_operator.pred_dataset_key = self._pred_dataset_key
- # Now let the built-in operator handles the work with the I/O spec and execution context.
- infer_operator.compute(op_input, op_output, context)
+ # Now emit data to the output ports of this operator
+ op_output.emit(infer_operator.compute_impl(input_image, context), self.output_name_seg)
+ op_output.emit(self.output_folder, self.output_name_saved_images_folder)
def pre_process(self, img_reader, out_dir: str = "./input_images") -> Compose:
"""Composes transforms for preprocessing input before predicting on a model."""
+ Path(out_dir).mkdir(parents=True, exist_ok=True)
+
my_key = self._input_dataset_key
return Compose(
[
LoadImaged(keys=my_key, reader=img_reader),
AddChanneld(keys=my_key),
+ # The SaveImaged transform can be commented out to save a couple seconds.
+ # Uncompress NIfTI file, nii, is used favoring speed over size, but can be changed to nii.gz
SaveImaged(
keys=my_key,
output_dir=out_dir,
output_postfix="",
resample=False,
+ output_ext=".nii",
),
Spacingd(keys=my_key, pixdim=(1.5, 1.5, 2.0), mode=("bilinear")),
Orientationd(keys=my_key, axcodes="RAS"),
@@ -117,6 +152,8 @@ def pre_process(self, img_reader, out_dir: str = "./input_images") -> Compose:
def post_process(self, pre_transforms: Compose, out_dir: str = "./prediction_output") -> Compose:
"""Composes transforms for postprocessing the prediction results."""
+ Path(out_dir).mkdir(parents=True, exist_ok=True)
+
pred_key = self._pred_dataset_key
return Compose(
[
@@ -125,6 +162,15 @@ def post_process(self, pre_transforms: Compose, out_dir: str = "./prediction_out
Invertd(
keys=pred_key, transform=pre_transforms, orig_keys=self._input_dataset_key, nearest_interp=True
),
- SaveImaged(keys=pred_key, output_dir=out_dir, output_postfix="seg", output_dtype=uint8, resample=False),
+ # The SaveImaged transform can be commented out to save a couple seconds.
+ # Uncompress NIfTI file, nii, is used favoring speed over size, but can be changed to nii.gz
+ SaveImaged(
+ keys=pred_key,
+ output_dir=out_dir,
+ output_postfix="seg",
+ output_dtype=uint8,
+ resample=False,
+ output_ext=".nii",
+ ),
]
)
diff --git a/examples/apps/breast_density_classifer_app/__main__.py b/examples/apps/breast_density_classifer_app/__main__.py
index 6c420630..c715a48e 100644
--- a/examples/apps/breast_density_classifer_app/__main__.py
+++ b/examples/apps/breast_density_classifer_app/__main__.py
@@ -1,4 +1,8 @@
+import logging
+
from app import BreastClassificationApp
if __name__ == "__main__":
- BreastClassificationApp(do_run=True)
+ logging.info(f"Begin {__name__}")
+ BreastClassificationApp().run()
+ logging.info(f"End {__name__}")
diff --git a/examples/apps/breast_density_classifer_app/app.py b/examples/apps/breast_density_classifer_app/app.py
index b87921f7..13cbdd2e 100644
--- a/examples/apps/breast_density_classifer_app/app.py
+++ b/examples/apps/breast_density_classifer_app/app.py
@@ -1,42 +1,76 @@
+import logging
+from pathlib import Path
+
from breast_density_classifier_operator import ClassifierOperator
-from monai.deploy.core import Application, env
+from monai.deploy.conditions import CountCondition
+from monai.deploy.core import AppContext, Application
from monai.deploy.operators.dicom_data_loader_operator import DICOMDataLoaderOperator
from monai.deploy.operators.dicom_series_selector_operator import DICOMSeriesSelectorOperator
from monai.deploy.operators.dicom_series_to_volume_operator import DICOMSeriesToVolumeOperator
from monai.deploy.operators.dicom_text_sr_writer_operator import DICOMTextSRWriterOperator, EquipmentInfo, ModelInfo
-@env(pip_packages=["highdicom>=0.18.2"])
+# @env(pip_packages=["monai~=1.1.0", "highdicom>=0.18.2", "pydicom >= 2.3.0"])
class BreastClassificationApp(Application):
+ """This is an AI breast density classification application.
+
+ The DL model was trained by Center for Augmented Intelligence in Imaging, Mayo Clinic, Florida,
+ and published on MONAI Model Zoo at
+ https://github.com/Project-MONAI/model-zoo/tree/dev/models/breast_density_classification
+ """
+
def __init__(self, *args, **kwargs):
+ self._logger = logging.getLogger("{}.{}".format(__name__, type(self).__name__))
super().__init__(*args, **kwargs)
def compose(self):
+ """Creates the app specific operators and chain them up in the processing DAG."""
+ logging.info(f"Begin {self.compose.__name__}")
+
+ # Use command line options over environment variables to init context.
+ app_context: AppContext = Application.init_app_context(self.argv)
+ app_input_path = Path(app_context.input_path)
+ app_output_path = Path(app_context.output_path)
+ model_path = Path(app_context.model_path)
+
model_info = ModelInfo(
"MONAI Model for Breast Density",
"BreastDensity",
"0.1",
"Center for Augmented Intelligence in Imaging, Mayo Clinic, Florida",
)
+
my_equipment = EquipmentInfo(manufacturer="MONAI Deploy App SDK", manufacturer_model="DICOM SR Writer")
my_special_tags = {"SeriesDescription": "Not for clinical use"}
- study_loader_op = DICOMDataLoaderOperator()
- series_selector_op = DICOMSeriesSelectorOperator(rules=Sample_Rules_Text)
- series_to_vol_op = DICOMSeriesToVolumeOperator()
- classifier_op = ClassifierOperator()
+ study_loader_op = DICOMDataLoaderOperator(
+ self, CountCondition(self, 1), input_folder=app_input_path, name="study_loader_op"
+ )
+ series_selector_op = DICOMSeriesSelectorOperator(self, rules=Sample_Rules_Text, name="series_selector_op")
+ series_to_vol_op = DICOMSeriesToVolumeOperator(self, name="series_to_vol_op")
+ classifier_op = ClassifierOperator(
+ self, app_context=app_context, output_folder=app_output_path, model_path=model_path, name="classifier_op"
+ )
sr_writer_op = DICOMTextSRWriterOperator(
- copy_tags=True, model_info=model_info, equipment_info=my_equipment, custom_tags=my_special_tags
+ self,
+ copy_tags=True,
+ model_info=model_info,
+ equipment_info=my_equipment,
+ custom_tags=my_special_tags,
+ output_folder=app_output_path,
+ name="sr_writer_op",
) # copy_tags=True to use Study and Patient modules of the original input
- self.add_flow(study_loader_op, series_selector_op, {"dicom_study_list": "dicom_study_list"})
+ self.add_flow(study_loader_op, series_selector_op, {("dicom_study_list", "dicom_study_list")})
self.add_flow(
- series_selector_op, series_to_vol_op, {"study_selected_series_list": "study_selected_series_list"}
+ series_selector_op, series_to_vol_op, {("study_selected_series_list", "study_selected_series_list")}
)
- self.add_flow(series_to_vol_op, classifier_op, {"image": "image"})
- self.add_flow(classifier_op, sr_writer_op, {"result_text": "classification_result"})
+ self.add_flow(series_to_vol_op, classifier_op, {("image", "image")})
+ self.add_flow(classifier_op, sr_writer_op, {("result_text", "text")})
# Pass the Study series to the SR writer for copying tags
- self.add_flow(series_selector_op, sr_writer_op, {"study_selected_series_list": "study_selected_series_list"})
+ self.add_flow(series_selector_op, sr_writer_op, {("study_selected_series_list", "study_selected_series_list")})
+
+ logging.info(f"End {self.compose.__name__}")
# This is a sample series selection rule in JSON, simply selecting a MG series.
@@ -69,4 +103,6 @@ def test():
if __name__ == "__main__":
- app = BreastClassificationApp(do_run=True)
+ logging.info(f"Begin {__name__}")
+ BreastClassificationApp().run()
+ logging.info(f"End {__name__}")
diff --git a/examples/apps/breast_density_classifer_app/breast_density_classifier_operator.py b/examples/apps/breast_density_classifer_app/breast_density_classifier_operator.py
index 9a51f70c..b74ec5a4 100644
--- a/examples/apps/breast_density_classifer_app/breast_density_classifier_operator.py
+++ b/examples/apps/breast_density_classifer_app/breast_density_classifier_operator.py
@@ -1,11 +1,12 @@
import json
-from typing import Dict, Text
+import os
+from pathlib import Path
+from typing import Dict, Optional
import torch
-import monai.deploy.core as md
from monai.data import DataLoader, Dataset
-from monai.deploy.core import ExecutionContext, Image, InputContext, IOType, Operator, OutputContext
+from monai.deploy.core import AppContext, ConditionType, Fragment, Image, Operator, OperatorSpec
from monai.deploy.operators.monai_seg_inference_operator import InMemImageReader
from monai.transforms import (
Activations,
@@ -20,14 +21,94 @@
)
-@md.input("image", Image, IOType.IN_MEMORY)
-@md.output("result_text", Text, IOType.IN_MEMORY)
+# @env(pip_packages=["monai~=1.1.0"])
class ClassifierOperator(Operator):
- def __init__(self):
- super().__init__()
+ """Performs breast density classification using a DL model with an image converted from a DICOM MG series.
+
+ Named inputs:
+ image: Image object for which to generate the classification.
+ output_folder: Optional, the path to save the results JSON file, overridingthe the one set on __init__
+
+ Named output:
+ result_text: The classification results in text.
+ """
+
+ DEFAULT_OUTPUT_FOLDER = Path.cwd() / "classification_results"
+ # For testing the app directly, the model should be at the following path.
+ MODEL_LOCAL_PATH = Path(os.environ.get("HOLOSCAN_MODEL_PATH", Path.cwd() / "model/model.ts"))
+
+ def __init__(
+ self,
+ frament: Fragment,
+ *args,
+ model_name: Optional[str] = "",
+ app_context: AppContext,
+ model_path: Path = MODEL_LOCAL_PATH,
+ output_folder: Path = DEFAULT_OUTPUT_FOLDER,
+ **kwargs,
+ ):
+ """Creates an instance with the reference back to the containing application/fragment.
+
+ fragment (Fragment): An instance of the Application class which is derived from Fragment.
+ model_name (str, optional): Name of the model. Default to "" for single model app.
+ model_path (Path): Path to the model file. Defaults to model/models.ts of current working dir.
+ output_folder (Path, optional): output folder for saving the classification results JSON file.
+ """
+
+ # the names used for the model inference input and output
self._input_dataset_key = "image"
self._pred_dataset_key = "pred"
+ # The names used for the operator input and output
+ self.input_name_image = "image"
+ self.output_name_result = "result_text"
+
+ # The name of the optional input port for passing data to override the output folder path.
+ self.input_name_output_folder = "output_folder"
+
+ # The output folder set on the object can be overriden at each compute by data in the optional named input
+ self.output_folder = output_folder
+
+ # Need the name when there are multiple models loaded
+ self._model_name = model_name.strip() if isinstance(model_name, str) else ""
+ # Need the path to load the models when they are not loaded in the execution context
+ self.model_path = model_path
+
+ # Use AppContect object for getting the loaded models
+ self.app_context = app_context
+
+ self.model = self._get_model(self.app_context, self.model_path, self._model_name)
+
+ super().__init__(frament, *args, **kwargs)
+
+ def _get_model(self, app_context: AppContext, model_path: Path, model_name: str):
+ """Load the model with the given name from context or model path
+
+ Args:
+ app_context (AppContext): The application context object holding the model(s)
+ model_path (Path): The path to the model file, as a backup to load model directly
+ model_name (str): The name of the model, when multiples are loaded in the context
+ """
+
+ if app_context.models:
+ # `app_context.models.get(model_name)` returns a model instance if exists.
+ # If model_name is not specified and only one model exists, it returns that model.
+ model = app_context.models.get(model_name)
+ else:
+ model = torch.jit.load(
+ ClassifierOperator.MODEL_LOCAL_PATH,
+ map_location=torch.device("cuda" if torch.cuda.is_available() else "cpu"),
+ )
+
+ return model
+
+ def setup(self, spec: OperatorSpec):
+ """Set up the operator named input and named output, both are in-memory objects."""
+
+ spec.input(self.input_name_image)
+ spec.input(self.input_name_output_folder).condition(ConditionType.NONE) # Optional for overriding.
+ spec.output(self.output_name_result).condition(ConditionType.NONE) # Not forcing a downstream receiver.
+
def _convert_dicom_metadata_datatype(self, metadata: Dict):
if not metadata:
return metadata
@@ -55,16 +136,22 @@ def _convert_dicom_metadata_datatype(self, metadata: Dict):
return metadata
- def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
- input_image = op_input.get("image")
+ def compute(self, op_input, op_output, context):
+ input_image = op_input.receive(self.input_name_image)
+ if not input_image:
+ raise ValueError("Input image is not found.")
+ if not isinstance(input_image, Image):
+ raise ValueError(f"Input is not the required type: {type(Image)!r}")
+
_reader = InMemImageReader(input_image)
input_img_metadata = self._convert_dicom_metadata_datatype(input_image.metadata())
img_name = str(input_img_metadata.get("SeriesInstanceUID", "Img_in_context"))
- output_path = context.output.get().path
-
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
- model = context.models.get()
+
+ # Need to get the model from context, when it is re-implemented, and for now, load it directly here.
+ # model = context.models.get()
+ model = torch.jit.load(self.model_path, map_location=device)
pre_transforms = self.pre_process(_reader)
post_transforms = self.post_process()
@@ -82,16 +169,16 @@ def compute(self, op_input: InputContext, op_output: OutputContext, context: Exe
result_dict = (
"A " + ":" + str(out[0]) + " B " + ":" + str(out[1]) + " C " + ":" + str(out[2]) + " D " + ":" + str(out[3])
)
- result_dict_out = {"A": str(out[0]), "B": str(out[1]), "C": str(out[2]), "D": str(out[3])}
- output_folder = context.output.get().path
- output_folder.mkdir(parents=True, exist_ok=True)
- output_path = output_folder / "output.json"
+ op_output.emit(result_dict, "result_text")
+
+ # Get output folder, with value in optional input port overriding the obj attribute
+ output_folder_on_compute = op_input.receive(self.input_name_output_folder) or self.output_folder
+ Path.mkdir(output_folder_on_compute, parents=True, exist_ok=True) # Let exception bubble up if raised.
+ output_path = output_folder_on_compute / "output.json"
with open(output_path, "w") as fp:
json.dump(result_dict, fp)
- op_output.set(result_dict, "result_text")
-
def pre_process(self, image_reader) -> Compose:
return Compose(
[
diff --git a/examples/apps/deploy_app_on_aarch64.md b/examples/apps/deploy_app_on_aarch64.md
new file mode 100644
index 00000000..e163814d
--- /dev/null
+++ b/examples/apps/deploy_app_on_aarch64.md
@@ -0,0 +1,9 @@
+# MONAI Application Package for ARMv8 AArch64 on Linux
+
+This article describes how to containerize a MONAI Deploy application, as a **MONAI Application Package**, targeting ARMv8 AArch64 on Linux.
+
+Section [Packaging App](https://docs.monai.io/projects/monai-deploy-app-sdk/en/stable/developing_with_sdk/packaging_app.html) in the MONAI Deploy App SDK [Users Guide](https://docs.monai.io/projects/monai-deploy-app-sdk/en/stable/index.html) describes the general steps to package an application into a MAP. Building MAPs for AArch64 on Linux with discrete GPU can be done with this simple change of command line options,
+
+`--platform x64-workstation` replaced with
+
+`--platform igx-orin-devkit --platform-config dgpu`
\ No newline at end of file
diff --git a/examples/apps/deply_app_on_aarch64_interim.md b/examples/apps/deply_app_on_aarch64_interim.md
deleted file mode 100644
index 7a38225f..00000000
--- a/examples/apps/deply_app_on_aarch64_interim.md
+++ /dev/null
@@ -1,114 +0,0 @@
-# Containerizing MONAI Deploy Application for ARMv8 AArch64 (Interim Solution)
-
-This article describes how to containerize a MONAI Deploy application targeting ARMv8 AArch64, without using the MONAI Deploy App SDK Packager or Runner as they do not yet support ARMv8 AArch64. A Docker image will be generated, though not in the form of the **MONAI Application Package**.
-
-## Overview of Solution
-
-The [MONAI Application Packager (Packager)](https://docs.monai.io/projects/monai-deploy-app-sdk/en/latest/developing_with_sdk/packaging_app.html) is a utility for building an application developed with the MONAI Deploy App SDK into a structured MONAI Application Package (**MAP**). The MAP produced by the Packager is a deployable and reusable docker image that can be launched by applicatons that can parse and understand MAP format, e.g. the [MONAI Application Runner (MAR)](https://docs.monai.io/projects/monai-deploy-app-sdk/en/latest/developing_with_sdk/executing_packaged_app_locally.html).
-
-The Packager and MAR, however, do not support AArch64 in APP SDK release v0.1, due to the following reasons,
-- The Packager limits the use of base Docker images to those targeting x86 on Ubuntu only
-- The Packager injects an binary executable that only supports x86 in the generated MAP, and sets it as the Docker entry point
-- The MAR runs the MAP Docker with the aforementioned entry point
-
-An interim solution is therefore provided to containerize and deploy a MONAI Deploy application for AArch64,
-- Make use of an trusted AArch64 compatible base image, e.g. [nvcr.io/nvidia/clara-agx:21.05-1.7-py3](https://ngc.nvidia.com/catalog/containers/nvidia:clara-agx:agx-pytorch) which is based on Ubuntu 18.04.5 LTS and already has PyTorch 1.7
-- Use custom Docker file to explicitly install dependencies with a `requirements` file and setting the application's main function as the entry point
-- Build the application docker with the aforementioned `Dockerfile` and `requirements` file on a AArch64 host computer. [Docker Buildx](https://docs.docker.com/buildx/working-with-buildx/) can also be used to build multi-platform images, though it is not used in this example
-- On the AArch64 host machine, use `docker run` command or a script to launch the application docker
-
-## Steps
-### Create the MONAI Deploy Application
-For general guidance on how to build a deploy application using MONAI Deploy App SDK, and test it on x86 with the Packager and Runner, please refer to [Developing with SDK](https://docs.monai.io/projects/monai-deploy-app-sdk/en/latest/developing_with_sdk/index.html).
-
-For the specific example on building and running a segmentation application, e.g. the Spleen segmentation application, please see [Creating a Segmentation App](https://docs.monai.io/projects/monai-deploy-app-sdk/en/latest/getting_started/tutorials/03_segmentation_app.html).
-
-In the following sections, the UNETR Multi-organ Segmentation application will be used as an example.
-
-### Create the requirements file
-Without using the MONAI Deploy App SDK Packager to automatically detect the dependencies of an application, one has to explicitly create the `requierments.txt` file to be used in the `Dockerfile`. Create the `requirements.txt` file in the application's folder with the content shown below,
-```bash
-monai>=0.8.1
-monai-deploy-app-sdk>=0.1.0
-nibabel
-numpy>=1.21
-pydicom>=1.4.2
-torch>=1.5
-```
-Note: The base image to be used already has torch 1.7 and numpy 19.5 pre-installed.
-
-### Crete the Custom Dockerfile
-Create the `Dockerfile` in the application folder with the content shown below,
-
-```bash
-ARG CONTAINER_REGISTRY=nvcr.io/nvidia/clara-agx
-ARG AGX_PT_TAG=21.05-1.7-py3
-FROM ${CONTAINER_REGISTRY}/agx-pytorch:${AGX_PT_TAG}
-
-# This is the name of the folder containing the application files.
-ENV MY_APP_NAME="ai_unetr_seg_app"
-
-USER root
-
-RUN pip3 install --no-cache-dir --upgrade setuptools==57.4.0 wheel==0.37.0
-
-WORKDIR /opt/$MY_APP_NAME
-
-COPY ./$MY_APP_NAME/requirements.txt ./
-RUN pip3 install --no-cache-dir -r requirements.txt
-
-# Copy the application source code.
-COPY ./$MY_APP_NAME ./
-ENTRYPOINT python3 -u ./app.py -i /input -m /model/model.ts -o /output
-```
-Note that
-- The application files are copied to `/opt/unetr_seg_app` in this example
-- The input DICOM instances are in folder `/input`
-- The Torch Script model file `model.ts` is in `/model`
-- The applicaton output will be in `/output`
-
-### Build the Docker Image targeting AArch64
-Copy the application folder including the `requirements.txt` and `Dockerfile` to the working directory, e.g. `my_apps`, on a AArch64 host machine, and ensure Docker is already installed. The application folder structure looks like below,
-```bash
-my_apps
- └─ ai_unetr_seg_app
- ├── app.py
- ├── Dockerfile
- ├── __init__.py
- ├── __main__.py
- ├── requirements.txt
- └── unetr_seg_operator.py
-```
-
-In working directory `my_apps`, build the Dcoker image, named `ai_unetr_seg_app` with the default tag `default`with the following command,
-```bash
-docker build -t ai_unetr_seg_app -f ai_unetr_seg_app/Dockerfile .
-```
-### Run the Application Docker Locally
-On launching the application docker, input DICOM instances as well model file `model.ts` must be available, and the output folder may be a mounted NFS file share hosted on a remote machine.
-A sample shell script is provided below,
-```
-# Root of the datasets folder, change as needed
-OUTPUT_ROOT="/mnt/nfs_clientshare"
-DATASETS_FOLDER="datasets"
-
-# App specific parameters, change as needed and ensure contents are present.
-APP_DATASET_FOLDER="unetr_dataset"
-INPUT_FOLDER="/media/m2/monai_apps/input"
-MODEL_FOLDER="/media/m2/monai_apps/models/unetr"
-DOCKER_IMAGE="ai_unetr_seg_app"
-
-APP_DATASET_PATH=${OUTPUT_ROOT}/${DATASETS_FOLDER}/${APP_DATASET_FOLDER}
-echo "Set to save rendering dataset to: ${APP_DATASET_PATH} ..."
-docker run -t --rm --shm-size=1G \
- -v ${INPUT_FOLDER}:/input \
- -v ${MODEL_FOLDER}:/model \
- -v ${APP_DATASET_PATH}:/output \
- ${DOCKER_IMAGE}
-echo "${DOCKER_IMAGE} completed."
-echo
-echo "Rendering dataset files are saved in the folder, ${APP_DATASET_PATH}:"
-ls ${APP_DATASET_PATH}
-```
-
-Once application docker terminates, check the application output in the folder shown in the console log.
\ No newline at end of file
diff --git a/examples/apps/dicom_series_to_image_app/__init__.py b/examples/apps/dicom_series_to_image_app/__init__.py
index 521cb31b..526cee59 100644
--- a/examples/apps/dicom_series_to_image_app/__init__.py
+++ b/examples/apps/dicom_series_to_image_app/__init__.py
@@ -1,3 +1,14 @@
+# Copyright 2021-2023 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 os
import sys
diff --git a/examples/apps/dicom_series_to_image_app/__main__.py b/examples/apps/dicom_series_to_image_app/__main__.py
index 412a8ca1..05eeb791 100644
--- a/examples/apps/dicom_series_to_image_app/__main__.py
+++ b/examples/apps/dicom_series_to_image_app/__main__.py
@@ -1,4 +1,15 @@
+# Copyright 2021-2023 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.
+
from app import App
if __name__ == "__main__":
- App(do_run=True)
+ App().run()
diff --git a/examples/apps/dicom_series_to_image_app/app.py b/examples/apps/dicom_series_to_image_app/app.py
index b820610d..6669f25f 100644
--- a/examples/apps/dicom_series_to_image_app/app.py
+++ b/examples/apps/dicom_series_to_image_app/app.py
@@ -1,4 +1,4 @@
-# Copyright 2021 MONAI Consortium
+# Copyright 2021-2023 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
@@ -9,8 +9,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+from pathlib import Path
-from monai.deploy.core import Application
+from monai.deploy.conditions import CountCondition
+from monai.deploy.core import AppContext, Application
from monai.deploy.operators.dicom_data_loader_operator import DICOMDataLoaderOperator
from monai.deploy.operators.dicom_series_selector_operator import DICOMSeriesSelectorOperator
from monai.deploy.operators.dicom_series_to_volume_operator import DICOMSeriesToVolumeOperator
@@ -18,18 +20,33 @@
class App(Application):
+ """This application loads DICOM files, converts them to 3D image, then to PNG files on disk.
+
+ This showcases the MONAI Deploy application framework
+ """
+
def compose(self):
- study_loader_op = DICOMDataLoaderOperator()
- series_selector_op = DICOMSeriesSelectorOperator()
- series_to_vol_op = DICOMSeriesToVolumeOperator()
- png_converter_op = PNGConverterOperator()
+ # Use command line options over environment variables to init context.
+ app_context: AppContext = Application.init_app_context(self.argv)
+ input_dcm_folder = Path(app_context.input_path)
+ output_folder = Path(app_context.output_path)
+ print(f"input_dcm_folder: {input_dcm_folder}")
+
+ # Set the first operator to run only once by setting the count condition to 1
+ study_loader_op = DICOMDataLoaderOperator(
+ self, CountCondition(self, 1), input_folder=input_dcm_folder, name="dcm_loader"
+ )
+ series_selector_op = DICOMSeriesSelectorOperator(self, name="series_selector")
+ series_to_vol_op = DICOMSeriesToVolumeOperator(self, name="series_to_vol")
+ png_converter_op = PNGConverterOperator(self, output_folder=output_folder, name="png_converter")
- self.add_flow(study_loader_op, series_selector_op, {"dicom_study_list": "dicom_study_list"})
+ # Create the execution DAG by linking operators' named output to named input.
+ self.add_flow(study_loader_op, series_selector_op, {("dicom_study_list", "dicom_study_list")})
self.add_flow(
- series_selector_op, series_to_vol_op, {"study_selected_series_list": "study_selected_series_list"}
+ series_selector_op, series_to_vol_op, {("study_selected_series_list", "study_selected_series_list")}
)
- self.add_flow(series_to_vol_op, png_converter_op, {"image": "image"})
+ self.add_flow(series_to_vol_op, png_converter_op, {("image", "image")})
if __name__ == "__main__":
- App(do_run=True)
+ App().run()
diff --git a/examples/apps/mednist_classifier_monaideploy/app.yaml b/examples/apps/mednist_classifier_monaideploy/app.yaml
new file mode 100644
index 00000000..aef9cf32
--- /dev/null
+++ b/examples/apps/mednist_classifier_monaideploy/app.yaml
@@ -0,0 +1,27 @@
+%YAML 1.2
+# SPDX-FileCopyrightText: Copyright (c) 2022-2023 MONAI. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0
+#
+# 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.
+---
+application:
+ title: MONAI Deploy App Package - MedNIST Classifier App
+ version: 1.0
+ inputFormats: ["file"]
+ outputFormats: ["file"]
+
+resources:
+ cpu: 1
+ gpu: 1
+ memory: 1Gi
+ gpuMemory: 1Gi
diff --git a/examples/apps/mednist_classifier_monaideploy/mednist_classifier_monaideploy.py b/examples/apps/mednist_classifier_monaideploy/mednist_classifier_monaideploy.py
index af301878..93eb3709 100644
--- a/examples/apps/mednist_classifier_monaideploy/mednist_classifier_monaideploy.py
+++ b/examples/apps/mednist_classifier_monaideploy/mednist_classifier_monaideploy.py
@@ -1,4 +1,4 @@
-# Copyright 2021 MONAI Consortium
+# Copyright 2021-2023 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
@@ -9,110 +9,230 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from typing import Text
-
-import monai.deploy.core as md
-from monai.deploy.core import (
- Application,
- DataPath,
- ExecutionContext,
- Image,
- InputContext,
- IOType,
- Operator,
- OutputContext,
-)
-from monai.deploy.operators import DICOMTextSRWriterOperator, EquipmentInfo, ModelInfo
+import logging
+import os
+from pathlib import Path
+from typing import Optional
+
+import torch
+
+from monai.deploy.conditions import CountCondition
+from monai.deploy.core import AppContext, Application, ConditionType, Fragment, Image, Operator, OperatorSpec
+from monai.deploy.operators.dicom_text_sr_writer_operator import DICOMTextSRWriterOperator, EquipmentInfo, ModelInfo
from monai.transforms import AddChannel, Compose, EnsureType, ScaleIntensity
MEDNIST_CLASSES = ["AbdomenCT", "BreastMRI", "CXR", "ChestCT", "Hand", "HeadCT"]
-@md.input("image", DataPath, IOType.DISK)
-@md.output("image", Image, IOType.IN_MEMORY)
-@md.env(pip_packages=["pillow"])
+# Decorator support is not available in this version of the SDK, to be re-introduced later
+# @md.env(pip_packages=["pillow"])
class LoadPILOperator(Operator):
"""Load image from the given input (DataPath) and set numpy array to the output (Image)."""
- def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
+ DEFAULT_INPUT_FOLDER = Path.cwd() / "input"
+ DEFAULT_OUTPUT_NAME = "image"
+
+ # For now, need to have the input folder as an instance attribute, set on init.
+ # If dynamically changing the input folder, per compute, then use a (optional) input port to convey the
+ # value of the input folder, which is then emitted by a upstream operator.
+ def __init__(
+ self,
+ fragment: Fragment,
+ *args,
+ input_folder: Path = DEFAULT_INPUT_FOLDER,
+ output_name: str = DEFAULT_OUTPUT_NAME,
+ **kwargs,
+ ):
+ """Creates an loader object with the input folder and the output port name overrides as needed.
+
+ Args:
+ fragment (Fragment): An instance of the Application class which is derived from Fragment.
+ input_folder (Path): Folder from which to load input file(s).
+ Defaults to `input` in the current working directory.
+ output_name (str): Name of the output port, which is an image object. Defaults to `image`.
+ """
+
+ self._logger = logging.getLogger("{}.{}".format(__name__, type(self).__name__))
+ self.input_path = input_folder
+ self.index = 0
+ self.output_name_image = (
+ output_name.strip() if output_name and len(output_name.strip()) > 0 else LoadPILOperator.DEFAULT_OUTPUT_NAME
+ )
+
+ super().__init__(fragment, *args, **kwargs)
+
+ def setup(self, spec: OperatorSpec):
+ """Set up the named input and output port(s)"""
+ spec.output(self.output_name_image)
+
+ def compute(self, op_input, op_output, context):
import numpy as np
from PIL import Image as PILImage
- input_path = op_input.get().path
+ # Input path is stored in the object attribute, but could change to use a named port if need be.
+ input_path = self.input_path
if input_path.is_dir():
- input_path = next(input_path.glob("*.*")) # take the first file
+ input_path = next(self.input_path.glob("*.*")) # take the first file
image = PILImage.open(input_path)
image = image.convert("L") # convert to greyscale image
image_arr = np.asarray(image)
output_image = Image(image_arr) # create Image domain object with a numpy array
- op_output.set(output_image)
+ op_output.emit(output_image, self.output_name_image) # cannot omit the name even if single output.
-@md.input("image", Image, IOType.IN_MEMORY)
-@md.output("result_text", Text, IOType.IN_MEMORY)
-@md.env(pip_packages=["monai"])
+# @md.env(pip_packages=["monai"])
class MedNISTClassifierOperator(Operator):
- """Classifies the given image and returns the class name."""
+ """Classifies the given image and returns the class name.
+
+ Named inputs:
+ image: Image object for which to generate the classification.
+ output_folder: Optional, the path to save the results JSON file, overridingthe the one set on __init__
+
+ Named output:
+ result_text: The classification results in text.
+ """
+
+ DEFAULT_OUTPUT_FOLDER = Path.cwd() / "classification_results"
+ # For testing the app directly, the model should be at the following path.
+ MODEL_LOCAL_PATH = Path(os.environ.get("HOLOSCAN_MODEL_PATH", Path.cwd() / "model/model.ts"))
+
+ def __init__(
+ self,
+ frament: Fragment,
+ *args,
+ app_context: AppContext,
+ model_name: Optional[str] = "",
+ model_path: Path = MODEL_LOCAL_PATH,
+ output_folder: Path = DEFAULT_OUTPUT_FOLDER,
+ **kwargs,
+ ):
+ """Creates an instance with the reference back to the containing application/fragment.
+
+ fragment (Fragment): An instance of the Application class which is derived from Fragment.
+ model_name (str, optional): Name of the model. Default to "" for single model app.
+ model_path (Path): Path to the model file. Defaults to model/models.ts of current working dir.
+ output_folder (Path, optional): output folder for saving the classification results JSON file.
+ """
+
+ # the names used for the model inference input and output
+ self._input_dataset_key = "image"
+ self._pred_dataset_key = "pred"
+
+ # The names used for the operator input and output
+ self.input_name_image = "image"
+ self.output_name_result = "result_text"
+
+ # The name of the optional input port for passing data to override the output folder path.
+ self.input_name_output_folder = "output_folder"
+
+ # The output folder set on the object can be overriden at each compute by data in the optional named input
+ self.output_folder = output_folder
+
+ # Need the name when there are multiple models loaded
+ self._model_name = model_name.strip() if isinstance(model_name, str) else ""
+ # Need the path to load the models when they are not loaded in the execution context
+ self.model_path = model_path
+ self.app_context = app_context
+ self.model = self._get_model(self.app_context, self.model_path, self._model_name)
+
+ # This needs to be at the end of the constructor.
+ super().__init__(frament, *args, **kwargs)
+
+ def _get_model(self, app_context: AppContext, model_path: Path, model_name: str):
+ """Load the model with the given name from context or model path
+
+ Args:
+ app_context (AppContext): The application context object holding the model(s)
+ model_path (Path): The path to the model file, as a backup to load model directly
+ model_name (str): The name of the model, when multiples are loaded in the context
+ """
+
+ if app_context.models:
+ # `app_context.models.get(model_name)` returns a model instance if exists.
+ # If model_name is not specified and only one model exists, it returns that model.
+ model = app_context.models.get(model_name)
+ else:
+ model = torch.jit.load(
+ MedNISTClassifierOperator.MODEL_LOCAL_PATH,
+ map_location=torch.device("cuda" if torch.cuda.is_available() else "cpu"),
+ )
+
+ return model
+
+ def setup(self, spec: OperatorSpec):
+ """Set up the operator named input and named output, both are in-memory objects."""
+
+ spec.input(self.input_name_image)
+ spec.input(self.input_name_output_folder).condition(ConditionType.NONE) # Optional for overriding.
+ spec.output(self.output_name_result).condition(ConditionType.NONE) # Not forcing a downstream receiver.
@property
def transform(self):
return Compose([AddChannel(), ScaleIntensity(), EnsureType()])
- def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
+ def compute(self, op_input, op_output, context):
import json
import torch
- img = op_input.get().asnumpy() # (64, 64), uint8
+ img = op_input.receive(self.input_name_image).asnumpy() # (64, 64), uint8. Input validation can be added.
image_tensor = self.transform(img) # (1, 64, 64), torch.float64
image_tensor = image_tensor[None].float() # (1, 1, 64, 64), torch.float32
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
image_tensor = image_tensor.to(device)
- model = context.models.get() # get a TorchScriptModel object
-
with torch.no_grad():
- outputs = model(image_tensor)
+ outputs = self.model(image_tensor)
_, output_classes = outputs.max(dim=1)
result = MEDNIST_CLASSES[output_classes[0]] # get the class name
print(result)
- op_output.set(result, "result_text")
+ op_output.emit(result, self.output_name_result)
- # Get output (folder) path and create the folder if not exists
- # The following gets the App context's output path, instead the operator's.
- output_folder = context.output.get().path
- output_folder.mkdir(parents=True, exist_ok=True)
-
- # Write result to "output.json"
- output_path = output_folder / "output.json"
+ # Get output folder, with value in optional input port overriding the obj attribute
+ output_folder_on_compute = op_input.receive(self.input_name_output_folder) or self.output_folder
+ Path.mkdir(output_folder_on_compute, parents=True, exist_ok=True) # Let exception bubble up if raised.
+ output_path = output_folder_on_compute / "output.json"
with open(output_path, "w") as fp:
json.dump(result, fp)
-@md.resource(cpu=1, gpu=1, memory="1Gi")
-@md.env(pip_packages=["pydicom >= 2.3.0", "highdicom>=0.18.2"]) # because of the use of DICOM writer operator
+# Decorator support is not available in this version of the SDK, to be re-introduced later
+# @md.resource(cpu=1, gpu=1, memory="1Gi")
+# @md.env(pip_packages=["pydicom >= 2.3.0", "highdicom>=0.18.2"]) # because of the use of DICOM writer operator
class App(Application):
"""Application class for the MedNIST classifier."""
def compose(self):
- load_pil_op = LoadPILOperator()
- classifier_op = MedNISTClassifierOperator()
+ # Use Commandline options over environment variables to init context.
+ app_context: AppContext = Application.init_app_context(self.argv)
+ app_input_path = Path(app_context.input_path)
+ app_output_path = Path(app_context.output_path)
+ model_path = Path(app_context.model_path)
+ load_pil_op = LoadPILOperator(self, CountCondition(self, 1), input_folder=app_input_path, name="pil_loader_op")
+ classifier_op = MedNISTClassifierOperator(
+ self, app_context=app_context, output_folder=app_output_path, model_path=model_path, name="classifier_op"
+ )
my_model_info = ModelInfo("MONAI WG Trainer", "MEDNIST Classifier", "0.1", "xyz")
my_equipment = EquipmentInfo(manufacturer="MOANI Deploy App SDK", manufacturer_model="DICOM SR Writer")
my_special_tags = {"SeriesDescription": "Not for clinical use. The result is for research use only."}
dicom_sr_operator = DICOMTextSRWriterOperator(
- copy_tags=False, model_info=my_model_info, equipment_info=my_equipment, custom_tags=my_special_tags
+ self,
+ copy_tags=False,
+ model_info=my_model_info,
+ equipment_info=my_equipment,
+ custom_tags=my_special_tags,
+ output_folder=app_output_path,
)
- self.add_flow(load_pil_op, classifier_op)
- self.add_flow(classifier_op, dicom_sr_operator, {"result_text": "classification_result"})
+ self.add_flow(load_pil_op, classifier_op, {("image", "image")})
+ self.add_flow(classifier_op, dicom_sr_operator, {("result_text", "text")})
if __name__ == "__main__":
- App(do_run=True)
+ App().run()
diff --git a/examples/apps/mednist_classifier_monaideploy/requirements.txt b/examples/apps/mednist_classifier_monaideploy/requirements.txt
new file mode 100644
index 00000000..aa0926f1
--- /dev/null
+++ b/examples/apps/mednist_classifier_monaideploy/requirements.txt
@@ -0,0 +1,7 @@
+monai>=1.2.0
+Pillow>=8.4.0
+pydicom>=2.3.0
+highdicom>=0.18.2
+SimpleITK>=2.0.0
+setuptools>=59.5.0 # for pkg_resources
+
diff --git a/examples/apps/simple_imaging_app/__main__.py b/examples/apps/simple_imaging_app/__main__.py
index 412a8ca1..19c8084d 100644
--- a/examples/apps/simple_imaging_app/__main__.py
+++ b/examples/apps/simple_imaging_app/__main__.py
@@ -1,4 +1,4 @@
from app import App
if __name__ == "__main__":
- App(do_run=True)
+ App().run()
diff --git a/examples/apps/simple_imaging_app/app.py b/examples/apps/simple_imaging_app/app.py
index e56dfe01..6f38b2a3 100644
--- a/examples/apps/simple_imaging_app/app.py
+++ b/examples/apps/simple_imaging_app/app.py
@@ -9,16 +9,20 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import logging
+from pathlib import Path
+
from gaussian_operator import GaussianOperator
from median_operator import MedianOperator
from sobel_operator import SobelOperator
-from monai.deploy.core import Application, env, resource
+from monai.deploy.conditions import CountCondition
+from monai.deploy.core import AppContext, Application
-@resource(cpu=1)
-# pip_packages can be a string that is a path(str) to requirements.txt file or a list of packages.
-@env(pip_packages=["scikit-image >= 0.17.2"])
+# Decorator support is not available in this version of the SDK, to be re-introduced later
+# @resource(cpu=1)
+# @env(pip_packages=["scikit-image >= 0.17.2"])
class App(Application):
"""This is a very basic application.
@@ -38,16 +42,40 @@ def compose(self):
Each operator has a single input and a single output port.
Each operator performs some kind of image processing function.
"""
- sobel_op = SobelOperator()
- median_op = MedianOperator()
- gaussian_op = GaussianOperator()
- self.add_flow(sobel_op, median_op)
- # self.add_flow(sobel_op, median_op, {"image": "image"})
- # self.add_flow(sobel_op, median_op, {"image": {"image"}})
+ # Use Commandline options over environment variables to init context.
+ app_context: AppContext = Application.init_app_context(self.argv)
+ sample_data_path = Path(app_context.input_path)
+ output_data_path = Path(app_context.output_path)
+ logging.info(f"sample_data_path: {sample_data_path}")
- self.add_flow(median_op, gaussian_op)
+ # Please note that the Application object, self, is passed as the first positonal argument
+ # and the others as kwargs.
+ # Also note the CountCondition of 1 on the first operator, indicating to the application executor
+ # to invoke this operator, hence the pipleline, only once.
+ sobel_op = SobelOperator(self, CountCondition(self, 1), input_path=sample_data_path, name="sobel_op")
+ median_op = MedianOperator(self, name="median_op")
+ gaussian_op = GaussianOperator(self, output_folder=output_data_path, name="gaussian_op")
+ self.add_flow(
+ sobel_op,
+ median_op,
+ {
+ ("out1", "in1"),
+ },
+ )
+ self.add_flow(
+ median_op,
+ gaussian_op,
+ {
+ (
+ "out1",
+ "in1",
+ )
+ },
+ )
if __name__ == "__main__":
- App(do_run=True)
+ logging.info(f"Begin {__name__}")
+ App().run()
+ logging.info(f"End {__name__}")
diff --git a/monai/deploy/packager/__init__.py b/examples/apps/simple_imaging_app/app.yaml
similarity index 56%
rename from monai/deploy/packager/__init__.py
rename to examples/apps/simple_imaging_app/app.yaml
index 528c344a..a2dc9011 100644
--- a/monai/deploy/packager/__init__.py
+++ b/examples/apps/simple_imaging_app/app.yaml
@@ -1,10 +1,27 @@
-# Copyright 2021 MONAI Consortium
+%YAML 1.2
+# SPDX-FileCopyrightText: Copyright (c) 2022-2023 MONAI. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0
+#
# 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
+#
+# 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.
+---
+application:
+ title: MONAI Deploy App Package - Simple Imaging App
+ version: 1.0
+ inputFormats: ["file"]
+ outputFormats: ["file"]
+
+resources:
+ cpu: 1
+ gpu: 1
+ memory: 1Gi
+ gpuMemory: 1Gi
diff --git a/examples/apps/simple_imaging_app/gaussian_operator.py b/examples/apps/simple_imaging_app/gaussian_operator.py
index c9f0cec8..e924afc9 100644
--- a/examples/apps/simple_imaging_app/gaussian_operator.py
+++ b/examples/apps/simple_imaging_app/gaussian_operator.py
@@ -9,34 +9,75 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import monai.deploy.core as md
-from monai.deploy.core import DataPath, ExecutionContext, Image, InputContext, IOType, Operator, OutputContext
+from pathlib import Path
+
+from monai.deploy.core import ConditionType, Fragment, Operator, OperatorSpec
-@md.input("image", Image, IOType.IN_MEMORY)
-@md.output("image", DataPath, IOType.DISK)
# If `pip_packages` is specified, the definition will be aggregated with the package dependency list of other
# operators and the application in packaging time.
# @md.env(pip_packages=["scikit-image >= 0.17.2"])
class GaussianOperator(Operator):
"""This Operator implements a smoothening based on Gaussian.
- It ingests a single input and provides a single output.
+ It has the following input and output:
+ single input:
+ an image array object
+ single output:
+ an image arrary object, without enforcing a downsteam receiver
+
+ Besides, this operator also saves the image file in the given output folder.
"""
- def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
+ DEFAULT_OUTPUT_FOLDER = Path.cwd() / "output"
+
+ def __init__(self, fragment: Fragment, *args, output_folder: Path, **kwargs):
+ """Create an instance to be part of the given application (fragment).
+
+ Args:
+ fragment (Fragment): The instance of Application class which is derived from Fragment
+ output_folder (Path): The folder to save the output file.
+ """
+ self.output_folder = output_folder if output_folder else GaussianOperator.DEFAULT_OUTPUT_FOLDER
+ self.index = 0
+
+ # If `self.sigma_default` is set here (e.g., `self.sigma_default = 0.2`), then
+ # the default value by `param()` in `setup()` will be ignored.
+ # (you can just call `spec.param("sigma_default")` in `setup()` to use the
+ # default value)
+ self.sigma_default = 0.2
+ self.channel_axis = 2
+
+ # Need to call the base class constructor last
+ super().__init__(fragment, *args, **kwargs)
+
+ def setup(self, spec: OperatorSpec):
+ spec.input("in1")
+ spec.output("out1").condition(ConditionType.NONE) # Condition is for no or not-ready receiver ports.
+ spec.param("sigma_default", 0.2)
+ spec.param("channel_axis", 2)
+
+ def compute(self, op_input, op_output, context):
import numpy as np
from skimage.filters import gaussian
from skimage.io import imsave
- data_in = op_input.get().asnumpy()
- data_out = gaussian(data_in, sigma=0.2, channel_axis=2) # Add the param introduced in 0.19.
+ self.index += 1
+ print(f"Number of times operator {self.name} whose class is defined in {__name__} called: {self.index}")
+
+ data_in = op_input.receive("in1")
+ data_out = gaussian(data_in, sigma=self.sigma_default, channel_axis=self.channel_axis)
# Make sure the data type is what PIL Image can support, as the imsave function calls PIL Image fromarray()
# Some details can be found at https://stackoverflow.com/questions/55319949/pil-typeerror-cannot-handle-this-data-type
+ print(f"Data type of output: {type(data_out)!r}, max = {np.max(data_out)!r}")
if np.max(data_out) <= 1:
data_out = (data_out * 255).astype(np.uint8)
+ print(f"Data type of output post conversion: {type(data_out)!r}, max = {np.max(data_out)!r}")
- output_folder = op_output.get().path
- output_path = output_folder / "final_output.png"
+ # For now, use attribute of self to find the output path.
+ self.output_folder.mkdir(parents=True, exist_ok=True)
+ output_path = self.output_folder / "final_output.png"
imsave(output_path, data_out)
+
+ op_output.emit(data_out, "out1")
diff --git a/examples/apps/simple_imaging_app/brain_mr_input.jpg b/examples/apps/simple_imaging_app/input/brain_mr_input.jpg
similarity index 100%
rename from examples/apps/simple_imaging_app/brain_mr_input.jpg
rename to examples/apps/simple_imaging_app/input/brain_mr_input.jpg
diff --git a/examples/apps/simple_imaging_app/median_operator.py b/examples/apps/simple_imaging_app/median_operator.py
index 488016b6..db92ac09 100644
--- a/examples/apps/simple_imaging_app/median_operator.py
+++ b/examples/apps/simple_imaging_app/median_operator.py
@@ -9,59 +9,41 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import monai.deploy.core as md
-from monai.deploy.core import ExecutionContext, Image, InputContext, IOType, Operator, OutputContext
+from monai.deploy.core import Fragment, Operator, OperatorSpec
-@md.input("image", Image, IOType.IN_MEMORY)
-@md.output("image", Image, IOType.IN_MEMORY)
# If `pip_packages` is specified, the definition will be aggregated with the package dependency list of other
# operators and the application in packaging time.
# @md.env(pip_packages=["scikit-image >= 0.17.2"])
-class MedianOperatorBase(Operator):
+class MedianOperator(Operator):
"""This Operator implements a noise reduction.
The algorithm is based on the median operator.
- It ingests a single input and provides a single output.
+ It ingests a single input and provides a single output, both are in-memory image arrays
"""
# Define __init__ method with super().__init__() if you want to override the default behavior.
- def __init__(self):
- super().__init__()
- # Do something
+ def __init__(self, fragment: Fragment, *args, **kwargs):
+ """Create an instance to be part of the given application (fragment).
- def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
- print("Executing base operator...")
+ Args:
+ fragment (Fragment): The instance of Application class which is derived from Fragment
+ """
+ self.index = 0
-class MedianOperator(MedianOperatorBase):
- """This operator is a subclass of the base operator to demonstrate the usage of inheritance."""
+ # Need to call the base class constructor last
+ super().__init__(fragment, *args, **kwargs)
- # Define __init__ method with super().__init__() if you want to override the default behavior.
- def __init__(self):
- super().__init__()
- # Do something
-
- def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
- # Execute the base operator's compute method.
- super().compute(op_input, op_output, context)
+ def setup(self, spec: OperatorSpec):
+ spec.input("in1")
+ spec.output("out1")
+ def compute(self, op_input, op_output, context):
from skimage.filters import median
- # `context.input.get().path` (Path) is the file/folder path of the input data from the application's context.
- # `context.output.get().path` (Path) is the file/folder path of the output data from the application's context.
- # `context.models.get(model_name)` returns a model instance
- # (a null model would be returned if model is not available)
- # If model_name is not specified and only one model exists, it returns that model.
- model = context.models.get() # a model object that inherits Model class
-
- # Get a model instance if exists
- if model: # if model is not a null model
- print(model.items())
- # # model.path for accessing the model's path
- # # model.name for accessing the model's name
- # result = model(input.get().asnumpy())
-
- data_in = op_input.get().asnumpy()
+ self.index += 1
+ print(f"Number of times operator {self.name} whose class is defined in {__name__} called: {self.index}")
+ data_in = op_input.receive("in1")
data_out = median(data_in)
- op_output.set(Image(data_out))
+ op_output.emit(data_out, "out1")
diff --git a/examples/apps/simple_imaging_app/requirements.txt b/examples/apps/simple_imaging_app/requirements.txt
new file mode 100644
index 00000000..613bfd94
--- /dev/null
+++ b/examples/apps/simple_imaging_app/requirements.txt
@@ -0,0 +1,2 @@
+scikit-image
+setuptools>=59.5.0 # for pkg_resources
\ No newline at end of file
diff --git a/examples/apps/simple_imaging_app/sobel_operator.py b/examples/apps/simple_imaging_app/sobel_operator.py
index ee833c77..63a8450f 100644
--- a/examples/apps/simple_imaging_app/sobel_operator.py
+++ b/examples/apps/simple_imaging_app/sobel_operator.py
@@ -9,29 +9,60 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import monai.deploy.core as md
-from monai.deploy.core import DataPath, ExecutionContext, Image, InputContext, IOType, Operator, OutputContext
+from pathlib import Path
+from monai.deploy.core import Fragment, Operator, OperatorSpec
-@md.input("image", DataPath, IOType.DISK)
-@md.output("image", Image, IOType.IN_MEMORY)
-# If `pip_packages` is specified, the definition will be aggregated with the package dependency list of other
-# operators and the application in packaging time.
-# @md.env(pip_packages=["scikit-image >= 0.17.2"])
+
+# # If `pip_packages` is specified, the definition will be aggregated with the package dependency list of other
+# # operators and the application in packaging time.
+# # @md.env(pip_packages=["scikit-image >= 0.17.2"])
class SobelOperator(Operator):
"""This Operator implements a Sobel edge detector.
- It has a single input and single output.
+ It has the following input and output:
+ single input:
+ a image file, first one found in the input folder
+ single output:
+ array object in memory
"""
- def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
+ DEFAULT_INPUT_FOLDER = Path.cwd() / "input"
+
+ def __init__(self, fragment: Fragment, *args, input_path: Path, **kwargs):
+ """Create an instance to be part of the given application (fragment).
+
+ Args:
+ fragment (Fragment): An instance of the Application class which is derived from Fragment
+ input_path (Path): The path of the input image file or folder containing the image file
+ """
+ self.index = 0
+
+ # May want to validate the path, but it should really be validated when the compute function is called, also,
+ # when file path as input is supported in the operator or execution context, input_folder needs not an attribute.
+ self.input_path = input_path if input_path else SobelOperator.DEFAULT_INPUT_FOLDER
+
+ # Need to call the base class constructor last
+ super().__init__(fragment, *args, **kwargs)
+
+ def setup(self, spec: OperatorSpec):
+ spec.output("out1")
+
+ def compute(self, op_input, op_output, context):
from skimage import filters, io
- input_path = op_input.get().path
+ self.index += 1
+ print(f"Number of times operator {self.name} whose class is defined in {__name__} called: {self.index}")
+
+ # Ideally the op_input or execution context should provide the file path
+ # to read data from, for operators that are file input based.
+ # For now, use a temporary way to get input path. e.g. value set on init
+ input_path = self.input_path
+ print(f"Input from: {input_path}, whose absolute path: {input_path.absolute()}")
if input_path.is_dir():
input_path = next(input_path.glob("*.*")) # take the first file
data_in = io.imread(input_path)[:, :, :3] # discard alpha channel if exists
data_out = filters.sobel(data_in)
- op_output.set(Image(data_out))
+ op_output.emit(data_out, "out1")
diff --git a/monai/deploy/__init__.py b/monai/deploy/__init__.py
index 7d1955f1..05090b52 100644
--- a/monai/deploy/__init__.py
+++ b/monai/deploy/__init__.py
@@ -12,14 +12,14 @@
.. autosummary::
:toctree: _autosummary
+ conditions
core
+ loggers
+ resources
utils
- packager
- runner
- cli
exceptions
"""
-from . import _version, cli, core, exceptions, packager, runner, utils
+from . import _version, conditions, core, exceptions, logger, resources, utils
__version__ = _version.get_versions()["version"]
diff --git a/monai/deploy/cli/exec_command.py b/monai/deploy/cli/exec_command.py
deleted file mode 100644
index 769d7518..00000000
--- a/monai/deploy/cli/exec_command.py
+++ /dev/null
@@ -1,76 +0,0 @@
-# Copyright 2021 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 os
-import runpy
-import sys
-from argparse import ArgumentParser, Namespace, _SubParsersAction
-from typing import List
-
-from monai.deploy.core.datastores.factory import DatastoreFactory
-from monai.deploy.core.executors.factory import ExecutorFactory
-from monai.deploy.core.graphs.factory import GraphFactory
-
-
-def create_exec_parser(subparser: _SubParsersAction, command: str, parents: List[ArgumentParser]) -> ArgumentParser:
- # Intentionally use `argparse.HelpFormatter` instead of `argparse.ArgumentDefaultsHelpFormatter`.
- # Default values for those options are None and those would be filled by `RuntimeEnv` object later.
- parser: ArgumentParser = subparser.add_parser(
- command, formatter_class=argparse.HelpFormatter, parents=parents, add_help=False
- )
-
- parser.add_argument("--input", "-i", help="Path to input folder/file (default: input)")
- parser.add_argument("--output", "-o", help="Path to output folder (default: output)")
- parser.add_argument("--model", "-m", help="Path to model(s) folder/file (default: models)")
- parser.add_argument(
- "--workdir",
- "-w",
- type=str,
- help="Path to workspace folder (default: A temporary '.monai_workdir' folder in the current folder)",
- )
- parser.add_argument(
- "--graph",
- help=f"Set Graph engine (default: {GraphFactory.DEFAULT})",
- choices=GraphFactory.NAMES,
- )
- parser.add_argument(
- "--datastore",
- help=f"Set Datastore (default: {DatastoreFactory.DEFAULT})",
- choices=DatastoreFactory.NAMES,
- )
- parser.add_argument(
- "--executor",
- help=f"Set Executor (default: {ExecutorFactory.DEFAULT})",
- choices=ExecutorFactory.NAMES,
- )
- parser.add_argument("remaining", nargs="*")
-
- return parser
-
-
-def execute_exec_command(args: Namespace):
- remaining = args.remaining
-
- if len(remaining) != 1:
- print("Missing command argument. Please provide an application path to execute.", file=sys.stderr)
- sys.exit(1)
-
- app_path = remaining[0]
-
- # Simulate executing 'python {app_path}'
- current_dir = os.path.abspath(os.path.dirname(app_path))
- if sys.path and os.path.abspath(sys.path[0]) != current_dir:
- sys.path.insert(0, current_dir)
-
- sys.argv.remove(app_path) # remove the application path from sys.argv
-
- runpy.run_path(app_path, run_name="__main__")
diff --git a/monai/deploy/conditions/__init__.py b/monai/deploy/conditions/__init__.py
new file mode 100644
index 00000000..cc6d84ba
--- /dev/null
+++ b/monai/deploy/conditions/__init__.py
@@ -0,0 +1,13 @@
+"""
+.. autosummary::
+ :toctree: _autosummary
+
+ BooleanCondition
+ CountCondition
+ DownstreamMessageAffordableCondition
+ MessageAvailableCondition
+ PeriodicCondition
+"""
+# Need to import explicit ones to quiet mypy complaints
+from holoscan.conditions import *
+from holoscan.conditions import CountCondition
diff --git a/monai/deploy/core/__init__.py b/monai/deploy/core/__init__.py
index a2a73b45..deba6250 100644
--- a/monai/deploy/core/__init__.py
+++ b/monai/deploy/core/__init__.py
@@ -13,24 +13,33 @@
:toctree: _autosummary
Application
+ Fragment
Operator
- env
- input
- output
- resource
- IOType
+ Condition
+ ConditionType
+ AppContext
ExecutionContext
+ OperatorSpec
+ IOType
InputContext
OutputContext
+ RuntimeEnv
+ init_app_context
+ parse_args
"""
-from .application import Application
+# Need to import explicit ones to quiet mypy complaints
+from holoscan.core import *
+from holoscan.core import Application, Condition, ConditionType, Fragment, Operator, OperatorSpec
+
+from .app_context import AppContext, init_app_context
+from .arg_parser import parse_args
from .domain.datapath import DataPath
from .domain.image import Image
-from .env import env
-from .execution_context import ExecutionContext
-from .io_context import InputContext, OutputContext
from .io_type import IOType
from .models import Model, ModelFactory, NamedModel, TorchScriptModel, TritonModel
-from .operator import Operator, input, output
-from .resource import resource
+from .runtime_env import RuntimeEnv
+
+# Add the function to the existing Application class, which could've been used as helper func too.
+# It is well understood that deriving from the Application base is a better approach, but maybe later.
+Application.init_app_context = init_app_context
diff --git a/monai/deploy/core/app_context.py b/monai/deploy/core/app_context.py
index dbc0e264..fb6a7c24 100644
--- a/monai/deploy/core/app_context.py
+++ b/monai/deploy/core/app_context.py
@@ -1,4 +1,4 @@
-# Copyright 2021 MONAI Consortium
+# Copyright 2021-2023 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
@@ -9,13 +9,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from typing import Dict, Optional
+import logging
+from os.path import abspath
+from typing import Dict, List, Optional
-from .resource import Resource
+from .arg_parser import parse_args, set_up_logging
+from .models.factory import ModelFactory
+from .models.model import Model
from .runtime_env import RuntimeEnv
-class AppContext:
+class AppContext(object):
"""A class to store the context of an application."""
def __init__(self, args: Dict[str, str], runtime_env: Optional[RuntimeEnv] = None):
@@ -24,10 +28,8 @@ def __init__(self, args: Dict[str, str], runtime_env: Optional[RuntimeEnv] = Non
# Set the runtime environment
self.runtime_env = runtime_env or RuntimeEnv()
- # Set the graph engine here because it would be used in the constructor of Application class so cannot be
- # updated in Application.run() method.
- self.graph = args.get("graph") or self.runtime_env.graph
-
+ self._model_loaded = False # If it has tried to load the models.
+ self.model_path = "" # To be set next.
self.update(args)
def update(self, args: Dict[str, str]):
@@ -38,20 +40,43 @@ def update(self, args: Dict[str, str]):
# Set the path to input/output/model
self.input_path = args.get("input") or self.args.get("input") or self.runtime_env.input
self.output_path = args.get("output") or self.args.get("output") or self.runtime_env.output
- self.model_path = args.get("model") or self.args.get("model") or self.runtime_env.model
self.workdir = args.get("workdir") or self.args.get("workdir") or self.runtime_env.workdir
- # Set the backend engines except for the graph engine
- self.datastore = args.get("datastore") or self.args.get("datastore") or self.runtime_env.datastore
- self.executor = args.get("executor") or self.args.get("executor") or self.runtime_env.executor
+ # If model has not been loaded, or the model path has changed, get the path and load model(s)
+ old_model_path = self.model_path
+ self.model_path = args.get("model") or self.args.get("model") or self.runtime_env.model
+ if old_model_path != self.model_path:
+ self._model_loaded = False # path changed, reset the flag to re-load
- # Set resource limits
- # TODO(gigony): Add cli option to set resource limits
- self.resource = Resource()
+ if not self._model_loaded:
+ self.models: Optional[Model] = ModelFactory.create(abspath(self.model_path))
+ self._model_loaded = True
def __repr__(self):
return (
- f"AppContext(graph={self.graph}, input_path={self.input_path}, output_path={self.output_path}, "
- f"model_path={self.model_path}, workdir={self.workdir}, datastore={self.datastore}, "
- f"executor={self.executor}, resource={self.resource})"
+ f"AppContext(input_path={self.input_path}, output_path={self.output_path}, "
+ f"model_path={self.model_path}, workdir={self.workdir})"
)
+
+
+def init_app_context(argv: Optional[List[str]] = None, runtime_env: Optional[RuntimeEnv] = None) -> AppContext:
+ """Initializes the app context with arguments and well-known environment variables.
+
+ The arguments, if passed in, override the attributes set with environment variables.
+
+ Args:
+ argv (Optional[List[str]], optional): arguments passed to the program. Defaults to None.
+
+ Returns:
+ AppContext: the AppContext object
+ """
+
+ args = parse_args(argv)
+ set_up_logging(args.log_level)
+ logging.info(f"Parsed args: {args}")
+
+ # The parsed args from the command line override that from the environment variables
+ app_context = AppContext({key: val for key, val in vars(args).items() if val}, runtime_env)
+ logging.info(f"AppContext object: {app_context}")
+
+ return app_context
diff --git a/monai/deploy/core/application.py b/monai/deploy/core/application.py
deleted file mode 100644
index f8e8f504..00000000
--- a/monai/deploy/core/application.py
+++ /dev/null
@@ -1,448 +0,0 @@
-# Copyright 2021 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 sys
-from abc import ABC, abstractmethod
-from pathlib import Path
-from typing import Dict, Optional, Set, Type, Union
-
-from monai.deploy.cli.main import LOG_CONFIG_FILENAME, parse_args, set_up_logging
-from monai.deploy.core.graphs.factory import GraphFactory
-from monai.deploy.core.models import ModelFactory
-from monai.deploy.exceptions import IOMappingError
-from monai.deploy.utils.importutil import get_class_file_path, get_docstring, is_subclass
-from monai.deploy.utils.sizeutil import convert_bytes
-from monai.deploy.utils.version import get_sdk_semver
-
-from .app_context import AppContext
-from .datastores import DatastoreFactory
-from .env import BaseEnv
-from .executors import ExecutorFactory
-from .graphs.graph import Graph
-from .operator import Operator
-from .operator_info import IO
-from .runtime_env import RuntimeEnv
-
-
-class Application(ABC):
- """This is the base application class.
-
- All applications should be extended from this Class.
- The application class provides support for chaining up operators, as well
- as mechanism to execute the application.
- """
-
- # Application's name. if not specified.
- name: str = ""
- # Application's description. if not specified.
- description: str = ""
- # Application's version. or '0.0.0' if not specified.
- version: str = ""
-
- # Special attribute to identify the application.
- # Used by the CLI executing get_application() or is_subclass() from deploy.utils.importutil to
- # determine the application to run.
- # This is needed to identify Application class across different environments (e.g. by `runpy.run_path()`).
- _class_id: str = "monai.application"
-
- _env: Optional["ApplicationEnv"] = None
-
- def __init__(
- self,
- runtime_env: Optional[RuntimeEnv] = None,
- do_run: bool = False,
- path: Optional[Union[str, Path]] = None,
- ):
- """Constructor for the application class.
-
- It initializes the application's graph, the runtime environment and the application context.
-
- if `do_run` is True, it would accept user's arguments from the application's context and
- execute the application.
-
- Args:
- runtime_env (Optional[RuntimeEnv]): The runtime environment to use.
- do_run (bool): Whether to run the application.
- path (Optional[Union[str, Path]]): The path to the application (Python file path).
- This path is used for launching the application to get the package information from
- `monai.deploy.utils.importutil.get_application` method.
- """
- # Setup app description
- if not self.name:
- self.name = self.__class__.__name__
- if not self.description:
- self.description = get_docstring(self.__class__)
- if not self.version:
- try:
- from monai.deploy._version import get_versions
-
- self.version = get_versions()["version"]
- except ImportError:
- self.version = "0.0.0"
-
- # Set the application path
- if path:
- self.path = Path(path)
- else:
- self.path = get_class_file_path(self.__class__)
-
- # Set the runtime environment
- if str(self.path) == "ipython":
- self.in_ipython = True
- else:
- self.in_ipython = False
-
- # Setup program arguments
- if path is not None or self.in_ipython:
- # If `path` is specified, it means that it is called by
- # monai.deploy.utils.importutil.get_application() to get the package info.
- # If `self.in_ipython` is True, it means that it is called by ipython environment.
- # In both cases, we should not parse the arguments from the command line.
- argv = [sys.executable, str(self.path)] # use default parameters
- else:
- argv = sys.argv
-
- # Parse the command line arguments
- args = parse_args(argv, default_command="exec")
-
- context = AppContext(args.__dict__, runtime_env)
-
- self._context: AppContext = context
-
- self._graph: Graph = GraphFactory.create(context.graph)
-
- # Execute the builder to set up the application
- self._builder()
-
- # Compose operators
- self.compose()
-
- if do_run:
- self.run(log_level=args.log_level)
-
- @classmethod
- def __subclasshook__(cls, c: Type) -> bool:
- return is_subclass(c, cls._class_id)
-
- def _builder(self):
- """This method is called by the constructor of Application to set up the operator.
-
- This method returns `self` to allow for method chaining and new `_builder()` method is
- chained by decorators.
-
- Returns:
- An instance of Application.
- """
- return self
-
- @property
- def context(self) -> AppContext:
- """Returns the context of this application."""
- return self._context
-
- @property
- def graph(self) -> Graph:
- """Gives access to the DAG.
-
- Returns:
- Instance of the DAG
- """
- return self._graph
-
- @property
- def env(self):
- """Gives access to the environment.
-
- This sets a default value for the application's environment if not set.
-
- Returns:
- An instance of ApplicationEnv.
- """
- if self._env is None:
- self._env = ApplicationEnv()
- return self._env
-
- def add_operator(self, operator: Operator):
- """Adds an operator to the graph.
-
- Args:
- operator (Operator): An instance of the operator of type Operator.
- """
- # Ensure that the operator is valid
- operator.ensure_valid()
-
- self._graph.add_operator(operator)
-
- def add_flow(
- self, source_op: Operator, destination_op: Operator, io_map: Optional[Dict[str, Union[str, Set[str]]]] = None
- ):
- """Adds a flow from source to destination.
-
- An output port of the source operator is connected to one of the
- input ports of a destination operators.
-
- Args:
- source_op (Operator): An instance of the source operator of type Operator.
- destination_op (Operator): An instance of the destination operator of type Operator.
- io_map (Optional[Dict[str, Union[str, Set[str]]]]): A dictionary of mapping from the source operator's label
- to the destination operator's label(s).
- """
-
- # Ensure that the source and destination operators are valid
- source_op.ensure_valid()
- destination_op.ensure_valid()
-
- op_output_labels = source_op.op_info.get_labels(IO.OUTPUT)
- op_input_labels = destination_op.op_info.get_labels(IO.INPUT)
- if not io_map:
- if len(op_output_labels) > 1:
- raise IOMappingError(
- "The source operator has more than one output port "
- f"({', '.join(op_output_labels)}) so mapping should be specified explicitly!"
- )
- if len(op_input_labels) > 1:
- raise IOMappingError(
- f"The destination operator has more than one output port ({', '.join(op_input_labels)}) "
- "so mapping should be specified explicitly!"
- )
- io_map = {"": {""}}
-
- # Convert io_map's values to the set of strings.
- io_maps: Dict[str, Set[str]] = io_map # type: ignore
- for k, v in io_map.items():
- if isinstance(v, str):
- io_maps[k] = {v}
-
- # Verify that the source & destination operator have the input and output ports specified by the io_map
- output_labels = list(io_maps.keys())
-
- if len(op_output_labels) == 1 and len(output_labels) != 1:
- raise IOMappingError(
- f"The source operator({source_op.name}) has only one port with label "
- f"{next(iter(op_output_labels))!r} but io_map specifies {len(output_labels)} "
- f"labels({', '.join(output_labels)}) to the source operator's output port"
- )
-
- for output_label in output_labels:
- if output_label not in op_output_labels:
- if len(op_output_labels) == 1 and len(output_labels) == 1 and output_label == "":
- # Set the default output port label.
- io_maps[next(iter(op_output_labels))] = io_maps[output_label]
- del io_maps[output_label]
- break
- raise IOMappingError(
- f"The source operator({source_op.name}) has no output port with label {output_label!r}. "
- f"It should be one of ({', '.join(op_output_labels)})."
- )
-
- output_labels = list(io_maps.keys()) # re-evaluate output_labels
- for output_label in output_labels:
- input_labels = io_maps[output_label]
-
- if len(op_input_labels) == 1 and len(input_labels) != 1:
- raise IOMappingError(
- f"The destination operator({destination_op.name}) has only one port with label "
- f"{next(iter(op_input_labels))!r} but io_map specifies {len(input_labels)} "
- f"labels({', '.join(input_labels)}) to the destination operator's input port"
- )
-
- for input_label in input_labels:
- if input_label not in op_input_labels:
- if len(op_input_labels) == 1 and len(input_labels) == 1 and input_label == "":
- # Set the default input port label.
- input_labels.clear()
- input_labels.add(next(iter(op_input_labels)))
- break
- raise IOMappingError(
- f"The destination operator({destination_op.name}) has no input port with label {input_label!r}."
- f" It should be one of ({', '.join(op_input_labels)})."
- )
-
- self._graph.add_flow(source_op, destination_op, io_maps)
-
- def get_package_info(self, model_path: Union[str, Path] = "") -> Dict:
- """Returns the package information of this application.
-
- Args:
- model_path (Union[str, Path]): The path to the model directory.
- Returns:
- A dictionary containing the package information of this application.
- """
- app_path = self.path.name
- command = f"python3 -u /opt/monai/app/{app_path}"
- resource = self.context.resource
-
- # Get model name/path list
- # - If no model files are found at `model_path`, None will be returned by the ModelFactory.create method and
- # the `model_list` will be an empty list.
- # - If the path represents a model repository (one or more model objects. Necessary condition is model_path is
- # a folder), then `model_list` will abe a list of model objects (name and path).
- # - If only one model is found at model_path or model_path is a valid model file, `model_list` would be a
- # single model object list.
- model_list = []
- if model_path:
- models = ModelFactory.create(model_path)
- if models:
- model_list = models.get_model_list()
-
- # Get pip requirement list
- spec_list = self.env.pip_packages
- for op in self.graph.get_operators():
- spec_list.extend(op.env.pip_packages)
- spec_set = set()
- pip_requirement_list = []
- for p in spec_list:
- spec = p.strip().lower()
- if spec not in spec_set:
- pip_requirement_list.append(spec)
- spec_set.add(spec)
-
- return {
- "app-name": self.name,
- "app-version": self.version,
- "sdk-version": get_sdk_semver(),
- "command": command,
- "resource": {
- "cpu": resource.cpu,
- "gpu": resource.gpu,
- "memory": convert_bytes(resource.memory),
- },
- "models": model_list,
- "pip-packages": pip_requirement_list,
- }
-
- def run(
- self,
- log_level: Optional[str] = None,
- input: Optional[str] = None,
- output: Optional[str] = None,
- model: Optional[str] = None,
- workdir: Optional[str] = None,
- datastore: Optional[str] = None,
- executor: Optional[str] = None,
- ) -> None:
- """Runs the application.
-
- This method accepts `log_level` to set the log level of the application.
-
- Other arguments are used to specify the `input`, `output`, `model`, `workdir`, `datastore`, and `executor`.
- (Cannot set `graph` because it is set and used by the constructor.)
-
- If those arguments are not specified, values in the application context will be used.
-
- This method is useful when you want to interactively run the application inside IPython (Jupyter Notebook).
-
- For example, you can run the following code in a notebook:
-
- >>> from pathlib import Path
- >>> import monai.deploy.core as md
- >>> from monai.deploy.core import (
- >>> Application,
- >>> DataPath,
- >>> ExecutionContext,
- >>> InputContext,
- >>> IOType,
- >>> Operator,
- >>> OutputContext,
- >>> )
- >>>
- >>> @md.input("path", DataPath, IOType.DISK)
- >>> @md.output("path", DataPath, IOType.DISK)
- >>> class FirstOperator(Operator):
- >>> def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
- >>> print(f"First Operator. input:{op_input.get().path}, model:{context.models.get().path}")
- >>> output_path = Path("output_first.txt")
- >>> output_path.write_text("first output\\n")
- >>> output.set(DataPath(output_path))
- >>>
- >>> @md.input("path", DataPath, IOType.DISK)
- >>> @md.output("path", DataPath, IOType.DISK)
- >>> class SecondOperator(Operator):
- >>> def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
- >>> print(f"First Operator. output:{op_output.get().path}, model:{context.models.get().path}")
- >>> # The leaf operators can only read output DataPath and should not set output DataPath.
- >>> output_path = op_output.get().path / "output_second.txt"
- >>> output_path.write_text("second output\\n")
- >>>
- >>> class App(Application):
- >>> def compose(self):
- >>> first_op = FirstOperator()
- >>> second_op = SecondOperator()
- >>>
- >>> self.add_flow(first_op, second_op)
- >>>
- >>> if __name__ == "__main__":
- >>> App(do_run=True)
-
- >>> app = App()
- >>> app.run(input="inp", output="out", model="model.pt")
-
- >>> !ls out
-
- Args:
- log_level (Optional[str]): A log level.
- input (Optional[str]): An input data path.
- output (Optional[str]): An output data path.
- model (Optional[str]): A model path.
- workdir (Optional[str]): A working directory path.
- datastore (Optional[str]): A datastore path.
- executor (Optional[str]): An executor name.
- """
- # Set arguments
- args = {}
- if input is not None:
- args["input"] = input
- if output is not None:
- args["output"] = output
- if model is not None:
- args["model"] = model
- if workdir is not None:
- args["workdir"] = workdir
- if datastore is not None:
- args["datastore"] = datastore
- if executor is not None:
- args["executor"] = executor
-
- # If no arguments are specified and if runtime is in IPython, do not run the application.
- if len(args) == 0 and self.in_ipython:
- return
-
- # Update app context
- app_context = self.context
- app_context.update(args)
-
- # Set up logging (try to load `LOG_CONFIG_FILENAME` in the application folder)
- # and run the application
- app_log_config_path = self.path.parent / LOG_CONFIG_FILENAME
- set_up_logging(log_level, config_path=app_log_config_path)
-
- datastore_obj = DatastoreFactory.create(app_context.datastore)
- executor_obj = ExecutorFactory.create(app_context.executor, {"app": self, "datastore": datastore_obj})
- executor_obj.run()
-
- @abstractmethod
- def compose(self):
- """This is a method that needs to implemented by all subclasses.
-
- Derived appications will chain up the operators inside this compose
- method.
-
- """
- pass
-
-
-class ApplicationEnv(BaseEnv):
- """Settings for the application environment.
-
- This class is used to specify the environment settings for the application.
- """
-
- pass
diff --git a/monai/deploy/cli/main.py b/monai/deploy/core/arg_parser.py
similarity index 51%
rename from monai/deploy/cli/main.py
rename to monai/deploy/core/arg_parser.py
index 4b136251..97ecb127 100644
--- a/monai/deploy/cli/main.py
+++ b/monai/deploy/core/arg_parser.py
@@ -1,4 +1,4 @@
-# Copyright 2021 MONAI Consortium
+# Copyright 2021-2023 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
@@ -8,25 +8,28 @@
# 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 logging.config
from pathlib import Path
from typing import List, Optional, Union
-# Specify available commands here to execute 'exec' command by default
-# if no command is specified.
-COMMAND_LIST = ["exec", "package", "run"]
+from monai.deploy.utils import argparse_types
LOG_CONFIG_FILENAME = "logging.json"
-def parse_args(argv: Optional[List[str]] = None, default_command: Optional[str] = None) -> argparse.Namespace:
- from monai.deploy.cli.exec_command import create_exec_parser
- from monai.deploy.packager.package_command import create_package_parser
- from monai.deploy.runner.run_command import create_run_parser
+def parse_args(argv: Optional[List[str]] = None) -> argparse.Namespace:
+ """Parses the arguments passed to the application.
+
+ Args:
+ argv (Optional[List[str]], optional): The command line arguments to parse.
+ The first item should be the path to the python executable.
+ If not specified, ``sys.argv`` is used. Defaults to None.
+ Returns:
+ argparse.Namespace: parsed arguments.
+ """
if argv is None:
import sys
@@ -37,8 +40,8 @@ def parse_args(argv: Optional[List[str]] = None, default_command: Optional[str]
# value from here doesn't override the value in `LOG_CONFIG_FILENAME` unless the user indends to do
# so. If the user doesn't use this flag to set log level, this argument is set to "None"
# and the logging level specified in `LOG_CONFIG_FILENAME` is used.
- parent_parser = argparse.ArgumentParser()
- parent_parser.add_argument(
+ parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+ parser.add_argument(
"-l",
"--log-level",
dest="log_level",
@@ -46,35 +49,25 @@ def parse_args(argv: Optional[List[str]] = None, default_command: Optional[str]
choices=["DEBUG", "INFO", "WARN", "ERROR", "CRITICAL"],
help="Set the logging level (default: INFO)",
)
-
- parser = argparse.ArgumentParser(
- parents=[parent_parser], formatter_class=argparse.ArgumentDefaultsHelpFormatter, add_help=False
+ parser.add_argument(
+ "--input", "-i", type=argparse_types.valid_existing_path, help="Path to input folder/file (default: input)"
+ )
+ parser.add_argument(
+ "--output", "-o", type=argparse_types.valid_dir_path, help="Path to output folder (default: output)"
+ )
+ parser.add_argument(
+ "--model", "-m", type=argparse_types.valid_existing_path, help="Path to model(s) folder/file (default: models)"
+ )
+ parser.add_argument(
+ "--workdir",
+ "-w",
+ type=argparse_types.valid_dir_path,
+ help="Path to workspace folder (default: A temporary '.monai_workdir' folder in the current folder)",
)
-
- subparser = parser.add_subparsers(dest="command")
-
- # Parser for `exec` command
- create_exec_parser(subparser, "exec", parents=[parent_parser])
-
- # Parser for `package` command
- create_package_parser(subparser, "package", parents=[parent_parser])
-
- # Parser for `run` command
- create_run_parser(subparser, "run", parents=[parent_parser])
-
- # By default, execute `exec` command
- command = argv[1:2]
- if default_command and (not command or command[0] not in COMMAND_LIST):
- argv.insert(1, default_command) # insert default command
args = parser.parse_args(argv[1:])
args.argv = argv # save argv for later use in runpy
- # Print help if no command is specified
- if args.command is None:
- parser.print_help()
- parser.exit()
-
return args
@@ -100,29 +93,3 @@ def set_up_logging(level: Optional[str], config_path: Union[str, Path] = LOG_CON
if level is not None and "root" in config_dict:
config_dict["root"]["level"] = level
logging.config.dictConfig(config_dict)
-
-
-def main(argv: Optional[List[str]] = None, default_command: Optional[str] = None):
- args = parse_args(argv, default_command)
-
- # Set up logging level if the command is not `exec`
- # (`exec` command sets up the logging in the constructor of Application class)
- if args.command != "exec":
- set_up_logging(args.log_level)
-
- if args.command == "exec":
- from monai.deploy.cli.exec_command import execute_exec_command
-
- execute_exec_command(args)
- elif args.command == "package":
- from monai.deploy.packager.package_command import execute_package_command
-
- execute_package_command(args)
- elif args.command == "run":
- from monai.deploy.runner.run_command import execute_run_command
-
- execute_run_command(args)
-
-
-if __name__ == "__main__":
- main()
diff --git a/monai/deploy/core/env.py b/monai/deploy/core/env.py
deleted file mode 100644
index 513c8306..00000000
--- a/monai/deploy/core/env.py
+++ /dev/null
@@ -1,85 +0,0 @@
-# Copyright 2021 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.
-
-from pathlib import Path
-from typing import List, Optional, Union
-
-from monai.deploy.exceptions import ItemAlreadyExistsError, UnknownTypeError
-
-
-class BaseEnv:
- """Settings for the environment.
-
- This class is used to specify the environment settings for the application or the operator.
- """
-
- def __init__(self, pip_packages: Optional[Union[str, List[str]]] = None):
- """Constructor of the BaseEnv class.
-
- Args:
- pip_packages Optional[Union[str, List[str]]]: A string that is a path to requirements.txt file
- or a list of packages to install.
-
- Returns:
- An instance of OperatorEnv.
- """
- if type(pip_packages) is str:
- requirements_path = Path(pip_packages)
-
- if requirements_path.exists():
- pip_packages = requirements_path.read_text().strip().splitlines() # make it a list
- else:
- raise FileNotFoundError(f"The {requirements_path!r} file does not exist!")
-
- self._pip_packages = list(pip_packages or [])
-
- @property
- def pip_packages(self) -> List[str]:
- """Get the list of pip packages.
-
- Returns:
- A list of pip packages.
- """
- return self._pip_packages
-
- def __str__(self):
- return "{}(pip_packages={})".format(self.__class__.__name__, self._pip_packages)
-
-
-def env(pip_packages: Optional[Union[str, List[str]]] = None):
- """A decorator that adds an environment specification to either Operator or Application.
-
- Args:
- pip_packages: A string that is a path to requirements.txt file or a list of packages to install.
-
- Returns:
- A decorator that adds an environment specification to either Operator or Application.
- """
- # Import the classes here to avoid circular import.
- from .application import Application, ApplicationEnv
- from .operator import Operator, OperatorEnv
-
- def decorator(cls):
- if hasattr(cls, "_env") and cls._env:
- raise ItemAlreadyExistsError(f"@env decorator is aleady specified for {cls}.")
-
- if issubclass(cls, Operator):
- environment = OperatorEnv(pip_packages=pip_packages)
- elif issubclass(cls, Application):
- environment = ApplicationEnv(pip_packages=pip_packages)
- else:
- raise UnknownTypeError(f"@env decorator cannot be specified for {cls}.")
-
- cls._env = environment
-
- return cls
-
- return decorator
diff --git a/monai/deploy/core/execution_context.py b/monai/deploy/core/execution_context.py
deleted file mode 100644
index 021afdb0..00000000
--- a/monai/deploy/core/execution_context.py
+++ /dev/null
@@ -1,126 +0,0 @@
-# Copyright 2021 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.
-
-from typing import Optional
-
-from monai.deploy.core.domain.datapath import NamedDataPath
-
-# To avoid "Cannot resolve forward reference" error
-# : https://github.com/agronholm/sphinx-autodoc-typehints#dealing-with-circular-imports
-from . import operator
-from .datastores import Datastore, MemoryDatastore
-from .io_context import InputContext, OutputContext
-from .models import Model
-
-
-class BaseExecutionContext:
- """A base execution context for the application.
-
- BaseExecutionContext is responsible for storing the input and output data paths,
- and the models.
-
- Those pieces of information are used by the Operator (in `compute()` method) to perform the execution.
-
- The input and output data paths from the application's context are available through
- `context.input.get()` and `context.output.get()`.
- """
-
- def __init__(
- self,
- datastore: Optional[Datastore],
- input: NamedDataPath,
- output: NamedDataPath,
- models: Optional[Model] = None,
- ):
- if datastore is None:
- self._storage: Datastore = MemoryDatastore()
- else:
- self._storage = datastore
-
- self._input = input
- self._output = output
-
- if models is None:
- self._models = Model("") # set a null model
- else:
- self._models = models
-
- @property
- def storage(self) -> Datastore:
- return self._storage
-
- @property
- def input(self) -> NamedDataPath:
- return self._input
-
- @property
- def output(self) -> NamedDataPath:
- return self._output
-
- @property
- def models(self) -> Model:
- return self._models
-
-
-class ExecutionContext(BaseExecutionContext):
- """An execution context for the operator."""
-
- def __init__(self, context: BaseExecutionContext, op: "operator.Operator"):
- super().__init__(context.storage, context.input, context.output, context.models)
- self._context = context
- self._op = op
- self._input_context = InputContext(self)
- self._output_context = OutputContext(self)
-
- @property
- def op(self):
- return self._op
-
- def get_execution_index(self):
- """Returns the execution index for the operator.
-
- The execution index is incremented every time before the operator is executed.
- For the first time, the execution index is set to 0.
-
- Returns:
- The execution index(int) for the operator.
- """
- storage = self._context.storage
- parent_node = f"/operators/{self.op.uid}"
- key = f"{parent_node}/execution_index"
- if storage.exists(key):
- return storage.get(key)
- else:
- storage.put(key, 0)
- return 0
-
- def increase_execution_index(self):
- """Increases the execution index for the operator.
-
- This index number would be increased once for each call to the operator
- so that the operator can be executed multiple times.
- """
- storage = self._context.storage
- parent_node = f"/operators/{self.op.uid}"
- key = f"{parent_node}/execution_index"
- new_execution_index = self.get_execution_index() + 1
- storage.put(key, new_execution_index)
- return new_execution_index
-
- @property
- def input_context(self):
- """Returns the input context for the operator."""
- return self._input_context
-
- @property
- def output_context(self):
- """Returns the output context for the operator."""
- return self._output_context
diff --git a/monai/deploy/core/executors/__init__.py b/monai/deploy/core/executors/__init__.py
deleted file mode 100644
index 21038967..00000000
--- a/monai/deploy/core/executors/__init__.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright 2021 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.
-"""
-.. autosummary::
- :toctree: _autosummary
-
- ExecutorFactory
- Executor
- SingleProcessExecutor
-"""
-
-from .executor import Executor
-from .factory import ExecutorFactory
-
-# from .multi_process_executor import MultiProcessExecutor
-# from .multi_threaded_executor import MultiThreadedExecutor
-from .single_process_executor import SingleProcessExecutor
-
-# __all__ = ["Executor", "SingleProcessExecutor", "ExecutorFactory"]
diff --git a/monai/deploy/core/executors/executor.py b/monai/deploy/core/executors/executor.py
deleted file mode 100644
index 43019fd0..00000000
--- a/monai/deploy/core/executors/executor.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright 2021 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.
-
-from abc import ABC, abstractmethod
-from typing import Dict, Optional
-
-# https://github.com/agronholm/sphinx-autodoc-typehints#dealing-with-circular-imports
-from monai.deploy.core import application
-from monai.deploy.core.datastores import Datastore, DatastoreFactory
-
-
-class Executor(ABC):
- """This is the base class that enables execution of an application."""
-
- def __init__(self, app: "application.Application", datastore: Optional[Datastore] = None, **kwargs: Dict):
- """Constructor of the class.
-
- Given an application it invokes the compose method on the app, which
- in turn creates the necessary operator and links them up.
-
- Args:
- app: An application that needs to be executed.
- datastore: A data store that is used to store the data.
- """
- self._app = app
- if datastore:
- self._datastore = datastore
- else:
- self._datastore = DatastoreFactory.create(DatastoreFactory.DEFAULT)
-
- @property
- def app(self) -> "application.Application":
- """Returns the application that is executed by the executor."""
- return self._app
-
- @property
- def datastore(self) -> Datastore:
- """Returns the data store that is used to store the data."""
- return self._datastore
-
- @abstractmethod
- def run(self):
- """Run the app.
-
- It is called to execute an application.
- This method needs to be implemented by specific concrete subclasses
- of `Executor`.
- """
- pass
diff --git a/monai/deploy/core/executors/factory.py b/monai/deploy/core/executors/factory.py
deleted file mode 100644
index fbf9f148..00000000
--- a/monai/deploy/core/executors/factory.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright 2021 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.
-
-from typing import Dict, Optional
-
-from monai.deploy.exceptions import UnknownTypeError
-
-from .executor import Executor
-from .single_process_executor import SingleProcessExecutor
-
-
-class ExecutorFactory:
- """ExecutorFactory is an abstract class that provides a way to create an executor object."""
-
- NAMES = ["single_process_executor"]
- DEFAULT = "single_process_executor"
-
- @staticmethod
- def create(executor_type: str, executor_params: Optional[Dict] = None) -> Executor:
- """Creates an executor object.
-
- Args:
- executor_type (str): A type of the executor.
- executor_params (Dict): A dictionary of parameters of the executor.
-
- Returns:
- Executor: An executor object.
- """
-
- executor_params = executor_params or {}
-
- if executor_type == "single_process_executor":
- return SingleProcessExecutor(**executor_params)
- else:
- raise UnknownTypeError(f"Unknown executor type: {executor_type}")
diff --git a/monai/deploy/core/executors/multi_process_executor.py b/monai/deploy/core/executors/multi_process_executor.py
deleted file mode 100644
index e0f04d84..00000000
--- a/monai/deploy/core/executors/multi_process_executor.py
+++ /dev/null
@@ -1,50 +0,0 @@
-# # Copyright 2021 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.
-
-# from multiprocessing import Process
-# from queue import Queue
-
-# from monai.deploy.core.executors.executor import Executor
-# from monai.deploy.core import Application
-# from monai.deploy.core.datastores import Datastore
-
-
-# class MultiProcessExecutor(Executor):
-# def __init__(self, app: Application):
-# super().__init__(app)
-# self._storage = Datastore.get_instance()
-
-# def execute(self):
-# g = self.app.graph
-# for node in self._root_nodes:
-
-# q = Queue()
-# q.put(node)
-
-# while not q.empty():
-# n = q.get()
-# edges = g.out_edges(n)
-# self._launch_operator(n)
-
-# for e in edges:
-# # Figure out how to deal with duplicate nodes
-# q.put(e[1])
-# edge_data = g.get_edge_data(e[0], e[1])
-# output = node.get_output(edge_data["source_op_port"])
-# key1 = (e[0].get_uid(), "output", edge_data["source_op_port"])
-# self._storage.store(key1, output)
-# key2 = (e[1].get_uid(), "input", edge_data["destination_op_port"])
-# self._storage.store(key2, output)
-
-# def _launch_operator(self, op):
-# p = Process(target=op.execute)
-# p.start()
-# p.join()
diff --git a/monai/deploy/core/executors/multi_threaded_executor.py b/monai/deploy/core/executors/multi_threaded_executor.py
deleted file mode 100644
index 8de1f4b5..00000000
--- a/monai/deploy/core/executors/multi_threaded_executor.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# # Copyright 2021 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.
-
-# from queue import Queue
-
-# from monai.deploy.core import Application
-# from monai.deploy.core.executors.executor import Executor
-# from monai.deploy.core.datastores import Datastore
-
-
-# class MultiThreadedExecutor(Executor):
-# def __init__(self, app: Application):
-# super().__init__(app)
-# self._storage = Datastore.get_instance()
-
-# def execute(self):
-# g = self.app.graph
-# for node in self._root_nodes:
-
-# q = Queue()
-# q.put(node)
-
-# while not q.empty():
-# n = q.get()
-# edges = g.out_edges(n)
-# n.execute()
-
-# for e in edges:
-
-# # Figure out how to deal with duplicate nodes
-# q.put(e[1])
-# edge_data = g.get_edge_data(e[0], e[1])
-# output = node.get_output(edge_data["source_op_port"])
-# key1 = (e[0].get_uid(), "output", edge_data["source_op_port"])
-# self._storage.store(key1, output)
-# key2 = (e[1].get_uid(), "input", edge_data["destination_op_port"])
-# self._storage.store(key2, output)
diff --git a/monai/deploy/core/executors/single_process_executor.py b/monai/deploy/core/executors/single_process_executor.py
deleted file mode 100644
index 85c01665..00000000
--- a/monai/deploy/core/executors/single_process_executor.py
+++ /dev/null
@@ -1,155 +0,0 @@
-# Copyright 2021 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 os
-import shutil
-from pathlib import Path
-
-from colorama import Fore
-
-from monai.deploy.core.domain.datapath import DataPath, NamedDataPath
-from monai.deploy.core.execution_context import BaseExecutionContext, ExecutionContext
-from monai.deploy.core.io_type import IOType
-from monai.deploy.core.models import ModelFactory
-from monai.deploy.core.operator_info import IO
-from monai.deploy.exceptions import IOMappingError
-
-from .executor import Executor
-
-TEMP_WORKDIR = ".monai_workdir" # working directory name used when no `workdir` is specified
-
-
-class SingleProcessExecutor(Executor):
- """This class implements execution of a MONAI App
- in a single process in environment.
- """
-
- def run(self):
- """Run the app.
-
- This method executes operators of the graph in topological order:
-
- - If a node (operator) is a root node, its input is treated as a data path (DataPath, IOType.DISK).
- - If a node (operator) is a leaf node, its output is treated as a data path (DataPath, IOType.DISK).
- - After the execution of an operator, the output of the operator is used as the input of the next operator.
- """
- app_context = self.app.context
- # Take paths as absolute paths
- models = ModelFactory.create(os.path.abspath(app_context.model_path))
- input_path = os.path.abspath(self.app.context.input_path)
- output_path = os.path.abspath(self.app.context.output_path)
-
- # Create the output directory if it does not exist
- if not os.path.exists(output_path):
- os.makedirs(output_path, exist_ok=True)
-
- # Store old pwd
- old_pwd = os.getcwd()
-
- # If workdir is not specified, create a temporary path (.monai_workdir)
- if not self.app.context.workdir:
- if os.path.exists(TEMP_WORKDIR):
- shutil.rmtree(TEMP_WORKDIR)
- os.mkdir(TEMP_WORKDIR)
- workdir = os.path.abspath(TEMP_WORKDIR)
- else:
- # Absolute path of the working directory
- workdir = os.path.abspath(self.app.context.workdir)
-
- # Create execution context
- # Currently, we only allow a single input/output path (with empty label: "").
- # TODO(gigony): Supports multiple inputs/outputs (#87)
- exec_context = BaseExecutionContext(
- self.datastore,
- input=NamedDataPath({"": DataPath(input_path, read_only=True)}),
- output=NamedDataPath({"": DataPath(output_path, read_only=True)}),
- models=models,
- )
-
- g = self.app.graph
-
- try:
- for op in g.gen_worklist():
- op_exec_context = ExecutionContext(exec_context, op)
-
- # Set source input for a label if op is a root node and (,) == (DataPath,IOType.DISK)
- is_root = g.is_root(op)
- if is_root:
- input_op_info = op.op_info
- input_labels = input_op_info.get_labels(IO.INPUT)
- for input_label in input_labels:
- input_data_type = input_op_info.get_data_type(IO.INPUT, input_label)
- input_storage_type = input_op_info.get_storage_type(IO.INPUT, input_label)
- if issubclass(input_data_type, DataPath) and input_storage_type == IOType.DISK:
- op_exec_context.input_context.set(DataPath(input_path, read_only=True), input_label)
-
- # Set destination output for a label if op is a leaf node and (,) == (DataPath,IOType.DISK)
- is_leaf = g.is_leaf(op)
- if is_leaf:
- output_op_info = op.op_info
- output_labels = output_op_info.get_labels(IO.OUTPUT)
- for output_label in output_labels:
- output_data_type = output_op_info.get_data_type(IO.OUTPUT, output_label)
- output_storage_type = output_op_info.get_storage_type(IO.OUTPUT, output_label)
- if issubclass(output_data_type, DataPath) and output_storage_type == IOType.DISK:
- op_exec_context.output_context.set(DataPath(output_path, read_only=True), output_label)
-
- # Change the current working directory to the working directory of the operator
- # op_output_folder == f"{workdir}/operators/{op.uid}/{op_exec_context.get_execution_index()}/{IO.OUTPUT}"
- relative_output_path = Path(op_exec_context.output_context.get_group_path(IO.OUTPUT)).relative_to("/")
- op_output_folder = str(Path(workdir, relative_output_path))
- os.makedirs(op_output_folder, exist_ok=True)
- os.chdir(op_output_folder)
-
- # Execute pre_compute()
- print(Fore.BLUE + "Going to initiate execution of operator %s" % op.__class__.__name__ + Fore.RESET)
- op.pre_compute()
-
- # Execute compute()
- print(
- Fore.GREEN
- + "Executing operator %s " % op.__class__.__name__
- + Fore.YELLOW
- + "(Process ID: %s, Operator ID: %s)" % (os.getpid(), op.uid)
- + Fore.RESET
- )
- op.compute(op_exec_context.input_context, op_exec_context.output_context, op_exec_context)
-
- # Execute post_compute()
- print(Fore.BLUE + "Done performing execution of operator %s\n" % op.__class__.__name__ + Fore.RESET)
- op.post_compute()
-
- # Set input to next operator
- next_ops = g.gen_next_operators(op)
- for next_op in next_ops:
- io_map = g.get_io_map(op, next_op)
- if not io_map:
- import inspect
-
- raise IOMappingError(
- f"No IO mappings found for {op.name} -> {next_op.name} in "
- f"{inspect.getabsfile(self.app.__class__)}"
- )
-
- next_op_exec_context = ExecutionContext(exec_context, next_op)
- for out_label, in_labels in io_map.items():
- output = op_exec_context.output_context.get(out_label)
- for in_label in in_labels:
- next_op_exec_context.input_context.set(output, in_label)
- finally:
- # Always restore pwd even if an exception is raised (This logic can be run in an IPython environment)
- os.chdir(old_pwd)
-
- # Remove a temporary workdir
- old_pwd = os.getcwd()
- if os.path.exists(TEMP_WORKDIR):
- shutil.rmtree(TEMP_WORKDIR)
diff --git a/monai/deploy/core/graphs/factory.py b/monai/deploy/core/graphs/factory.py
deleted file mode 100644
index 6855e1a5..00000000
--- a/monai/deploy/core/graphs/factory.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright 2021 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.
-
-from typing import Dict, Optional
-
-from monai.deploy.exceptions import UnknownTypeError
-
-from .graph import Graph
-from .nx_digraph import NetworkXGraph
-
-
-class GraphFactory:
- """GraphFactory is an abstract class that provides a way to create a graph object."""
-
- NAMES = ["nx_digraph"]
- DEFAULT = "nx_digraph"
-
- @staticmethod
- def create(graph_type: str, graph_params: Optional[Dict] = None) -> Graph:
- """Creates a graph object.
-
- Args:
- graph_type (str): A type of the graph.
- graph_params (Dict): A dictionary of parameters of the graph.
-
- Returns:
- Graph: A graph object.
- """
-
- graph_params = graph_params or {}
-
- if graph_type == "nx_digraph":
- return NetworkXGraph(**graph_params)
- # elif graph_type == 'py':
- # return PyGraph(graph_params)
- else:
- raise UnknownTypeError(f"Unknown graph type: {graph_type}")
diff --git a/monai/deploy/core/graphs/graph.py b/monai/deploy/core/graphs/graph.py
deleted file mode 100644
index c8ab012b..00000000
--- a/monai/deploy/core/graphs/graph.py
+++ /dev/null
@@ -1,98 +0,0 @@
-# Copyright 2021 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.
-
-from abc import ABC, abstractmethod
-from typing import Dict, Generator, Optional, Set
-
-from monai.deploy.core.operator import Operator
-
-
-class Graph(ABC):
- """Abstract class for graph."""
-
- @abstractmethod
- def add_operator(self, op: Operator):
- """Add a node to the graph."""
- pass
-
- @abstractmethod
- def add_flow(self, op_u: Operator, op_v: Operator, io_map: Dict[str, Set[str]]):
- """Add an edge to the graph.
-
- Args:
- op_u (Operator): A source operator.
- op_v (Operator): A destination operator.
- io_map (Dict[str, Set[str]]): A dictionary of mapping from the source operator's label to the destination
- operator's label(s).
- """
- pass
-
- @abstractmethod
- def get_io_map(self, op_u: Operator, op_v) -> Dict[str, Set[str]]:
- """Get a mapping from the source operator's output label to the destination operator's input label.
- Args:
- op_u (Operator): A source operator.
- op_v (Operator): A destination operator.
- Returns:
- A dictionary of mapping from the source operator's output label to the destination operator's
- input label(s).
- """
- pass
-
- @abstractmethod
- def is_root(self, op: Operator) -> bool:
- """Check if the operator is a root operator.
-
- Args:
- op (Operator): A node in the graph.
- Returns:
- True if the operator is a root operator.
- """
- pass
-
- @abstractmethod
- def is_leaf(self, op: Operator) -> bool:
- """Check if the operator is a leaf operator.
-
- Args:
- op (Operator): A node in the graph.
- Returns:
- True if the operator is a leaf operator.
- """
- pass
-
- @abstractmethod
- def get_root_operators(self) -> Generator[Operator, None, None]:
- """Get all root operators.
-
- Returns:
- A generator of root operators.
- """
- pass
-
- @abstractmethod
- def get_operators(self) -> Generator[Operator, None, None]:
- """Get all operators.
-
- Returns:
- A generator of operators.
- """
- pass
-
- @abstractmethod
- def gen_worklist(self) -> Generator[Optional[Operator], None, None]:
- """Get worklist."""
- pass
-
- @abstractmethod
- def gen_next_operators(self, op: Operator) -> Generator[Optional[Operator], None, None]:
- """Get next operators."""
- pass
diff --git a/monai/deploy/core/graphs/nx_digraph.py b/monai/deploy/core/graphs/nx_digraph.py
deleted file mode 100644
index a02ae250..00000000
--- a/monai/deploy/core/graphs/nx_digraph.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# Copyright 2021 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.
-
-from typing import Dict, Generator, Optional, Set
-
-import networkx as nx
-from networkx.algorithms.dag import topological_sort
-
-from monai.deploy.core.operator import Operator
-
-from .graph import Graph
-
-
-class NetworkXGraph(Graph):
- """NetworkX graph implementation."""
-
- def __init__(self, **kwargs: Dict):
- self._graph = nx.DiGraph()
-
- def add_operator(self, op: Operator):
- self._graph.add_node(op)
-
- def add_flow(self, op_u: Operator, op_v: Operator, io_map: Dict[str, Set[str]]):
- self._graph.add_edge(op_u, op_v, io_map=io_map)
-
- def get_io_map(self, op_u: Operator, op_v) -> Dict[str, Set[str]]:
- io_map: Dict[str, Set[str]] = self._graph.get_edge_data(op_u, op_v).get("io_map")
- return io_map
-
- def is_root(self, op: Operator) -> bool:
- return bool(self._graph.in_degree(op) == 0)
-
- def is_leaf(self, op: Operator) -> bool:
- return bool(self._graph.out_degree(op) == 0)
-
- def get_root_operators(self) -> Generator[Operator, None, None]:
- return (op for (op, degree) in self._graph.in_degree() if degree == 0)
-
- def get_operators(self) -> Generator[Operator, None, None]:
- return (op for op in self._graph.nodes())
-
- def gen_worklist(self) -> Generator[Optional[Operator], None, None]:
- worklist: Generator[Optional[Operator], None, None] = topological_sort(self._graph)
- return worklist
-
- def gen_next_operators(self, op: Operator) -> Generator[Optional[Operator], None, None]:
- for _, v in self._graph.out_edges(op):
- yield v
diff --git a/monai/deploy/core/io_context.py b/monai/deploy/core/io_context.py
deleted file mode 100644
index 75947aaf..00000000
--- a/monai/deploy/core/io_context.py
+++ /dev/null
@@ -1,131 +0,0 @@
-# Copyright 2021 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.
-
-from abc import ABC
-from typing import TYPE_CHECKING, Any, Set
-
-from typeguard import check_type
-
-# To avoid "Cannot resolve forward reference" error
-# : https://github.com/agronholm/sphinx-autodoc-typehints#dealing-with-circular-imports
-from . import execution_context
-
-if TYPE_CHECKING:
- from .execution_context import ExecutionContext
- from .operator import Operator
- from .datastores.datastore import Datastore
- from .operator_info import OperatorInfo
-
-from monai.deploy.exceptions import IOMappingError, ItemAlreadyExistsError, ItemNotExistsError
-
-from .domain.datapath import DataPath
-
-
-class IOContext(ABC):
- """Base class for IO context."""
-
- _io_kind = "undefined"
-
- def __init__(self, execution_context: "execution_context.ExecutionContext"):
- """Constructor for IOContext."""
- self._execution_context: "ExecutionContext" = execution_context
- self._op: Operator = execution_context.op
- self._op_info: OperatorInfo = self._op.op_info
- self._labels: Set[str] = self._op_info.get_labels(self._io_kind)
- self._storage: Datastore = execution_context.storage
-
- def get_default_label(self, label: str = "") -> str:
- """Get a default label for IO context."""
- if label not in self._labels:
- if label == "" and len(self._labels) == 1:
- label = next(iter(self._labels))
- else:
- raise IOMappingError(
- f"{label!r} is not a valid {self._io_kind} of the operator({self._op.name}). "
- f"It should be one of ({', '.join(self._labels)})."
- )
- return label
-
- def get_group_path(self, postfix: str = "") -> str:
- """Returns the path for the group.
-
- The group path returned would be:
- "/operators/{self._op.uid}/{execution_index}/{postfix}"
-
- Args:
- postfix: The postfix for the path.
-
- Returns:
- The path for the group.
- """
- execution_index = self._execution_context.get_execution_index()
- path = f"/operators/{self._op.uid}/{execution_index}/{postfix}"
- return path
-
- def get(self, label: str = "") -> Any:
- """Returns the data for the operator.
-
- It uses a sub path ({self._io_kind}/{label}) to get the data.
- The final group path (key) would be:
-
- "/operators/{self._op.uid}/{execution_index}/{self._io_kind}/{label}"
- """
- label = self.get_default_label(label)
- key = self.get_group_path(f"{self._io_kind}/{label}")
- storage = self._storage
- if not storage.exists(key):
- raise ItemNotExistsError(f"{key!r} does not exist.")
- return storage.get(key)
-
- def set(self, value: Any, label: str = ""):
- """Sets the data for the operator.
-
- It uses a sub path ({self._io_kind}/{label}) to set the data.
- The final group path (key) would be:
-
- "/operators/{self._op.uid}/{execution_index}/{self._io_kind}/{label}"
- """
- label = self.get_default_label(label)
- key = self.get_group_path(f"{self._io_kind}/{label}")
- storage = self._storage
- if storage.exists(key):
- raise ItemAlreadyExistsError(f"{key} already exists.")
- else:
- # Convert to the absolute path if 'value' is an instance of DataPath and it is a relative path.
- # This is to keep the actual path of the data in the storage across different Operator execution contexts.
- if isinstance(value, DataPath):
- value.to_absolute()
-
- # Verify the type of the value is matching the type of the input/output of the operator.
- # Use 'typeguard' package because Python's built-in isinstance() does not support parameterized generic type
- # checking: https://www.python.org/dev/peps/pep-0585/#id15
- data_type = self._op_info.get_data_type(self._io_kind, label)
- try:
- check_type(value, data_type)
- except TypeError as err:
- raise IOMappingError(
- f"The data type of {label!r} in the {self._io_kind} of {self._op!r} is {data_type}, but the value"
- f" to set is the data type of {type(value)}."
- ) from err
-
- storage.put(key, value)
-
-
-class InputContext(IOContext):
- """An input context for an operator."""
-
- _io_kind = "input"
-
-
-class OutputContext(IOContext):
- """An output context for an operator."""
-
- _io_kind = "output"
diff --git a/monai/deploy/core/io_type.py b/monai/deploy/core/io_type.py
index 4e42b0d5..247f5f2a 100644
--- a/monai/deploy/core/io_type.py
+++ b/monai/deploy/core/io_type.py
@@ -1,4 +1,4 @@
-# Copyright 2021 MONAI Consortium
+# Copyright 2021-2023 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
diff --git a/monai/deploy/core/operator.py b/monai/deploy/core/operator.py
deleted file mode 100644
index b9680d95..00000000
--- a/monai/deploy/core/operator.py
+++ /dev/null
@@ -1,290 +0,0 @@
-# Copyright 2021 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 uuid
-from abc import ABC, abstractmethod
-from typing import Optional, Type, Union
-
-from monai.deploy.exceptions import UnknownTypeError
-from monai.deploy.utils.importutil import is_subclass
-
-from .env import BaseEnv
-from .execution_context import ExecutionContext
-from .io_context import InputContext, OutputContext
-from .io_type import IOType
-from .operator_info import IO, OperatorInfo
-
-
-class Operator(ABC):
- """This is the base Operator class.
-
- An operator in MONAI Deploy performs a unit of work for the application.
- An operator has multiple in/out and output ports.
- Each port specifies an interaction point through which a operator can
- communicate with other operators.
- """
-
- # Special attribute to identify the operator.
- # Used by is_subclass() from deploy.utils.importutil to
- # determine the operatorapplication to run.
- # This is needed to identify Operator class across different environments (e.g. by `runpy.run_path()`).
- _class_id: str = "monai.operator"
-
- _env: Optional["OperatorEnv"] = None
-
- def __init__(self, *args, **kwargs):
- """Constructor of the base operator.
-
- It creates an instance of Data Store which holds on
- to all inputs and outputs relavant for this operator.
-
- Args:
- args: Arguments.
- kwargs: Keyword arguments.
-
- """
- super().__init__()
- self._uid: uuid.UUID = uuid.uuid4()
- self._op_info: OperatorInfo = OperatorInfo()
-
- # Execute the builder to set up the operator
- self._builder()
-
- @classmethod
- def __subclasshook__(cls, c: Type) -> bool:
- return is_subclass(c, cls._class_id)
-
- def _builder(self):
- """This method is called by the constructor of Operator to set up the operator.
-
- This method returns `self` to allow for method chaining and new `_builder()` method is
- chained by decorators.
-
- Returns:
- An instance of Operator.
- """
- return self
-
- def __hash__(self):
- return hash(self._uid)
-
- def __eq__(self, other):
- return self._uid == other._uid
-
- def add_input(self, label: str, data_type: Type, storage_type: Union[int, IOType]):
- self._op_info.add_label(IO.INPUT, label)
- self._op_info.set_data_type(IO.INPUT, label, data_type)
- self._op_info.set_storage_type(IO.INPUT, label, storage_type)
-
- def add_output(self, label: str, data_type: Type, storage_type: Union[int, IOType]):
- self._op_info.add_label(IO.OUTPUT, label)
- self._op_info.set_data_type(IO.OUTPUT, label, data_type)
- self._op_info.set_storage_type(IO.OUTPUT, label, storage_type)
-
- @property
- def name(self) -> str:
- """Returns the name of this operator."""
- return self.__class__.__name__
-
- @property
- def uid(self) -> uuid.UUID:
- """Gives access to the UID of the operator.
-
- Returns:
- UID of the operator.
- """
- return self._uid
-
- @property
- def op_info(self) -> OperatorInfo:
- """Retrieves the operator info.
-
- Args:
-
- Returns:
- An instance of OperatorInfo.
-
- """
- return self._op_info
-
- @property
- def env(self) -> "OperatorEnv":
- """Gives access to the environment.
-
- This sets a default value for the operator's environment if not set.
-
- Returns:
- An instance of OperatorEnv.
- """
- if self._env is None:
- self._env = OperatorEnv()
- return self._env
-
- def ensure_valid(self):
- """Ensures that the operator is valid.
-
- This method needs to be executed by `add_operator()` and `add_flow()` methods in the `compose()` method of the
- application.
- This sets default values for the operator in the graph if necessary.
- (e.g., set default value for the operator's input port, set default
- value for the operator's output port, etc.)
- """
- self.op_info.ensure_valid()
-
- def pre_compute(self):
- """This method gets executed before `compute()` of an operator is called.
-
- This is a preperatory step before the operator executes its main job.
- This needs to be overridden by a base class for any meaningful action.
- """
- pass
-
- @abstractmethod
- def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
- """An abstract method that needs to be implemented by the user.
-
- The original input and output paths from the CLI are available through
- `context.input.get()` and `context.output.get()`. The type of the returned value is `DataPath`.
-
- >>> context.input.get().path # (Path) - The input path from the application's context
- >>> context.output.get().path # (Path) - The output path from the application's context
-
- Both "input" and "output" are arguments passed to the application when the app is set to execute.
- The input and output paths are in the context of the whole application, and are read only once the application
- starts executing. Any operators in the application workflow graph can access the `context.input` and access
- the input to the application.
-
- `context.models.get("")` returns a model instance and a null model would be returned
- if model is not available.
-
- If is not specified and only one model exists, it returns that model.
-
- >>> model = context.models.get() # a model object that inherits Model class
-
- >>> # Get a model instance if exists
- >>> if model: # if model is not a null model
- >>> print(model.items())
- >>> # model.path for accessing the model's path
- >>> # model.name for accessing the model's name
- >>> # result = model(op_input.get().asnumpy())
-
- Similar way, `op_input.get("")` returns the input data of the specified label for the operator.
-
- If is not specified and only one input exists, it returns that input.
-
- >>> op_input.get() # an input object that inherits a type specified by @input decorator of the operator.
-
- If this operator is a leaf operator in the workflow graph, then the output path of the operator (the output
- path in local machine that is specified by CLI) is available through `op_output.get().path`.
- Otherwise, it is expected that the output of the operator is set through `op_output.set()` method.
-
- For example, if the input and output data type are both `Image` objects, then the following logic is expected:
-
- >>> data_in = op_input.get().asnumpy() # get the input data as numpy array
- >>> data_out = process(data_in) # process the input data
- >>> op_output.set(Image(data_out)) # set the output data
-
- If the operator is a leaf operator in the workflow graph and the operator output's
- `(, ) == (DataPath, DISK)`, you cannot call `op_output.set()` method.
- Instead, you can use the destination path available by `op_output.get().path` to store output data and the
- following logic is expected:
-
- >>> output_folder = op_output.get().path # get the output folder path
- >>> output_path = output_folder / "final_output.png" # get the output file path
-
- >>> imsave(output_path, data_out) # save the output data
-
- Args:
- op_input (InputContext): An input context for the operator.
- op_output (OutputContext): An output context for the operator.
- context (ExecutionContext): An execution context for the operator.
- """
- pass
-
- def post_compute(self):
- """This method gets executed after "compute()" of an operator is called.
-
- This is a post-execution step before the operator is done doing its
- main action.
- This needs to be overridden by a base class for any meaningful action.
- """
- pass
-
-
-def input(label: str = "", data_type: Type = object, storage_type: Union[int, IOType] = IOType.UNKNOWN):
- """A decorator that adds input specification to the operator.
-
- Args:
- label (str): A label for the input port.
- data_type (Type): A data type of the input.
- storage_type (Union[int, IOType]): A storage type of the input.
-
- Returns:
- A decorator that adds input specification to the operator.
- """
-
- def decorator(cls):
- if issubclass(cls, Operator):
- builder = cls.__dict__.get("_builder")
- else:
- raise UnknownTypeError("Use @input decorator only for a subclass of Operator!")
-
- def new_builder(self: Operator):
- # Execute (this) outer decorator first so decorators are executed in order
- self.add_input(label, data_type, storage_type)
- if builder:
- builder(self) # execute the original builder
- return self
-
- cls._builder = new_builder
- return cls
-
- return decorator
-
-
-def output(label: str = "", data_type: Type = object, storage_type: Union[int, IOType] = IOType.UNKNOWN):
- """A decorator that adds output specification to the operator.
-
- Args:
- label (str): A label for the output port.
- data_type (Type): A data type of the output.
- storage_type (Union[int, IOType]): A storage type of the output.
-
- Returns:
- A decorator that adds output specification to the operator.
- """
-
- def decorator(cls):
- if issubclass(cls, Operator):
- builder = cls.__dict__.get("_builder")
- else:
- raise UnknownTypeError("Use @output decorator only for a subclass of Operator!")
-
- def new_builder(self: Operator):
- # Execute (this) outer decorator first so decorators are executed in order
- self.add_output(label, data_type, storage_type)
- if builder:
- builder(self) # execute the original builder
- return self
-
- cls._builder = new_builder
- return cls
-
- return decorator
-
-
-class OperatorEnv(BaseEnv):
- """Settings for the operator environment.
-
- This class is used to specify the environment settings for the operator.
- """
-
- pass
diff --git a/monai/deploy/core/operator_info.py b/monai/deploy/core/operator_info.py
deleted file mode 100644
index 9f0a001e..00000000
--- a/monai/deploy/core/operator_info.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# Copyright 2021 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.
-
-from enum import Enum
-from typing import Dict, Set, Type, Union
-
-from .domain.datapath import DataPath
-from .io_type import IOType
-
-
-class IO(Enum):
- UNDEFINED = "undefined"
- INPUT = "input"
- OUTPUT = "output"
-
- def __str__(self):
- return self.value
-
-
-class OperatorInfo:
- """A class to store information about operator's input and output data types and storage types."""
-
- def __init__(self):
- # Initializing the attributes
- self.labels: Dict[IO, Set[str]] = {IO.INPUT: set(), IO.OUTPUT: set()}
- self.data_type: Dict[IO, Dict[str, Type]] = {IO.INPUT: {}, IO.OUTPUT: {}}
- self.storage_type: Dict[IO, Dict[str, IOType]] = {IO.INPUT: {}, IO.OUTPUT: {}}
-
- def ensure_valid(self):
- """Ensure that the operator info is valid.
-
- This sets default values for OperatorInfo.
- """
- for kind in [IO.INPUT, IO.OUTPUT]:
- if len(self.labels[kind]) == 0:
- self.labels[kind].add("")
- self.data_type[kind][""] = DataPath
- self.storage_type[kind][""] = IOType.DISK
-
- def add_label(self, io_kind: Union[IO, str], label: str):
- io_kind = IO(io_kind)
- self.labels[io_kind].add(label)
-
- def get_labels(self, io_kind: Union[IO, str]) -> Set[str]:
- io_kind = IO(io_kind)
- return self.labels[io_kind]
-
- def set_data_type(self, io_kind: Union[IO, str], label: str, data_type: Type):
- io_kind = IO(io_kind)
- self.data_type[io_kind][label] = data_type
-
- def get_data_type(self, io_kind: Union[IO, str], label: str) -> Type:
- io_kind = IO(io_kind)
- return self.data_type[io_kind][label]
-
- def set_storage_type(self, io_kind: Union[IO, str], label: str, storage_type: Union[int, IOType]):
- io_kind = IO(io_kind)
- self.storage_type[io_kind][label] = IOType(storage_type)
-
- def get_storage_type(self, io_kind: Union[IO, str], label: str) -> IOType:
- io_kind = IO(io_kind)
- return self.storage_type[io_kind][label]
diff --git a/monai/deploy/core/resource.py b/monai/deploy/core/resource.py
deleted file mode 100644
index 5cbd8768..00000000
--- a/monai/deploy/core/resource.py
+++ /dev/null
@@ -1,141 +0,0 @@
-# Copyright 2021 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.
-
-from typing import Optional, Union
-
-from monai.deploy.exceptions import ItemAlreadyExistsError, UnknownTypeError, WrongValueError
-from monai.deploy.utils.sizeutil import get_bytes
-
-
-class Resource:
- """Class responible for resource limits.
-
- Each resource limit value is None (its access would return 0) and the value is overriden by @resource decorator
- and then by the CLI arguments.
-
- To do so, first, each resource limit value is set to None unless those values are set by the CLI arguments.
- Then, if the resource limit value is None and the user specifies a value through @resource decorator,
- the value is set to the given attribute.
- """
-
- def __init__(self, cpu: Optional[int] = None, memory: Optional[int] = None, gpu: Optional[int] = None):
- self._cpu = cpu
- self._memory = memory
- self._gpu = gpu
-
- @property
- def cpu(self) -> int:
- if self._cpu is None:
- return 0
- return self._cpu
-
- @property
- def memory(self) -> int:
- if self._memory is None:
- return 0
- return self._memory
-
- @property
- def gpu(self) -> int:
- # TODO(gigony): check if the gpu limit can be distinguished between all gpus vs zero gpu.
- # https://github.com/NVIDIA/k8s-device-plugin/issues/61
- if self._gpu is None:
- return 0
- return self._gpu
-
- def set_resource_limits(
- self,
- cpu_limit: Optional[int] = None,
- memory_limit: Optional[Union[int, str]] = None,
- gpu_limit: Optional[int] = None,
- ):
- """Sets resource limits from the given values if each attribute is not None."""
-
- if cpu_limit is not None:
- if self._cpu is None:
- self._cpu = cpu_limit
- else:
- raise ItemAlreadyExistsError(
- f"'cpu' wouldn't be set to {cpu_limit} because it is already set to {self._cpu} by the runtime"
- " environment."
- )
-
- if gpu_limit is not None:
- if self._gpu is None:
- self._gpu = gpu_limit
- else:
- raise ItemAlreadyExistsError(
- f"'gpu' wouldn't be set to {gpu_limit} because it is already set to {self._gpu} by the runtime"
- " environment."
- )
-
- if type(memory_limit) == str:
- try:
- self._memory = get_bytes(memory_limit)
- except Exception as err:
- raise WrongValueError(
- f"Memory size specified in the application (via @resource) is not valid: {err.args[0]}"
- ) from err
- elif type(memory_limit) == int:
- if self._memory is None:
- self._memory = memory_limit
- else:
- raise ItemAlreadyExistsError(
- f"'memory' wouldn't be set to {memory_limit} because it is already set to {self._memory}"
- " by the runtime environment."
- )
-
- def __str__(self):
- return "Resource(cpu={}, memory={}, gpu={})".format(self.cpu, self.memory, self.gpu)
-
-
-def resource(
- cpu: Optional[int] = None,
- memory: Optional[Union[int, str]] = None,
- gpu: Optional[int] = None,
-):
- """A decorator that adds an resource requirement to the application.
-
- Args:
- cpu: A number of CPU cores required.
- memory: A string or integer representation of bytes to be converted.
- (eg. "0.3 Gib", "3mb", "1024", 65536)
- gpu: A number of GPUs required.
-
- Returns:
- A decorator that adds an resource requirement to the application.
- """
-
- # Import here to avoid circular imports
- from .application import Application
-
- def decorator(cls):
- if issubclass(cls, Application):
- builder = cls.__dict__.get("_builder")
- else:
- raise UnknownTypeError("Use @resource decorator only for a subclass of Application!")
-
- def new_builder(self: Application):
- # Execute (this) outer decorator first so decorators are executed in order
- try:
- self.context.resource.set_resource_limits(cpu, memory, gpu)
- except ItemAlreadyExistsError as err:
- raise ItemAlreadyExistsError(f"In @resource decorator at {self.name}, {err.args[0]}") from err
-
- if builder:
- builder(self) # execute the original builder
-
- return self
-
- cls._builder = new_builder
- return cls
-
- return decorator
diff --git a/monai/deploy/core/runtime_env.py b/monai/deploy/core/runtime_env.py
index 63ef1670..f169e1c7 100644
--- a/monai/deploy/core/runtime_env.py
+++ b/monai/deploy/core/runtime_env.py
@@ -13,35 +13,25 @@
from abc import ABC
from typing import Dict, Optional, Tuple
-from monai.deploy.core.datastores.factory import DatastoreFactory
-from monai.deploy.core.executors.factory import ExecutorFactory
-from monai.deploy.core.graphs.factory import GraphFactory
-
class RuntimeEnv(ABC):
- """Class responsible to managing run time settings.
+ """Class responsible for managing run time settings.
The expected environment variables are the keys in the defaults dictionary,
and they can be set to override the defaults.
"""
ENV_DEFAULT: Dict[str, Tuple[str, ...]] = {
- "input": ("MONAI_INPUTPATH", "input"),
- "output": ("MONAI_OUTPUTPATH", "output"),
- "model": ("MONAI_MODELPATH", "models"),
- "workdir": ("MONAI_WORKDIR", ""),
- "graph": ("MONAI_GRAPH", GraphFactory.DEFAULT), # The 'MONAI_GRAPH' is not part of MAP spec.
- "datastore": ("MONAI_DATASTORE", DatastoreFactory.DEFAULT), # The 'MONAI_DATASTORE' is not part of MAP spec.
- "executor": ("MONAI_EXECUTOR", ExecutorFactory.DEFAULT), # The 'MONAI_EXECUTOR' is not part of MAP spec.
+ "input": ("HOLOSCAN_INPUT_PATH", "input"),
+ "output": ("HOLOSCAN_OUTPUT_PATH", "output"),
+ "model": ("HOLOSCAN_MODEL_PATH", "models"),
+ "workdir": ("HOLOSCAN_WORKDIR", ""),
}
input: str = ""
output: str = ""
model: str = ""
workdir: str = ""
- graph: str = ""
- datastore: str = ""
- executor: str = ""
def __init__(self, defaults: Optional[Dict[str, Tuple[str, ...]]] = None):
if defaults is None:
diff --git a/monai/deploy/executors/__init__.py b/monai/deploy/executors/__init__.py
new file mode 100644
index 00000000..2d78aba4
--- /dev/null
+++ b/monai/deploy/executors/__init__.py
@@ -0,0 +1 @@
+from holoscan.executors import *
diff --git a/monai/deploy/graphs/__init__.py b/monai/deploy/graphs/__init__.py
new file mode 100644
index 00000000..6005a2d7
--- /dev/null
+++ b/monai/deploy/graphs/__init__.py
@@ -0,0 +1 @@
+from holoscan.graphs import *
diff --git a/monai/deploy/logger/__init__.py b/monai/deploy/logger/__init__.py
new file mode 100644
index 00000000..e455dc05
--- /dev/null
+++ b/monai/deploy/logger/__init__.py
@@ -0,0 +1,4 @@
+from holoscan.logger import *
+
+# Can also use explicit list, e.g.
+# from holoscan.logger import set_log_level
diff --git a/monai/deploy/operators/__init__.py b/monai/deploy/operators/__init__.py
index 64d9554c..75176dab 100644
--- a/monai/deploy/operators/__init__.py
+++ b/monai/deploy/operators/__init__.py
@@ -33,6 +33,10 @@
NiftiDataLoader
"""
+# If needed, can choose to expose some or all of Holoscan SDK built-in operators.
+# from holoscan.operators import *
+from holoscan.operators import PingRxOp, PingTxOp, VideoStreamRecorderOp, VideoStreamReplayerOp
+
from .clara_viz_operator import ClaraVizOperator
from .dicom_data_loader_operator import DICOMDataLoaderOperator
from .dicom_encapsulated_pdf_writer_operator import DICOMEncapsulatedPDFWriterOperator
diff --git a/monai/deploy/operators/clara_viz_operator.py b/monai/deploy/operators/clara_viz_operator.py
index 450dec07..6524cd19 100644
--- a/monai/deploy/operators/clara_viz_operator.py
+++ b/monai/deploy/operators/clara_viz_operator.py
@@ -1,4 +1,4 @@
-# Copyright 2022 MONAI Consortium
+# Copyright 2022-2023 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
@@ -11,8 +11,7 @@
import numpy as np
-import monai.deploy.core as md
-from monai.deploy.core import ExecutionContext, Image, InputContext, IOType, Operator, OutputContext
+from monai.deploy.core import Fragment, Operator, OperatorSpec
from monai.deploy.utils.importutil import optional_import
DataDefinition, _ = optional_import("clara.viz.core", name="DataDefinition")
@@ -24,17 +23,32 @@
VBox, _ = optional_import("ipywidgets", name="VBox")
-@md.input("image", Image, IOType.IN_MEMORY)
-@md.input("seg_image", Image, IOType.IN_MEMORY)
-@md.env(pip_packages=["clara.viz.core", "clara.viz.widgets", "IPython"])
+# @md.env(pip_packages=["clara.viz.core", "clara.viz.widgets", "IPython"])
class ClaraVizOperator(Operator):
"""
This operator uses Clara Viz to provide interactive view of a 3D volume including segmentation mask.
+
+ Named input(s):
+ image: Image object of the input image, including key metadata, e.g. pixel spacings and orientations.
+ seg_image: Image object of the segmentation image derived from the input image.
"""
- def __init__(self):
- """Constructor of the operator."""
- super().__init__()
+ def __init__(self, fragement: Fragment, *args, **kwargs):
+ """Constructor of the operator.
+
+ Args:
+ fragment (Fragment): An instance of the Application class which is derived from Fragment.
+ """
+
+ self.input_name_image = "image"
+ self.input_name_seg_image = "seg_image"
+
+ super().__init__(fragement, *args, **kwargs)
+
+ def setup(self, spec: OperatorSpec):
+ spec.input(self.input_name_image)
+ spec.input(self.input_name_seg_image)
+ # There is no output for downstream receiver(s), but interactive UI.
@staticmethod
def _build_array(image, order):
@@ -75,7 +89,7 @@ def _build_array(image, order):
return array
- def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
+ def compute(self, op_input, op_output, context):
"""Displays the input image and segmentation mask
Args:
@@ -83,12 +97,12 @@ def compute(self, op_input: InputContext, op_output: OutputContext, context: Exe
op_output (OutputContext): An output context for the operator.
context (ExecutionContext): An execution context for the operator.
"""
- input_image = op_input.get("image")
+ input_image = op_input.receive(self.input_name_image)
if not input_image:
- raise ValueError("Input image is not found.")
- input_seg_image = op_input.get("seg_image")
+ raise ValueError("Original density image not received in the input.")
+ input_seg_image = op_input.receive(self.input_name_seg_image)
if not input_seg_image:
- raise ValueError("Input segmentation image is not found.")
+ raise ValueError("Segmentation image not received in the input.")
# build the data definition
data_definition = DataDefinition()
diff --git a/monai/deploy/operators/dicom_data_loader_operator.py b/monai/deploy/operators/dicom_data_loader_operator.py
index 9dda1807..f07a45ef 100644
--- a/monai/deploy/operators/dicom_data_loader_operator.py
+++ b/monai/deploy/operators/dicom_data_loader_operator.py
@@ -1,4 +1,4 @@
-# Copyright 2021-2022 MONAI Consortium
+# Copyright 2021-2023 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
@@ -14,8 +14,7 @@
from pathlib import Path
from typing import List
-import monai.deploy.core as md
-from monai.deploy.core import DataPath, ExecutionContext, InputContext, IOType, Operator, OutputContext
+from monai.deploy.core import ConditionType, Fragment, Operator, OperatorSpec
from monai.deploy.core.domain.dicom_series import DICOMSeries
from monai.deploy.core.domain.dicom_study import DICOMStudy
from monai.deploy.exceptions import ItemNotExistsError
@@ -29,31 +28,82 @@
InvalidDicomError, _ = optional_import("pydicom.errors", name="InvalidDicomError")
-@md.input("dicom_files", DataPath, IOType.DISK)
-@md.output("dicom_study_list", List[DICOMStudy], IOType.IN_MEMORY)
-@md.env(pip_packages=["pydicom >= 1.4.2"])
+# @md.env(pip_packages=["pydicom >= 1.4.2"])
class DICOMDataLoaderOperator(Operator):
- """
- This operator loads a collection of DICOM Studies in memory
- given a directory which contains a list of SOP Instances.
+ """This operator loads DICOM studies into memory from a folder of DICOM instance files.
+
+ Named Input:
+ input_folder: Path to the folder containing DICOM instance files. Optional and not requiring input.
+ If present, data from this input will be used as the input folder of DICOM instance files.
+
+ Name Output:
+ dicom_study_list: A list of DICOMStudy objects in memory. The name can be changed via attribute, `output_name`.
"""
- def __init__(self, must_load: bool = True, *args, **kwargs):
- """Creates an instance of this class
+ DEFAULT_INPUT_FOLDER = Path.cwd() / "input"
+ DEFAULT_OUTPUT_NAME = "dicom_study_list"
+
+ # For now, need to have the input folder as an instance attribute, set on init, because even there is the optional
+ # named input to receive data containing the path, there might not be upstream operator to emit the data.
+ def __init__(
+ self,
+ fragment: Fragment,
+ *args,
+ input_folder: Path = DEFAULT_INPUT_FOLDER,
+ output_name: str = DEFAULT_OUTPUT_NAME,
+ must_load: bool = True,
+ **kwargs,
+ ):
+ """Creates an instance of this class.
Args:
+ fragment (Fragment): An instance of the Application class which is derived from Fragment.
+ input_folder (Path): Folder containing DICOM instance files to load from.
+ Defaults to `input` in the current working directory.
+ Can be overridden by via the named input receiving from other's output.
+ output_name (str): The name for the output, which is list of DICOMStudy objects.
+ Defaults to `dicom_study_list`, and if None or blank passed in.
must_load (bool): If true, raise exception if no study is loaded.
Defaults to True.
"""
- super().__init__(*args, **kwargs)
- self._must_load = must_load
- def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
+ self._logger = logging.getLogger("{}.{}".format(__name__, type(self).__name__))
+ self._must_load = must_load
+ self.input_path = input_folder
+ self.index = 0
+ self.input_name = "input_folder"
+ self.output_name = (
+ output_name.strip()
+ if output_name and len(output_name.strip()) > 0
+ else DICOMDataLoaderOperator.DEFAULT_OUTPUT_NAME
+ )
+
+ super().__init__(fragment, *args, **kwargs)
+
+ def setup(self, spec: OperatorSpec):
+ spec.input(self.input_name).condition(ConditionType.NONE) # Optional input, not requiring upstream emitter.
+ spec.output(self.output_name)
+
+ def compute(self, op_input, op_output, context):
"""Performs computation for this operator and handlesI/O."""
- input_path = op_input.get().path
+ self.index += 1
+ input_path = None
+ try:
+ input_path = op_input.receive(self.input_name)
+ except Exception:
+ pass
+
+ if not input_path or not Path(input_path).is_dir():
+ self._logger.info(f"No or invalid input path from the optional input port: {input_path}")
+ # Use the object attribute if it is valid
+ if self.input_path and self.input_path.is_dir():
+ input_path = self.input_path
+ else:
+ raise ValueError(f"No valid input path from input port or obj attribute: {self.input_path}")
+
dicom_study_list = self.load_data_to_studies(input_path)
- op_output.set(dicom_study_list, "dicom_study_list")
+ op_output.emit(dicom_study_list, self.output_name)
def load_data_to_studies(self, input_path: Path):
"""Load DICOM data from files into DICOMStudy objects in a list.
@@ -115,7 +165,7 @@ def _load_data(self, files: List[str]):
try:
sop_instances.append(dcmread(file))
except InvalidDicomError as ex:
- logging.warning(f"Ignored {file}, reason being: {ex}")
+ self._logger.warn(f"Ignored {file}, reason being: {ex}")
for sop_instance in sop_instances:
study_instance_uid = sop_instance[0x0020, 0x000D].value.name # name is the UID as str
@@ -277,9 +327,9 @@ def populate_series_attributes(self, series, sop_instance):
def test():
current_file_dir = Path(__file__).parent.resolve()
- data_path = current_file_dir.joinpath("../../../examples/ai_spleen_seg_data/dcm")
+ data_path = current_file_dir.joinpath("../../../inputs/spleen_ct/dcm")
- loader = DICOMDataLoaderOperator()
+ loader = DICOMDataLoaderOperator(Fragment())
study_list = loader.load_data_to_studies(data_path.absolute())
for study in study_list:
@@ -294,7 +344,7 @@ def test():
# sop = sop.get_native_sop_instance()
print(f" 'StudyInstanceUID': {sop['StudyInstanceUID'].repval}")
print(f" (0x0020, 0x000D): {sop[0x0020, 0x000D].repval}")
- print(f" 'SeriesInstanceUID': {sop['SeriesInstanceUID'].value.name}")
+ print(f" 'SeriesInstanceUID': {sop['SeriesInstanceUID'].value.name}")
print(f" (0x0020, 0x000E): {sop[0x0020, 0x000E].value.name}")
print(f" 'SOPInstanceUID': {sop['SOPInstanceUID'].value.name}")
print(f" (0008,0018): {sop[0x0008, 0x0018].value.name}")
@@ -306,13 +356,13 @@ def test():
# Need to get pydicom dataset to use properties and get method of a dict.
ds = sop.get_native_sop_instance()
print(f" 'StudyInstanceUID': {ds.StudyInstanceUID if ds.StudyInstanceUID else ''}")
- print(f" 'SeriesDescription': {ds.SeriesDescription if ds.SeriesDescription else ''}")
+ print(f" 'SeriesDescription': {ds.SeriesDescription if ds.SeriesDescription else ''}")
print(
- " 'IssuerOfPatientID':"
+ " 'IssuerOfPatientID':"
f" {ds.get('IssuerOfPatientID', '').repval if ds.get('IssuerOfPatientID', '') else '' }"
)
try:
- print(f" 'IssuerOfPatientID': {ds.IssuerOfPatientID if ds.IssuerOfPatientID else '' }")
+ print(f" 'IssuerOfPatientID': {ds.IssuerOfPatientID if ds.IssuerOfPatientID else '' }")
except AttributeError:
print(
" If the IssuerOfPatientID does not exist, ds.IssuerOfPatientID would throw AttributeError."
@@ -323,15 +373,15 @@ def test():
break
# Test raising exception, or not, depending on if set to must_load.
non_dcm_dir = current_file_dir.parent / "utils"
- print(f"{non_dcm_dir}")
+ print(f"Test loading from dir without dcm files: {non_dcm_dir}")
try:
loader.load_data_to_studies(non_dcm_dir)
except ItemNotExistsError as ex:
- print(f"Tested exception when no studies loaded & must_load is True: {ex}")
+ print(f"Test passed: exception when no studies loaded & must_load flag is True: {ex}")
- relaxed_loader = DICOMDataLoaderOperator(must_load=False)
+ relaxed_loader = DICOMDataLoaderOperator(Fragment(), must_load=False)
study_list = relaxed_loader.load_data_to_studies(non_dcm_dir)
- print(f"Loaded studies length of {len(study_list)} is OK when must_load is set to False.")
+ print(f"Test passed: {len(study_list)} study loaded and is OK when must_load flag is False.")
if __name__ == "__main__":
diff --git a/monai/deploy/operators/dicom_encapsulated_pdf_writer_operator.py b/monai/deploy/operators/dicom_encapsulated_pdf_writer_operator.py
index bd66915f..c2085c2b 100644
--- a/monai/deploy/operators/dicom_encapsulated_pdf_writer_operator.py
+++ b/monai/deploy/operators/dicom_encapsulated_pdf_writer_operator.py
@@ -10,10 +10,10 @@
# limitations under the License.
import logging
-from ast import Bytes
+import os
from io import BytesIO
from pathlib import Path
-from typing import Dict, List, Optional
+from typing import Dict, Optional, Union
from monai.deploy.utils.importutil import optional_import
@@ -26,37 +26,51 @@
Sequence, _ = optional_import("pydicom.sequence", name="Sequence")
PdfReader, _ = optional_import("PyPDF2", name="PdfReader")
-import monai.deploy.core as md
-from monai.deploy.core import DataPath, ExecutionContext, InputContext, IOType, Operator, OutputContext
+from monai.deploy.core import ConditionType, Fragment, Operator, OperatorSpec
from monai.deploy.core.domain.dicom_series import DICOMSeries
from monai.deploy.core.domain.dicom_series_selection import StudySelectedSeries
-from monai.deploy.exceptions import ItemNotExistsError
from monai.deploy.operators.dicom_utils import EquipmentInfo, ModelInfo, save_dcm_file, write_common_modules
from monai.deploy.utils.version import get_sdk_semver
-# The SR writer operator class
-@md.input("pdf_bytes", Bytes, IOType.IN_MEMORY)
-@md.input("pdf_file", DataPath, IOType.DISK)
-@md.input("study_selected_series_list", List[StudySelectedSeries], IOType.IN_MEMORY)
-@md.output("dicom_instance", DataPath, IOType.DISK)
-@md.env(pip_packages=["pydicom >= 1.4.2", "PyPDF2 >= 2.11.1", "monai"])
+# @md.env(pip_packages=["pydicom >= 1.4.2", "PyPDF2 >= 2.11.1", "monai"])
class DICOMEncapsulatedPDFWriterOperator(Operator):
+ """Class to write DICOM Encapsulated PDF Instance with provided PDF bytes in memory.
+
+ Named inputs:
+ pdf_bytes: Bytes of the the PDF content.
+ study_selected_series_list: Optional, DICOM series for copying metadata from.
+
+ Named output:
+ None
+
+ File output:
+ Generaed DICOM instance file in the provided output folder.
+ """
+
+ # File extension for the generated DICOM Part 10 file.
DCM_EXTENSION = ".dcm"
+ # The default output folder for saveing the generated DICOM instance file.
+ DEFAULT_OUTPUT_FOLDER = Path(os.getcwd()) / "output"
def __init__(
self,
- copy_tags: bool,
+ fragment: Fragment,
+ *args,
+ output_folder: Union[str, Path],
model_info: ModelInfo,
equipment_info: Optional[EquipmentInfo] = None,
+ copy_tags: bool = True,
custom_tags: Optional[Dict[str, str]] = None,
- *args,
**kwargs,
):
"""Class to write DICOM Encapsulated PDF Instance with PDF bytes in memory or in a file.
Args:
- copy_tags (bool): True for copying DICOM attributes from a provided DICOMSeries.
+ fragment (Fragment): An instance of the Application class which is derived from Fragment.
+ output_folder (str or Path): The folder for saving the generated DICOM instance file.
+ copy_tags (bool): True, default, for copying DICOM attributes from a provided DICOMSeries.
+ If True and no DICOMSeries obj provided, runtime exception is thrown.
model_info (ModelInfo): Object encapsulating model creator, name, version and UID.
equipment_info (EquipmentInfo, optional): Object encapsulating info for DICOM Equipment Module.
Defaults to None.
@@ -67,12 +81,20 @@ def __init__(
ValueError: If copy_tags is true and no DICOMSeries object provided, or
if PDF bytes cannot be found in memory or loaded from the file.
"""
- super().__init__(*args, **kwargs)
+
self._logger = logging.getLogger("{}.{}".format(__name__, type(self).__name__))
+
+ # Need to init the output folder until the execution context supports dynamic FS path
+ # Not trying to create the folder to avoid exception on init
+ self.output_folder = (
+ Path(output_folder) if output_folder else DICOMEncapsulatedPDFWriterOperator.DEFAULT_OUTPUT_FOLDER
+ )
self.copy_tags = copy_tags
self.model_info = model_info if model_info else ModelInfo()
self.equipment_info = equipment_info if equipment_info else EquipmentInfo()
self.custom_tags = custom_tags
+ self.input_name_bytes = "pdf_bytes"
+ self.input_name_dcm_series = "study_selected_series_list"
# Set own Modality and SOP Class UID
# Modality, e.g.,
@@ -93,8 +115,21 @@ def __init__(
except Exception:
self.software_version_number = ""
self.operators_name = f"AI Algorithm {self.model_info.name}"
+ super().__init__(fragment, *args, **kwargs)
- def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
+ def setup(self, spec: OperatorSpec):
+ """Set up the named input(s), and output(s) if applicable.
+
+ This operator does not have an output for the next operator, rather file output only.
+
+ Args:
+ spec (OperatorSpec): The Operator specification for inputs and outputs etc.
+ """
+
+ spec.input(self.input_name_bytes)
+ spec.input(self.input_name_dcm_series).condition(ConditionType.NONE) # Optional input
+
+ def compute(self, op_input, op_output, context):
"""Performs computation for this operator and handles I/O.
For now, only a single result content is supported, which could be in bytes or a path
@@ -112,24 +147,15 @@ def compute(self, op_input: InputContext, op_output: OutputContext, context: Exe
# Gets the input, prepares the output folder, and then delegates the processing.
pdf_bytes: bytes = b""
- try:
- pdf_bytes = op_input.get("pdf_bytes")
- except ItemNotExistsError:
- try:
- file_path = op_input.get("pdf_file")
- except ItemNotExistsError:
- raise ValueError("None of the named inputs can be found.") from None
- # Read file, and if exception, let it bubble up
- with open(file_path.path, "rb") as f:
- pdf_bytes = f.read().strip()
-
+ pdf_bytes = op_input.receive(self.input_name_bytes)
if not pdf_bytes or not len(pdf_bytes.strip()):
raise IOError("Input is read but blank.")
+ study_selected_series_list = None
try:
- study_selected_series_list = op_input.get("study_selected_series_list")
- except ItemNotExistsError:
- study_selected_series_list = None
+ study_selected_series_list = op_input.receive(self.input_name_dcm_series)
+ except Exception:
+ pass
dicom_series = None # It can be None if not to copy_tags.
if self.copy_tags:
@@ -143,11 +169,11 @@ def compute(self, op_input: InputContext, op_output: OutputContext, context: Exe
dicom_series = selected_series.series
break
- output_dir = op_output.get().path
- output_dir.mkdir(parents=True, exist_ok=True)
+ # The output folder should come from the execution context when it is supported.
+ self.output_folder.mkdir(parents=True, exist_ok=True)
# Now ready to starting writing the DICOM instance
- self.write(pdf_bytes, dicom_series, output_dir)
+ self.write(pdf_bytes, dicom_series, self.output_folder)
def write(self, content_bytes, dicom_series: Optional[DICOMSeries], output_dir: Path):
"""Writes DICOM object
@@ -223,47 +249,52 @@ def _is_pdf_bytes(self, content: bytes):
return True
-def test():
- from monai.deploy.operators.dicom_data_loader_operator import DICOMDataLoaderOperator
- from monai.deploy.operators.dicom_series_selector_operator import DICOMSeriesSelectorOperator
-
- current_file_dir = Path(__file__).parent.resolve()
- dcm_folder = current_file_dir.joinpath("../../../inputs/livertumor_ct/dcm/1-CT_series_liver_tumor_from_nii014")
- pdf_file = current_file_dir.joinpath("../../../inputs/pdf/TestPDF.pdf")
- out_path = "output_pdf_op"
- pdf_bytes = b"Not PDF bytes."
- test_copy_tags = False
-
- loader = DICOMDataLoaderOperator()
- series_selector = DICOMSeriesSelectorOperator()
- sr_writer = DICOMEncapsulatedPDFWriterOperator(
- copy_tags=test_copy_tags,
- model_info=None,
- equipment_info=EquipmentInfo(),
- custom_tags={"SeriesDescription": "Report from AI algorithm. Not for clinical use."},
- )
-
- # Testing with the main entry functions
- dicom_series = None
- if test_copy_tags:
- study_list = loader.load_data_to_studies(Path(dcm_folder).absolute())
- study_selected_series_list = series_selector.filter(None, study_list)
- # Get the first DICOM Series, as for now, only expecting this.
- if not study_selected_series_list or len(study_selected_series_list) < 1:
- raise ValueError("Missing input, list of 'StudySelectedSeries'.")
- for study_selected_series in study_selected_series_list:
- if not isinstance(study_selected_series, StudySelectedSeries):
- raise ValueError("Element in input is not expected type, 'StudySelectedSeries'.")
- for selected_series in study_selected_series.selected_series:
- print(type(selected_series))
- dicom_series = selected_series.series
- print(type(dicom_series))
-
- with open(pdf_file, "rb") as f:
- pdf_bytes = f.read()
-
- sr_writer.write(pdf_bytes, dicom_series, Path(out_path).absolute())
-
-
-if __name__ == "__main__":
- test()
+# Commenting out the following as pttype complains about the contructor for no reason
+# def test(test_copy_tags: bool = True):
+# from monai.deploy.operators.dicom_data_loader_operator import DICOMDataLoaderOperator
+# from monai.deploy.operators.dicom_series_selector_operator import DICOMSeriesSelectorOperator
+
+# current_file_dir = Path(__file__).parent.resolve()
+# dcm_folder = current_file_dir.joinpath("../../../inputs/livertumor_ct/dcm/1-CT_series_liver_tumor_from_nii014")
+# pdf_file = current_file_dir.joinpath("../../../inputs/pdf/TestPDF.pdf")
+# out_path = Path("output_pdf_op").absolute()
+# pdf_bytes = b"Not PDF bytes."
+
+# fragment = Fragment()
+# loader = DICOMDataLoaderOperator(fragment, name="loader_op")
+# series_selector = DICOMSeriesSelectorOperator(fragment, name="selector_op")
+# sr_writer = DICOMEncapsulatedPDFWriterOperator(
+# fragment,
+# output_folder=out_path,
+# copy_tags=test_copy_tags,
+# model_info=None,
+# equipment_info=EquipmentInfo(),
+# custom_tags={"SeriesDescription": "Report from AI algorithm. Not for clinical use."},
+# name="writer_op",
+# )
+
+# # Testing with the main entry functions
+# dicom_series = None
+# if test_copy_tags:
+# study_list = loader.load_data_to_studies(Path(dcm_folder).absolute())
+# study_selected_series_list = series_selector.filter(None, study_list)
+# # Get the first DICOM Series, as for now, only expecting this.
+# if not study_selected_series_list or len(study_selected_series_list) < 1:
+# raise ValueError("Missing input, list of 'StudySelectedSeries'.")
+# for study_selected_series in study_selected_series_list:
+# if not isinstance(study_selected_series, StudySelectedSeries):
+# raise ValueError("Element in input is not expected type, 'StudySelectedSeries'.")
+# for selected_series in study_selected_series.selected_series:
+# print(type(selected_series))
+# dicom_series = selected_series.series
+# print(type(dicom_series))
+
+# with open(pdf_file, "rb") as f:
+# pdf_bytes = f.read()
+
+# sr_writer.write(pdf_bytes, dicom_series, out_path)
+
+
+# if __name__ == "__main__":
+# test(test_copy_tags=True)
+# test(test_copy_tags=False)
diff --git a/monai/deploy/operators/dicom_seg_writer_operator.py b/monai/deploy/operators/dicom_seg_writer_operator.py
index 124415e5..55840f61 100644
--- a/monai/deploy/operators/dicom_seg_writer_operator.py
+++ b/monai/deploy/operators/dicom_seg_writer_operator.py
@@ -1,4 +1,4 @@
-# Copyright 2021 MONAI Consortium
+# Copyright 2021-2023 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
@@ -36,8 +36,7 @@
Code, _ = optional_import("pydicom.sr.coding", name="Code")
hd, _ = optional_import("highdicom")
-import monai.deploy.core as md
-from monai.deploy.core import DataPath, ExecutionContext, Image, InputContext, IOType, Operator, OutputContext
+from monai.deploy.core import ConditionType, Fragment, Image, Operator, OperatorSpec
from monai.deploy.core.domain.dicom_series import DICOMSeries
from monai.deploy.core.domain.dicom_series_selection import StudySelectedSeries
@@ -155,29 +154,38 @@ def to_segment_description(self, segment_number: int) -> hd.seg.SegmentDescripti
)
-@md.input("seg_image", Image, IOType.IN_MEMORY)
-@md.input("study_selected_series_list", List[StudySelectedSeries], IOType.IN_MEMORY)
-@md.output("dicom_seg_instance", DataPath, IOType.DISK)
-@md.env(pip_packages=["pydicom >= 2.3.0", "highdicom >= 0.18.2"])
+# @md.env(pip_packages=["pydicom >= 2.3.0", "highdicom >= 0.18.2, "SimpleITK>=2.0.0"])
class DICOMSegmentationWriterOperator(Operator):
"""
This operator writes out a DICOM Segmentation Part 10 file to disk
+
+ Named inputs:
+ seg_image: The Image object of the segment.
+ study_selected_series_list: The DICOM series from which the segment was derived.
+ output_folder: Optional, folder for file output, overriding what is set on the object.
+
+ Named output:
+ None
+
+ File output:
+ Generated DICOM instance file in the output folder set on this object or optional input.
"""
- # Supported input image format, based on extension.
+ DEFAULT_OUTPUT_FOLDER = Path.cwd() / "output"
+ # Supported input image format, based on extension. Intended for file based input.
SUPPORTED_EXTENSIONS = [".nii", ".nii.gz", ".mhd"]
# DICOM instance file extension. Case insensitive in string comparison.
DCM_EXTENSION = ".dcm"
def __init__(
self,
+ fragment: Fragment,
+ *args,
segment_descriptions: List[SegmentDescription],
+ output_folder: Path,
custom_tags: Optional[Dict[str, str]] = None,
- omit_empty_frames: bool = True,
- *args,
**kwargs,
):
- super().__init__(*args, **kwargs)
"""Instantiates the DICOM Seg Writer instance with optional list of segment label strings.
Each unique, non-zero integer value in the segmentation image represents a segment that must be
@@ -192,19 +200,36 @@ def __init__(
segment label information, including label value, name, description etc.
Args:
+ fragment (Fragment): An instance of the Application class which is derived from Fragment.
segment_descriptions: List[SegmentDescription]
Object encapsulating the description of each segment present in the segmentation.
- custom_tags: Optional[Dict[str, str]], optional
+ output_folder: Folder for file output, overridden by named input on compute.
+ Defaults to current working dir's child folder, output.
+ custom_tags: OptonalDict[str, str], optional
Dictionary for setting custom DICOM tags using Keywords and str values only
- omit_empty_frames: bool, optional
- Whether to omit frames that contain no segmented pixels from the output segmentation.
"""
self._seg_descs = [sd.to_segment_description(n) for n, sd in enumerate(segment_descriptions, 1)]
self._custom_tags = custom_tags
- self._omit_empty_frames = omit_empty_frames
+ self.output_folder = output_folder if output_folder else DICOMSegmentationWriterOperator.DEFAULT_OUTPUT_FOLDER
+
+ self.input_name_seg = "seg_image"
+ self.input_name_series = "study_selected_series_list"
+ self.input_name_output_folder = "output_folder"
+
+ super().__init__(fragment, *args, **kwargs)
+
+ def setup(self, spec: OperatorSpec):
+ """Set up the named input(s), and output(s) if applicable, aka ports.
- def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
+ Args:
+ spec (OperatorSpec): The Operator specification for inputs and outputs etc.
+ """
+ spec.input(self.input_name_seg)
+ spec.input(self.input_name_series)
+ spec.input(self.input_name_output_folder).condition(ConditionType.NONE) # Optional input not requiring sender.
+
+ def compute(self, op_input, op_output, context):
"""Performs computation for this operator and handles I/O.
For now, only a single segmentation image object or file is supported and the selected DICOM
@@ -218,47 +243,54 @@ def compute(self, op_input: InputContext, op_output: OutputContext, context: Exe
"""
# Gets the input, prepares the output folder, and then delegates the processing.
- study_selected_series_list = op_input.get("study_selected_series_list")
+ study_selected_series_list = op_input.receive(self.input_name_series)
if not study_selected_series_list or len(study_selected_series_list) < 1:
- raise ValueError("Missing input, list of 'StudySelectedSeries'.")
+ raise ValueError(f"Missing input, [{StudySelectedSeries}].")
for study_selected_series in study_selected_series_list:
if not isinstance(study_selected_series, StudySelectedSeries):
- raise ValueError("Element in input is not expected type, 'StudySelectedSeries'.")
+ raise ValueError(f"Element in input is not expected type, {StudySelectedSeries}.")
+
+ seg_image = op_input.receive(self.input_name_seg)
- seg_image = op_input.get("seg_image")
- # In case the Image object is not in the input, and input is the seg image file folder path.
- if not isinstance(seg_image, Image):
- if isinstance(seg_image, DataPath):
- seg_image, _ = self.select_input_file(seg_image.path)
+ # In case the input is not the Image object, rather image file path.
+ if not isinstance(seg_image, (Image, np.ndarray)) and (isinstance(seg_image, (Path, str))):
+ seg_image_file, _ = self.select_input_file(str(seg_image))
+ if Path(seg_image_file).is_file():
+ seg_image = self._image_file_to_numpy(seg_image_file)
else:
- raise ValueError("Input 'seg_image' is not Image or DataPath.")
+ raise ValueError("Input 'seg_image' is not an Image or a path.")
- output_dir = op_output.get().path
- output_dir.mkdir(parents=True, exist_ok=True)
+ # If the optional named input, output_folder, has content, use it instead of the one set on the object.
+ # Since this input is optional, must check if data present and if Path or str.
+ output_folder = None
+ try:
+ output_folder = op_input.receive(self.input_name_output_folder)
+ except Exception:
+ pass
- self.process_images(seg_image, study_selected_series_list, output_dir)
+ if not output_folder or not isinstance(output_folder, (Path, str)):
+ output_folder = self.output_folder
+
+ output_folder.mkdir(parents=True, exist_ok=True)
+ self.process_images(seg_image, study_selected_series_list, output_folder)
def process_images(
self, image: Union[Image, Path], study_selected_series_list: List[StudySelectedSeries], output_dir: Path
):
""" """
- # Get the seg image in numpy, and if the image is passed in as object, need to fake a input path.
- seg_image_numpy = None
- input_path = "dicom_seg"
if isinstance(image, Image):
seg_image_numpy = image.asnumpy()
- elif isinstance(image, Path):
- input_path = str(image) # It is expected that this is the image file path.
- seg_image_numpy = self._image_file_to_numpy(input_path)
- else:
- raise ValueError("'image' is not an Image object or a supported image file.")
+ elif isinstance(image, (Path, str)):
+ seg_image_numpy = self._image_file_to_numpy(str(image))
+ elif not isinstance(image, np.ndarray):
+ raise ValueError("'image' is not a numpy array, Image object, or supported image file.")
# Pick DICOM Series that was used as input for getting the seg image.
# For now, first one in the list.
for study_selected_series in study_selected_series_list:
if not isinstance(study_selected_series, StudySelectedSeries):
- raise ValueError("Element in input is not expected type, 'StudySelectedSeries'.")
+ raise ValueError(f"Element in input is not expected type, {StudySelectedSeries}.")
selected_series = study_selected_series.selected_series[0]
dicom_series = selected_series.series
self.create_dicom_seg(seg_image_numpy, dicom_series, output_dir)
@@ -268,11 +300,7 @@ def create_dicom_seg(self, image: np.ndarray, dicom_series: DICOMSeries, output_
# Generate SOP instance UID, and use it as dcm file name too
seg_sop_instance_uid = hd.UID() # generate_uid() can be used too.
- if not output_dir.is_dir():
- try:
- output_dir.mkdir(parents=True, exist_ok=True)
- except Exception:
- raise ValueError("output_dir {output_dir} does not exist and failed to be created.") from None
+ output_dir.mkdir(parents=True, exist_ok=True) # Bubble up the exception if fails.
output_path = output_dir / f"{seg_sop_instance_uid}{DICOMSegmentationWriterOperator.DCM_EXTENSION}"
dicom_dataset_list = [i.get_native_sop_instance() for i in dicom_series.get_sop_instances()]
@@ -280,7 +308,7 @@ def create_dicom_seg(self, image: np.ndarray, dicom_series: DICOMSeries, output_
try:
version_str = get_sdk_semver() # SDK Version
except Exception:
- version_str = "0.1" # Fall back to the initial version
+ version_str = "" # Fall back to blank for unknown version
seg = hd.seg.Segmentation(
source_images=dicom_dataset_list,
@@ -295,7 +323,6 @@ def create_dicom_seg(self, image: np.ndarray, dicom_series: DICOMSeries, output_
manufacturer_model_name="MONAI Deploy App SDK",
software_versions=version_str,
device_serial_number="0000",
- omit_empty_frames=self._omit_empty_frames,
)
# Adding a few tags that are not in the Dataset
@@ -396,7 +423,7 @@ def test():
current_file_dir = Path(__file__).parent.resolve()
data_path = current_file_dir.joinpath("../../../inputs/spleen_ct_tcia")
- out_dir = Path("output_seg_op").absolute()
+ out_dir = Path.cwd() / "output_seg_op"
segment_descriptions = [
SegmentDescription(
segment_label="Spleen",
@@ -408,10 +435,13 @@ def test():
)
]
- loader = DICOMDataLoaderOperator()
- series_selector = DICOMSeriesSelectorOperator()
- dcm_to_volume_op = DICOMSeriesToVolumeOperator()
- seg_writer = DICOMSegmentationWriterOperator(segment_descriptions)
+ fragment = Fragment()
+ loader = DICOMDataLoaderOperator(fragment, name="dcm_loader")
+ series_selector = DICOMSeriesSelectorOperator(fragment, name="series_selector")
+ dcm_to_volume_op = DICOMSeriesToVolumeOperator(fragment, name="series_to_vol")
+ seg_writer = DICOMSegmentationWriterOperator(
+ fragment, segment_descriptions=segment_descriptions, output_folder=out_dir, name="seg_writer"
+ )
# Testing with more granular functions
study_list = loader.load_data_to_studies(data_path.absolute())
diff --git a/monai/deploy/operators/dicom_series_selector_operator.py b/monai/deploy/operators/dicom_series_selector_operator.py
index fd40e461..c7d21ccf 100644
--- a/monai/deploy/operators/dicom_series_selector_operator.py
+++ b/monai/deploy/operators/dicom_series_selector_operator.py
@@ -1,4 +1,4 @@
-# Copyright 2021 MONAI Consortium
+# Copyright 2021-2023 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
@@ -13,22 +13,23 @@
import numbers
import re
from json import loads as json_loads
-from typing import Dict, List, Text
+from typing import List
-import monai.deploy.core as md
-from monai.deploy.core import ExecutionContext, InputContext, IOType, Operator, OutputContext
+from monai.deploy.core import ConditionType, Fragment, Operator, OperatorSpec
from monai.deploy.core.domain.dicom_series import DICOMSeries
from monai.deploy.core.domain.dicom_series_selection import SelectedSeries, StudySelectedSeries
from monai.deploy.core.domain.dicom_study import DICOMStudy
-from monai.deploy.exceptions import ItemNotExistsError
-@md.input("dicom_study_list", List[DICOMStudy], IOType.IN_MEMORY)
-@md.input("selection_rules", Dict, IOType.IN_MEMORY) # This overrides the rules in the instance.
-@md.output("study_selected_series_list", List[StudySelectedSeries], IOType.IN_MEMORY)
class DICOMSeriesSelectorOperator(Operator):
"""This operator selects a list of DICOM Series in a DICOM Study for a given set of selection rules.
+ Named input:
+ dicom_study_list: A list of DICOMStudy objects.
+
+ Named output:
+ study_selected_series_list: A list of StudySelectedSeries objects. Downstream receiver optional.
+
This class can be considered a base class, and a derived class can override the 'filer' function to with
custom logics.
@@ -68,40 +69,39 @@ class DICOMSeriesSelectorOperator(Operator):
}
"""
- def __init__(self, rules: Text = "", all_matched: bool = False, *args, **kwargs) -> None:
- super().__init__(*args, **kwargs)
+ def __init__(self, fragment: Fragment, *args, rules: str = "", all_matched: bool = False, **kwargs) -> None:
"""Instantiate an instance.
Args:
+ fragment (Fragment): An instance of the Application class which is derived from Fragment.
rules (Text): Selection rules in JSON string.
all_matched (bool): Gets all matched series in a study. Defaults to False for first match only.
"""
+ # rules: Text = "", all_matched: bool = False,
+
# Delay loading the rules as JSON string till compute time.
self._rules_json_str = rules if rules and rules.strip() else None
- self._all_matched = all_matched
+ self._all_matched = all_matched # all_matched
+ self.input_name_study_list = "dicom_study_list"
+ self.output_name_selected_series = "study_selected_series_list"
- def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
- """Performs computation for this operator."""
+ super().__init__(fragment, *args, **kwargs)
- dicom_study_list = None
- selection_rules = None
- try:
- dicom_study_list = op_input.get("dicom_study_list")
- except ItemNotExistsError as ex:
- logging.exception(f"Failed to find input 'dicom_study_list', {ex}")
- raise
+ def setup(self, spec: OperatorSpec):
+ spec.input(self.input_name_study_list)
+ spec.output(self.output_name_selected_series).condition(ConditionType.NONE) # Receiver optional
- try:
- selection_rules = op_input.get("selection_rules")
- except ItemNotExistsError:
- # OK for not providing selection rules.
- pass
+ # Can use the config file to alter the selection rules per app run
+ # spec.param("selection_rules")
- if not selection_rules:
- selection_rules = self._load_rules() if self._rules_json_str else None
+ def compute(self, op_input, op_output, context):
+ """Performs computation for this operator."""
+
+ dicom_study_list = op_input.receive(self.input_name_study_list)
+ selection_rules = self._load_rules() if self._rules_json_str else None
study_selected_series = self.filter(selection_rules, dicom_study_list, self._all_matched)
- op_output.set(study_selected_series, "study_selected_series_list")
+ op_output.emit(study_selected_series, self.output_name_selected_series)
def filter(self, selection_rules, dicom_study_list, all_matched: bool = False) -> List[StudySelectedSeries]:
"""Selects the series with the given matching rules.
@@ -133,7 +133,7 @@ def filter(self, selection_rules, dicom_study_list, all_matched: bool = False) -
logging.warn("No selection rules given; select all series.")
return self._select_all_series(dicom_study_list)
- selections = selection_rules.get("selections", None)
+ selections = selection_rules.get("selections", None) # TODO type is not json now.
# If missing selections in the rules then it is an error.
if not selections:
raise ValueError('Expected "selections" not found in the rules.')
@@ -177,11 +177,9 @@ def _select_all_series(self, dicom_study_list: List[DICOMStudy]) -> List[StudySe
study_selected_series_list = []
for study in dicom_study_list:
logging.info(f"Working on study, instance UID: {study.StudyInstanceUID}")
- print(f"Working on study, instance UID: {study.StudyInstanceUID}")
study_selected_series = StudySelectedSeries(study)
for series in study.get_all_series():
logging.info(f"Working on series, instance UID: {str(series.SeriesInstanceUID)}")
- print(f"Working on series, instance UID: {str(series.SeriesInstanceUID)}")
selected_series = SelectedSeries("", series, None) # No selection name or Image obj.
study_selected_series.add_selected_series(selected_series)
study_selected_series_list.append(study_selected_series)
@@ -295,11 +293,12 @@ def test():
from monai.deploy.operators.dicom_data_loader_operator import DICOMDataLoaderOperator
current_file_dir = Path(__file__).parent.resolve()
- data_path = current_file_dir.joinpath("../../../examples/ai_spleen_seg_data/dcm-multi")
+ data_path = current_file_dir.joinpath("../../../inputs/spleen_ct/dcm").absolute()
- loader = DICOMDataLoaderOperator()
- study_list = loader.load_data_to_studies(data_path.absolute())
- selector = DICOMSeriesSelectorOperator()
+ fragment = Fragment()
+ loader = DICOMDataLoaderOperator(fragment, name="loader_op")
+ selector = DICOMSeriesSelectorOperator(fragment, name="selector_op")
+ study_list = loader.load_data_to_studies(data_path)
sample_selection_rule = json_loads(Sample_Rules_Text)
print(f"Selection rules in JSON:\n{sample_selection_rule}")
study_selected_seriee_list = selector.filter(sample_selection_rule, study_list)
diff --git a/monai/deploy/operators/dicom_series_to_volume_operator.py b/monai/deploy/operators/dicom_series_to_volume_operator.py
index e89dd265..6beb0e35 100644
--- a/monai/deploy/operators/dicom_series_to_volume_operator.py
+++ b/monai/deploy/operators/dicom_series_to_volume_operator.py
@@ -1,4 +1,4 @@
-# Copyright 2021-2022 MONAI Consortium
+# Copyright 2021-2023 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
@@ -16,30 +16,49 @@
import numpy as np
-import monai.deploy.core as md
-from monai.deploy.core import ExecutionContext, Image, InputContext, IOType, Operator, OutputContext
+from monai.deploy.core import ConditionType, Fragment, Operator, OperatorSpec
from monai.deploy.core.domain.dicom_series_selection import StudySelectedSeries
+from monai.deploy.core.domain.image import Image
-@md.input("study_selected_series_list", List[StudySelectedSeries], IOType.IN_MEMORY)
-@md.output("image", Image, IOType.IN_MEMORY)
class DICOMSeriesToVolumeOperator(Operator):
"""This operator converts an instance of DICOMSeries into an Image object.
The loaded Image Object can be used for further processing via other operators.
The data array will be a 3D image NumPy array with index order of `DHW`.
Channel is limited to 1 as of now, and `C` is absent in the NumPy array.
+
+ Named Input:
+ study_selected_series_list: List of StudySelectedSeries.
+ Named Output:
+ image: Image object.
"""
- def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
+ def __init__(self, fragment: Fragment, *args, **kwargs):
+ """Create an instance for a containing application object.
+
+ Args:
+ fragment (Fragment): An instance of the Application class which is derived from Fragment.
+ """
+
+ self.input_name_series = "study_selected_series_list"
+ self.output_name_image = "image"
+ # Need to call the base class constructor last
+ super().__init__(fragment, *args, **kwargs)
+
+ def setup(self, spec: OperatorSpec):
+ spec.input(self.input_name_series)
+ spec.output(self.output_name_image).condition(ConditionType.NONE)
+
+ def compute(self, op_input, op_output, context):
"""Performs computation for this operator and handles I/O."""
- study_selected_series_list = op_input.get("study_selected_series_list")
+ study_selected_series_list = op_input.receive(self.input_name_series)
# TODO: need to get a solution to correctly annotate and consume multiple image outputs.
# For now, only supports the one and only one selected series.
image = self.convert_to_image(study_selected_series_list)
- op_output.set(image, "image")
+ op_output.emit(image, self.output_name_image)
def convert_to_image(self, study_selected_series_list: List[StudySelectedSeries]) -> Union[Image, None]:
"""Extracts the pixel data from a DICOM Series and other attributes to create an Image object"""
@@ -395,15 +414,16 @@ def test():
from monai.deploy.operators.dicom_series_selector_operator import DICOMSeriesSelectorOperator
current_file_dir = Path(__file__).parent.resolve()
- data_path = current_file_dir.joinpath("../../../examples/ai_spleen_seg_data/dcm")
- loader = DICOMDataLoaderOperator()
- study_list = loader.load_data_to_studies(Path(data_path).absolute())
+ data_path = current_file_dir.joinpath("../../../inputs/spleen_ct/dcm").absolute()
- series_selector = DICOMSeriesSelectorOperator()
- study_selected_series_list = series_selector.filter(None, study_list)
+ fragment = Fragment()
+ loader = DICOMDataLoaderOperator(fragment, name="loader_op")
+ series_selector = DICOMSeriesSelectorOperator(fragment, name="selector_op")
+ vol_op = DICOMSeriesToVolumeOperator(fragment, name="series_to_vol_op")
- op = DICOMSeriesToVolumeOperator()
- image = op.convert_to_image(study_selected_series_list)
+ study_list = loader.load_data_to_studies(data_path)
+ study_selected_series_list = series_selector.filter(None, study_list)
+ image = vol_op.convert_to_image(study_selected_series_list)
print(f"Image NumPy array shape (index order DHW): {image.asnumpy().shape}")
for k, v in image.metadata().items():
diff --git a/monai/deploy/operators/dicom_text_sr_writer_operator.py b/monai/deploy/operators/dicom_text_sr_writer_operator.py
index 5b7937e3..1b0fd21c 100644
--- a/monai/deploy/operators/dicom_text_sr_writer_operator.py
+++ b/monai/deploy/operators/dicom_text_sr_writer_operator.py
@@ -11,7 +11,7 @@
import logging
from pathlib import Path
-from typing import Dict, List, Optional, Text
+from typing import Dict, Optional, Union
from monai.deploy.utils.importutil import optional_import
@@ -23,38 +23,51 @@
FileDataset, _ = optional_import("pydicom.dataset", name="FileDataset")
Sequence, _ = optional_import("pydicom.sequence", name="Sequence")
-import monai.deploy.core as md
-from monai.deploy.core import DataPath, ExecutionContext, InputContext, IOType, Operator, OutputContext
+from monai.deploy.core import ConditionType, Fragment, Operator, OperatorSpec
from monai.deploy.core.domain.dicom_series import DICOMSeries
from monai.deploy.core.domain.dicom_series_selection import StudySelectedSeries
-from monai.deploy.exceptions import ItemNotExistsError
from monai.deploy.operators.dicom_utils import EquipmentInfo, ModelInfo, save_dcm_file, write_common_modules
from monai.deploy.utils.version import get_sdk_semver
-# The SR writer operator class
-@md.input("classification_result", Text, IOType.IN_MEMORY)
-@md.input("classification_result_file", DataPath, IOType.DISK)
-@md.input("study_selected_series_list", List[StudySelectedSeries], IOType.IN_MEMORY)
-@md.output("dicom_instance", DataPath, IOType.DISK)
-@md.env(pip_packages=["pydicom >= 1.4.2", "monai"])
+# @md.env(pip_packages=["pydicom >= 1.4.2", "monai"])
class DICOMTextSRWriterOperator(Operator):
+ """Class to write DICOM Text SR Instance with provided text input.
+
+ Named inputs:
+ text: text content to be encapsulated in a DICOM instance file.
+ study_selected_series_list: Optional, DICOM series for copying metadata from.
+
+ Named output:
+ None
+
+ File output:
+ Generaed DICOM instance file in the provided output folder.
+ """
+
# File extension for the generated DICOM Part 10 file.
DCM_EXTENSION = ".dcm"
+ # The default output folder for saveing the generated DICOM instance file.
+ # DEFAULT_OUTPUT_FOLDER = Path(os.path.join(os.path.dirname(__file__))) / "output"
+ DEFAULT_OUTPUT_FOLDER = Path.cwd() / "output"
def __init__(
self,
- copy_tags: bool,
+ fragment: Fragment,
+ *args,
+ output_folder: Union[str, Path],
model_info: ModelInfo,
+ copy_tags: bool = True,
equipment_info: Optional[EquipmentInfo] = None,
custom_tags: Optional[Dict[str, str]] = None,
- *args,
**kwargs,
):
"""Class to write DICOM SR SOP Instance for AI textual result in memory or in a file.
Args:
- copy_tags (bool): True for copying DICOM attributes from a provided DICOMSeries.
+ output_folder (str or Path): The folder for saving the generated DICOM instance file.
+ copy_tags (bool): True, default, for copying DICOM attributes from a provided DICOMSeries.
+ If True and no DICOMSeries obj provided, runtime exception is thrown.
model_info (ModelInfo): Object encapsulating model creator, name, version and UID.
equipment_info (EquipmentInfo, optional): Object encapsulating info for DICOM Equipment Module.
Defaults to None.
@@ -65,12 +78,17 @@ def __init__(
ValueError: If copy_tags is true and no DICOMSeries object provided, or
if result cannot be found either in memory or from file.
"""
- super().__init__(*args, **kwargs)
self._logger = logging.getLogger("{}.{}".format(__name__, type(self).__name__))
+
+ # Need to init the output folder until the execution context supports dynamic FS path
+ # Not trying to create the folder to avoid exception on init
+ self.output_folder = Path(output_folder) if output_folder else DICOMTextSRWriterOperator.DEFAULT_OUTPUT_FOLDER
self.copy_tags = copy_tags
self.model_info = model_info if model_info else ModelInfo()
self.equipment_info = equipment_info if equipment_info else EquipmentInfo()
self.custom_tags = custom_tags
+ self.input_name_text = "text"
+ self.input_name_dcm_series = "study_selected_series_list"
# Set own Modality and SOP Class UID
# Modality, e.g.,
@@ -90,7 +108,21 @@ def __init__(
self.software_version_number = ""
self.operators_name = f"AI Algorithm {self.model_info.name}"
- def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
+ super().__init__(fragment, *args, **kwargs)
+
+ def setup(self, spec: OperatorSpec):
+ """Set up the named input(s), and output(s) if applicable.
+
+ This operator does not have an output for the next operator, rather file output only.
+
+ Args:
+ spec (OperatorSpec): The Operator specification for inputs and outputs etc.
+ """
+
+ spec.input(self.input_name_text)
+ spec.input(self.input_name_dcm_series).condition(ConditionType.NONE) # Optional input
+
+ def compute(self, op_input, op_output, context):
"""Performs computation for this operator and handles I/O.
For now, only a single result content is supported, which could be in memory or an accessible file.
@@ -107,25 +139,15 @@ def compute(self, op_input: InputContext, op_output: OutputContext, context: Exe
"""
# Gets the input, prepares the output folder, and then delegates the processing.
- result_text = ""
- try:
- result_text = str(op_input.get("classification_result")).strip()
- except ItemNotExistsError:
- try:
- file_path = op_input.get("classification_result_file")
- except ItemNotExistsError:
- raise ValueError("None of the named inputs for result can be found.") from None
- # Read file, and if exception, let it bubble up
- with open(file_path.path, "r") as f:
- result_text = f.read().strip()
-
+ result_text = str(op_input.receive(self.input_name_text)).strip()
if not result_text:
raise IOError("Input is read but blank.")
+ study_selected_series_list = None
try:
- study_selected_series_list = op_input.get("study_selected_series_list")
- except ItemNotExistsError:
- study_selected_series_list = None
+ study_selected_series_list = op_input.receive(self.input_name_dcm_series)
+ except Exception:
+ pass
dicom_series = None # It can be None if not to copy_tags.
if self.copy_tags:
@@ -139,11 +161,11 @@ def compute(self, op_input: InputContext, op_output: OutputContext, context: Exe
dicom_series = selected_series.series
break
- output_dir = op_output.get().path
- output_dir.mkdir(parents=True, exist_ok=True)
+ # The output folder should come from the execution context when it is supported.
+ self.output_folder.mkdir(parents=True, exist_ok=True)
# Now ready to starting writing the DICOM instance
- self.write(result_text, dicom_series, output_dir)
+ self.write(result_text, dicom_series, self.output_folder)
def write(self, content_text, dicom_series: Optional[DICOMSeries], output_dir: Path):
"""Writes DICOM object
@@ -237,43 +259,48 @@ def write(self, content_text, dicom_series: Optional[DICOMSeries], output_dir: P
self._logger.info(f"DICOM SOP instance saved in {file_path}")
-def test():
- from monai.deploy.operators.dicom_data_loader_operator import DICOMDataLoaderOperator
- from monai.deploy.operators.dicom_series_selector_operator import DICOMSeriesSelectorOperator
-
- current_file_dir = Path(__file__).parent.resolve()
- data_path = current_file_dir.joinpath("../../../inputs/livertumor_ct/dcm/1-CT_series_liver_tumor_from_nii014")
- out_path = "output_sr_op"
- test_report_text = "Tumors detected in Liver using MONAI Liver Tumor Seg model."
- test_copy_tags = True
-
- loader = DICOMDataLoaderOperator()
- series_selector = DICOMSeriesSelectorOperator()
- sr_writer = DICOMTextSRWriterOperator(
- copy_tags=test_copy_tags,
- model_info=None,
- equipment_info=EquipmentInfo(),
- custom_tags={"SeriesDescription": "Textual report from AI algorithm. Not for clinical use."},
- )
-
- # Testing with the main entry functions
- dicom_series = None
- if test_copy_tags:
- study_list = loader.load_data_to_studies(Path(data_path).absolute())
- study_selected_series_list = series_selector.filter(None, study_list)
- # Get the first DICOM Series, as for now, only expecting this.
- if not study_selected_series_list or len(study_selected_series_list) < 1:
- raise ValueError("Missing input, list of 'StudySelectedSeries'.")
- for study_selected_series in study_selected_series_list:
- if not isinstance(study_selected_series, StudySelectedSeries):
- raise ValueError("Element in input is not expected type, 'StudySelectedSeries'.")
- for selected_series in study_selected_series.selected_series:
- print(type(selected_series))
- dicom_series = selected_series.series
- print(type(dicom_series))
-
- sr_writer.write(test_report_text, dicom_series, Path(out_path).absolute())
-
-
-if __name__ == "__main__":
- test()
+# Commenting out the following as pttype complains about the contructor for no reason
+# def test(test_copy_tags: bool = True):
+# from monai.deploy.operators.dicom_data_loader_operator import DICOMDataLoaderOperator
+# from monai.deploy.operators.dicom_series_selector_operator import DICOMSeriesSelectorOperator
+
+# current_file_dir = Path(__file__).parent.resolve()
+# data_path = current_file_dir.joinpath("../../../inputs/livertumor_ct/dcm/1-CT_series_liver_tumor_from_nii014")
+# out_path = Path("output_sr_op").absolute()
+# test_report_text = "Tumors detected in Liver using MONAI Liver Tumor Seg model."
+
+# fragment = Fragment()
+# loader = DICOMDataLoaderOperator(fragment, name="loader_op")
+# series_selector = DICOMSeriesSelectorOperator(fragment, name="selector_op")
+# sr_writer = DICOMTextSRWriterOperator(
+# fragment,
+# output_folder=out_path,
+# copy_tags=test_copy_tags,
+# model_info=None,
+# equipment_info=EquipmentInfo(),
+# custom_tags={"SeriesDescription": "Textual report from AI algorithm. Not for clinical use."},
+# name="sr_writer"
+# )
+
+# # Testing with the main entry functions
+# dicom_series = None
+# if test_copy_tags:
+# study_list = loader.load_data_to_studies(Path(data_path).absolute())
+# study_selected_series_list = series_selector.filter(None, study_list)
+# # Get the first DICOM Series, as for now, only expecting this.
+# if not study_selected_series_list or len(study_selected_series_list) < 1:
+# raise ValueError("Missing input, list of 'StudySelectedSeries'.")
+# for study_selected_series in study_selected_series_list:
+# if not isinstance(study_selected_series, StudySelectedSeries):
+# raise ValueError("Element in input is not expected type, 'StudySelectedSeries'.")
+# for selected_series in study_selected_series.selected_series:
+# print(type(selected_series))
+# dicom_series = selected_series.series
+# print(type(dicom_series))
+
+# sr_writer.write(test_report_text, dicom_series, out_path)
+
+
+# if __name__ == "__main__":
+# test(True)
+# test(False)
diff --git a/monai/deploy/operators/inference_operator.py b/monai/deploy/operators/inference_operator.py
index d1f47a00..81ee226e 100644
--- a/monai/deploy/operators/inference_operator.py
+++ b/monai/deploy/operators/inference_operator.py
@@ -1,4 +1,4 @@
-# Copyright 2021 MONAI Consortium
+# Copyright 2021-2023 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
@@ -9,10 +9,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from abc import abstractmethod
from typing import Any, Dict, Tuple, Union
-from monai.deploy.core import ExecutionContext, Image, InputContext, Operator, OutputContext
+from monai.deploy.core import Fragment, Image, Operator
class InferenceOperator(Operator):
@@ -22,11 +21,11 @@ class InferenceOperator(Operator):
a given model, post-transforms, and final results generation.
"""
- def __init__(self, *args, **kwargs):
+ def __init__(self, fragment: Fragment, *args, **kwargs):
"""Constructor of the operator."""
- super().__init__()
+ super().__init__(fragment, *args, **kwargs)
- @abstractmethod
+ # @abstractmethod
def pre_process(self, data: Any, *args, **kwargs) -> Union[Image, Any, Tuple[Any, ...], Dict[Any, Any]]:
"""Transforms input before being used for predicting on a model.
@@ -38,8 +37,8 @@ def pre_process(self, data: Any, *args, **kwargs) -> Union[Image, Any, Tuple[Any
raise NotImplementedError(f"Subclass {self.__class__.__name__} must implement this method.")
- @abstractmethod
- def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
+ # @abstractmethod
+ def compute(self, op_input, op_output, context):
"""An abstract method that needs to be implemented by the user.
Args:
@@ -49,7 +48,7 @@ def compute(self, op_input: InputContext, op_output: OutputContext, context: Exe
"""
pass
- @abstractmethod
+ # @abstractmethod
def predict(self, data: Any, *args, **kwargs) -> Union[Image, Any, Tuple[Any, ...], Dict[Any, Any]]:
"""Predicts results using the models(s) with input tensors.
@@ -60,7 +59,7 @@ def predict(self, data: Any, *args, **kwargs) -> Union[Image, Any, Tuple[Any, ..
"""
raise NotImplementedError(f"Subclass {self.__class__.__name__} must implement this method.")
- @abstractmethod
+ # @abstractmethod
def post_process(self, data: Any, *args, **kwargs) -> Union[Image, Any, Tuple[Any, ...], Dict[Any, Any]]:
"""Transform the prediction results from the model(s).
diff --git a/monai/deploy/operators/monai_bundle_inference_operator.py b/monai/deploy/operators/monai_bundle_inference_operator.py
index f2702b10..89d873a7 100644
--- a/monai/deploy/operators/monai_bundle_inference_operator.py
+++ b/monai/deploy/operators/monai_bundle_inference_operator.py
@@ -23,10 +23,7 @@
import numpy as np
-import monai.deploy.core as md
-from monai.deploy.core import DataPath, ExecutionContext, Image, InputContext, IOType, OutputContext
-from monai.deploy.core.operator import OperatorEnv
-from monai.deploy.exceptions import ItemNotExistsError
+from monai.deploy.core import AppContext, Fragment, Image, IOType, OperatorSpec
from monai.deploy.utils.importutil import optional_import
from .inference_operator import InferenceOperator
@@ -80,7 +77,7 @@ def _read_from_archive(archive, root_name: str, config_name: str, do_search=True
for suffix in bundle_suffixes:
path = Path(root_name, config_folder, config_name).with_suffix(suffix)
try:
- logging.debug(f"Trying to read config {config_name!r} content from {path}.")
+ logging.debug(f"Trying to read config {config_name!r} content from {path!r}.")
content_text = archive.read(str(path))
break
except Exception:
@@ -94,7 +91,7 @@ def _read_from_archive(archive, root_name: str, config_name: str, do_search=True
for suffix in bundle_suffixes:
for n in name_list:
if (f"{config_name}{suffix}").casefold in n.casefold():
- logging.debug(f"Trying to read content of config {config_name!r} from {n}.")
+ logging.debug(f"Trying to read content of config {config_name!r} from {n!r}.")
content_text = archive.read(n)
break
@@ -276,7 +273,7 @@ def _ensure_str_list(config_names):
# operator may choose to pass in a accessible bundle path at development and packaging stage. Ideally,
# the bundle path should be passed in by the Packager, e.g. via env var, when the App is initialized.
# As of now, the Packager only passes in the model path after the App including all operators are init'ed.
-@md.env(pip_packages=["monai>=1.0.0", "torch>=1.10.02", "numpy>=1.21", "nibabel>=3.2.1"])
+# @md.env(pip_packages=["monai>=1.0.0", "torch>=1.10.02", "numpy>=1.21", "nibabel>=3.2.1"])
class MonaiBundleInferenceOperator(InferenceOperator):
"""This inference operator automates the inference operation for a given MONAI Bundle.
@@ -296,10 +293,8 @@ class MonaiBundleInferenceOperator(InferenceOperator):
This operator is expected to be linked with both source and destination operators, e.g. receiving an `Image` object from
the `DICOMSeriesToVolumeOperator`, and passing a segmentation `Image` to the `DICOMSegmentationWriterOperator`.
In such cases, the I/O storage type can only be `IN_MEMORY` due to the restrictions imposed by the application executor.
- However, when used as the first operator in an application, its input storage type needs to be `DISK`, and the file needs
- to be a Python pickle file, e.g. containing an `Image` instance. When used as the last operator, its output storage type
- also needs to `DISK` with the path being the application's output folder, and the operator's output will be saved as
- a pickle file whose name is the same as the output name.
+
+ For the time being, the input and output to this operator are limited to in_memory object.
"""
known_io_data_types = {
@@ -311,29 +306,35 @@ class MonaiBundleInferenceOperator(InferenceOperator):
kw_preprocessed_inputs = "preprocessed_inputs"
+ # For testing the app directly, the model should be at the following path.
+ MODEL_LOCAL_PATH = Path(os.environ.get("HOLOSCAN_MODEL_PATH", Path.cwd() / "model/model.ts"))
+
def __init__(
self,
+ fragment: Fragment,
+ *args,
+ app_context: AppContext,
input_mapping: List[IOMapping],
output_mapping: List[IOMapping],
model_name: Optional[str] = "",
- bundle_path: Optional[str] = "",
+ bundle_path: Optional[Union[Path, str]] = None,
bundle_config_names: Optional[BundleConfigNames] = DEFAULT_BundleConfigNames,
- *args,
**kwargs,
):
- """_summary_
+ """Create an instance of this class, associated with an Application/Fragment.
Args:
+ fragment (Fragment): An instance of the Application class which is derived from Fragment.
+ app_context (AppContext): Object holding the I/O and model paths, and potentially loaded models.
input_mapping (List[IOMapping]): Define the inputs' name, type, and storage type.
output_mapping (List[IOMapping]): Defines the outputs' name, type, and storage type.
model_name (Optional[str], optional): Name of the model/bundle, needed in multi-model case.
Defaults to "".
- bundle_path (Optional[str], optional): For completing . Defaults to None.
+ bundle_path (Optional[str], optional): Known path to the bundle file. Defaults to None.
bundle_config_names (BundleConfigNames, optional): Relevant config item names in a the bundle.
Defaults to DEFAULT_BundleConfigNames.
"""
- super().__init__(*args, **kwargs)
self._executing = False
self._lock = Lock()
@@ -350,29 +351,35 @@ def __init__(
# there is still a need to define what op inputs/outputs map to what keys in the bundle config,
# along with the op input/output storage type.
# Also, the App Executor needs to set the IO context of the operator before calling the compute function.
- self._add_inputs(self._input_mapping)
- self._add_outputs(self._output_mapping)
+ # Delay till setup is called, as the Application object does support the add_input and add_output now.
+ # self._add_inputs(self._input_mapping)
+ # self._add_outputs(self._output_mapping)
# Complete the init if the bundle path is known, otherwise delay till the compute function is called
# and try to get the model/bundle path from the execution context.
try:
- self._bundle_path = (
- Path(bundle_path).expanduser().resolve() if bundle_path and len(bundle_path.strip()) > 0 else None
- )
+ self._bundle_path = Path(bundle_path) if bundle_path and len(str(bundle_path).strip()) > 0 else None
- if self._bundle_path and self._bundle_path.exists():
+ if self._bundle_path and self._bundle_path.is_file():
self._init_config(self._bundle_config_names.config_names)
self._init_completed = True
else:
- logging.debug(f"Bundle path, {self._bundle_path}, not valid. Will get it in the execution context.")
+ logging.debug(
+ f"Bundle, at path {self._bundle_path}, not available. Will get it in the execution context."
+ )
self._bundle_path = None
except Exception:
logging.warn("Bundle parsing is not completed on init, delayed till this operator is called to execute.")
self._bundle_path = None
+ self._fragment = fragment # In case it is needed.
+ self.app_context = app_context
+
# Lazy init of model network till execution time when the context is fully set.
self._model_network: Any = None
+ super().__init__(fragment, *args, **kwargs)
+
@property
def model_name(self) -> str:
return self._model_name
@@ -420,11 +427,13 @@ def _init_config(self, config_names):
# When this function is NOT called by the __init__, setting the pip_packages env here
# will not get dependencies to the App SDK Packager to install the packages in the MAP.
- pip_packages = ["monai"] + [f"{k}=={v}" for k, v in meta["optional_packages_version"].items()]
- if self._env:
- self._env.pip_packages.extend(pip_packages) # Duplicates will be figured out on use.
- else:
- self._env = OperatorEnv(pip_packages=pip_packages)
+ # pip_packages = ["monai"] + [f"{k}=={v}" for k, v in meta["optional_packages_version"].items()]
+
+ # Currently not support adding and installing dependent pip package at runtime.
+ # if self._env:
+ # self._env.pip_packages.extend(pip_packages) # Duplicates will be figured out on use.
+ # else:
+ # self._env = OperatorEnv(pip_packages=pip_packages)
if parser.get("device") is not None:
self._device = parser.get_parsed_content("device")
@@ -515,7 +524,13 @@ def _add_outputs(self, output_mapping: List[IOMapping]):
[self.add_output(v.label, v.data_type, v.storage_type) for v in output_mapping]
- def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
+ def setup(self, spec: OperatorSpec):
+ [spec.input(v.label) for v in self._input_mapping]
+ for v in self._output_mapping:
+ if v.storage_type == IOType.IN_MEMORY: # As of now the output port type can only be in_memory object.
+ spec.output(v.label)
+
+ def compute(self, op_input, op_output, context):
"""Infers with the input(s) and saves the prediction result(s) to output
Args:
@@ -531,12 +546,15 @@ def compute(self, op_input: InputContext, op_output: OutputContext, context: Exe
# `context.models.get(model_name)` returns a model instance if exists.
# If model_name is not specified and only one model exists, it returns that model.
- self._model_network = context.models.get(self._model_name) if context.models else None
+ # The models are loaded on contruction via the AppContext object in turn the model factory.
+ self._model_network = self.app_context.models.get(self._model_name) if self.app_context.models else None
+
if self._model_network:
if not self._init_completed:
with self._lock:
if not self._init_completed:
self._bundle_path = self._model_network.path
+ logging.info(f"Parsing from bundle_path: {self._bundle_path}")
self._init_config(self._bundle_config_names.config_names)
self._init_completed = True
elif self._bundle_path:
@@ -639,7 +657,7 @@ def post_process(self, data: Any, *args, **kwargs) -> Union[Image, Any, Tuple[An
return self._postproc(data)
- def _receive_input(self, name: str, op_input: InputContext, context: ExecutionContext):
+ def _receive_input(self, name: str, op_input, context):
"""Extracts the input value for the given input name."""
# The op_input can have the storage type of IN_MEMORY with the data type being Image or others,
@@ -650,22 +668,22 @@ def _receive_input(self, name: str, op_input: InputContext, context: ExecutionCo
# as the op_input is the input for processing transforms, not necessarily directly for the network.
in_conf = self._inputs[name]
itype = self._get_io_data_type(in_conf)
- value = op_input.get(name)
+ value = op_input.receive(name)
metadata = None
- if isinstance(value, DataPath):
- if not value.path.exists():
- raise ValueError(f"Input path, {value.path}, does not exist.")
+ if isinstance(value, Path):
+ if not value.exists():
+ raise ValueError(f"Input path, {value}, does not exist.")
- file_path = value.path / name
+ file_path = value / name
# The named input can only be a folder as of now, but just in case things change.
- if value.path.is_file():
- file_path = value.path
- elif not file_path.exists() and value.path.is_dir:
+ if value.is_file():
+ file_path = value
+ elif not file_path.exists() and value.is_dir():
# Expect one and only one file exists for use.
- files = [f for f in value.path.glob("*") if f.is_file()]
+ files = [f for f in value.glob("*") if f.is_file()]
if len(files) != 1:
- raise ValueError(f"Input path, {value.path}, should have one and only one file.")
+ raise ValueError(f"Input path, {value}, should have one and only one file.")
file_path = files[0]
@@ -689,7 +707,7 @@ def _receive_input(self, name: str, op_input: InputContext, context: ExecutionCo
return value, metadata
- def _send_output(self, value: Any, name: str, metadata: Dict, op_output: OutputContext, context: ExecutionContext):
+ def _send_output(self, value: Any, name: str, metadata: Dict, op_output, context):
"""Send the given output value to the output context."""
logging.debug(f"Setting output {name}")
@@ -731,8 +749,8 @@ def _send_output(self, value: Any, name: str, metadata: Dict, op_output: OutputC
# and for leaf node if the storage type is IN_MEMORY.
try:
op_output_config = op_output.get(name)
- if isinstance(op_output_config, DataPath):
- output_file = op_output_config.path / name
+ if isinstance(op_output_config, Path):
+ output_file = op_output_config / name
output_file.parent.mkdir(exist_ok=True)
# Save pickle file
with open(output_file, "wb") as wf:
@@ -741,11 +759,11 @@ def _send_output(self, value: Any, name: str, metadata: Dict, op_output: OutputC
# Cannot (re)set/modify the op_output path to the actual file like below
# op_output.set(str(output_file), name)
else:
- op_output.set(result, name)
- except ItemNotExistsError:
+ op_output.emit(result, name)
+ except Exception:
# The following throws if the output storage type is DISK, but The OutputContext
# currently does not expose the storage type. Try and let it throw if need be.
- op_output.set(result, name)
+ op_output.emit(result, name)
def _convert_from_image(self, img: Image) -> Tuple[np.ndarray, Dict]:
"""Converts the Image object to the expected numpy array with metadata dictionary.
diff --git a/monai/deploy/operators/monai_seg_inference_operator.py b/monai/deploy/operators/monai_seg_inference_operator.py
index f0f85bc1..9fa2c5b2 100644
--- a/monai/deploy/operators/monai_seg_inference_operator.py
+++ b/monai/deploy/operators/monai_seg_inference_operator.py
@@ -1,4 +1,4 @@
-# Copyright 2021-2002 MONAI Consortium
+# Copyright 2021-2023 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
@@ -9,6 +9,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import logging
+import os
+from pathlib import Path
from threading import Lock
from typing import Any, Dict, List, Optional, Sequence, Tuple, Union
@@ -37,8 +40,7 @@
# Dynamic class is not handled so make it Any for now: https://github.com/python/mypy/issues/2477
Compose: Any = Compose_
-import monai.deploy.core as md
-from monai.deploy.core import ExecutionContext, Image, InputContext, IOType, OutputContext
+from monai.deploy.core import AppContext, ConditionType, Fragment, Image, OperatorSpec
from .inference_operator import InferenceOperator
@@ -52,9 +54,7 @@ class InfererType(StrEnum):
SLIDING_WINDOW = "sliding_window"
-@md.input("image", Image, IOType.IN_MEMORY)
-@md.output("seg_image", Image, IOType.IN_MEMORY)
-@md.env(pip_packages=["monai>=1.0.0", "torch>=1.10.2", "numpy>=1.21"])
+# @md.env(pip_packages=["monai>=1.0.0", "torch>=1.10.2", "numpy>=1.21"])
class MonaiSegInferenceOperator(InferenceOperator):
"""This segmentation operator uses MONAI transforms and Sliding Window Inference.
@@ -63,40 +63,52 @@ class MonaiSegInferenceOperator(InferenceOperator):
as a named Image object in memory.
If specified in the post transforms, results may also be saved to disk.
+
+ Named Input:
+ image: Image object of the input image.
+
+ Named Output:
+ seg_image: Image object of the segmentation image. Not requiring a ready receiver.
"""
# For testing the app directly, the model should be at the following path.
- MODEL_LOCAL_PATH = "model/model.ts"
+ MODEL_LOCAL_PATH = Path(os.environ.get("HOLOSCAN_MODEL_PATH", Path.cwd() / "model/model.ts"))
def __init__(
self,
+ fragment: Fragment,
+ *args,
roi_size: Optional[Union[Sequence[int], int]],
pre_transforms: Compose,
post_transforms: Compose,
+ app_context: AppContext,
model_name: Optional[str] = "",
overlap: float = 0.25,
sw_batch_size: int = 4,
inferer: Union[InfererType, str] = InfererType.SLIDING_WINDOW,
- *args,
+ model_path: Path = MODEL_LOCAL_PATH,
**kwargs,
):
"""Creates a instance of this class.
Args:
+ fragment (Fragment): An instance of the Application class which is derived from Fragment.
roi_size (Union[Sequence[int], int]): The window size to execute "SLIDING_WINDOW" evaluation.
An optional input only to be passed for "SLIDING_WINDOW".
If using a "SIMPLE" Inferer, this input is ignored.
pre_transforms (Compose): MONAI Compose object used for pre-transforms.
post_transforms (Compose): MONAI Compose object used for post-transforms.
+ app_context (AppContext): Object holding the I/O and model paths, and potentially loaded models.
model_name (str, optional): Name of the model. Default to "" for single model app.
overlap (float): The amount of overlap between scans along each spatial dimension. Defaults to 0.25.
Applicable for "SLIDING_WINDOW" only.
sw_batch_size(int): The batch size to run window slices. Defaults to 4.
- Applicable for "SLIDING_WINDOW" only.
+ Applicable for "SLIDING_WINDOW" only.
inferer (InfererType): The type of inferer to use, "SIMPLE" or "SLIDING_WINDOW". Defaults to "SLIDING_WINDOW".
+ model_path (Path): Path to the model file. Defaults to model/models.ts of current working dir.
"""
- super().__init__()
+ self._logger = logging.getLogger("{}.{}".format(__name__, type(self).__name__))
self._executing = False
self._lock = Lock()
self._input_dataset_key = "image"
@@ -111,6 +123,45 @@ def __init__(
self._sw_batch_size = sw_batch_size
self._inferer = inferer
+ # Add this so that the local model path can be set from the calling app
+ self.model_path = model_path
+ self.input_name_image = "image"
+ self.output_name_seg = "seg_image"
+
+ # The execution context passed in on compute does not have the required model info, so need to
+ # get and keep the model via the AppContext obj on construction.
+ self.app_context = app_context
+
+ self.model = self._get_model(self.app_context, self.model_path, self._model_name)
+
+ super().__init__(fragment, *args, **kwargs)
+
+ def _get_model(self, app_context: AppContext, model_path: Path, model_name: str):
+ """Load the model with the given name from context or model path
+
+ Args:
+ app_context (AppContext): The application context object holding the model(s)
+ model_path (Path): The path to the model file, as a backup to load model directly
+ model_name (str): The name of the model, when multiples are loaded in the context
+ """
+
+ if app_context.models:
+ # `app_context.models.get(model_name)` returns a model instance if exists.
+ # If model_name is not specified and only one model exists, it returns that model.
+ model = app_context.models.get(model_name)
+ else:
+ self._logger.info(f"Loading TorchScript model from: {model_path!r}")
+ model = torch.jit.load(
+ self.model_path,
+ map_location=torch.device("cuda" if torch.cuda.is_available() else "cpu"),
+ )
+
+ return model
+
+ def setup(self, spec: OperatorSpec):
+ spec.input(self.input_name_image)
+ spec.output(self.output_name_seg).condition(ConditionType.NONE) # Downstream receiver optional.
+
@property
def roi_size(self):
"""The ROI size of tensors used in prediction."""
@@ -207,13 +258,13 @@ def _convert_dicom_metadata_datatype(self, metadata: Dict):
except Exception:
pass
- print("Converted Image object metadata:")
+ self._logger.info("Converted Image object metadata:")
for k, v in metadata.items():
- print(f"{k}: {v}, type {type(v)}")
+ self._logger.info(f"{k}: {v}, type {type(v)}")
return metadata
- def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
+ def compute(self, op_input, op_output, context):
"""Infers with the input image and save the predicted image to output
Args:
@@ -221,84 +272,82 @@ def compute(self, op_input: InputContext, op_output: OutputContext, context: Exe
op_output (OutputContext): An output context for the operator.
context (ExecutionContext): An execution context for the operator.
"""
+
with self._lock:
if self._executing:
raise RuntimeError("Operator is already executing.")
else:
self._executing = True
try:
- input_image = op_input.get("image")
+ input_image = op_input.receive(self.input_name_image)
if not input_image:
raise ValueError("Input is None.")
-
- # Need to try to convert the data type of a few metadata attributes.
- input_img_metadata = self._convert_dicom_metadata_datatype(input_image.metadata())
- # Need to give a name to the image as in-mem Image obj has no name.
- img_name = str(input_img_metadata.get("SeriesInstanceUID", "Img_in_context"))
-
- pre_transforms: Compose = self._pre_transform
- post_transforms: Compose = self._post_transforms
- self._reader = InMemImageReader(input_image)
-
- pre_transforms = self._pre_transform if self._pre_transform else self.pre_process(self._reader)
- post_transforms = self._post_transforms if self._post_transforms else self.post_process(pre_transforms)
-
- device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
- model = None
- if context.models:
- # `context.models.get(model_name)` returns a model instance if exists.
- # If model_name is not specified and only one model exists, it returns that model.
- model = context.models.get(self._model_name)
- else:
- print(f"Loading TorchScript model from: {MonaiSegInferenceOperator.MODEL_LOCAL_PATH}")
- model = torch.jit.load(MonaiSegInferenceOperator.MODEL_LOCAL_PATH, map_location=device)
-
- dataset = Dataset(data=[{self._input_dataset_key: img_name}], transform=pre_transforms)
- dataloader = DataLoader(dataset, batch_size=1, shuffle=False, num_workers=0)
-
- with torch.no_grad():
- for d in dataloader:
- images = d[self._input_dataset_key].to(device)
- if self._inferer == InfererType.SLIDING_WINDOW:
- # Uses the util function to drive the sliding_window inferer
- d[self._pred_dataset_key] = sliding_window_inference(
- inputs=images,
- roi_size=self._roi_size,
- sw_batch_size=self._sw_batch_size,
- overlap=self._overlap,
- predictor=model,
- )
- elif self._inferer == InfererType.SIMPLE:
- # Instantiates the SimpleInferer and directly uses its __call__ function
- d[self._pred_dataset_key] = simple_inference()(inputs=images, network=model)
- else:
- raise ValueError(
- f"Unknown inferer: {self._inferer}. Available options are sliding_window or simple."
- )
- d = [post_transforms(i) for i in decollate_batch(d)]
- out_ndarray = d[0][self._pred_dataset_key].cpu().numpy()
- # Need to squeeze out the channel dim fist
- out_ndarray = np.squeeze(out_ndarray, 0)
- # NOTE: The domain Image object simply contains a Arraylike obj as image as of now.
- # When the original DICOM series is converted by the Series to Volume operator,
- # using pydicom pixel_array, the 2D ndarray of each slice has index order HW, and
- # when all slices are stacked with depth as first axis, DHW. In the pre-transforms,
- # the image gets transposed to WHD and used as such in the inference pipeline.
- # So once post-transforms have completed, and the channel is squeezed out,
- # the resultant ndarray for the prediction image needs to be transposed back, so the
- # array index order is back to DHW, the same order as the in-memory input Image obj.
- out_ndarray = out_ndarray.T.astype(np.uint8)
- print(f"Output Seg image numpy array shaped: {out_ndarray.shape}")
- print(f"Output Seg image pixel max value: {np.amax(out_ndarray)}")
- print(f"Output Seg image pixel min value: {np.amin(out_ndarray)}")
- out_image = Image(out_ndarray, input_img_metadata)
- op_output.set(out_image, "seg_image")
-
+ op_output.emit(self.compute_impl(input_image, context), self.output_name_seg)
finally:
# Reset state on completing this method execution.
with self._lock:
self._executing = False
+ def compute_impl(self, input_image, context):
+ if not input_image:
+ raise ValueError("Input is None.")
+
+ # Need to try to convert the data type of a few metadata attributes.
+ input_img_metadata = self._convert_dicom_metadata_datatype(input_image.metadata())
+ # Need to give a name to the image as in-mem Image obj has no name.
+ img_name = str(input_img_metadata.get("SeriesInstanceUID", "Img_in_context"))
+
+ pre_transforms: Compose = self._pre_transform
+ post_transforms: Compose = self._post_transforms
+ self._reader = InMemImageReader(input_image)
+
+ pre_transforms = self._pre_transform if self._pre_transform else self.pre_process(self._reader)
+ post_transforms = self._post_transforms if self._post_transforms else self.post_process(pre_transforms)
+
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
+ dataset = Dataset(data=[{self._input_dataset_key: img_name}], transform=pre_transforms)
+ dataloader = DataLoader(
+ dataset, batch_size=1, shuffle=False, num_workers=0
+ ) # Should the batch_size be dynamic?
+
+ with torch.no_grad():
+ for d in dataloader:
+ images = d[self._input_dataset_key].to(device)
+ if self._inferer == InfererType.SLIDING_WINDOW:
+ d[self._pred_dataset_key] = sliding_window_inference(
+ inputs=images,
+ roi_size=self._roi_size,
+ sw_batch_size=self.sw_batch_size,
+ overlap=self.overlap,
+ predictor=self.model,
+ )
+ elif self._inferer == InfererType.SIMPLE:
+ # Instantiates the SimpleInferer and directly uses its __call__ function
+ d[self._pred_dataset_key] = simple_inference()(inputs=images, network=self.model)
+ else:
+ raise ValueError(
+ f"Unknown inferer: {self._inferer!r}. Available options are "
+ f"{InfererType.SLIDING_WINDOW!r} and {InfererType.SIMPLE!r}."
+ )
+
+ d = [post_transforms(i) for i in decollate_batch(d)]
+ out_ndarray = d[0][self._pred_dataset_key].cpu().numpy()
+ # Need to squeeze out the channel dim fist
+ out_ndarray = np.squeeze(out_ndarray, 0)
+ # NOTE: The domain Image object simply contains a Arraylike obj as image as of now.
+ # When the original DICOM series is converted by the Series to Volume operator,
+ # using pydicom pixel_array, the 2D ndarray of each slice has index order HW, and
+ # when all slices are stacked with depth as first axis, DHW. In the pre-transforms,
+ # the image gets transposed to WHD and used as such in the inference pipeline.
+ # So once post-transforms have completed, and the channel is squeezed out,
+ # the resultant ndarray for the prediction image needs to be transposed back, so the
+ # array index order is back to DHW, the same order as the in-memory input Image obj.
+ out_ndarray = out_ndarray.T.astype(np.uint8)
+ self._logger.info(f"Output Seg image numpy array shaped: {out_ndarray.shape}")
+ self._logger.info(f"Output Seg image pixel max value: {np.amax(out_ndarray)}")
+
+ return Image(out_ndarray, input_img_metadata)
+
def pre_process(self, data: Any, *args, **kwargs) -> Union[Any, Image, Tuple[Any, ...], Dict[Any, Any]]:
"""Transforms input before being used for predicting on a model.
diff --git a/monai/deploy/operators/nii_data_loader_operator.py b/monai/deploy/operators/nii_data_loader_operator.py
index 9a5cc6dc..67b0e070 100644
--- a/monai/deploy/operators/nii_data_loader_operator.py
+++ b/monai/deploy/operators/nii_data_loader_operator.py
@@ -1,4 +1,4 @@
-# Copyright 2021-2022 MONAI Consortium
+# Copyright 2021-2023 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
@@ -9,31 +9,73 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+
+import logging
+from pathlib import Path
+
import numpy as np
-import monai.deploy.core as md
-from monai.deploy.core import DataPath, ExecutionContext, InputContext, IOType, Operator, OutputContext
+from monai.deploy.core import ConditionType, Fragment, Operator, OperatorSpec
from monai.deploy.utils.importutil import optional_import
SimpleITK, _ = optional_import("SimpleITK")
-@md.input("image_path", DataPath, IOType.DISK)
-@md.output("image", np.ndarray, IOType.IN_MEMORY)
-@md.env(pip_packages=["SimpleITK>=2.0.2"])
+# @md.env(pip_packages=["SimpleITK>=2.0.2"])
class NiftiDataLoader(Operator):
"""
This operator reads a nifti image, extracts the numpy array and forwards it to the next operator
+
+ Named input:
+ image_path: Path to the image file, optional. Use it to override the input path set on the object.
+
+ Named output:
+ image: A Numpy array object. Downstream receiver optional.
"""
- def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
- input_path = op_input.get().path
+ def __init__(self, fragment: Fragment, *args, input_path: Path, **kwargs) -> None:
+ """Creates an instance with the file path to load image from.
+
+ Args:
+ fragment (Fragment): An instance of the Application class which is derived from Fragment.
+ input_path (Path): The file Path to read from, overridden by valid named input on compute.
+ """
+ self._logger = logging.getLogger("{}.{}".format(__name__, type(self).__name__))
+ self.input_path = input_path # Allow to be None, to be overridden when compute is called.
+ self.input_name_path = "image_path"
+ self.output_name_image = "image"
+
+ # Need to call the base class constructor last
+ super().__init__(fragment, *args, **kwargs)
+
+ def setup(self, spec: OperatorSpec):
+ spec.input(self.input_name_path).condition(ConditionType.NONE)
+ spec.output(self.output_name_image).condition(ConditionType.NONE) # Fine for no or not-ready receiver ports.
+
+ def compute(self, op_input, op_output, context):
+ """Performs computation with the provided context."""
+
+ # The named input port is optional, so must check for and validate the data
+ input_path = None
+ try:
+ input_path = op_input.receive(self.input_name_path)
+ except Exception:
+ pass
+
+ if not input_path or not Path(input_path).is_file:
+ self._logger.info(f"No or invalid file path from the optional input port: {input_path}")
+ # Try to fall back to use the object attribute if it is valid
+ if self.input_path and self.input_path.is_file():
+ input_path = self.input_path
+ else:
+ raise ValueError(f"No valid file path from input port or obj attribute: {self.input_path}")
+
image_np = self.convert_and_save(input_path)
- op_output.set(image_np)
+ op_output.emit(image_np, self.output_name_image)
def convert_and_save(self, nii_path):
"""
- reads the nifti image and
+ reads the nifti image and returns a numpy image array
"""
image_reader = SimpleITK.ImageFileReader()
image_reader.SetFileName(str(nii_path))
@@ -43,8 +85,10 @@ def convert_and_save(self, nii_path):
def test():
- filepath = "/home/gupta/Documents/mni_icbm152_nlin_sym_09a/mni_icbm152_gm_tal_nlin_sym_09a.nii"
- nii_operator = NiftiDataLoader()
+ # Make sure the file path is correct.
+ filepath = Path(__file__).parent.resolve() / "../../../inputs/lung_seg_ct/nii/volume-covid19-A-0001.nii"
+ fragment = Fragment()
+ nii_operator = NiftiDataLoader(fragment, input_path=filepath)
_ = nii_operator.convert_and_save(filepath)
diff --git a/monai/deploy/operators/png_converter_operator.py b/monai/deploy/operators/png_converter_operator.py
index 89c9d35e..a11a5184 100644
--- a/monai/deploy/operators/png_converter_operator.py
+++ b/monai/deploy/operators/png_converter_operator.py
@@ -1,4 +1,4 @@
-# Copyright 2021 MONAI Consortium
+# Copyright 2021-2023 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
@@ -10,11 +10,14 @@
# limitations under the License.
-from os import makedirs
+from os import getcwd, makedirs
from os.path import join
+from pathlib import Path
+from typing import Union
-import monai.deploy.core as md
-from monai.deploy.core import DataPath, ExecutionContext, Image, InputContext, IOType, Operator, OutputContext
+import numpy as np
+
+from monai.deploy.core import Fragment, Image, Operator, OperatorSpec
from monai.deploy.operators.dicom_data_loader_operator import DICOMDataLoaderOperator
from monai.deploy.operators.dicom_series_to_volume_operator import DICOMSeriesToVolumeOperator
from monai.deploy.utils.importutil import optional_import
@@ -22,26 +25,63 @@
PILImage, _ = optional_import("PIL", name="Image")
-@md.input("image", Image, IOType.IN_MEMORY)
-@md.output("image", DataPath, IOType.DISK)
-@md.env(pip_packages=["Pillow >= 8.0.0"])
+# @md.env(pip_packages=["Pillow >= 8.0.0", "numpy"])
class PNGConverterOperator(Operator):
"""
- This operator writes out a 3D Volumetric Image to disk in a slice by slice manner
+ This operator writes out a 3D Volumetric Image to to a file folder in a slice by slice manner.
+
+ Named input:
+ image: Image object or numpy ndarray
+
+ Named output:
+ None
+
+ File output:
+ Generated PNG image file(s) saved in the provided output folder.
"""
- def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
- input_path = op_input.get("image")
- output_dir = op_output.get().path
- output_dir.mkdir(parents=True, exist_ok=True)
- self.convert_and_save(input_path, output_dir)
+ # The default output folder for saving the generated DICOM instance file.
+ DEFAULT_OUTPUT_FOLDER = Path(getcwd()) / "output"
+
+ def __init__(
+ self,
+ fragment: Fragment,
+ *args,
+ output_folder: Union[str, Path],
+ **kwargs,
+ ):
+ """Class to write out a 3D Volumetric Image to a file folder in a slice by slice manner.
+
+ Args:
+ fragment (Fragment): An instance of the Application class which is derived from Fragment.
+ output_folder (str or Path): The folder for saving the generated DICOM instance file.
+ """
+
+ self.output_folder = output_folder if output_folder else PNGConverterOperator.DEFAULT_OUTPUT_FOLDER
+ self.input_name_image = "image"
+ # Need to call the base class constructor last
+ super().__init__(fragment, *args, **kwargs)
+
+ def setup(self, spec: OperatorSpec):
+ spec.input(self.input_name_image)
+
+ def compute(self, op_input, op_output, context):
+ input_image = op_input.receive(self.input_name_image)
+ self.output_folder.mkdir(parents=True, exist_ok=True)
+ self.convert_and_save(input_image, self.output_folder)
def convert_and_save(self, image, path):
"""
extracts the slices in originally acquired direction (often axial)
- and saves then in PNG format slice by slice in the specified directory
+ and saves them in PNG format slice by slice in the specified directory
"""
- image_data = image.asnumpy()
+
+ if isinstance(image, Image):
+ image_data = image.asnumpy()
+ elif isinstance(image, np.ndarray):
+ image_data = image
+ else:
+ raise ValueError(f"Input is not Image or ndarray, {type(image)}.")
image_shape = image_data.shape
num_images = image_shape[0]
@@ -58,12 +98,13 @@ def main():
from pathlib import Path
current_file_dir = Path(__file__).parent.resolve()
- data_path = current_file_dir.joinpath("../../../examples/ai_spleen_seg_data/dcm")
- out_path = "png-output"
+ data_path = current_file_dir.joinpath("../../../inputs/spleen_ct/dcm")
+ out_path = "output_png"
makedirs(out_path, exist_ok=True)
files = []
- loader = DICOMDataLoaderOperator()
+ fragment = Fragment()
+ loader = DICOMDataLoaderOperator(fragment, name="dcm_loader")
loader._list_files(
data_path,
files,
@@ -71,18 +112,22 @@ def main():
study_list = loader._load_data(files)
series = study_list[0].get_all_series()[0]
- op1 = DICOMSeriesToVolumeOperator()
+ print(f"The loaded series object properties:\n{series}")
+
+ op1 = DICOMSeriesToVolumeOperator(fragment, name="series_to_vol")
op1.prepare_series(series)
voxels = op1.generate_voxel_data(series)
metadata = op1.create_metadata(series)
image = op1.create_volumetric_image(voxels, metadata)
- op2 = PNGConverterOperator()
- op2.convert_and_save(image, out_path)
-
- print(f"The loaded series object properties:\n{series}")
print(f"The converted Image object metadata:\n{metadata}")
+ op2 = PNGConverterOperator(fragment, output_folder=out_path, name="png_converter")
+ # Not mocking the operator context, so bypassing compute
+ op2.convert_and_save(image, op2.output_folder)
+
+ print(f"The converted PNG files are in: {out_path}")
+
if __name__ == "__main__":
main()
diff --git a/monai/deploy/operators/publisher_operator.py b/monai/deploy/operators/publisher_operator.py
index 82a199cc..a46d9362 100644
--- a/monai/deploy/operators/publisher_operator.py
+++ b/monai/deploy/operators/publisher_operator.py
@@ -9,15 +9,16 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from os import makedirs, path
+import logging
+from os import getcwd, makedirs, path
from pathlib import Path
from shutil import copy
+from typing import Union
-import monai.deploy.core as md
-from monai.deploy.core import DataPath, ExecutionContext, InputContext, IOType, Operator, OutputContext
+from monai.deploy.core import Operator
-@md.input("saved_images_folder", DataPath, IOType.DISK)
+# @md.input("saved_images_folder", DataPath, IOType.DISK)
# If `pip_packages` is specified, the definition will be aggregated with the package dependency list of other
# operators and the application in packaging time.
# @md.env(pip_packages=[])
@@ -28,9 +29,41 @@ class PublisherOperator(Operator):
generates the render config file and the meta data file, then save all in the `publish` folder of the app.
"""
- def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
+ # The default input folder for saveing the generated DICOM instance file.
+ DEFAULT_INPUT_FOLDER = Path(getcwd()) / "input"
+
+ # The default output folder for saveing the generated DICOM instance file.
+ DEFAULT_OUTPUT_FOLDER = Path(getcwd()) / "output"
+
+ def __init__(
+ self,
+ *args,
+ input_folder: Union[str, Path],
+ output_folder: Union[str, Path],
+ **kwargs,
+ ):
+ """Class to write DICOM Encapsulated PDF Instance with PDF bytes in memory or in a file.
+
+ Args:
+ input_folder (str or Path): The folder to read the input and segment mask files.
+ output_folder (str or Path): The folder to save the published files.
+ """
+
+ self._logger = logging.getLogger("{}.{}".format(__name__, type(self).__name__))
+
+ # Need to get the input folder in init until the execution context supports input path.
+ self.input_folder = Path(input_folder) if input_folder else PublisherOperator.DEFAULT_INPUT_FOLDER
+
+ # Need to get the output folder in init until the execution context supports output path.
+ # Not trying to create the folder to avoid exception on init
+ self.output_dir = Path(output_folder) if output_folder else PublisherOperator.DEFAULT_OUTPUT_FOLDER
+
+ super().__init__(*args, **kwargs)
+
+ def compute(self, op_input, op_output, context):
saved_images_folder = op_input.get("saved_images_folder").path
- if not path.isdir(saved_images_folder):
+
+ if not self.input_folder.is_dir():
raise ValueError("Expected a folder path for saved_image_folder input")
density_path, mask_path = self._find_density_and_mask_files(saved_images_folder)
diff --git a/monai/deploy/operators/stl_conversion_operator.py b/monai/deploy/operators/stl_conversion_operator.py
index 71f3ddd7..12a078c7 100644
--- a/monai/deploy/operators/stl_conversion_operator.py
+++ b/monai/deploy/operators/stl_conversion_operator.py
@@ -1,4 +1,4 @@
-# Copyright 2022 MONAI Consortium
+# Copyright 2022-2023 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
@@ -13,9 +13,8 @@
import os
import shutil
import tempfile
-from ast import Bytes
from pathlib import Path
-from typing import Dict, Optional
+from typing import Dict, Optional, Union
import numpy as np
@@ -29,52 +28,74 @@
resize, _ = optional_import("skimage.transform", name="resize")
trimesh, _ = optional_import("trimesh")
-import monai.deploy.core as md
-from monai.deploy.core import ExecutionContext, Image, InputContext, IOType, Operator, OutputContext
+from monai.deploy.core import ConditionType, Fragment, Image, Operator, OperatorSpec
__all__ = ["STLConversionOperator", "STLConverter"]
-@md.input("image", Image, IOType.IN_MEMORY)
-@md.output("stl_output", Bytes, IOType.IN_MEMORY) # Only available when run as non-leaf operator
# nibabel is required by the dependent class STLConverter.
-@md.env(
- pip_packages=["numpy>=1.21", "nibabel >= 3.2.1", "numpy-stl>=2.12.0", "scikit-image>=0.17.2", "trimesh>=3.8.11"]
-)
+# @md.env(
+# pip_packages=["numpy>=1.21", "nibabel >= 3.2.1", "numpy-stl>=2.12.0", "scikit-image>=0.17.2", "trimesh>=3.8.11"]
+# )
class STLConversionOperator(Operator):
- """Converts volumetric image to surface mesh in STL format, file output only.
+ """Converts volumetric image to surface mesh in STL format.
- Only when used as a non-leaf operator is the output of STL binary stored in memory idenfied by the output label.
- If a file path is provided, the STL binary will be saved in the the application's output folder of the current run.
+ If a file path is provided, the STL binary will be saved in the said output folder.
+ This operator also save the STL file as bytes in memory, idenfied by the named output. Being optional,
+ this output does not require any downstream receiver.
+
+ Named inputs:
+ image: Image object for which to generate surface mesh.
+ output_file: Optional, the path of the file to save the mesh in STL format.
+ If provided, this will overrider the output file path set on the object.
+
+ Named output:
+ stl_bytes: Bytes of the surface mesh STL file. Optional, not requiring a downstram receiver.
"""
def __init__(
- self, output_file=None, class_id=None, is_smooth=True, keep_largest_connected_component=True, *args, **kwargs
- ):
+ self,
+ fragment: Fragment,
+ *args,
+ output_file: Union[Path, str],
+ class_id=None,
+ is_smooth=True,
+ keep_largest_connected_component=True,
+ **kwargs,
+ ) -> None:
"""Creates an object to generate a surface mesh and saves it as an STL file if the path is provided.
Args:
- output_file (str, optional): output STL file relative path. Default to None for no file output.
+ fragment (Fragment): An instance of the Application class which is derived from Fragment.
+ output_file ([Path,str], optional): output STL file path. None for no file output.
class_id (array, optional): Class label ids. Defaults to None.
is_smooth (bool, optional): smoothing or not. Defaults to True.
keep_largest_connected_component (bool, optional): Defaults to True.
"""
- super().__init__(*args, **kwargs)
+
self._logger = logging.getLogger("{}.{}".format(__name__, type(self).__name__))
self._class_id = class_id
self._is_smooth = is_smooth
self._keep_largest_connected_component = keep_largest_connected_component
- self._output_file = output_file if output_file and len(str(output_file)) > 0 else None
-
+ self._output_file = Path(output_file) if output_file and len(str(output_file)) > 0 else None
self._converter = STLConverter(*args, **kwargs)
- def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
+ self.input_name_image = "image"
+ self.input_name_output_file = "output_file"
+ self.output_name_stl_bytes = "stl_bytes"
+
+ super().__init__(fragment, *args, **kwargs)
+
+ def setup(self, spec: OperatorSpec):
+ spec.input(self.input_name_image)
+ spec.input(self.input_name_output_file).condition(ConditionType.NONE) # Optional, set as needed.
+ spec.output(self.output_name_stl_bytes).condition(ConditionType.NONE) # No receivers required.
+
+ def compute(self, op_input, op_output, context):
"""Gets the input (image), processes it and sets results in the output.
- When used in a leaf operator, this function cannot set its output as in-memory object due to
- current limitation.
- If a file path is provided, the STL binary will be saved in the the application's output
- folder of the current run.
+ This function sets the mesh in STL bytes in its named output, which require no receivers.
+ If provided, the mesh will be saved to the file in STL format.
Args:
op_input (InputContext): An input context for the operator.
@@ -82,25 +103,20 @@ def compute(self, op_input: InputContext, op_output: OutputContext, context: Exe
context (ExecutionContext): An execution context for the operator.
"""
- input_image = op_input.get("image")
+ input_image = op_input.receive(self.input_name_image)
if not input_image:
- raise ValueError("Input is None.")
+ raise ValueError("Input image is not received.")
- # Use the app's current run output folder as parent to the STL output path.
- if self._output_file and len(str(self._output_file)) > 0:
- _output_file = context.output.get().path / self._output_file
- _output_file.parent.mkdir(parents=True, exist_ok=True)
- self._logger.info(f"Output will be saved in file {_output_file}.")
+ _output_file = op_input.receive(self.input_name_output_file)
+ if not _output_file:
+ # Use the object's attribute to get the STL output path, if any.
+ if self._output_file and len(str(self._output_file)) > 0:
+ _output_file = Path(self._output_file)
+ _output_file.parent.mkdir(parents=True, exist_ok=True)
+ self._logger.info(f"Output will be saved in file {_output_file}.")
stl_bytes = self._convert(input_image, _output_file)
-
- try:
- # TODO: Need a way to find if the operator is run as leaf node in order to
- # avoid setting in_memory object.
- if self.op_info.get_storage_type("output", "stl_output") == IOType.IN_MEMORY:
- op_output.set(stl_bytes)
- except Exception as ex:
- self._logger.warn(f"In_memory output cannot be used when run as non-leaf operator. {ex}")
+ op_output.emit(stl_bytes, self.output_name_stl_bytes)
def _convert(self, image: Image, output_file: Optional[Path] = None):
"""
@@ -115,8 +131,6 @@ def _convert(self, image: Image, output_file: Optional[Path] = None):
# Use path in the output_file arg if provided.
if isinstance(output_file, Path):
output_file.parent.mkdir(exist_ok=True)
- else:
- output_file = self._output_file
return self._converter.convert(
image=image,
@@ -127,13 +141,11 @@ def _convert(self, image: Image, output_file: Optional[Path] = None):
)
-class STLConverter(object):
+class STLConverter:
"""Converts volumetric image to surface mesh in STL"""
def __init__(self, *args, **kwargs):
"""Creates an instance to generate a surface mesh in STL with an Image object."""
-
- super().__init__(*args, **kwargs)
self._logger = logging.getLogger("{}.{}".format(__name__, type(self).__name__))
def convert(
@@ -428,18 +440,20 @@ def test():
from monai.deploy.operators.dicom_series_to_volume_operator import DICOMSeriesToVolumeOperator
current_file_dir = Path(__file__).parent.resolve()
- data_path = current_file_dir.joinpath("../../../examples/ai_spleen_seg_data/dcm")
+ data_path = current_file_dir.joinpath("../../../inputs/spleen_ct/dcm")
+ output_path = Path.cwd() / "output_stl/test.stl"
- loader = DICOMDataLoaderOperator()
- series_selector = DICOMSeriesSelectorOperator()
- dcm_to_volume_op = DICOMSeriesToVolumeOperator()
- stl_writer = STLConversionOperator()
+ fragment = Fragment()
+ loader = DICOMDataLoaderOperator(fragment, name="dcm_loader")
+ series_selector = DICOMSeriesSelectorOperator(fragment, name="series_selector")
+ dcm_to_volume_op = DICOMSeriesToVolumeOperator(fragment, name="dcm_to_vol")
+ stl_writer = STLConversionOperator(fragment, output_file=output_path, name="stl_writer")
# Testing with the main entry functions
study_list = loader.load_data_to_studies(data_path.absolute())
study_selected_series_list = series_selector.filter(None, study_list)
image = dcm_to_volume_op.convert_to_image(study_selected_series_list)
- stl_writer._convert(image, Path("stl/test.stl"))
+ stl_writer._convert(image, Path("output_stl/test.stl"))
if __name__ == "__main__":
diff --git a/monai/deploy/packager/README.md b/monai/deploy/packager/README.md
deleted file mode 100644
index 415da8a5..00000000
--- a/monai/deploy/packager/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# MONAI Application Packager
diff --git a/monai/deploy/packager/constants.py b/monai/deploy/packager/constants.py
deleted file mode 100644
index 0be5d4e1..00000000
--- a/monai/deploy/packager/constants.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright 2021 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.
-
-
-class DefaultValues:
- """
- This class contains default values for various parameters.
- """
-
- DOCKER_FILE_NAME = "dockerfile"
- BASE_IMAGE = "nvcr.io/nvidia/pytorch:22.08-py3"
- DOCKERFILE_TYPE = "pytorch"
- WORK_DIR = "/var/monai/"
- INPUT_DIR = "input"
- OUTPUT_DIR = "output"
- MODELS_DIR = "/opt/monai/models"
- API_VERSION = "0.1.0"
- TIMEOUT = 0
diff --git a/monai/deploy/packager/package_command.py b/monai/deploy/packager/package_command.py
deleted file mode 100644
index 39ce5088..00000000
--- a/monai/deploy/packager/package_command.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# Copyright 2021 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
-from argparse import ArgumentParser, Namespace, _SubParsersAction
-from typing import List
-
-from monai.deploy.packager import util as packager_util
-
-
-def create_package_parser(subparser: _SubParsersAction, command: str, parents: List[ArgumentParser]) -> ArgumentParser:
- parser: ArgumentParser = subparser.add_parser(
- command, formatter_class=argparse.HelpFormatter, parents=parents, add_help=False
- )
-
- parser.add_argument("application", type=str, help="MONAI application path")
- parser.add_argument(
- "--tag",
- "-t",
- required=True,
- type=str,
- help="MONAI Application Package (MAP) name and optionally a tag in the 'name:tag' format.",
- )
- parser.add_argument(
- "--model", "-m", type=str, help="Path to a model file or a directory containing all models as subdirectories"
- )
- parser.add_argument("--base", "-b", type=str, help="Base Docker Image")
- parser.add_argument("--input-dir", "-i", type=str, help="Directory mounted in container for Application Input")
- parser.add_argument("--models-dir", type=str, help="Directory mounted in container for Models Path")
- parser.add_argument("--output-dir", "-o", type=str, help="Directory mounted in container for Application Output")
- parser.add_argument("--working-dir", "-w", type=str, help="Directory mounted in container for Application")
- parser.add_argument("--no-cache", "-n", action="store_true", help="Do not use cache when building image")
- parser.add_argument(
- "--requirements",
- "-r",
- type=str,
- help="Optional path to requirements.txt containing package dependencies of the application",
- )
- parser.add_argument("--timeout", type=str, help="Timeout")
- parser.add_argument("--version", type=str, help="Set the version of the Application")
-
- return parser
-
-
-def execute_package_command(args: Namespace):
- packager_util.package_application(args)
diff --git a/monai/deploy/packager/templates.py b/monai/deploy/packager/templates.py
deleted file mode 100644
index a84bba38..00000000
--- a/monai/deploy/packager/templates.py
+++ /dev/null
@@ -1,214 +0,0 @@
-# Copyright 2021-2022 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
-
-COMMON_FOOTPRINT = """
- USER root
-
- RUN pip install --no-cache-dir --upgrade setuptools==59.5.0 pip==22.3 wheel==0.37.1 numpy>=1.21.6
-
- RUN mkdir -p /etc/monai/ \\
- && mkdir -p /opt/monai/ \\
- && mkdir -p {working_dir} \\
- && mkdir -p {app_dir} \\
- && mkdir -p {executor_dir} \\
- && mkdir -p {full_input_path} \\
- && mkdir -p {full_output_path} \\
- && mkdir -p {models_dir}
-
- {models_string}
-
- COPY ./pip/requirements.txt {map_requirements_path}
-
- RUN curl {executor_url} -o {executor_dir}/executor.zip \\
- && unzip {executor_dir}/executor.zip -d {executor_dir}/executor_pkg \\
- && mv {executor_dir}/executor_pkg/lib/native/linux-x64/* {executor_dir} \\
- && rm -f {executor_dir}/executor.zip \\
- && rm -rf {executor_dir}/executor_pkg \\
- && chmod +x {executor_dir}/monai-exec
-
- ENV PATH=/root/.local/bin:$PATH
-
- RUN pip install --no-cache-dir --user -r {map_requirements_path}
-
- # Override monai-deploy-app-sdk module
- COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-packages/monai/deploy/
- RUN echo "User site package location: $(python3 -m site --user-site)" \\
- && [ "$(python3 -m site --user-site)" != "/root/.local/lib/python3.8/site-packages" ] \\
- && mkdir -p $(python3 -m site --user-site)/monai/deploy \\
- && cp -r /root/.local/lib/python3.8/site-packages/monai/deploy/* $(python3 -m site --user-site)/monai/deploy/ \\
- || true
-
- COPY ./map/app.json /etc/monai/
- COPY ./map/pkg.json /etc/monai/
-
- COPY ./app {app_dir}
-
- # Set the working directory
- WORKDIR {working_dir}
-
- ENTRYPOINT [ "/opt/monai/executor/monai-exec" ]
-"""
-
-UBUNTU_DOCKERFILE_TEMPLATE = (
- """FROM {base_image}
-
- LABEL base="{base_image}"
- LABEL tag="{tag}"
- LABEL version="{app_version}"
- LABEL sdk_version="{sdk_version}"
-
- ENV DEBIAN_FRONTEND=noninteractive
- ENV TERM=xterm-256color
- ENV MONAI_INPUTPATH={full_input_path}
- ENV MONAI_OUTPUTPATH={full_output_path}
- ENV MONAI_WORKDIR={working_dir}
- ENV MONAI_APPLICATION={app_dir}
- ENV MONAI_TIMEOUT={timeout}
- ENV MONAI_MODELPATH={models_dir}
-
- RUN apt update \\
- && apt upgrade -y --no-install-recommends \\
- && apt install -y --no-install-recommends \\
- build-essential \\
- python3 \\
- python3-pip \\
- python3-setuptools \\
- curl \\
- unzip \\
- && apt autoremove -y \\
- && rm -rf /var/lib/apt/lists/* \\
- && rm -f /usr/bin/python /usr/bin/pip \\
- && ln -s /usr/bin/python3 /usr/bin/python \\
- && ln -s /usr/bin/pip3 /usr/bin/pip
- """
- + COMMON_FOOTPRINT
-)
-
-PYTORCH_DOCKERFILE_TEMPLATE = (
- """FROM {base_image}
-
- LABEL base="{base_image}"
- LABEL tag="{tag}"
- LABEL version="{app_version}"
- LABEL sdk_version="{sdk_version}"
-
- ENV DEBIAN_FRONTEND=noninteractive
- ENV TERM=xterm-256color
- ENV MONAI_INPUTPATH={full_input_path}
- ENV MONAI_OUTPUTPATH={full_output_path}
- ENV MONAI_WORKDIR={working_dir}
- ENV MONAI_APPLICATION={app_dir}
- ENV MONAI_TIMEOUT={timeout}
- ENV MONAI_MODELPATH={models_dir}
-
- RUN apt update \\
- && apt upgrade -y --no-install-recommends \\
- && apt install -y --no-install-recommends \\
- curl \\
- unzip \\
- && apt autoremove -y \\
- && rm -rf /var/lib/apt/lists/*
- """
- + COMMON_FOOTPRINT
-)
-
-DOCKERIGNORE_TEMPLATE = """
-# Git
-**/.git
-**/.gitignore
-**/.gitconfig
-
-# CI
-**/.codeclimate.yml
-**/.travis.yml
-**/.taskcluster.yml
-
-# Docker
-**/docker-compose.yml
-**/.docker
-
-# Byte-compiled/optimized/DLL files for Python
-**/__pycache__
-**/*.pyc
-**/.Python
-**/*$py.class
-
-# Conda folders
-**/.conda
-**/conda-bld
-
-# Distribution / packaging
-**/.Python
-**/.cmake
-**/cmake-build*/
-**/build-*/
-**/develop-eggs/
-**/.eggs/
-**/sdist/
-**/wheels/
-**/*.egg-info/
-**/.installed.cfg
-**/*.egg
-**/MANIFEST
-
-# PyInstaller
-# Usually these files are written by a python script from a template
-# before PyInstaller builds the exe, so as to inject date/other infos into it.
-**/*.manifest
-**/*.spec
-
-# Installer logs
-**/pip-log.txt
-**/pip-delete-this-directory.txt
-
-# Unit test / coverage reports
-**/htmlcov/
-**/.tox/
-**/.coverage
-**/.coverage.*
-**/.cache
-**/nosetests.xml
-**/coverage.xml
-**/*.cover
-**/*.log
-**/.hypothesis/
-**/.pytest_cache/
-
-# mypy
-**/.mypy_cache/
-
-## VSCode IDE
-**/.vscode
-
-# Jupyter Notebook
-**/.ipynb_checkpoints
-
-# Environments
-**/.env
-**/.venv
-**/env/
-**/venv/
-**/ENV/
-**/env.bak/
-**/venv.bak/
-"""
-
-TEMPLATE_MAP = {
- "ubuntu": UBUNTU_DOCKERFILE_TEMPLATE,
- "pytorch": PYTORCH_DOCKERFILE_TEMPLATE,
- ".dockerignore": DOCKERIGNORE_TEMPLATE,
-}
-
-
-class Template:
- @staticmethod
- def get_template(name: str) -> str:
- return TEMPLATE_MAP[name]
diff --git a/monai/deploy/packager/util.py b/monai/deploy/packager/util.py
deleted file mode 100644
index a2e7a07e..00000000
--- a/monai/deploy/packager/util.py
+++ /dev/null
@@ -1,361 +0,0 @@
-# Copyright 2021 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 json
-import logging
-import os
-import shutil
-import subprocess
-import sys
-import tempfile
-from argparse import Namespace
-from pathlib import Path
-from typing import Dict
-
-from monai.deploy.exceptions import WrongValueError
-from monai.deploy.packager.constants import DefaultValues
-from monai.deploy.packager.templates import Template
-from monai.deploy.utils.fileutil import checksum
-from monai.deploy.utils.importutil import dist_module_path, dist_requires, get_application
-from monai.deploy.utils.spinner import ProgressSpinner
-
-logger = logging.getLogger("app_packager")
-
-executor_url = "https://globalcdn.nuget.org/packages/monai.deploy.executor.0.1.0-prealpha.4.nupkg"
-
-
-def verify_base_image(base_image: str) -> str:
- """Helper function which validates whether valid base image passed to Packager.
- Additionally, this function provides the string identifier of the dockerfile
- template to build MAP
- Args:
- base_image (str): potential base image to build MAP Docker image
- Returns:
- str: returns string identifier of the dockerfile template to build MAP
- if valid base image provided, returns empty string otherwise
- """
- if "rocm" in base_image:
- valid_prefixes = {"rocm/pytorch": "ubuntu"}
- else:
- valid_prefixes = {"nvcr.io/nvidia/cuda": "ubuntu", "nvcr.io/nvidia/pytorch": "pytorch"}
-
- for prefix, template in valid_prefixes.items():
- if prefix in base_image:
- return template
-
- return ""
-
-
-def initialize_args(args: Namespace) -> Dict:
- """Processes and formats input arguements for Packager
- Args:
- args (Namespace): Input arguements for Packager from CLI
- Returns:
- Dict: Processed set of input arguements for Packager
- """
- processed_args = dict()
-
- # Parse arguements and set default values if any are missing
- processed_args["application"] = args.application
- processed_args["tag"] = args.tag
- processed_args["docker_file_name"] = DefaultValues.DOCKER_FILE_NAME
- processed_args["working_dir"] = args.working_dir if args.working_dir else DefaultValues.WORK_DIR
- processed_args["app_dir"] = "/opt/monai/app"
- processed_args["executor_dir"] = "/opt/monai/executor"
- processed_args["input_dir"] = args.input if args.input_dir else DefaultValues.INPUT_DIR
- processed_args["output_dir"] = args.output if args.output_dir else DefaultValues.OUTPUT_DIR
- processed_args["models_dir"] = args.models if args.models_dir else DefaultValues.MODELS_DIR
- processed_args["no_cache"] = args.no_cache
- processed_args["timeout"] = args.timeout if args.timeout else DefaultValues.TIMEOUT
- processed_args["api-version"] = DefaultValues.API_VERSION
- processed_args["requirements"] = ""
-
- if args.requirements:
- if not args.requirements.endswith(".txt"):
- logger.error(
- f"Improper path to requirements.txt provided: {args.requirements}, defaulting to sdk provided values"
- )
- else:
- processed_args["requirements"] = args.requirements
-
- # Verify proper base image:
- dockerfile_type = ""
-
- if args.base:
- dockerfile_type = verify_base_image(args.base)
- if not dockerfile_type:
- logger.error(
- "Provided base image '{}' is not supported \n Please provide a ROCm or Cuda"
- " based Pytorch image from \n https://hub.docker.com/r/rocm/pytorch or"
- " https://ngc.nvidia.com/ (nvcr.io/nvidia)".format(args.base)
- )
-
- sys.exit(1)
-
- processed_args["dockerfile_type"] = dockerfile_type if args.base else DefaultValues.DOCKERFILE_TYPE
-
- base_image = DefaultValues.BASE_IMAGE
- if args.base:
- base_image = args.base
- else:
- base_image = os.getenv("MONAI_BASEIMAGE", DefaultValues.BASE_IMAGE)
-
- processed_args["base_image"] = base_image
-
- # Obtain SDK provide application values
- app_obj = get_application(args.application)
- if app_obj:
- processed_args["application_info"] = app_obj.get_package_info(args.model)
- else:
- raise WrongValueError("Application from '{}' not found".format(args.application))
-
- # Use version number if provided through CLI, otherwise use value provided by SDK
- processed_args["version"] = args.version if args.version else processed_args["application_info"]["app-version"]
-
- return processed_args
-
-
-def build_image(args: dict, temp_dir: str):
- """Creates dockerfile and builds MONAI Application Package (MAP) image
- Args:
- args (dict): Input arguements for Packager
- temp_dir (str): Temporary directory to build MAP
- """
- # Parse arguements for dockerfile
- tag = args["tag"]
- docker_file_name = args["docker_file_name"]
- base_image = args["base_image"]
- dockerfile_type = args["dockerfile_type"]
- working_dir = args["working_dir"]
- app_dir = args["app_dir"]
- executor_dir = args["executor_dir"]
- input_dir = args["input_dir"]
- full_input_path = os.path.join(working_dir, input_dir)
- output_dir = args["output_dir"]
- full_output_path = os.path.join(working_dir, output_dir)
- models_dir = args["models_dir"]
- timeout = args["timeout"]
- application_path = args["application"]
- local_requirements_file = args["requirements"]
- no_cache = args["no_cache"]
- app_version = args["version"]
-
- # Copy application files to temp directory (under 'app' folder)
- target_application_path = os.path.join(temp_dir, "app")
- if os.path.isfile(application_path):
- os.makedirs(target_application_path, exist_ok=True)
- shutil.copy(application_path, target_application_path)
- else:
- shutil.copytree(application_path, target_application_path)
-
- # Copy monai-app-sdk module to temp directory (under 'monai-deploy-app-sdk' folder)
- monai_app_sdk_path = os.path.join(dist_module_path("monai-deploy-app-sdk"), "monai", "deploy")
- target_monai_app_sdk_path = os.path.join(temp_dir, "monai-deploy-app-sdk")
- shutil.copytree(monai_app_sdk_path, target_monai_app_sdk_path)
-
- # Parse SDK provided values
- sdk_version = args["application_info"]["sdk-version"]
- local_models = args["application_info"]["models"]
- pip_packages = args["application_info"]["pip-packages"]
-
- # Append required packages for SDK to pip_packages
- monai_app_sdk_requires = dist_requires("monai-deploy-app-sdk")
- pip_packages.extend(monai_app_sdk_requires)
-
- pip_folder = os.path.join(temp_dir, "pip")
- os.makedirs(pip_folder, exist_ok=True)
- pip_requirements_path = os.path.join(pip_folder, "requirements.txt")
- with open(pip_requirements_path, "w") as requirements_file:
- # Use local requirements.txt packages if provided, otherwise use sdk provided packages
- if local_requirements_file:
- with open(local_requirements_file, "r") as lr:
- for line in lr:
- requirements_file.write(line)
- else:
- requirements_file.writelines("\n".join(pip_packages))
-
- # Parameter for the Dockerfile for copying content to internal path
- map_requirements_path = str(Path(app_dir) / "requirements.txt")
-
- # Copy model files to temp directory (under 'model' folder)
- target_models_path = os.path.join(temp_dir, "models")
- os.makedirs(target_models_path, exist_ok=True)
- for model_entry in local_models:
- model_name = model_entry["name"]
- model_path = model_entry["path"]
-
- dest_model_path = os.path.join(target_models_path, model_name)
-
- if os.path.isfile(model_path):
- os.makedirs(dest_model_path, exist_ok=True)
- shutil.copy(model_path, dest_model_path)
- else:
- shutil.copytree(model_path, dest_model_path)
-
- models_string = f"RUN mkdir -p {models_dir}\n"
- models_string += f"COPY ./models {models_dir}\n"
-
- # Dockerfile template
- template_params = {
- "app_dir": app_dir,
- "app_version": app_version,
- "base_image": base_image,
- "executor_dir": executor_dir,
- "executor_url": executor_url,
- "full_input_path": full_input_path,
- "full_output_path": full_output_path,
- "map_requirements_path": map_requirements_path,
- "models_dir": models_dir,
- "models_string": models_string,
- "sdk_version": sdk_version,
- "tag": tag,
- "timeout": timeout,
- "working_dir": working_dir,
- }
- docker_template_string = Template.get_template(dockerfile_type).format(**template_params)
-
- # Write out dockerfile
- logger.debug(docker_template_string)
- docker_file_path = os.path.join(temp_dir, docker_file_name)
- with open(docker_file_path, "w") as docker_file:
- docker_file.write(docker_template_string)
-
- # Write out .dockerignore file
- dockerignore_file_path = os.path.join(temp_dir, ".dockerignore")
- with open(dockerignore_file_path, "w") as dockerignore_file:
- docker_ignore_template = Template.get_template(".dockerignore")
- dockerignore_file.write(docker_ignore_template)
-
- # Build dockerfile into an MAP image
- docker_build_cmd = f"""docker build -f {docker_file_path!r} -t {tag} {temp_dir!r}"""
- if sys.platform != "win32":
- docker_build_cmd += """ --build-arg MONAI_UID=$(id -u) --build-arg MONAI_GID=$(id -g)"""
- if no_cache:
- docker_build_cmd += " --no-cache"
- proc = subprocess.Popen(docker_build_cmd, stdout=subprocess.PIPE, shell=True)
-
- logger.debug("Docker image build command: %s", docker_build_cmd)
-
- spinner = ProgressSpinner("Building MONAI Application Package... ")
- spinner.start()
-
- while proc.poll() is None:
- if proc.stdout:
- logger.debug(proc.stdout.readline().decode("utf-8"))
-
- spinner.stop()
- return_code = proc.returncode
-
- if return_code == 0:
- logger.info(f"Successfully built {tag}")
-
-
-def create_app_manifest(args: Dict, temp_dir: str):
- """Creates Application manifest .json file
- Args:
- args (Dict): Input arguements for Packager
- temp_dir (str): Temporary directory to build MAP
- """
- input_dir = args["input_dir"]
- output_dir = args["output_dir"]
- working_dir = args["working_dir"]
- api_version = args["api-version"]
- app_version = args["version"]
- timeout = args["timeout"]
-
- command = args["application_info"]["command"]
- sdk_version = args["application_info"]["sdk-version"]
- environment = args["application_info"]["environment"] if "environment" in args["application_info"] else {}
-
- app_manifest = {}
- app_manifest["api-version"] = api_version
- app_manifest["sdk-version"] = sdk_version
- app_manifest["command"] = command
- app_manifest["environment"] = environment
- app_manifest["working-directory"] = working_dir
- app_manifest["input"] = {}
- app_manifest["input"]["path"] = input_dir
- app_manifest["input"]["formats"] = []
- app_manifest["output"] = {}
- app_manifest["output"]["path"] = output_dir
- app_manifest["output"]["format"] = {}
- app_manifest["version"] = app_version
- app_manifest["timeout"] = timeout
-
- app_manifest_string = json.dumps(app_manifest, sort_keys=True, indent=4, separators=(",", ": "))
-
- map_folder_path = os.path.join(temp_dir, "map")
- os.makedirs(map_folder_path, exist_ok=True)
- with open(os.path.join(map_folder_path, "app.json"), "w") as app_manifest_file:
- app_manifest_file.write(app_manifest_string)
-
-
-def create_package_manifest(args: Dict, temp_dir: str):
- """Creates package manifest .json file
- Args:
- args (Dict): Input arguements for Packager
- temp_dir (str): Temporary directory to build MAP
- """
- models_dir = args["models_dir"]
- working_dir = args["working_dir"]
- api_version = args["api-version"]
- app_version = args["version"]
-
- sdk_version = args["application_info"]["sdk-version"]
- cpu = args["application_info"]["resource"]["cpu"]
- gpu = args["application_info"]["resource"]["gpu"]
- memory = args["application_info"]["resource"]["memory"]
- models = args["application_info"]["models"]
-
- package_manifest = {}
- package_manifest["api-version"] = api_version
- package_manifest["sdk-version"] = sdk_version
- package_manifest["application-root"] = working_dir
- package_manifest["models"] = []
-
- for model_entry in models:
- local_model_name = model_entry["name"]
- local_model_path = model_entry["path"]
- # Here, the model name is conformant to the specification of the MAP.
- # '-'
- model_name = f"""{local_model_name[:63]}-{checksum(local_model_path)}"""
- model_file = os.path.basename(model_entry["path"])
- model_path = os.path.join(models_dir, local_model_name, model_file)
- package_manifest["models"].append({"name": model_name, "path": model_path})
-
- package_manifest["resources"] = {}
- package_manifest["resources"]["cpu"] = cpu
- package_manifest["resources"]["gpu"] = gpu
- package_manifest["resources"]["memory"] = memory
- package_manifest["version"] = app_version
-
- package_manifest_string = json.dumps(package_manifest, sort_keys=True, indent=4, separators=(",", ": "))
-
- with open(os.path.join(temp_dir, "map", "pkg.json"), "w") as package_manifest_file:
- package_manifest_file.write(package_manifest_string)
-
-
-def package_application(args: Namespace):
- """Driver function for invoking all functions for creating and
- building the MONAI Application package image
- Args:
- args (Namespace): Input arguements for Packager from CLI
- """
- # Initialize arguements for package
- initialized_args = initialize_args(args)
-
- with tempfile.TemporaryDirectory(prefix="monai_tmp", dir=".") as temp_dir:
- # Create Manifest Files
- create_app_manifest(initialized_args, temp_dir)
- create_package_manifest(initialized_args, temp_dir)
-
- # Build MONAI Application Package image
- build_image(initialized_args, temp_dir)
diff --git a/monai/deploy/resources/__init__.py b/monai/deploy/resources/__init__.py
new file mode 100644
index 00000000..d3da7a80
--- /dev/null
+++ b/monai/deploy/resources/__init__.py
@@ -0,0 +1 @@
+from holoscan.resources import *
diff --git a/monai/deploy/runner/README.md b/monai/deploy/runner/README.md
deleted file mode 100644
index 5e975845..00000000
--- a/monai/deploy/runner/README.md
+++ /dev/null
@@ -1,25 +0,0 @@
-# MONAI Application Runner
-
-The MONAI Application Runner (MAR) is a command-line utility that allows users to run and test their MONAI Application Package (MAP) locally. MAR is developed to make the running and testing of MAPs locally an easy process for developers and scientists by abstracting away the need to understand the internal details of the MAP. MAR allows the users to specify input and output paths on the local file system which it maps to the input and output of MAP during execution.
-
-## Syntax
-
-```bash
-monai-deploy run [:tag] [-q|--quiet]
-```
-
-### Arguments
-
-#### Positional arguments
-
-| Name | Format | Description |
-| -------- | -------------------------------- | ------------------------------------------------------------- |
-| MAP | `container-image-name[:tag]` | MAP container image name with or without image tag. |
-| input | directory path | Local folder path that contains input dataset for the MAP. |
-| output | directory path | Local folder path to store output from the executing MAP. |
-
-#### Optional arguments
-
-| Name | Shorthand | Default | Description |
-| ------------------- | ---------- | ---------- | -------------------------------------------------------------- |
-| quiet | -q | False | Suppress the STDOUT and print only STDERR from the application. |
diff --git a/monai/deploy/runner/__init__.py b/monai/deploy/runner/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/monai/deploy/runner/requirements.txt b/monai/deploy/runner/requirements.txt
deleted file mode 100644
index e69de29b..00000000
diff --git a/monai/deploy/runner/run_command.py b/monai/deploy/runner/run_command.py
deleted file mode 100644
index f492c903..00000000
--- a/monai/deploy/runner/run_command.py
+++ /dev/null
@@ -1,50 +0,0 @@
-# Copyright 2021 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 logging
-from argparse import ArgumentParser, HelpFormatter, Namespace, _SubParsersAction
-from typing import List
-
-from monai.deploy.runner import runner
-from monai.deploy.utils import argparse_types
-
-logger = logging.getLogger("app_runner")
-
-
-def create_run_parser(subparser: _SubParsersAction, command: str, parents: List[ArgumentParser]) -> ArgumentParser:
- parser: ArgumentParser = subparser.add_parser(
- command, formatter_class=HelpFormatter, parents=parents, add_help=False
- )
-
- parser.add_argument("map", metavar="", help="MAP image name")
-
- parser.add_argument(
- "input", metavar=" ", type=argparse_types.valid_dir_path, help="Input data directory path"
- )
-
- parser.add_argument(
- "output", metavar="", type=argparse_types.valid_dir_path, help="Output data directory path"
- )
-
- parser.add_argument(
- "-q",
- "--quiet",
- dest="quiet",
- action="store_true",
- default=False,
- help="Suppress the STDOUT and print only STDERR from the application (default: False)",
- )
-
- return parser
-
-
-def execute_run_command(args: Namespace):
- runner.main(args)
diff --git a/monai/deploy/runner/runner.py b/monai/deploy/runner/runner.py
deleted file mode 100644
index a195ced4..00000000
--- a/monai/deploy/runner/runner.py
+++ /dev/null
@@ -1,206 +0,0 @@
-# Copyright 2021 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 logging
-import posixpath
-import shutil
-import sys
-import tempfile
-from pathlib import Path
-from typing import Tuple
-
-from monai.deploy.runner.utils import get_requested_gpus, run_cmd, verify_image
-from monai.deploy.utils.deviceutil import has_rocm
-
-logger = logging.getLogger("app_runner")
-
-
-def fetch_map_manifest(map_name: str) -> Tuple[dict, dict, int]:
- """
- Execute MONAI Application Package and fetch application manifest.
-
- Args:
- map_name: MAP image name.
-
- Returns:
- app_info: application manifest as a python dict
- pkg_info: package manifest as a python dict
- returncode: command return code
- """
- logger.info("\nReading MONAI App Package manifest...")
-
- with tempfile.TemporaryDirectory() as info_dir:
- if sys.platform == "win32":
- cmd = f'docker run --rm -a STDOUT -a STDERR -v " {info_dir}":/var/run/monai/export/config {map_name}'
- else:
- cmd = f"""docker_id=$(docker create {map_name})
-docker cp $docker_id:/etc/monai/app.json "{info_dir}/app.json"
-docker cp $docker_id:/etc/monai/pkg.json "{info_dir}/pkg.json"
-docker rm -v $docker_id > /dev/null
-"""
- returncode = run_cmd(cmd)
- if returncode != 0:
- return {}, {}, returncode
-
- app_json = Path(f"{info_dir}/app.json")
- pkg_json = Path(f"{info_dir}/pkg.json")
-
- logger.debug("-------------------application manifest-------------------")
- logger.debug(app_json.read_text())
- logger.debug("----------------------------------------------\n")
-
- logger.debug("-------------------package manifest-------------------")
- logger.debug(pkg_json.read_text())
- logger.debug("----------------------------------------------\n")
-
- app_info = json.loads(app_json.read_text())
- pkg_info = json.loads(pkg_json.read_text())
- return app_info, pkg_info, returncode
-
-
-def run_app(map_name: str, input_path: Path, output_path: Path, app_info: dict, pkg_info: dict, quiet: bool) -> int:
- """
- Executes the MONAI Application.
-
- Args:
- map_name: MONAI Application Package
- input_path: input directory path
- output_path: output directory path
- app_info: application manifest dictionary
- pkg_info: package manifest dictionary
- quiet: boolean flag indicating quiet mode
-
- Returns:
- returncode: command returncode
- """
- cmd = "docker run --rm -a STDERR"
-
- # Use nvidia-docker if GPU resources are requested
- requested_gpus = get_requested_gpus(pkg_info)
- if requested_gpus > 0:
- if not has_rocm():
- cmd = "nvidia-docker run --rm -a STDERR"
-
- if not quiet:
- cmd += " -a STDOUT"
-
- # Use POSIX path for input and output paths as local paths are mounted to those paths in the container.
- map_input = Path(app_info["input"]["path"]).as_posix()
- map_output = Path(app_info["output"]["path"]).as_posix()
- if not posixpath.isabs(map_input):
- map_input = posixpath.join(app_info["working-directory"], map_input)
-
- if not posixpath.isabs(map_output):
- map_output = posixpath.join(app_info["working-directory"], map_output)
-
- cmd += ' -e MONAI_INPUTPATH="{}"'.format(map_input)
- cmd += ' -e MONAI_OUTPUTPATH="{}"'.format(map_output)
- # TODO(bhatt-piyush): Handle model environment correctly (maybe solved by fixing 'monai-exec')
- cmd += " -e MONAI_MODELPATH=/opt/monai/models"
-
- map_command = app_info["command"]
- # TODO(bhatt-piyush): Fix 'monai-exec' to work correctly.
- cmd += ' -v "{}":"{}" -v "{}":"{}" --shm-size=1g --entrypoint "/bin/bash" "{}" -c "{}"'.format(
- input_path.absolute(), map_input, output_path.absolute(), map_output, map_name, map_command
- )
- # cmd += " -v {}:{} -v {}:{} {}".format(
- # input_path.absolute(), map_input, output_path.absolute(), map_output, map_name
- # )
- logger.debug("Executing command: %s", cmd)
-
- return run_cmd(cmd)
-
-
-def dependency_verification(map_name: str) -> bool:
- """Check if all the dependencies are installed or not.
-
- Args:
- map_name: MONAI Application Package
-
- Returns:
- True if all dependencies are satisfied, otherwise False.
- """
- logger.info("Checking dependencies...")
-
- # check for docker
- prog = "docker"
- logger.info('--> Verifying if "%s" is installed...\n', prog)
- if not shutil.which(prog):
- logger.error('ERROR: "%s" not installed, please install docker.', prog)
- return False
-
- # check for map image
- logger.info('--> Verifying if "%s" is available...\n', map_name)
- if not verify_image(map_name):
- logger.error("ERROR: Unable to fetch required image.")
- return False
-
- return True
-
-
-def pkg_specific_dependency_verification(pkg_info: dict) -> bool:
- """Checks for any package specific dependencies.
-
- Currently it verifies the following dependencies:
- * If gpu has been requested by the application, verify that nvidia-docker is installed.
-
- Args:
- pkg_info: package manifest as a python dict
-
- Returns:
- True if all dependencies are satisfied, otherwise False.
- """
- requested_gpus = get_requested_gpus(pkg_info)
- if requested_gpus > 0:
- if not has_rocm():
- # check for nvidia-docker
- prog = "nvidia-docker"
- logger.info('--> Verifying if "%s" is installed...\n', prog)
- if not shutil.which(prog):
- logger.error('ERROR: "%s" not installed, please install nvidia-docker.', prog)
- return False
-
- return True
-
-
-def main(args: argparse.Namespace):
- """
- Main entry function for MONAI Application Runner.
-
- Args:
- args: parsed arguments
-
- Returns:
- None
- """
- if not dependency_verification(args.map):
- logger.error("Execution Aborted")
- sys.exit(1)
-
- # Fetch application manifest from MAP
- app_info, pkg_info, returncode = fetch_map_manifest(args.map)
- if returncode != 0:
- logger.error("ERROR: Failed to fetch MAP manifest.")
- logger.error("Execution Aborted")
- sys.exit(1)
-
- if not pkg_specific_dependency_verification(pkg_info):
- logger.error("Execution Aborted")
- sys.exit(1)
-
- # Run MONAI Application
- returncode = run_app(args.map, args.input, args.output, app_info, pkg_info, quiet=args.quiet)
-
- if returncode != 0:
- logger.error('\nERROR: MONAI Application "%s" failed.', args.map)
- sys.exit(1)
diff --git a/monai/deploy/runner/utils.py b/monai/deploy/runner/utils.py
deleted file mode 100644
index 02b7ae6e..00000000
--- a/monai/deploy/runner/utils.py
+++ /dev/null
@@ -1,82 +0,0 @@
-# Copyright 2021 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 logging
-import subprocess
-
-logger = logging.getLogger("app_runner")
-
-
-def get_requested_gpus(pkg_info: dict) -> int:
- """Gets requested number of gpus in the package manifest
-
- Args:
- pkg_info: package manifest as a python dict
-
- Returns:
- int: requested number of gpus in the package manifest
- """
- num_gpu: int = pkg_info.get("resources", {}).get("gpu", 0)
- return num_gpu
-
-
-def run_cmd(cmd: str) -> int:
- """
- Executes command and return the returncode of the executed command.
-
- Redirects stderr of the executed command to stdout.
-
- Args:
- cmd: command to execute.
-
- Returns:
- output: child process returncode after the command has been executed.
- """
- proc = subprocess.Popen(cmd, universal_newlines=True, shell=True)
- return proc.wait()
-
-
-def verify_image(image: str) -> bool:
- """Checks if the container image is present locally and tries to pull if not found.
-
- Args:
- image: container image
-
- Returns:
- True if either image is already present or if it was successfully pulled.
- """
-
- def _check_image_exists_locally(image_tag):
- response = subprocess.check_output(
- ["docker", "images", image_tag, "--format", "{{.Repository}}:{{.Tag}}"], universal_newlines=True
- )
-
- if image_tag in response:
- logger.info('"%s" found.', image_tag)
- return True
-
- return False
-
- def _pull_image(image_tag: str) -> bool:
- cmd = f"docker pull {image_tag}"
- returncode = run_cmd(cmd)
-
- if returncode != 0:
- return False
-
- return True
-
- logger.info('Checking for MAP "%s" locally', image)
- if not _check_image_exists_locally(image):
- logger.warning('"%s" not found locally.\n\nTrying to pull from registry...', image)
- return _pull_image(image)
-
- return True
diff --git a/monai/deploy/utils/importutil.py b/monai/deploy/utils/importutil.py
index 486dfc9e..d56b7d42 100644
--- a/monai/deploy/utils/importutil.py
+++ b/monai/deploy/utils/importutil.py
@@ -166,8 +166,9 @@ def optional_import(
version_checker: Callable[..., bool] = min_version,
name: str = "",
descriptor: str = OPTIONAL_IMPORT_MSG_FMT,
- version_args=None,
+ version_args: Any = None,
allow_namespace_pkg: bool = False,
+ as_type: str = "default",
) -> Tuple[Any, bool]:
"""
Imports an optional module specified by `module` string.
@@ -182,6 +183,10 @@ def optional_import(
descriptor: a format string for the final error message when using a not imported module.
version_args: additional parameters to the version checker.
allow_namespace_pkg: whether importing a namespace package is allowed. Defaults to False.
+ as_type: there are cases where the optionally imported object is used as
+ a base class, or a decorator, the exceptions should raise accordingly. The current supported values
+ are "default" (call once to raise), "decorator" (call the constructor and the second call to raise),
+ and anything else will return a lazy class that can be used as a base class (call the constructor to raise).
Returns:
The imported module and a boolean flag indicating whether the import is successful.
@@ -268,6 +273,21 @@ def __call__(self, *_args, **_kwargs):
"""
raise self._exception
+ def __getitem__(self, item):
+ raise self._exception
+
+ def __iter__(self):
+ raise self._exception
+
+ if as_type == "default":
+ return _LazyRaise(), False
+
+ class _LazyCls(_LazyRaise):
+ def __init__(self, *_args, **kwargs):
+ super().__init__()
+ if not as_type.startswith("decorator"):
+ raise self._exception
+
return _LazyRaise(), False
@@ -341,10 +361,86 @@ def dist_requires(project_name: str) -> List[str]:
return []
+holoscan_init_content_txt = """
+# SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0
+#
+# 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.
+
+# We import core and gxf to make sure they're available before other modules that rely on them
+from . import core, gxf
+
+as_tensor = core.Tensor.as_tensor
+__all__ = ["as_tensor", "core", "gxf"]
+
+# Other modules are exposed to the public API but will only be lazily loaded
+_EXTRA_MODULES = [
+ "conditions",
+ "executors",
+ "graphs",
+ "logger",
+ "operators",
+ "resources",
+]
+__all__.extend(_EXTRA_MODULES)
+
+
+# Autocomplete
+def __dir__():
+ return __all__
+
+
+# Lazily load extra modules
+def __getattr__(name):
+ import importlib
+ import sys
+
+ if name in _EXTRA_MODULES:
+ module_name = f"{__name__}.{name}"
+ module = importlib.import_module(module_name) # import
+ sys.modules[module_name] = module # cache
+ return module
+ else:
+ raise AttributeError(f"module {__name__} has no attribute {name}")
+
+"""
+
+
+def fix_holoscan_import():
+ """Fix holoscan __init__ to enable lazy load for avoiding failure on loading low level libs."""
+
+ try:
+ project_name = "holoscan"
+ holoscan_init_path = Path(dist_module_path(project_name)) / project_name / "__init__.py"
+
+ with open(str(holoscan_init_path), "w") as f_w:
+ f_w.write(holoscan_init_content_txt)
+ return str(holoscan_init_path)
+ except Exception as ex:
+ return ex
+
+
if __name__ == "__main__":
"""Utility functions that can be used in the command line."""
argv = sys.argv
+ if len(argv) == 2 and argv[1] == "fix_holoscan_import":
+ file_path = fix_holoscan_import()
+ if file_path:
+ print(file_path)
+ sys.exit(0)
+ else:
+ sys.exit(1)
if len(argv) == 3 and argv[1] == "is_dist_editable":
if is_dist_editable(argv[2]):
sys.exit(0)
diff --git a/monai/deploy/utils/version.py b/monai/deploy/utils/version.py
index 7220b064..930368f5 100644
--- a/monai/deploy/utils/version.py
+++ b/monai/deploy/utils/version.py
@@ -125,7 +125,7 @@ def get_sdk_semver():
else:
raise ValueError(f"Invalid semver string: {semver_str!r} (from {version_str!r})")
else:
- raise ValueError(f"Invalid version string: {version_str}")
+ raise ValueError(f"Invalid version string: {version_str!r}")
if __name__ == "__main__":
diff --git a/notebooks/tutorials/01_simple_app.ipynb b/notebooks/tutorials/01_simple_app.ipynb
index f3652c4e..b343563a 100644
--- a/notebooks/tutorials/01_simple_app.ipynb
+++ b/notebooks/tutorials/01_simple_app.ipynb
@@ -1,12 +1,13 @@
{
"cells": [
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"# Creating a Simple Image Processing App with MONAI Deploy App SDK\n",
"\n",
- "This tutorial shows how to develop a simple image processing application can be created with MONAI Deploy App SDK.\n",
+ "This tutorial shows how a simple image processing application can be created with MONAI Deploy App SDK.\n",
"\n",
"\n",
"## Creating Operators and connecting them in Application class\n",
@@ -14,15 +15,15 @@
"We will implement an application that consists of three Operators:\n",
"\n",
"- **SobelOperator**: Apply a Sobel edge detector.\n",
- " - **Input**: a file path ([`DataPath`](/modules/_autosummary/monai.deploy.core.domain.DataPath))\n",
+ " - **Input**: a file path (`Path`)\n",
" - **Output**: an image object in memory ([`Image`](/modules/_autosummary/monai.deploy.core.domain.Image))\n",
"- **MedianOperator**: Apply a Median filter for noise reduction.\n",
" - **Input**: an image object in memory ([`Image`](/modules/_autosummary/monai.deploy.core.domain.Image))\n",
" - **Output**: an image object in memory ([`Image`](/modules/_autosummary/monai.deploy.core.domain.Image))\n",
"- **GaussianOperator**: Apply a Gaussian filter for smoothening.\n",
" - **Input**: an image object in memory ([`Image`](/modules/_autosummary/monai.deploy.core.domain.Image))\n",
- " - **Output**: a file path ([`DataPath`](/modules/_autosummary/monai.deploy.core.domain.DataPath))\n",
- " \n",
+ " - **Output**: a file path (`Path`)\n",
+ "\n",
"The workflow of the application would look like this.\n",
"\n",
"```{mermaid}\n",
@@ -35,16 +36,16 @@
" MedianOperator --|> GaussianOperator : image...image\n",
"\n",
" class SobelOperator {\n",
- " image : DISK\n",
- " image(out) IN_MEMORY\n",
+ " image : Path\n",
+ " image(out) : IN_MEMORY\n",
" }\n",
" class MedianOperator {\n",
" image : IN_MEMORY\n",
- " image(out) IN_MEMORY\n",
+ " image(out) : IN_MEMORY\n",
" }\n",
" class GaussianOperator {\n",
" image : IN_MEMORY\n",
- " image(out) DISK\n",
+ " image(out) : Path\n",
" }\n",
"```\n",
"\n",
@@ -64,10 +65,11 @@
"%matplotlib inline\n",
"\n",
"# Install MONAI Deploy App SDK package\n",
- "!python -c \"import monai.deploy\" || pip install --upgrade -q \"monai-deploy-app-sdk\""
+ "!python -c \"import monai.deploy\" || pip install -q \"monai-deploy-app-sdk\""
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -87,13 +89,13 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "Test input file path: '/tmp/normal-brain-mri-4.png'\n"
+ "Test input file path: '/tmp/simple_app/normal-brain-mri-4.png'\n"
]
},
{
"data": {
"text/plain": [
- ""
+ ""
]
},
"execution_count": 2,
@@ -102,7 +104,7 @@
},
{
"data": {
- "image/png": "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o1EcPnwYR44c2cCebR4MDw8jm81WjGEqlcLBgwfVGB45cgTpdBoHDhxQZQ4fPoxoNIoXXnjhsvf5SkE+nwcAdHR0AABefPFFrKysVIzl7t27sW3btoqxvPXWW9Hb26vKPPDAAygUCnjttdcuY++vDKytreGJJ57AwsICDh06FI5hFXj00Ufx0EMPVYwZEM7HoDhx4gQGBgZw3XXX4ZFHHsHo6CiAyzuOm+o0pKmpKaytrVXcNAD09vbizTff3KBebS5ks1kAMI4hv8tms+jp6an4vrGxER0dHarMtYb19XV8+tOfxj333INbbrkFwPlxam5uRjqdriirj6VprPndtYJXX30Vhw4dwtLSEtra2vCNb3wDN910E44ePRqOYQA88cQT+NnPfoaf/OQnF30Xzkd7HDx4EF/96ldx4403Ynx8HH/2Z3+Ge++9F8eOHbus47ipCDhEiI3Co48+imPHjuG5557b6K5sStx44404evQo8vk8/uM//gMf+chH8Oyzz250tzYVzpw5g0996lN4+umnEYvFNro7mxoPPvig+nvv3r04ePAghoaG8LWvfQ3xePyy9WNTmaC7urrQ0NBwUTTaxMQE+vr6NqhXmwscJ68x7Ovrw+TkZMX3q6urmJmZuSbH+ZOf/CS+9a1v4Qc/+AEGBwfV5319fSiXy5ibm6sor4+laaz53bWC5uZmXH/99di/fz8ef/xx7Nu3D3/7t38bjmEAvPjii5icnMTtt9+OxsZGNDY24tlnn8Xf/d3fobGxEb29veFYVol0Oo0bbrgBJ0+evKxzclMRcHNzM/bv349nnnlGfba+vo5nnnkGhw4d2sCebR7s2LEDfX19FWNYKBTwwgsvqDE8dOgQ5ubm8OKLL6oy3//+97G+vo6DBw9e9j5vFBzHwSc/+Ul84xvfwPe//33s2LGj4vv9+/ejqampYiyPHz+O0dHRirF89dVXKwSap59+GslkEjfddNPluZErEOvr61heXg7HMADe85734NVXX8XRo0fVz4EDB/DII4+ov8OxrA7z8/M4deoU+vv7L++crCqEbAPxxBNPOC0tLc5Xv/pV5/XXX3d++7d/20mn0xXRaNc6isWi89JLLzkvvfSSA8D567/+a+ell15yRkZGHMc5vw0pnU47//Vf/+W88sorzgc+8AHjNqTbbrvNeeGFF5znnnvO2bVr1zW3DekTn/iEk0qlnB/+8IcV2xUWFxdVmY9//OPOtm3bnO9///vOT3/6U+fQoUPOoUOH1PfcrnD//fc7R48edb773e863d3d19S2j89//vPOs88+6wwPDzuvvPKK8/nPf96JRCLO9773PcdxwjGsBTIK2nHCsbTFZz/7WeeHP/yhMzw87PzoRz9yDh8+7HR1dTmTk5OO41y+cdx0BOw4jvP3f//3zrZt25zm5mbnzjvvdJ5//vmN7tIVhR/84AcOgIt+PvKRjziOc34r0p/8yZ84vb29TktLi/Oe97zHOX78eEUd09PTzsMPP+y0tbU5yWTS+ehHP+oUi8UNuJuNg2kMAThf+cpXVJlSqeT8zu/8jpPJZJzW1lbngx/8oDM+Pl5Rz9tvv+08+OCDTjwed7q6upzPfvazzsrKymW+m43Db/7mbzpDQ0NOc3Oz093d7bznPe9R5Os44RjWAp2Aw7G0w4c//GGnv7/faW5udrZs2eJ8+MMfdk6ePKm+v1zjGJ4HHCJEiBAhQmwANpUPOESIECFChLhaEBJwiBAhQoQIsQEICThEiBAhQoTYAIQEHCJEiBAhQmwAQgIOESJEiBAhNgAhAYcIESJEiBAbgJCAQ4QIESJEiA1ASMAhQoQIESLEBiAk4BAhQoQIEWIDEBJwiBAhQoQIsQEICThEiBAhQoTYAPw/PrqZCbjWN/UAAAAASUVORK5CYII=",
+ "image/png": "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9IlPfMJJpVLOD3/4w4rtCouLi6rMxz/+cWfbtm3O97//feenP/2pc+jQIefQoUPqe25XuP/++52jR4863/3ud53u7u5ratvH5z//eefZZ591hoeHnVdeecX5/Oc/70QiEed73/ue4zjhGNYCGQXtOOFY2uKzn/2s88Mf/tAZHh52fvSjHzmHDx92urq6nMnJScdxLt84bjoCdhzH+fu//3tn27ZtTnNzs3PnnXc6zz///EZ36YrCD37wAwfART8f+chHHMc5vxXpT/7kT5ze3l6npaXFec973uMcP368oo7p6Wnn4Ycfdtra2pxkMul89KMfdYrF4gbczcbBNIYAnK985SuqTKlUcn7nd37HyWQyTmtrq/PBD37QGR8fr6jn7bffdh588EEnHo87XV1dzmc/+1lnZWXlMt/NxuE3f/M3naGhIae5udnp7u523vOe9yjydZxwDGuBTsDhWNrhwx/+sNPf3+80Nzc7W7ZscT784Q87J0+eVN9frnEMzwMOESJEiBAhNgCbygccIkSIECFCXC0ICThEiBAhQoTYAIQEHCJEiBAhQmwAQgIOESJEiBAhNgAhAYcIESJEiBAbgJCAQ4QIESJEiA1ASMAhQoQIESLEBiAk4BAhQoQIEWIDEBJwiBAhQoQIsQEICThEiBAhQoTYAIQEHCJEiBAhQmwA/h98RZkJ0aXveQAAAABJRU5ErkJggg==",
"text/plain": [
""
]
@@ -112,12 +114,16 @@
}
],
"source": [
+ "test_input_folder = \"/tmp/simple_app\"\n",
+ "test_input_path = test_input_folder + \"/normal-brain-mri-4.png\"\n",
+ "\n",
"!python -c \"import wget\" || pip install -q \"wget\"\n",
+ "!mkdir -p {test_input_folder}\n",
"\n",
"from skimage import io\n",
"import wget\n",
"\n",
- "test_input_path = \"/tmp/normal-brain-mri-4.png\"\n",
+ "\n",
"wget.download(\"https://user-images.githubusercontent.com/1928522/133383228-2357d62d-316c-46ad-af8a-359b56f25c87.png\", test_input_path)\n",
"\n",
"print(f\"Test input file path: {test_input_path!r}\")\n",
@@ -127,168 +133,280 @@
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
- "### Setup imports\n",
+ "### Set up environment variables\n",
+ "The application uses well-known enviornment variables for the input/output data path, working dir, as well as AI model file path if applicable. Defaults are used if these environment variable are absent.\n",
"\n",
- "Let's import necessary classes/decorators to define Application and Operator."
+ "In this example, only the input data path and output path need to be set."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "env: HOLOSCAN_INPUT_FOLDER=/tmp/simple_app\n",
+ "env: HOLOSCAN_INPUT_PATH=/tmp/simple_app/normal-brain-mri-4.png\n",
+ "env: HOLOSCAN_OUTPUT_PATH=output\n",
+ "/tmp/simple_app/normal-brain-mri-4.png\n"
+ ]
+ }
+ ],
+ "source": [
+ "output_path = \"output\"\n",
+ "%env HOLOSCAN_INPUT_FOLDER {test_input_folder}\n",
+ "%env HOLOSCAN_INPUT_PATH {test_input_path}\n",
+ "%env HOLOSCAN_OUTPUT_PATH {output_path}\n",
+ "%ls $HOLOSCAN_INPUT_PATH"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Setup imports\n",
+ "\n",
+ "Let's import necessary classes/decorators to define the application and operators."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
"outputs": [],
"source": [
- "import monai.deploy.core as md # 'md' stands for MONAI Deploy (or can use 'core' instead)\n",
- "from monai.deploy.core import (\n",
- " Application,\n",
- " DataPath,\n",
- " ExecutionContext,\n",
- " Image,\n",
- " InputContext,\n",
- " IOType,\n",
- " Operator,\n",
- " OutputContext,\n",
- ")"
+ "from pathlib import Path\n",
+ "\n",
+ "from monai.deploy.conditions import CountCondition\n",
+ "from monai.deploy.core import AppContext, Application, ConditionType, Fragment, Operator, OperatorSpec"
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"### Creating Operator classes\n",
"\n",
- "Each Operator class inherits [Operator](/modules/_autosummary/monai.deploy.core.Operator) class and input/output properties are specified by using [@input](/modules/_autosummary/monai.deploy.core.input)/[@output](/modules/_autosummary/monai.deploy.core.output) decorators.\n",
- "\n",
- "Note that the first operator(SobelOperator)'s input and the last operator(GaussianOperator)'s output are [DataPath](/modules/_autosummary/monai.deploy.core.domain.DataPath) type with [IOType.DISK](/modules/_autosummary/monai.deploy.core.IOType). Those paths are mapped into input and output paths given by the user during the execution.\n",
+ "Each Operator class inherits from the [Operator](/modules/_autosummary/monai.deploy.core.Operator) class, with the input and output ports of the operator specified using the `setup` method. Business logic would be implemented in the compute method.\n",
"\n",
- "Business logic would be implemented in the compute() method.\n",
+ ":::{note}\n",
+ "- the way to specify operator input and output in this version of the App SDK is different from versions, up to and including V0.5, where Python decorators are used. Decorator support will be re-introduced in future releases\n",
+ "- the first operator(SobelOperator)'s input and the last operator(GaussianOperator)'s output are data paths, which are not data types supported by operator ports but as object can be used as optional input and output. In the example, these paths are passed in as arguments to the constructor and the operator classes have defined logic on using the paths, e.g. reading from or writing to the path. The application class is responsible for setting the path by parsing the well-known environment variables\n",
+ ":::\n",
"\n",
"#### SobelOperator\n",
"\n",
- "SobelOperator is the first operator (A root operator in the workflow graph). op_input.get(label) (since only one input is defined in this operator, we don't need to specify an input label) would return an object of [DataPath](/modules/_autosummary/monai.deploy.core.domain.DataPath) and the input file/folder path would be available by accessing the `path` property (`op_input.get().path`).\n",
+ "SobelOperator is the first operator (the root operator in the workflow graph). It reads from the input file/folder path, which is passed in as an argument on the constructor and assigned to an attribute.\n",
"\n",
- "Once an image data (as a Numpy array) is loaded and processed, [Image](/modules/_autosummary/monai.deploy.core.domain.Image) object is created from the image data and set to the output (op_output.set(value, label) )."
+ "Once loaded and processed, the image data (as a Numpy array) is set to the output (op_output.emit(value, label) )."
]
},
{
"cell_type": "code",
- "execution_count": 4,
+ "execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
- "@md.input(\"image\", DataPath, IOType.DISK)\n",
- "@md.output(\"image\", Image, IOType.IN_MEMORY)\n",
- "# If `pip_packages` is specified, the definition will be aggregated with the package dependency list of other\n",
- "# operators and the application in packaging time.\n",
- "# @md.env(pip_packages=[\"scikit-image >= 0.17.2\"])\n",
"class SobelOperator(Operator):\n",
" \"\"\"This Operator implements a Sobel edge detector.\n",
"\n",
- " It has a single input and single output.\n",
+ " It has the following input and output:\n",
+ " single input:\n",
+ " a image file, first one found in the input folder\n",
+ " single output:\n",
+ " array object in memory\n",
" \"\"\"\n",
"\n",
- " def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):\n",
+ " DEFAULT_INPUT_FOLDER = Path.cwd() / \"input\"\n",
+ "\n",
+ " def __init__(self, fragment: Fragment, *args, input_path: Path, **kwargs):\n",
+ " \"\"\"Create an instance to be part of the given application (fragment).\n",
+ "\n",
+ " Args:\n",
+ " fragment (Fragment): An instance of the Application class which is derived from Fragment\n",
+ " input_path (Path): The path of the input image file or folder containing the image file\n",
+ " \"\"\"\n",
+ " self.index = 0\n",
+ "\n",
+ " # May want to validate the path, but it should really be validated when the compute function is called, also,\n",
+ " # when file path as input is supported in the operator or execution context, input_folder needs not an attribute.\n",
+ " self.input_path = (\n",
+ " input_path if input_path else SobelOperator.DEFAULT_INPUT_FOLDER\n",
+ " )\n",
+ "\n",
+ " # Need to call the base class constructor last\n",
+ " super().__init__(fragment, *args, **kwargs)\n",
+ "\n",
+ " def setup(self, spec: OperatorSpec):\n",
+ " spec.output(\"out1\")\n",
+ "\n",
+ " def compute(self, op_input, op_output, context):\n",
" from skimage import filters, io\n",
"\n",
- " input_path = op_input.get().path\n",
+ " self.index += 1\n",
+ " print(f\"Number of times operator {self.name} whose class is defined in {__name__} called: {self.index}\")\n",
+ "\n",
+ " # Ideally the op_input or execution context should provide the file path\n",
+ " # to read data from, for operators that are file input based.\n",
+ " # For now, use a temporary way to get input path. e.g. value set on init\n",
+ " input_path = self.input_path\n",
+ " print(f\"Input from: {input_path}, whose absolute path: {input_path.absolute()}\")\n",
" if input_path.is_dir():\n",
" input_path = next(input_path.glob(\"*.*\")) # take the first file\n",
"\n",
" data_in = io.imread(input_path)[:, :, :3] # discard alpha channel if exists\n",
" data_out = filters.sobel(data_in)\n",
"\n",
- " op_output.set(Image(data_out))"
+ " op_output.emit(data_out, \"out1\")"
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"#### MedianOperator\n",
"\n",
- "MedianOperator is a middle operator that accepts data from SobelOperator and pass the processed image data to GaussianOperator.\n",
- "\n",
- "Its input and output data types are [Image](/modules/_autosummary/monai.deploy.core.domain.Image) and the Numpy array data is available through `asnumpy()` method (`op_input.get().asnumpy()`).\n",
+ "MedianOperator is a middle operator that accepts data from SobelOperator and passes the processed image data to GaussianOperator.\n",
"\n",
- "Again, once an image data (as a Numpy array) is loaded and processed, [Image](/modules/_autosummary/monai.deploy.core.domain.Image) object is created and set to the output (op_output.set(value, label) )."
+ "Its input data type is image in Numpy array. Once received at the input (`op_input.receive(label)`), the image is transformed and set to the output (`op_output.emit(value, label)`)."
]
},
{
"cell_type": "code",
- "execution_count": 5,
+ "execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
- "@md.input(\"image\", Image, IOType.IN_MEMORY)\n",
- "@md.output(\"image\", Image, IOType.IN_MEMORY)\n",
- "# If `pip_packages` is specified, the definition will be aggregated with the package dependency list of other\n",
- "# operators and the application in packaging time.\n",
- "# @md.env(pip_packages=[\"scikit-image >= 0.17.2\"])\n",
"class MedianOperator(Operator):\n",
" \"\"\"This Operator implements a noise reduction.\n",
"\n",
" The algorithm is based on the median operator.\n",
- " It ingests a single input and provides a single output.\n",
+ " It ingests a single input and provides a single output, both are in-memory image arrays\n",
" \"\"\"\n",
"\n",
- " def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):\n",
+ " # Define __init__ method with super().__init__() if you want to override the default behavior.\n",
+ " def __init__(self, fragment: Fragment, *args, **kwargs):\n",
+ " \"\"\"Create an instance to be part of the given application (fragment).\n",
+ "\n",
+ " Args:\n",
+ " fragment (Fragment): The instance of Application class which is derived from Fragment\n",
+ " \"\"\"\n",
+ "\n",
+ " self.index = 0\n",
+ "\n",
+ " # Need to call the base class constructor last\n",
+ " super().__init__(fragment, *args, **kwargs)\n",
+ "\n",
+ " def setup(self, spec: OperatorSpec):\n",
+ " spec.input(\"in1\")\n",
+ " spec.output(\"out1\")\n",
+ "\n",
+ " def compute(self, op_input, op_output, context):\n",
" from skimage.filters import median\n",
"\n",
- " data_in = op_input.get().asnumpy()\n",
+ " self.index += 1\n",
+ " print(f\"Number of times operator {self.name} whose class is defined in {__name__} called: {self.index}\")\n",
+ " data_in = op_input.receive(\"in1\")\n",
" data_out = median(data_in)\n",
- " op_output.set(Image(data_out))"
+ " op_output.emit(data_out, \"out1\")"
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"#### GaussianOperator\n",
"\n",
- "GaussianOperator is the last operator (A leaf operator in the workflow graph) and the output path of this operator is mapped to the user-provided output folder so we cannot set a path to `op_output` variable (e.g., `op_output.set(Image(data_out))`).\n",
+ "GaussianOperator is the last operator (a leaf operator in the workflow graph) and saves the processed image to a file, whose path is provided via an argument on the constructor.\n",
"\n",
- "Instead, we can get the output path through `op_output.get().path` and save the processed image data into a file."
+ "This operator can also output the image in Numpy array in memory without requiring a receiver for it. This can be set up by using the optional output condition in the function `setup`."
]
},
{
"cell_type": "code",
- "execution_count": 6,
+ "execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
- "@md.input(\"image\", Image, IOType.IN_MEMORY)\n",
- "@md.output(\"image\", DataPath, IOType.DISK)\n",
- "# If `pip_packages` is specified, the definition will be aggregated with the package dependency list of other\n",
- "# operators and the application in packaging time.\n",
- "# @md.env(pip_packages=[\"scikit-image >= 0.17.2\"])\n",
"class GaussianOperator(Operator):\n",
" \"\"\"This Operator implements a smoothening based on Gaussian.\n",
"\n",
- " It ingests a single input and provides a single output.\n",
+ " It has the following input and output:\n",
+ " single input:\n",
+ " an image array object\n",
+ " single output:\n",
+ " an image arrary object, without enforcing a downsteam receiver\n",
+ "\n",
+ " Besides, this operator also saves the image file in the given output folder.\n",
" \"\"\"\n",
"\n",
- " def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):\n",
+ " DEFAULT_OUTPUT_FOLDER = Path.cwd() / \"output\"\n",
+ "\n",
+ " def __init__(self, fragment: Fragment, *args, output_folder: Path, **kwargs):\n",
+ " \"\"\"Create an instance to be part of the given application (fragment).\n",
+ "\n",
+ " Args:\n",
+ " fragment (Fragment): The instance of Application class which is derived from Fragment\n",
+ " output_folder (Path): The folder to save the output file.\n",
+ " \"\"\"\n",
+ " self.output_folder = output_folder if output_folder else GaussianOperator.DEFAULT_OUTPUT_FOLDER\n",
+ " self.index = 0\n",
+ "\n",
+ " # If `self.sigma_default` is set here (e.g., `self.sigma_default = 0.2`), then\n",
+ " # the default value by `param()` in `setup()` will be ignored.\n",
+ " # (you can just call `spec.param(\"sigma_default\")` in `setup()` to use the\n",
+ " # default value)\n",
+ " self.sigma_default = 0.2\n",
+ " self.channel_axis = 2\n",
+ "\n",
+ " # Need to call the base class constructor last\n",
+ " super().__init__(fragment, *args, **kwargs)\n",
+ "\n",
+ " def setup(self, spec: OperatorSpec):\n",
+ " spec.input(\"in1\")\n",
+ " spec.output(\"out1\").condition(ConditionType.NONE) # Condition is for no or not-ready receiver ports.\n",
+ " spec.param(\"sigma_default\", 0.2)\n",
+ " spec.param(\"channel_axis\", 2)\n",
+ "\n",
+ " def compute(self, op_input, op_output, context):\n",
" from skimage.filters import gaussian\n",
" from skimage.io import imsave\n",
" import numpy as np\n",
"\n",
- " data_in = op_input.get().asnumpy()\n",
- " data_out = gaussian(data_in, sigma=0.2, channel_axis=2)\n",
+ " self.index += 1\n",
+ " print(f\"Number of times operator {self.name} whose class is defined in {__name__} called: {self.index}\")\n",
+ "\n",
+ " data_in = op_input.receive(\"in1\")\n",
+ " data_out = gaussian(data_in, sigma=self.sigma_default, channel_axis=self.channel_axis)\n",
"\n",
" # Make sure the data type is what PIL Image can support, as the imsave function calls PIL Image fromarray()\n",
" # Some details can be found at https://stackoverflow.com/questions/55319949/pil-typeerror-cannot-handle-this-data-type\n",
+ " print(f\"Data type of output: {type(data_out)!r}, max = {np.max(data_out)!r}\")\n",
" if np.max(data_out) <= 1:\n",
- " data_out = (data_out * 255).astype(np.uint8)\n",
+ " data_out = (data_out*255).astype(np.uint8)\n",
+ " print(f\"Data type of output post conversion: {type(data_out)!r}, max = {np.max(data_out)!r}\")\n",
+ "\n",
+ " # For now, use attribute of self to find the output path.\n",
+ " self.output_folder.mkdir(parents=True, exist_ok=True)\n",
+ " output_path = self.output_folder / \"final_output.png\"\n",
+ " imsave(output_path, data_out)\n",
"\n",
- " output_folder = op_output.get().path\n",
- " output_path = output_folder / \"final_output.png\"\n",
- " imsave(output_path, data_out)"
+ " op_output.emit(data_out, \"out1\")\n"
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -298,18 +416,30 @@
"\n",
"It defines `App` class, inheriting [Application](/modules/_autosummary/monai.deploy.core.Application) class.\n",
"\n",
- "The requirements (resource and package dependency) for the App can be specified by using [@resource](/modules/_autosummary/monai.deploy.core.resource) and [@env](/modules/_autosummary/monai.deploy.core.env) decorators."
+ "In `compose()` method, objects of `SobelOperator`, `MedianOperator`, and `GaussianOperator` classes are created\n",
+ "and connected through self.add_flow() .\n",
+ "\n",
+ "> add_flow(source_op, destination_op, io_map=None)\n",
+ "\n",
+ "`io_map` is a dictionary of mapping from the source operator's label to the destination operator's label(s) and its type is `Set[Tuple[str, str]]`.\n",
+ "\n",
+ "We can skip specifying `io_map` if both the number of `source_op`'s outputs and the number of `destination_op`'s inputs are one so `self.add_flow(sobel_op, median_op)` is same with `self.add_flow(sobel_op, median_op, {\"image\": \"image\"})` or `self.add_flow(sobel_op, median_op, {\"image\": {\"image\"}})`."
]
},
{
"cell_type": "code",
- "execution_count": 7,
+ "execution_count": 8,
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "The statement, App().run(), is needed when this is run directly by the interpreter.\n"
+ ]
+ }
+ ],
"source": [
- "@md.resource(cpu=1)\n",
- "# pip_packages can be a string that is a path(str) to requirements.txt file or a list of packages.\n",
- "@md.env(pip_packages=[\"scikit-image >= 0.17.2\"])\n",
"class App(Application):\n",
" \"\"\"This is a very basic application.\n",
"\n",
@@ -329,31 +459,44 @@
" Each operator has a single input and a single output port.\n",
" Each operator performs some kind of image processing function.\n",
" \"\"\"\n",
- " sobel_op = SobelOperator()\n",
- " median_op = MedianOperator()\n",
- " gaussian_op = GaussianOperator()\n",
+ " app_context = Application.init_app_context({}) # Do not pass argv in Jupyter notebook\n",
+ " sample_data_path = Path(app_context.input_path)\n",
+ " output_data_path = Path(app_context.output_path)\n",
+ " print(f\"sample_data_path: {sample_data_path}\")\n",
+ "\n",
+ " # Please note that the Application object, self, is passed as the first positonal argument\n",
+ " # and the others as kwargs.\n",
+ " # Also note the CountCondition of 1 on the first operator, indicating to the application executor\n",
+ " # to invoke this operator, hence the pipleline, only once.\n",
+ " sobel_op = SobelOperator(self, CountCondition(self, 1), input_path=sample_data_path, name=\"sobel_op\")\n",
+ " median_op = MedianOperator(self, name=\"median_op\")\n",
+ " gaussian_op = GaussianOperator(self, output_folder=output_data_path, name=\"gaussian_op\")\n",
+ " self.add_flow(\n",
+ " sobel_op,\n",
+ " median_op,\n",
+ " {\n",
+ " (\"out1\", \"in1\"),\n",
+ " },\n",
+ " )\n",
+ " self.add_flow(\n",
+ " median_op,\n",
+ " gaussian_op,\n",
+ " {\n",
+ " (\n",
+ " \"out1\",\n",
+ " \"in1\",\n",
+ " )\n",
+ " },\n",
+ " ) # Using port name is optional for single port cases\n",
"\n",
- " self.add_flow(sobel_op, median_op)\n",
- " # self.add_flow(sobel_op, median_op, {\"image\": {\"image\"}})\n",
"\n",
- " self.add_flow(median_op, gaussian_op)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "In `compose()` method, objects of `SobelOperator`, `MedianOperator`, and `GaussianOperator` classes are created\n",
- "and connected through self.add_flow() .\n",
- "\n",
- "> add_flow(source_op, destination_op, io_map=None)\n",
- "\n",
- "`io_map` is a dictionary of mapping from the source operator's label to the destination operator's label(s) and its type is `Dict[str, str|Set[str]]`. \n",
- "\n",
- "We can skip specifying `io_map` if both the number of `source_op`'s outputs and the number of `destination_op`'s inputs are one so `self.add_flow(sobel_op, median_op)` is same with `self.add_flow(sobel_op, median_op, {\"image\": \"image\"})` or `self.add_flow(sobel_op, median_op, {\"image\": {\"image\"}})`.\n"
+ "if __name__ == \"__main__\":\n",
+ " print(\"The statement, App().run(), is needed when this is run directly by the interpreter.\")\n",
+ " # App().run()"
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -362,41 +505,67 @@
"We can execute the app in the Jupyter notebook."
]
},
- {
- "cell_type": "code",
- "execution_count": 8,
- "metadata": {},
- "outputs": [],
- "source": [
- "app = App()"
- ]
- },
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "[2023-08-30 00:09:09,515] [INFO] (root) - Parsed args: Namespace(argv=[], input=None, log_level=None, model=None, output=None, workdir=None)\n",
+ "[2023-08-30 00:09:09,523] [INFO] (root) - AppContext object: AppContext(input_path=/tmp/simple_app/normal-brain-mri-4.png, output_path=output, model_path=models, workdir=)\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "sample_data_path: /tmp/simple_app/normal-brain-mri-4.png\n",
+ "Number of times operator sobel_op whose class is defined in __main__ called: 1\n",
+ "Input from: /tmp/simple_app/normal-brain-mri-4.png, whose absolute path: /tmp/simple_app/normal-brain-mri-4.png\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "[info] [gxf_executor.cpp:210] Creating context\n",
+ "[info] [gxf_executor.cpp:1595] Loading extensions from configs...\n",
+ "[info] [gxf_executor.cpp:1741] Activating Graph...\n",
+ "[info] [gxf_executor.cpp:1771] Running Graph...\n",
+ "[info] [gxf_executor.cpp:1773] Waiting for completion...\n",
+ "[info] [gxf_executor.cpp:1774] Graph execution waiting. Fragment: \n",
+ "[info] [greedy_scheduler.cpp:190] Scheduling 3 entities\n"
+ ]
+ },
{
"name": "stdout",
"output_type": "stream",
"text": [
- "\u001b[34mGoing to initiate execution of operator SobelOperator\u001b[39m\n",
- "\u001b[32mExecuting operator SobelOperator \u001b[33m(Process ID: 392143, Operator ID: f824ca43-651a-4ec8-a9ff-d3575b31234b)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator SobelOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator MedianOperator\u001b[39m\n",
- "\u001b[32mExecuting operator MedianOperator \u001b[33m(Process ID: 392143, Operator ID: 01534244-2cde-499d-a060-1b5443a1618b)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator MedianOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator GaussianOperator\u001b[39m\n",
- "\u001b[32mExecuting operator GaussianOperator \u001b[33m(Process ID: 392143, Operator ID: 6547b79e-aab7-4e63-a0b6-e0b5a5c35286)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator GaussianOperator\n",
- "\u001b[39m\n"
+ "Number of times operator median_op whose class is defined in __main__ called: 1\n",
+ "Number of times operator gaussian_op whose class is defined in __main__ called: 1\n",
+ "Data type of output: , max = 0.35821119421406195\n",
+ "Data type of output post conversion: , max = 91\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "[info] [greedy_scheduler.cpp:369] Scheduler stopped: Some entities are waiting for execution, but there are no periodic or async entities to get out of the deadlock.\n",
+ "[info] [greedy_scheduler.cpp:398] Scheduler finished.\n",
+ "[info] [gxf_executor.cpp:1783] Graph execution deactivating. Fragment: \n",
+ "[info] [gxf_executor.cpp:1784] Deactivating Graph...\n",
+ "[info] [gxf_executor.cpp:1787] Graph execution finished. Fragment: \n",
+ "[info] [gxf_executor.cpp:229] Destroying context\n"
]
}
],
"source": [
- "app.run(input=test_input_path, output=\"output\")"
+ "!rm -rf {output_path}\n",
+ "App().run()"
]
},
{
@@ -408,12 +577,12 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "final_output.png output.json\n"
+ "final_output.png\n"
]
}
],
"source": [
- "!ls output"
+ "!ls {output_path}"
]
},
{
@@ -424,7 +593,7 @@
{
"data": {
"text/plain": [
- ""
+ ""
]
},
"execution_count": 11,
@@ -433,7 +602,7 @@
},
{
"data": {
- "image/png": "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",
+ "image/png": "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",
"text/plain": [
""
]
@@ -443,11 +612,13 @@
}
],
"source": [
- "output_image = io.imread(\"output/final_output.png\")\n",
+ "output_image_path = output_path + \"/final_output.png\"\n",
+ "output_image = io.imread(output_image_path)\n",
"io.imshow(output_image)"
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -481,6 +652,7 @@
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -502,35 +674,65 @@
],
"source": [
"%%writefile simple_imaging_app/sobel_operator.py\n",
- "import monai.deploy.core as md\n",
- "from monai.deploy.core import (\n",
- " DataPath,\n",
- " ExecutionContext,\n",
- " Image,\n",
- " InputContext,\n",
- " IOType,\n",
- " Operator,\n",
- " OutputContext,\n",
- ")\n",
- "\n",
- "\n",
- "@md.input(\"image\", DataPath, IOType.DISK)\n",
- "@md.output(\"image\", Image, IOType.IN_MEMORY)\n",
+ "\n",
+ "from pathlib import Path\n",
+ "from monai.deploy.core import Fragment, Operator, OperatorSpec\n",
+ "\n",
"class SobelOperator(Operator):\n",
- " def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):\n",
+ " \"\"\"This Operator implements a Sobel edge detector.\n",
+ "\n",
+ " It has the following input and output:\n",
+ " single input:\n",
+ " a image file, first one found in the input folder\n",
+ " single output:\n",
+ " array object in memory\n",
+ " \"\"\"\n",
+ "\n",
+ " DEFAULT_INPUT_FOLDER = Path.cwd() / \"input\"\n",
+ "\n",
+ " def __init__(self, fragment: Fragment, *args, input_path: Path, **kwargs):\n",
+ " \"\"\"Create an instance to be part of the given application (fragment).\n",
+ "\n",
+ " Args:\n",
+ " fragment (Fragment): An instance of the Application class which is derived from Fragment\n",
+ " input_path (Path): The path of the input image file or folder containing the image file\n",
+ " \"\"\"\n",
+ " self.index = 0\n",
+ "\n",
+ " # May want to validate the path, but it should really be validated when the compute function is called, also,\n",
+ " # when file path as input is supported in the operator or execution context, input_folder needs not an attribute.\n",
+ " self.input_path = (\n",
+ " input_path if input_path else SobelOperator.DEFAULT_INPUT_FOLDER\n",
+ " )\n",
+ "\n",
+ " # Need to call the base class constructor last\n",
+ " super().__init__(fragment, *args, **kwargs)\n",
+ "\n",
+ " def setup(self, spec: OperatorSpec):\n",
+ " spec.output(\"out1\")\n",
+ "\n",
+ " def compute(self, op_input, op_output, context):\n",
" from skimage import filters, io\n",
"\n",
- " input_path = op_input.get().path\n",
+ " self.index += 1\n",
+ " print(f\"Number of times operator {self.name} whose class is defined in {__name__} called: {self.index}\")\n",
+ "\n",
+ " # Ideally the op_input or execution context should provide the file path\n",
+ " # to read data from, for operators that are file input based.\n",
+ " # For now, use a temporary way to get input path. e.g. value set on init\n",
+ " input_path = self.input_path\n",
+ " print(f\"Input from: {input_path}, whose absolute path: {input_path.absolute()}\")\n",
" if input_path.is_dir():\n",
" input_path = next(input_path.glob(\"*.*\")) # take the first file\n",
"\n",
" data_in = io.imread(input_path)[:, :, :3] # discard alpha channel if exists\n",
" data_out = filters.sobel(data_in)\n",
"\n",
- " op_output.set(Image(data_out))"
+ " op_output.emit(data_out, \"out1\")"
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -552,22 +754,47 @@
],
"source": [
"%%writefile simple_imaging_app/median_operator.py\n",
- "import monai.deploy.core as md\n",
- "from monai.deploy.core import ExecutionContext, Image, InputContext, IOType, Operator, OutputContext, output\n",
+ "from monai.deploy.core import Fragment, Operator, OperatorSpec\n",
"\n",
"\n",
- "@md.input(\"image\", Image, IOType.IN_MEMORY)\n",
- "@md.output(\"image\", Image, IOType.IN_MEMORY)\n",
+ "# Decorator support is not available in this version of the SDK, to be re-introduced later\n",
+ "# @md.env(pip_packages=[\"scikit-image >= 0.17.2\"])\n",
"class MedianOperator(Operator):\n",
- " def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):\n",
+ " \"\"\"This Operator implements a noise reduction.\n",
+ "\n",
+ " The algorithm is based on the median operator.\n",
+ " It ingests a single input and provides a single output, both are in-memory image arrays\n",
+ " \"\"\"\n",
+ "\n",
+ " # Define __init__ method with super().__init__() if you want to override the default behavior.\n",
+ " def __init__(self, fragment: Fragment, *args, **kwargs):\n",
+ " \"\"\"Create an instance to be part of the given application (fragment).\n",
+ "\n",
+ " Args:\n",
+ " fragment (Fragment): The instance of Application class which is derived from Fragment\n",
+ " \"\"\"\n",
+ "\n",
+ " self.index = 0\n",
+ "\n",
+ " # Need to call the base class constructor last\n",
+ " super().__init__(fragment, *args, **kwargs)\n",
+ "\n",
+ " def setup(self, spec: OperatorSpec):\n",
+ " spec.input(\"in1\")\n",
+ " spec.output(\"out1\")\n",
+ "\n",
+ " def compute(self, op_input, op_output, context):\n",
" from skimage.filters import median\n",
"\n",
- " data_in = op_input.get().asnumpy()\n",
+ " self.index += 1\n",
+ " print(f\"Number of times operator {self.name} whose class is defined in {__name__} called: {self.index}\")\n",
+ " data_in = op_input.receive(\"in1\")\n",
" data_out = median(data_in)\n",
- " op_output.set(Image(data_out))"
+ " op_output.emit(data_out, \"out1\")\n"
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -589,40 +816,81 @@
],
"source": [
"%%writefile simple_imaging_app/gaussian_operator.py\n",
- "import monai.deploy.core as md\n",
- "from monai.deploy.core import (\n",
- " DataPath,\n",
- " ExecutionContext,\n",
- " Image,\n",
- " InputContext,\n",
- " IOType,\n",
- " Operator,\n",
- " OutputContext,\n",
- ")\n",
- "\n",
- "\n",
- "@md.input(\"image\", Image, IOType.IN_MEMORY)\n",
- "@md.output(\"image\", DataPath, IOType.DISK)\n",
+ "from pathlib import Path\n",
+ "\n",
+ "from monai.deploy.core import ConditionType, Fragment, Operator, OperatorSpec\n",
+ "\n",
+ "\n",
+ "# Decorator support is not available in this version of the SDK, to be re-introduced later\n",
+ "# @md.env(pip_packages=[\"scikit-image >= 0.17.2\"])\n",
"class GaussianOperator(Operator):\n",
- " def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):\n",
+ " \"\"\"This Operator implements a smoothening based on Gaussian.\n",
+ "\n",
+ " It has the following input and output:\n",
+ " single input:\n",
+ " an image array object\n",
+ " single output:\n",
+ " an image arrary object, without enforcing a downsteam receiver\n",
+ "\n",
+ " Besides, this operator also saves the image file in the given output folder.\n",
+ " \"\"\"\n",
+ "\n",
+ " DEFAULT_OUTPUT_FOLDER = Path.cwd() / \"output\"\n",
+ "\n",
+ " def __init__(self, fragment: Fragment, *args, output_folder: Path, **kwargs):\n",
+ " \"\"\"Create an instance to be part of the given application (fragment).\n",
+ "\n",
+ " Args:\n",
+ " fragment (Fragment): The instance of Application class which is derived from Fragment\n",
+ " output_folder (Path): The folder to save the output file.\n",
+ " \"\"\"\n",
+ " self.output_folder = output_folder if output_folder else GaussianOperator.DEFAULT_OUTPUT_FOLDER\n",
+ " self.index = 0\n",
+ "\n",
+ " # If `self.sigma_default` is set here (e.g., `self.sigma_default = 0.2`), then\n",
+ " # the default value by `param()` in `setup()` will be ignored.\n",
+ " # (you can just call `spec.param(\"sigma_default\")` in `setup()` to use the\n",
+ " # default value)\n",
+ " self.sigma_default = 0.2\n",
+ " self.channel_axis = 2\n",
+ "\n",
+ " # Need to call the base class constructor last\n",
+ " super().__init__(fragment, *args, **kwargs)\n",
+ "\n",
+ " def setup(self, spec: OperatorSpec):\n",
+ " spec.input(\"in1\")\n",
+ " spec.output(\"out1\").condition(ConditionType.NONE) # Condition is for no or not-ready receiver ports.\n",
+ " spec.param(\"sigma_default\", 0.2)\n",
+ " spec.param(\"channel_axis\", 2)\n",
+ "\n",
+ " def compute(self, op_input, op_output, context):\n",
" from skimage.filters import gaussian\n",
" from skimage.io import imsave\n",
" import numpy as np\n",
"\n",
- " data_in = op_input.get().asnumpy()\n",
- " data_out = gaussian(data_in, sigma=0.2, channel_axis=2)\n",
+ " self.index += 1\n",
+ " print(f\"Number of times operator {self.name} whose class is defined in {__name__} called: {self.index}\")\n",
+ "\n",
+ " data_in = op_input.receive(\"in1\")\n",
+ " data_out = gaussian(data_in, sigma=self.sigma_default, channel_axis=self.channel_axis)\n",
"\n",
" # Make sure the data type is what PIL Image can support, as the imsave function calls PIL Image fromarray()\n",
" # Some details can be found at https://stackoverflow.com/questions/55319949/pil-typeerror-cannot-handle-this-data-type\n",
+ " print(f\"Data type of output: {type(data_out)!r}, max = {np.max(data_out)!r}\")\n",
" if np.max(data_out) <= 1:\n",
- " data_out = (data_out * 255).astype(np.uint8)\n",
+ " data_out = (data_out*255).astype(np.uint8)\n",
+ " print(f\"Data type of output post conversion: {type(data_out)!r}, max = {np.max(data_out)!r}\")\n",
"\n",
- " output_folder = op_output.get().path\n",
- " output_path = output_folder / \"final_output.png\"\n",
- " imsave(output_path, data_out)"
+ " # For now, use attribute of self to find the output path.\n",
+ " self.output_folder.mkdir(parents=True, exist_ok=True)\n",
+ " output_path = self.output_folder / \"final_output.png\"\n",
+ " imsave(output_path, data_out)\n",
+ "\n",
+ " op_output.emit(data_out, \"out1\")\n"
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -644,37 +912,84 @@
],
"source": [
"%%writefile simple_imaging_app/app.py\n",
- "import monai.deploy.core as md\n",
+ "import logging\n",
+ "from pathlib import Path\n",
+ "\n",
"from gaussian_operator import GaussianOperator\n",
"from median_operator import MedianOperator\n",
"from sobel_operator import SobelOperator\n",
"\n",
- "from monai.deploy.core import Application\n",
+ "from monai.deploy.conditions import CountCondition\n",
+ "from monai.deploy.core import AppContext, Application\n",
"\n",
"\n",
- "@md.resource(cpu=1)\n",
- "@md.env(pip_packages=[\"scikit-image >= 0.17.2\"])\n",
+ "# Decorator support is not available in this version of the SDK, to be re-introduced later\n",
+ "# @resource(cpu=1)\n",
"class App(Application):\n",
+ " \"\"\"This is a very basic application.\n",
+ "\n",
+ " This showcases the MONAI Deploy application framework.\n",
+ " \"\"\"\n",
+ "\n",
+ " # App's name. ('App') if not specified.\n",
+ " name = \"simple_imaging_app\"\n",
+ " # App's description. if not specified.\n",
+ " description = \"This is a very simple application.\"\n",
+ " # App's version. or '0.0.0' if not specified.\n",
+ " version = \"0.1.0\"\n",
+ "\n",
" def compose(self):\n",
- " sobel_op = SobelOperator()\n",
- " median_op = MedianOperator()\n",
- " gaussian_op = GaussianOperator()\n",
+ " \"\"\"This application has three operators.\n",
+ "\n",
+ " Each operator has a single input and a single output port.\n",
+ " Each operator performs some kind of image processing function.\n",
+ " \"\"\"\n",
+ " # Use Commandline options over environment variables to init context.\n",
+ " app_context = Application.init_app_context(self.argv)\n",
+ " sample_data_path = Path(app_context.input_path)\n",
+ " output_data_path = Path(app_context.output_path)\n",
+ " logging.info(f\"sample_data_path: {sample_data_path}\")\n",
+ "\n",
+ " # Please note that the Application object, self, is passed as the first positonal argument\n",
+ " # and the others as kwargs.\n",
+ " # Also note the CountCondition of 1 on the first operator, indicating to the application executor\n",
+ " # to invoke this operator, hence the pipleline, only once.\n",
+ " sobel_op = SobelOperator(self, CountCondition(self, 1), input_path=sample_data_path, name=\"sobel_op\")\n",
+ " median_op = MedianOperator(self, name=\"median_op\")\n",
+ " gaussian_op = GaussianOperator(self, output_folder=output_data_path, name=\"gaussian_op\")\n",
+ " self.add_flow(\n",
+ " sobel_op,\n",
+ " median_op,\n",
+ " {\n",
+ " (\"out1\", \"in1\"),\n",
+ " },\n",
+ " )\n",
+ " self.add_flow(\n",
+ " median_op,\n",
+ " gaussian_op,\n",
+ " {\n",
+ " (\n",
+ " \"out1\",\n",
+ " \"in1\",\n",
+ " )\n",
+ " },\n",
+ " )\n",
"\n",
- " self.add_flow(sobel_op, median_op)\n",
- " self.add_flow(median_op, gaussian_op)\n",
"\n",
- "# Run the application when this file is executed.\n",
"if __name__ == \"__main__\":\n",
- " App(do_run=True)"
+ " logging.info(f\"Begin {__name__}\")\n",
+ " App().run()\n",
+ " logging.info(f\"End {__name__}\")\n"
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"```python\n",
"if __name__ == \"__main__\":\n",
- " App(do_run=True)\n",
+ " App().run()\n",
"```\n",
"\n",
"The above lines are needed to execute the application code by using `python` interpreter.\n",
@@ -702,7 +1017,7 @@
"from app import App\n",
"\n",
"if __name__ == \"__main__\":\n",
- " App(do_run=True)"
+ " App().run()"
]
},
{
@@ -714,8 +1029,8 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "app.py\t\t __main__.py\t __pycache__\n",
- "gaussian_operator.py median_operator.py sobel_operator.py\n"
+ "app.py\t gaussian_operator.py\tmedian_operator.py requirements.txt\n",
+ "app.yaml __main__.py\t\t__pycache__\t sobel_operator.py\n"
]
}
],
@@ -724,10 +1039,15 @@
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
- "In this time, let's execute the app in the command line."
+ "This time, let's execute the app in the command line.\n",
+ "\n",
+ ":::{note}\n",
+ "Since the environment variables have been set and contain the correct paths, it is not necessary to provide the command line options on running the application, though the following demonstrates the use of the options.\n",
+ ":::"
]
},
{
@@ -739,78 +1059,113 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "\u001b[34mGoing to initiate execution of operator SobelOperator\u001b[39m\n",
- "\u001b[32mExecuting operator SobelOperator \u001b[33m(Process ID: 392307, Operator ID: bf71b6a9-448b-4ec6-8c55-5adc01727491)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator SobelOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator MedianOperator\u001b[39m\n",
- "\u001b[32mExecuting operator MedianOperator \u001b[33m(Process ID: 392307, Operator ID: 9d65479c-d249-408a-9023-05c2948b2345)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator MedianOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator GaussianOperator\u001b[39m\n",
- "\u001b[32mExecuting operator GaussianOperator \u001b[33m(Process ID: 392307, Operator ID: 1789c85f-7a05-4d8c-90f5-d619eea35de2)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator GaussianOperator\n",
- "\u001b[39m\n"
+ "[2023-08-30 00:09:17,221] [INFO] (root) - Parsed args: Namespace(argv=['simple_imaging_app', '-i', '/tmp/simple_app', '-o', 'output', '-l', 'DEBUG'], input=PosixPath('/tmp/simple_app'), log_level='DEBUG', model=None, output=PosixPath('/home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/output'), workdir=None)\n",
+ "[2023-08-30 00:09:17,223] [INFO] (root) - AppContext object: AppContext(input_path=/tmp/simple_app, output_path=/home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/output, model_path=models, workdir=)\n",
+ "[2023-08-30 00:09:17,223] [INFO] (root) - sample_data_path: /tmp/simple_app\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:210] Creating context\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1595] Loading extensions from configs...\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1741] Activating Graph...\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1771] Running Graph...\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1773] Waiting for completion...\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1774] Graph execution waiting. Fragment: \n",
+ "[\u001b[32minfo\u001b[m] [greedy_scheduler.cpp:190] Scheduling 3 entities\n",
+ "Number of times operator sobel_op whose class is defined in sobel_operator called: 1\n",
+ "Input from: /tmp/simple_app, whose absolute path: /tmp/simple_app\n",
+ "[2023-08-30 00:09:17,302] [DEBUG] (PIL.PngImagePlugin) - STREAM b'IHDR' 16 13\n",
+ "[2023-08-30 00:09:17,302] [DEBUG] (PIL.PngImagePlugin) - STREAM b'sRGB' 41 1\n",
+ "[2023-08-30 00:09:17,302] [DEBUG] (PIL.PngImagePlugin) - STREAM b'gAMA' 54 4\n",
+ "[2023-08-30 00:09:17,302] [DEBUG] (PIL.PngImagePlugin) - STREAM b'pHYs' 70 9\n",
+ "[2023-08-30 00:09:17,302] [DEBUG] (PIL.PngImagePlugin) - STREAM b'IDAT' 91 65445\n",
+ "[2023-08-30 00:09:17,302] [DEBUG] (PIL.PngImagePlugin) - STREAM b'IHDR' 16 13\n",
+ "[2023-08-30 00:09:17,302] [DEBUG] (PIL.PngImagePlugin) - STREAM b'sRGB' 41 1\n",
+ "[2023-08-30 00:09:17,302] [DEBUG] (PIL.PngImagePlugin) - STREAM b'gAMA' 54 4\n",
+ "[2023-08-30 00:09:17,302] [DEBUG] (PIL.PngImagePlugin) - STREAM b'pHYs' 70 9\n",
+ "[2023-08-30 00:09:17,302] [DEBUG] (PIL.PngImagePlugin) - STREAM b'IDAT' 91 65445\n",
+ "[2023-08-30 00:09:17,308] [DEBUG] (PIL.Image) - Error closing: Operation on closed image\n",
+ "Number of times operator median_op whose class is defined in median_operator called: 1\n",
+ "Number of times operator gaussian_op whose class is defined in gaussian_operator called: 1\n",
+ "Data type of output: , max = 0.35821119421406195\n",
+ "Data type of output post conversion: , max = 91\n",
+ "[2023-08-30 00:09:17,513] [DEBUG] (PIL.Image) - Importing BlpImagePlugin\n",
+ "[2023-08-30 00:09:17,514] [DEBUG] (PIL.Image) - Importing BmpImagePlugin\n",
+ "[2023-08-30 00:09:17,514] [DEBUG] (PIL.Image) - Importing BufrStubImagePlugin\n",
+ "[2023-08-30 00:09:17,514] [DEBUG] (PIL.Image) - Importing CurImagePlugin\n",
+ "[2023-08-30 00:09:17,515] [DEBUG] (PIL.Image) - Importing DcxImagePlugin\n",
+ "[2023-08-30 00:09:17,515] [DEBUG] (PIL.Image) - Importing DdsImagePlugin\n",
+ "[2023-08-30 00:09:17,515] [DEBUG] (PIL.Image) - Importing EpsImagePlugin\n",
+ "[2023-08-30 00:09:17,516] [DEBUG] (PIL.Image) - Importing FitsImagePlugin\n",
+ "[2023-08-30 00:09:17,516] [DEBUG] (PIL.Image) - Importing FliImagePlugin\n",
+ "[2023-08-30 00:09:17,516] [DEBUG] (PIL.Image) - Importing FpxImagePlugin\n",
+ "[2023-08-30 00:09:17,516] [DEBUG] (PIL.Image) - Image: failed to import FpxImagePlugin: No module named 'olefile'\n",
+ "[2023-08-30 00:09:17,516] [DEBUG] (PIL.Image) - Importing FtexImagePlugin\n",
+ "[2023-08-30 00:09:17,517] [DEBUG] (PIL.Image) - Importing GbrImagePlugin\n",
+ "[2023-08-30 00:09:17,517] [DEBUG] (PIL.Image) - Importing GifImagePlugin\n",
+ "[2023-08-30 00:09:17,517] [DEBUG] (PIL.Image) - Importing GribStubImagePlugin\n",
+ "[2023-08-30 00:09:17,517] [DEBUG] (PIL.Image) - Importing Hdf5StubImagePlugin\n",
+ "[2023-08-30 00:09:17,517] [DEBUG] (PIL.Image) - Importing IcnsImagePlugin\n",
+ "[2023-08-30 00:09:17,518] [DEBUG] (PIL.Image) - Importing IcoImagePlugin\n",
+ "[2023-08-30 00:09:17,518] [DEBUG] (PIL.Image) - Importing ImImagePlugin\n",
+ "[2023-08-30 00:09:17,519] [DEBUG] (PIL.Image) - Importing ImtImagePlugin\n",
+ "[2023-08-30 00:09:17,519] [DEBUG] (PIL.Image) - Importing IptcImagePlugin\n",
+ "[2023-08-30 00:09:17,519] [DEBUG] (PIL.Image) - Importing JpegImagePlugin\n",
+ "[2023-08-30 00:09:17,519] [DEBUG] (PIL.Image) - Importing Jpeg2KImagePlugin\n",
+ "[2023-08-30 00:09:17,519] [DEBUG] (PIL.Image) - Importing McIdasImagePlugin\n",
+ "[2023-08-30 00:09:17,520] [DEBUG] (PIL.Image) - Importing MicImagePlugin\n",
+ "[2023-08-30 00:09:17,520] [DEBUG] (PIL.Image) - Image: failed to import MicImagePlugin: No module named 'olefile'\n",
+ "[2023-08-30 00:09:17,520] [DEBUG] (PIL.Image) - Importing MpegImagePlugin\n",
+ "[2023-08-30 00:09:17,520] [DEBUG] (PIL.Image) - Importing MpoImagePlugin\n",
+ "[2023-08-30 00:09:17,522] [DEBUG] (PIL.Image) - Importing MspImagePlugin\n",
+ "[2023-08-30 00:09:17,522] [DEBUG] (PIL.Image) - Importing PalmImagePlugin\n",
+ "[2023-08-30 00:09:17,523] [DEBUG] (PIL.Image) - Importing PcdImagePlugin\n",
+ "[2023-08-30 00:09:17,523] [DEBUG] (PIL.Image) - Importing PcxImagePlugin\n",
+ "[2023-08-30 00:09:17,523] [DEBUG] (PIL.Image) - Importing PdfImagePlugin\n",
+ "[2023-08-30 00:09:17,528] [DEBUG] (PIL.Image) - Importing PixarImagePlugin\n",
+ "[2023-08-30 00:09:17,528] [DEBUG] (PIL.Image) - Importing PngImagePlugin\n",
+ "[2023-08-30 00:09:17,528] [DEBUG] (PIL.Image) - Importing PpmImagePlugin\n",
+ "[2023-08-30 00:09:17,528] [DEBUG] (PIL.Image) - Importing PsdImagePlugin\n",
+ "[2023-08-30 00:09:17,528] [DEBUG] (PIL.Image) - Importing QoiImagePlugin\n",
+ "[2023-08-30 00:09:17,528] [DEBUG] (PIL.Image) - Importing SgiImagePlugin\n",
+ "[2023-08-30 00:09:17,528] [DEBUG] (PIL.Image) - Importing SpiderImagePlugin\n",
+ "[2023-08-30 00:09:17,529] [DEBUG] (PIL.Image) - Importing SunImagePlugin\n",
+ "[2023-08-30 00:09:17,529] [DEBUG] (PIL.Image) - Importing TgaImagePlugin\n",
+ "[2023-08-30 00:09:17,529] [DEBUG] (PIL.Image) - Importing TiffImagePlugin\n",
+ "[2023-08-30 00:09:17,529] [DEBUG] (PIL.Image) - Importing WebPImagePlugin\n",
+ "[2023-08-30 00:09:17,530] [DEBUG] (PIL.Image) - Importing WmfImagePlugin\n",
+ "[2023-08-30 00:09:17,530] [DEBUG] (PIL.Image) - Importing XbmImagePlugin\n",
+ "[2023-08-30 00:09:17,531] [DEBUG] (PIL.Image) - Importing XpmImagePlugin\n",
+ "[2023-08-30 00:09:17,531] [DEBUG] (PIL.Image) - Importing XVThumbImagePlugin\n",
+ "[\u001b[32minfo\u001b[m] [greedy_scheduler.cpp:369] Scheduler stopped: Some entities are waiting for execution, but there are no periodic or async entities to get out of the deadlock.\n",
+ "[\u001b[32minfo\u001b[m] [greedy_scheduler.cpp:398] Scheduler finished.\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1783] Graph execution deactivating. Fragment: \n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1784] Deactivating Graph...\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1787] Graph execution finished. Fragment: \n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:229] Destroying context\n"
]
}
],
"source": [
- "!python simple_imaging_app -i {test_input_path} -o output"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Above command is same with the following command line:"
+ "!rm -rf {output_path}\n",
+ "!python simple_imaging_app -i {test_input_folder} -o {output_path} -l DEBUG"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\u001b[34mGoing to initiate execution of operator SobelOperator\u001b[39m\n",
- "\u001b[32mExecuting operator SobelOperator \u001b[33m(Process ID: 392355, Operator ID: db7c9af2-0d61-4ef0-80a3-225659635f8c)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator SobelOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator MedianOperator\u001b[39m\n",
- "\u001b[32mExecuting operator MedianOperator \u001b[33m(Process ID: 392355, Operator ID: 523c9aeb-7683-4043-bc44-fece70361921)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator MedianOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator GaussianOperator\u001b[39m\n",
- "\u001b[32mExecuting operator GaussianOperator \u001b[33m(Process ID: 392355, Operator ID: db126942-577f-482e-b241-db43f2c473fa)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator GaussianOperator\n",
- "\u001b[39m\n"
- ]
- }
- ],
- "source": [
- "!monai-deploy exec simple_imaging_app -i {test_input_path} -o output"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 21,
- "metadata": {},
"outputs": [
{
"data": {
"text/plain": [
- ""
+ ""
]
},
- "execution_count": 21,
+ "execution_count": 20,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
- "image/png": "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",
+ "image/png": "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",
"text/plain": [
""
]
@@ -820,11 +1175,13 @@
}
],
"source": [
- "output_image = io.imread(\"output/final_output.png\")\n",
+ "#output_image_path was set as before, output_image_path = output_path + \"/final_output.png\"\n",
+ "output_image = io.imread(output_image_path)\n",
"io.imshow(output_image)"
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -832,10 +1189,43 @@
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
- "Let's package the app with MONAI Application Packager ."
+ "Let's package the app with MONAI Application Packager .\n",
+ "\n",
+ "In this version of the App SDK, we need to write out the configuration yaml file as well as the package requirements file, in the application folder."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Overwriting simple_imaging_app/app.yaml\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%writefile simple_imaging_app/app.yaml\n",
+ "%YAML 1.2\n",
+ "---\n",
+ "application:\n",
+ " title: MONAI Deploy App Package - Simple Imaging App\n",
+ " version: 1.0\n",
+ " inputFormats: [\"file\"]\n",
+ " outputFormats: [\"file\"]\n",
+ "\n",
+ "resources:\n",
+ " cpu: 1\n",
+ " gpu: 1\n",
+ " memory: 1Gi\n",
+ " gpuMemory: 1Gi"
]
},
{
@@ -847,53 +1237,396 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "Building MONAI Application Package... -\u001b[1A\u001b[1B\u001b[0G\u001b[?25l[+] Building 0.0s (0/1) \n",
- "\u001b[?25h\u001b[1A\u001b[0G\u001b[?25l[+] Building 0.1s (4/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m => [internal] load build context 0.0s\n",
- "\u001b[34m => => transferring context: 486.62kB 0.0s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[?25\\\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 0.2s (20/20) FINISHED \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring context: 486.62kB 0.0s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [11/15] RUN echo \"User site package location: $(python3 -m sit 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [12/15] COPY ./map/app.json /etc/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [13/15] COPY ./map/pkg.json /etc/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [14/15] COPY ./app /opt/monai/app 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [15/15] WORKDIR /var/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => exporting to image 0.0s\n",
- "\u001b[0m\u001b[34m => => exporting layers 0.0s\n",
- "\u001b[0m\u001b[34m => => writing image sha256:8da4c014d84a849aba76089e7f497f8988f14cb52b9b4 0.0s\n",
- "\u001b[0m\u001b[34m => => naming to docker.io/library/simple_app:latest 0.0s\n",
- "\u001b[0m\u001b[?25Done\n",
- "[2023-07-11 12:14:27,059] [INFO] (app_packager) - Successfully built simple_app:latest\n"
+ "Overwriting simple_imaging_app/requirements.txt\n"
+ ]
+ }
+ ],
+ "source": [
+ "%%writefile simple_imaging_app/requirements.txt\n",
+ "scikit-image\n",
+ "setuptools>=59.5.0 # for pkg_resources\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Now we can use the CLI package command to build the MONAI Application Package (MAP) container image based on a supported base image."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[2023-08-30 00:09:20,073] [INFO] (packager.parameters) - Application: /home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/simple_imaging_app\n",
+ "[2023-08-30 00:09:20,073] [INFO] (packager.parameters) - Detected application type: Python Module\n",
+ "[2023-08-30 00:09:20,074] [INFO] (packager) - Reading application configuration from /home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/simple_imaging_app/app.yaml...\n",
+ "[2023-08-30 00:09:20,075] [INFO] (packager) - Generating app.json...\n",
+ "[2023-08-30 00:09:20,075] [INFO] (packager) - Generating pkg.json...\n",
+ "[2023-08-30 00:09:20,076] [DEBUG] (common) - \n",
+ "=============== Begin app.json ===============\n",
+ "{\n",
+ " \"apiVersion\": \"1.0.0\",\n",
+ " \"command\": \"[\\\"python3\\\", \\\"/opt/holoscan/app\\\"]\",\n",
+ " \"environment\": {\n",
+ " \"HOLOSCAN_APPLICATION\": \"/opt/holoscan/app\",\n",
+ " \"HOLOSCAN_INPUT_PATH\": \"input/\",\n",
+ " \"HOLOSCAN_OUTPUT_PATH\": \"output/\",\n",
+ " \"HOLOSCAN_WORKDIR\": \"/var/holoscan\",\n",
+ " \"HOLOSCAN_MODEL_PATH\": \"/opt/holoscan/models\",\n",
+ " \"HOLOSCAN_CONFIG_PATH\": \"/var/holoscan/app.yaml\",\n",
+ " \"HOLOSCAN_APP_MANIFEST_PATH\": \"/etc/holoscan/app.json\",\n",
+ " \"HOLOSCAN_PKG_MANIFEST_PATH\": \"/etc/holoscan/pkg.json\",\n",
+ " \"HOLOSCAN_DOCS_PATH\": \"/opt/holoscan/docs\",\n",
+ " \"HOLOSCAN_LOGS_PATH\": \"/var/holoscan/logs\"\n",
+ " },\n",
+ " \"input\": {\n",
+ " \"path\": \"input/\",\n",
+ " \"formats\": null\n",
+ " },\n",
+ " \"liveness\": null,\n",
+ " \"output\": {\n",
+ " \"path\": \"output/\",\n",
+ " \"formats\": null\n",
+ " },\n",
+ " \"readiness\": null,\n",
+ " \"sdk\": \"monai-deploy\",\n",
+ " \"sdkVersion\": \"0.6.0\",\n",
+ " \"timeout\": 0,\n",
+ " \"version\": 1.0,\n",
+ " \"workingDirectory\": \"/var/holoscan\"\n",
+ "}\n",
+ "================ End app.json ================\n",
+ " \n",
+ "[2023-08-30 00:09:20,076] [DEBUG] (common) - \n",
+ "=============== Begin pkg.json ===============\n",
+ "{\n",
+ " \"apiVersion\": \"1.0.0\",\n",
+ " \"applicationRoot\": \"/opt/holoscan/app\",\n",
+ " \"modelRoot\": \"/opt/holoscan/models\",\n",
+ " \"models\": {},\n",
+ " \"resources\": {\n",
+ " \"cpu\": 1,\n",
+ " \"gpu\": 1,\n",
+ " \"memory\": \"1Gi\",\n",
+ " \"gpuMemory\": \"1Gi\"\n",
+ " },\n",
+ " \"version\": 1.0\n",
+ "}\n",
+ "================ End pkg.json ================\n",
+ " \n",
+ "[2023-08-30 00:09:20,088] [DEBUG] (packager.builder) - \n",
+ "========== Begin Dockerfile ==========\n",
+ "\n",
+ "\n",
+ "FROM nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu\n",
+ "\n",
+ "ENV DEBIAN_FRONTEND=noninteractive\n",
+ "ENV TERM=xterm-256color\n",
+ "\n",
+ "ARG UNAME\n",
+ "ARG UID\n",
+ "ARG GID\n",
+ "\n",
+ "RUN mkdir -p /etc/holoscan/ \\\n",
+ " && mkdir -p /opt/holoscan/ \\\n",
+ " && mkdir -p /var/holoscan \\\n",
+ " && mkdir -p /opt/holoscan/app \\\n",
+ " && mkdir -p /var/holoscan/input \\\n",
+ " && mkdir -p /var/holoscan/output\n",
+ "\n",
+ "LABEL base=\"nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu\"\n",
+ "LABEL tag=\"simple_imaging_app:1.0\"\n",
+ "LABEL org.opencontainers.image.title=\"MONAI Deploy App Package - Simple Imaging App\"\n",
+ "LABEL org.opencontainers.image.version=\"1.0\"\n",
+ "LABEL org.nvidia.holoscan=\"0.6.0\"\n",
+ "\n",
+ "ENV HOLOSCAN_ENABLE_HEALTH_CHECK=true\n",
+ "ENV HOLOSCAN_INPUT_PATH=/var/holoscan/input\n",
+ "ENV HOLOSCAN_OUTPUT_PATH=/var/holoscan/output\n",
+ "ENV HOLOSCAN_WORKDIR=/var/holoscan\n",
+ "ENV HOLOSCAN_APPLICATION=/opt/holoscan/app\n",
+ "ENV HOLOSCAN_TIMEOUT=0\n",
+ "ENV HOLOSCAN_MODEL_PATH=/opt/holoscan/models\n",
+ "ENV HOLOSCAN_DOCS_PATH=/opt/holoscan/docs\n",
+ "ENV HOLOSCAN_CONFIG_PATH=/var/holoscan/app.yaml\n",
+ "ENV HOLOSCAN_APP_MANIFEST_PATH=/etc/holoscan/app.json\n",
+ "ENV HOLOSCAN_PKG_MANIFEST_PATH=/etc/holoscan/pkg.json\n",
+ "ENV HOLOSCAN_LOGS_PATH=/var/holoscan/logs\n",
+ "ENV PATH=/root/.local/bin:/opt/nvidia/holoscan:$PATH\n",
+ "ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/libtorch/1.13.1/lib/:/opt/nvidia/holoscan/lib\n",
+ "\n",
+ "RUN apt-get update \\\n",
+ " && apt-get install -y curl jq \\\n",
+ " && rm -rf /var/lib/apt/lists/*\n",
+ "\n",
+ "ENV PYTHONPATH=\"/opt/holoscan/app:$PYTHONPATH\"\n",
+ "\n",
+ "\n",
+ "\n",
+ "RUN groupadd -g $GID $UNAME\n",
+ "RUN useradd -rm -d /home/$UNAME -s /bin/bash -g $GID -G sudo -u $UID $UNAME\n",
+ "RUN chown -R holoscan /var/holoscan \n",
+ "RUN chown -R holoscan /var/holoscan/input \n",
+ "RUN chown -R holoscan /var/holoscan/output \n",
+ "\n",
+ "# Set the working directory\n",
+ "WORKDIR /var/holoscan\n",
+ "\n",
+ "# Copy HAP/MAP tool script\n",
+ "COPY ./tools /var/holoscan/tools\n",
+ "RUN chmod +x /var/holoscan/tools\n",
+ "\n",
+ "\n",
+ "# Copy gRPC health probe\n",
+ "\n",
+ "USER $UNAME\n",
+ "\n",
+ "ENV PATH=/root/.local/bin:/home/holoscan/.local/bin:/opt/nvidia/holoscan:$PATH\n",
+ "\n",
+ "COPY ./pip/requirements.txt /tmp/requirements.txt\n",
+ "\n",
+ "RUN pip install --upgrade pip\n",
+ "RUN pip install --no-cache-dir --user -r /tmp/requirements.txt\n",
+ "\n",
+ "# Install Holoscan from PyPI org\n",
+ "RUN pip install holoscan==0.6.0\n",
+ "\n",
+ "\n",
+ "# Copy user-specified MONAI Deploy SDK file\n",
+ "COPY ./monai_deploy_app_sdk-0.5.1+22.g029f8bc.dirty-py3-none-any.whl /tmp/monai_deploy_app_sdk-0.5.1+22.g029f8bc.dirty-py3-none-any.whl\n",
+ "RUN pip install /tmp/monai_deploy_app_sdk-0.5.1+22.g029f8bc.dirty-py3-none-any.whl\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "COPY ./map/app.json /etc/holoscan/app.json\n",
+ "COPY ./app.config /var/holoscan/app.yaml\n",
+ "COPY ./map/pkg.json /etc/holoscan/pkg.json\n",
+ "\n",
+ "COPY ./app /opt/holoscan/app\n",
+ "\n",
+ "ENTRYPOINT [\"/var/holoscan/tools\"]\n",
+ "=========== End Dockerfile ===========\n",
+ "\n",
+ "[2023-08-30 00:09:20,088] [INFO] (packager.builder) - \n",
+ "===============================================================================\n",
+ "Building image for: x64-workstation\n",
+ " Architecture: linux/amd64\n",
+ " Base Image: nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu\n",
+ " Build Image: N/A \n",
+ " Cache: Enabled\n",
+ " Configuration: dgpu\n",
+ " Holoiscan SDK Package: pypi.org\n",
+ " MONAI Deploy App SDK Package: /home/mqin/src/monai-deploy-app-sdk/dist/monai_deploy_app_sdk-0.5.1+22.g029f8bc.dirty-py3-none-any.whl\n",
+ " gRPC Health Probe: N/A\n",
+ " SDK Version: 0.6.0\n",
+ " SDK: monai-deploy\n",
+ " Tag: simple_imaging_app-x64-workstation-dgpu-linux-amd64:1.0\n",
+ " \n",
+ "[2023-08-30 00:09:20,333] [INFO] (common) - Using existing Docker BuildKit builder `holoscan_app_builder`\n",
+ "[2023-08-30 00:09:20,333] [DEBUG] (packager.builder) - Building Holoscan Application Package: tag=simple_imaging_app-x64-workstation-dgpu-linux-amd64:1.0\n",
+ "#1 [internal] load .dockerignore\n",
+ "#1 transferring context: 33B\n",
+ "#1 transferring context: 1.79kB done\n",
+ "#1 DONE 0.1s\n",
+ "\n",
+ "#2 [internal] load build definition from Dockerfile\n",
+ "#2 transferring dockerfile: 2.64kB done\n",
+ "#2 DONE 0.1s\n",
+ "\n",
+ "#3 [internal] load metadata for nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu\n",
+ "#3 DONE 0.4s\n",
+ "\n",
+ "#4 [internal] load build context\n",
+ "#4 DONE 0.0s\n",
+ "\n",
+ "#5 importing cache manifest from local:10108727038215150215\n",
+ "#5 DONE 0.0s\n",
+ "\n",
+ "#6 [ 1/21] FROM nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu@sha256:9653f80f241fd542f25afbcbcf7a0d02ed7e5941c79763e69def5b1e6d9fb7bc\n",
+ "#6 resolve nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu@sha256:9653f80f241fd542f25afbcbcf7a0d02ed7e5941c79763e69def5b1e6d9fb7bc 0.0s done\n",
+ "#6 DONE 0.0s\n",
+ "\n",
+ "#7 importing cache manifest from nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu\n",
+ "#7 DONE 0.9s\n",
+ "\n",
+ "#4 [internal] load build context\n",
+ "#4 transferring context: 163.39kB 0.0s done\n",
+ "#4 DONE 0.1s\n",
+ "\n",
+ "#8 [ 9/21] WORKDIR /var/holoscan\n",
+ "#8 CACHED\n",
+ "\n",
+ "#9 [13/21] RUN pip install --upgrade pip\n",
+ "#9 CACHED\n",
+ "\n",
+ "#10 [ 4/21] RUN groupadd -g 1000 holoscan\n",
+ "#10 CACHED\n",
+ "\n",
+ "#11 [12/21] COPY ./pip/requirements.txt /tmp/requirements.txt\n",
+ "#11 CACHED\n",
+ "\n",
+ "#12 [ 6/21] RUN chown -R holoscan /var/holoscan\n",
+ "#12 CACHED\n",
+ "\n",
+ "#13 [15/21] RUN pip install holoscan==0.6.0\n",
+ "#13 CACHED\n",
+ "\n",
+ "#14 [16/21] COPY ./monai_deploy_app_sdk-0.5.1+22.g029f8bc.dirty-py3-none-any.whl /tmp/monai_deploy_app_sdk-0.5.1+22.g029f8bc.dirty-py3-none-any.whl\n",
+ "#14 CACHED\n",
+ "\n",
+ "#15 [ 8/21] RUN chown -R holoscan /var/holoscan/output\n",
+ "#15 CACHED\n",
+ "\n",
+ "#16 [ 3/21] RUN apt-get update && apt-get install -y curl jq && rm -rf /var/lib/apt/lists/*\n",
+ "#16 CACHED\n",
+ "\n",
+ "#17 [11/21] RUN chmod +x /var/holoscan/tools\n",
+ "#17 CACHED\n",
+ "\n",
+ "#18 [ 7/21] RUN chown -R holoscan /var/holoscan/input\n",
+ "#18 CACHED\n",
+ "\n",
+ "#19 [14/21] RUN pip install --no-cache-dir --user -r /tmp/requirements.txt\n",
+ "#19 CACHED\n",
+ "\n",
+ "#20 [ 2/21] RUN mkdir -p /etc/holoscan/ && mkdir -p /opt/holoscan/ && mkdir -p /var/holoscan && mkdir -p /opt/holoscan/app && mkdir -p /var/holoscan/input && mkdir -p /var/holoscan/output\n",
+ "#20 CACHED\n",
+ "\n",
+ "#21 [20/21] COPY ./map/pkg.json /etc/holoscan/pkg.json\n",
+ "#21 CACHED\n",
+ "\n",
+ "#22 [17/21] RUN pip install /tmp/monai_deploy_app_sdk-0.5.1+22.g029f8bc.dirty-py3-none-any.whl\n",
+ "#22 CACHED\n",
+ "\n",
+ "#23 [19/21] COPY ./app.config /var/holoscan/app.yaml\n",
+ "#23 CACHED\n",
+ "\n",
+ "#24 [10/21] COPY ./tools /var/holoscan/tools\n",
+ "#24 CACHED\n",
+ "\n",
+ "#25 [18/21] COPY ./map/app.json /etc/holoscan/app.json\n",
+ "#25 CACHED\n",
+ "\n",
+ "#26 [ 5/21] RUN useradd -rm -d /home/holoscan -s /bin/bash -g 1000 -G sudo -u 1000 holoscan\n",
+ "#26 CACHED\n",
+ "\n",
+ "#27 [21/21] COPY ./app /opt/holoscan/app\n",
+ "#27 CACHED\n",
+ "\n",
+ "#28 exporting to docker image format\n",
+ "#28 exporting layers done\n",
+ "#28 exporting manifest sha256:7a414ac96708c13dd2e15e2134807075b96eb40f1e16a0c9caf433f415792140 done\n",
+ "#28 exporting config sha256:1e2e576a3d23da01c03efa3c866cf22ecbcb75fa628e7edb6f2e0ffa7f6900b3 done\n",
+ "#28 sending tarball\n",
+ "#28 ...\n",
+ "\n",
+ "#29 importing to docker\n",
+ "#29 DONE 0.5s\n",
+ "\n",
+ "#28 exporting to docker image format\n",
+ "#28 sending tarball 40.7s done\n",
+ "#28 DONE 40.7s\n",
+ "\n",
+ "#30 exporting content cache\n",
+ "#30 preparing build cache for export\n",
+ "#30 writing layer sha256:0709800848b4584780b40e7e81200689870e890c38b54e96b65cd0a3b1942f2d done\n",
+ "#30 writing layer sha256:0ce020987cfa5cd1654085af3bb40779634eb3d792c4a4d6059036463ae0040d done\n",
+ "#30 writing layer sha256:0f65089b284381bf795d15b1a186e2a8739ea957106fa526edef0d738e7cda70 done\n",
+ "#30 writing layer sha256:12a47450a9f9cc5d4edab65d0f600dbbe8b23a1663b0b3bb2c481d40e074b580 done\n",
+ "#30 writing layer sha256:1de965777e2e37c7fabe00bdbf3d0203ca83ed30a71a5479c3113fe4fc48c4bb done\n",
+ "#30 writing layer sha256:24b5aa2448e920814dd67d7d3c0169b2cdacb13c4048d74ded3b4317843b13ff done\n",
+ "#30 writing layer sha256:268c96d4e21881b9b02957ef94da0eeb249c2b670d35bd1099347ae0f15b7a9b done\n",
+ "#30 writing layer sha256:2d42104dbf0a7cc962b791f6ab4f45a803f8a36d296f996aca180cfb2f3e30d0 done\n",
+ "#30 writing layer sha256:2fa1ce4fa3fec6f9723380dc0536b7c361d874add0baaddc4bbf2accac82d2ff done\n",
+ "#30 writing layer sha256:38794be1b5dc99645feabf89b22cd34fb5bdffb5164ad920e7df94f353efe9c0 done\n",
+ "#30 writing layer sha256:38f963dc57c1e7b68a738fe39ed9f9345df7188111a047e2163a46648d7f1d88 done\n",
+ "#30 writing layer sha256:3e7e4c9bc2b136814c20c04feb4eea2b2ecf972e20182d88759931130cfb4181 done\n",
+ "#30 writing layer sha256:3fd77037ad585442cd82d64e337f49a38ddba50432b2a1e563a48401d25c79e6 done\n",
+ "#30 writing layer sha256:41814ed91034b30ac9c44dfc604a4bade6138005ccf682372c02e0bead66dbc0 done\n",
+ "#30 writing layer sha256:45893188359aca643d5918c9932da995364dc62013dfa40c075298b1baabece3 done\n",
+ "#30 writing layer sha256:49bc651b19d9e46715c15c41b7c0daa007e8e25f7d9518f04f0f06592799875a done\n",
+ "#30 writing layer sha256:4c12db5118d8a7d909e4926d69a2192d2b3cd8b110d49c7504a4f701258c1ccc done\n",
+ "#30 writing layer sha256:4cc43a803109d6e9d1fd35495cef9b1257035f5341a2db54f7a1940815b6cc65 done\n",
+ "#30 writing layer sha256:4d32b49e2995210e8937f0898327f196d3fcc52486f0be920e8b2d65f150a7ab done\n",
+ "#30 writing layer sha256:4d6fe980bad9cd7b2c85a478c8033cae3d098a81f7934322fb64658b0c8f9854 done\n",
+ "#30 writing layer sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1\n",
+ "#30 preparing build cache for export 0.5s done\n",
+ "#30 writing layer sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 done\n",
+ "#30 writing layer sha256:5150182f1ff123399b300ca469e00f6c4d82e1b9b72652fb8ee7eab370245236 done\n",
+ "#30 writing layer sha256:51d9df4b19947155e6a9772cfc44d4bde1be74b8e3b3019c525ccfb894d43ef4 done\n",
+ "#30 writing layer sha256:593b5820e1f0928ae3939148a0a3b9c58ed117b33fc61ffd184393d2e6c42cb4 done\n",
+ "#30 writing layer sha256:595c38fa102c61c3dda19bdab70dcd26a0e50465b986d022a84fa69023a05d0f done\n",
+ "#30 writing layer sha256:59d451175f6950740e26d38c322da0ef67cb59da63181eb32996f752ba8a2f17 done\n",
+ "#30 writing layer sha256:5ad1f2004580e415b998124ea394e9d4072a35d70968118c779f307204d6bd17 done\n",
+ "#30 writing layer sha256:5eb65183a3d11174b5abe72026da705ac8258f9056e8e11ac3ca28ed6db3fbc5 done\n",
+ "#30 writing layer sha256:62598eafddf023e7f22643485f4321cbd51ff7eee743b970db12454fd3c8c675 done\n",
+ "#30 writing layer sha256:63d7e616a46987136f4cc9eba95db6f6327b4854cfe3c7e20fed6db0c966e380 done\n",
+ "#30 writing layer sha256:6939d591a6b09b14a437e5cd2d6082a52b6d76bec4f72d960440f097721da34f done\n",
+ "#30 writing layer sha256:698318e5a60e5e0d48c45bf992f205a9532da567fdfe94bd59be2e192975dd6f done\n",
+ "#30 writing layer sha256:6ddc1d0f91833b36aac1c6f0c8cea005c87d94bab132d46cc06d9b060a81cca3 done\n",
+ "#30 writing layer sha256:74ac1f5a47c0926bff1e997bb99985a09926f43bd0895cb27ceb5fa9e95f8720 done\n",
+ "#30 writing layer sha256:7577973918dd30e764733a352a93f418000bc3181163ca451b2307492c1a6ba9 done\n",
+ "#30 writing layer sha256:839f7088ab6d6cdaab613aab7f1ec078aa2a909559f4592f9dcb34ad4c8a1e42 done\n",
+ "#30 writing layer sha256:886c886d8a09d8befb92df75dd461d4f97b77d7cff4144c4223b0d2f6f2c17f2 done\n",
+ "#30 writing layer sha256:8a7451db9b4b817b3b33904abddb7041810a4ffe8ed4a034307d45d9ae9b3f2a done\n",
+ "#30 writing layer sha256:916f4054c6e7f10de4fd7c08ffc75fa23ebecca4eceb8183cb1023b33b1696c9 done\n",
+ "#30 writing layer sha256:9463aa3f56275af97693df69478a2dc1d171f4e763ca6f7b6f370a35e605c154 done\n",
+ "#30 writing layer sha256:94c4f534ca3de906e1661bb9bccbfa9f9748d875d1d92778697a61e3e762ffde done\n",
+ "#30 writing layer sha256:955fd173ed884230c2eded4542d10a97384b408537be6bbb7c4ae09ccd6fb2d0 done\n",
+ "#30 writing layer sha256:9c42a4ee99755f441251e6043b2cbba16e49818a88775e7501ec17e379ce3cfd done\n",
+ "#30 writing layer sha256:9c63be0a86e3dc4168db3814bf464e40996afda0031649d9faa8ff7568c3154f done\n",
+ "#30 writing layer sha256:9d989b2672cdb90093e998e0b94c689332d25e7494c1dfff74bb086cc7dab05a done\n",
+ "#30 writing layer sha256:9e04bda98b05554953459b5edef7b2b14d32f1a00b979a23d04b6eb5c191e66b done\n",
+ "#30 writing layer sha256:a4a0c690bc7da07e592514dccaa26098a387e8457f69095e922b6d73f7852502 done\n",
+ "#30 writing layer sha256:a4aafbc094d78a85bef41036173eb816a53bcd3e2564594a32f542facdf2aba6 done\n",
+ "#30 writing layer sha256:ae36a4d38b76948e39a5957025c984a674d2de18ce162a8caaa536e6f06fccea done\n",
+ "#30 writing layer sha256:b2fa40114a4a0725c81b327df89c0c3ed5c05ca9aa7f1157394d5096cf5460ce done\n",
+ "#30 writing layer sha256:b48a5fafcaba74eb5d7e7665601509e2889285b50a04b5b639a23f8adc818157 done\n",
+ "#30 writing layer sha256:c86976a083599e36a6441f36f553627194d05ea82bb82a78682e718fe62fccf6 done\n",
+ "#30 writing layer sha256:cb506fbdedc817e3d074f609e2edbf9655aacd7784610a1bbac52f2d7be25438 done\n",
+ "#30 writing layer sha256:d2a6fe65a1f84edb65b63460a75d1cac1aa48b72789006881b0bcfd54cd01ffd done\n",
+ "#30 writing layer sha256:d8d16d6af76dc7c6b539422a25fdad5efb8ada5a8188069fcd9d113e3b783304 done\n",
+ "#30 writing layer sha256:da250bc94d2969d5caed175341870b944c3b4a74c9af0bae1c1660fac13b7990 done\n",
+ "#30 writing layer sha256:ddc2ade4f6fe866696cb638c8a102cb644fa842c2ca578392802b3e0e5e3bcb7 done\n",
+ "#30 writing layer sha256:e2cfd7f6244d6f35befa6bda1caa65f1786cecf3f00ef99d7c9a90715ce6a03c done\n",
+ "#30 writing layer sha256:e94a4481e9334ff402bf90628594f64a426672debbdfb55f1290802e52013907 done\n",
+ "#30 writing layer sha256:eaf45e9f32d1f5a9983945a1a9f8dedbb475bc0f578337610e00b4dedec87c20 done\n",
+ "#30 writing layer sha256:eb411bef39c013c9853651e68f00965dbd826d829c4e478884a2886976e9c989 done\n",
+ "#30 writing layer sha256:edfe4a95eb6bd3142aeda941ab871ffcc8c19cf50c33561c210ba8ead2424759 done\n",
+ "#30 writing layer sha256:ef4466d6f927d29d404df9c5af3ef5733c86fa14e008762c90110b963978b1e7 done\n",
+ "#30 writing layer sha256:f346e3ecdf0bee048fa1e3baf1d3128ff0283b903f03e97524944949bd8882e5 done\n",
+ "#30 writing layer sha256:f3f9a00a1ce9aadda250aacb3e66a932676badc5d8519c41517fdf7ea14c13ed done\n",
+ "#30 writing layer sha256:f60a35c82433f4cfc4167240d52d87341204f29196716db10d5d1efceca61ea4 done\n",
+ "#30 writing layer sha256:fd849d9bd8889edd43ae38e9f21a912430c8526b2c18f3057a3b2cd74eb27b31 done\n",
+ "#30 writing layer sha256:ff1c6faca98dc5db7491d4ab471109c5932a09be6c6f87c1b375993719052c7c done\n",
+ "#30 writing config sha256:f998b87c5b1c42b3bd8b024c5ab2c7fb2e501296bef12002c76edd9f0f2904ed done\n",
+ "#30 writing manifest sha256:b7c4a839b7badff031c8a720d93abcb07ac1c0afe26d6a64a94cae167afa97d8 done\n",
+ "#30 DONE 0.5s\n",
+ "[2023-08-30 00:10:04,252] [INFO] (packager) - Build Summary:\n",
+ "\n",
+ "Platform: x64-workstation/dgpu\n",
+ " Status: Succeeded\n",
+ " Docker Tag: simple_imaging_app-x64-workstation-dgpu-linux-amd64:1.0\n",
+ " Tarball: None\n"
]
}
],
"source": [
- "!monai-deploy package simple_imaging_app --tag simple_app:latest # -l DEBUG"
+ "tag_prefix = \"simple_imaging_app\"\n",
+ "\n",
+ "!monai-deploy package simple_imaging_app -c simple_imaging_app/app.yaml -t {tag_prefix}:1.0 --platform x64-workstation -l DEBUG"
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -902,27 +1635,124 @@
"\n",
":::\n",
"\n",
- "We can see that the Docker image is created."
+ "We can see that the MAP Docker image is created."
]
},
{
"cell_type": "code",
- "execution_count": 23,
+ "execution_count": 24,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "simple_imaging_app-x64-workstation-dgpu-linux-amd64 1.0 1e2e576a3d23 45 minutes ago 10.8GB\n"
+ ]
+ }
+ ],
+ "source": [
+ "!docker image ls | grep {tag_prefix}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "We can choose to display and inspect the MAP manifests by running the container with the `show` command.\n",
+ "Furthermore, we can also extract the manifests and other contents in the MAP by using the `extract` command while mapping specific folder to the host's (we know that our MAP is compliant and supports these commands).\n",
+ "\n",
+ ":::{note}\n",
+ "The host folder for storing the extracted content must first be created by the user, and if it has been created by Docker on running the container, the folder needs to be deleted and re-created.\n",
+ ":::"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "simple_app latest 8da4c014d84a 34 minutes ago 15.1GB\n"
+ "Display manifests and extract MAP contents to the host folder, ./export\n",
+ "\n",
+ "============================== app.json ==============================\n",
+ "{\n",
+ " \"apiVersion\": \"1.0.0\",\n",
+ " \"command\": \"[\\\"python3\\\", \\\"/opt/holoscan/app\\\"]\",\n",
+ " \"environment\": {\n",
+ " \"HOLOSCAN_APPLICATION\": \"/opt/holoscan/app\",\n",
+ " \"HOLOSCAN_INPUT_PATH\": \"input/\",\n",
+ " \"HOLOSCAN_OUTPUT_PATH\": \"output/\",\n",
+ " \"HOLOSCAN_WORKDIR\": \"/var/holoscan\",\n",
+ " \"HOLOSCAN_MODEL_PATH\": \"/opt/holoscan/models\",\n",
+ " \"HOLOSCAN_CONFIG_PATH\": \"/var/holoscan/app.yaml\",\n",
+ " \"HOLOSCAN_APP_MANIFEST_PATH\": \"/etc/holoscan/app.json\",\n",
+ " \"HOLOSCAN_PKG_MANIFEST_PATH\": \"/etc/holoscan/pkg.json\",\n",
+ " \"HOLOSCAN_DOCS_PATH\": \"/opt/holoscan/docs\",\n",
+ " \"HOLOSCAN_LOGS_PATH\": \"/var/holoscan/logs\"\n",
+ " },\n",
+ " \"input\": {\n",
+ " \"path\": \"input/\",\n",
+ " \"formats\": null\n",
+ " },\n",
+ " \"liveness\": null,\n",
+ " \"output\": {\n",
+ " \"path\": \"output/\",\n",
+ " \"formats\": null\n",
+ " },\n",
+ " \"readiness\": null,\n",
+ " \"sdk\": \"monai-deploy\",\n",
+ " \"sdkVersion\": \"0.6.0\",\n",
+ " \"timeout\": 0,\n",
+ " \"version\": 1,\n",
+ " \"workingDirectory\": \"/var/holoscan\"\n",
+ "}\n",
+ "\n",
+ "============================== pkg.json ==============================\n",
+ "{\n",
+ " \"apiVersion\": \"1.0.0\",\n",
+ " \"applicationRoot\": \"/opt/holoscan/app\",\n",
+ " \"modelRoot\": \"/opt/holoscan/models\",\n",
+ " \"models\": {},\n",
+ " \"resources\": {\n",
+ " \"cpu\": 1,\n",
+ " \"gpu\": 1,\n",
+ " \"memory\": \"1Gi\",\n",
+ " \"gpuMemory\": \"1Gi\"\n",
+ " },\n",
+ " \"version\": 1\n",
+ "}\n",
+ "\n",
+ "2023-08-30 07:10:10 [INFO] Copying application from /opt/holoscan/app to /var/run/holoscan/export/app\n",
+ "\n",
+ "2023-08-30 07:10:10 [INFO] Copying application manifest file from /etc/holoscan/app.json to /var/run/holoscan/export/config/app.json\n",
+ "2023-08-30 07:10:10 [INFO] Copying pkg manifest file from /etc/holoscan/pkg.json to /var/run/holoscan/export/config/pkg.json\n",
+ "2023-08-30 07:10:10 [INFO] Copying application configuration from /var/holoscan/app.yaml to /var/run/holoscan/export/config/app.yaml\n",
+ "\n",
+ "2023-08-30 07:10:10 [INFO] Copying models from /opt/holoscan/models to /var/run/holoscan/export/models\n",
+ "2023-08-30 07:10:10 [INFO] '/opt/holoscan/models' cannot be found.\n",
+ "\n",
+ "2023-08-30 07:10:10 [INFO] Copying documentation from /opt/holoscan/docs/ to /var/run/holoscan/export/docs\n",
+ "2023-08-30 07:10:10 [INFO] '/opt/holoscan/docs/' cannot be found.\n",
+ "\n",
+ "app config\n"
]
}
],
"source": [
- "!docker image ls | grep simple_app"
+ "\n",
+ "!echo \"Display manifests and extract MAP contents to the host folder, ./export\"\n",
+ "!docker run --rm {tag_prefix}-x64-workstation-dgpu-linux-amd64:1.0 show\n",
+ "!rm -rf `pwd`/export && mkdir -p `pwd`/export\n",
+ "!docker run --rm -v `pwd`/export/:/var/run/holoscan/export/ {tag_prefix}-x64-workstation-dgpu-linux-amd64:1.0 extract\n",
+ "!ls `pwd`/export"
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -933,70 +1763,113 @@
},
{
"cell_type": "code",
- "execution_count": 24,
+ "execution_count": 26,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "MAP input folder files:\n",
- "normal-brain-mri-4.png\n",
- "Checking dependencies...\n",
- "--> Verifying if \"docker\" is installed...\n",
- "\n",
- "--> Verifying if \"simple_app:latest\" is available...\n",
- "\n",
- "Checking for MAP \"simple_app:latest\" locally\n",
- "\"simple_app:latest\" found.\n",
- "\n",
- "Reading MONAI App Package manifest...\n",
- "\u001b[sPreparing to copy...\u001b[?25l\u001b[u\u001b[2KCopying from container - 0B\u001b[?25h\u001b[u\u001b[2KSuccessfully copied 2.05kB to /tmp/tmp112gy4zc/app.json\n",
- "\u001b[sPreparing to copy...\u001b[?25l\u001b[u\u001b[2KCopying from container - 0B\u001b[?25h\u001b[u\u001b[2KSuccessfully copied 2.05kB to /tmp/tmp112gy4zc/pkg.json\n",
- "\u001b[34mGoing to initiate execution of operator SobelOperator\u001b[39m\n",
- "\u001b[32mExecuting operator SobelOperator \u001b[33m(Process ID: 1, Operator ID: dd587602-8c8b-464d-8c34-4c3904c57031)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator SobelOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator MedianOperator\u001b[39m\n",
- "\u001b[32mExecuting operator MedianOperator \u001b[33m(Process ID: 1, Operator ID: 08ebceb3-afb4-430a-8213-3524bded2b73)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator MedianOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator GaussianOperator\u001b[39m\n",
- "\u001b[32mExecuting operator GaussianOperator \u001b[33m(Process ID: 1, Operator ID: 12247318-62c2-43e4-9213-2a012ea07ec5)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator GaussianOperator\n",
- "\u001b[39m\n"
+ "[2023-08-30 00:10:13,473] [INFO] (runner) - Checking dependencies...\n",
+ "[2023-08-30 00:10:13,473] [INFO] (runner) - --> Verifying if \"docker\" is installed...\n",
+ "\n",
+ "[2023-08-30 00:10:13,473] [INFO] (runner) - --> Verifying if \"docker-buildx\" is installed...\n",
+ "\n",
+ "[2023-08-30 00:10:13,473] [INFO] (runner) - --> Verifying if \"simple_imaging_app-x64-workstation-dgpu-linux-amd64:1.0\" is available...\n",
+ "\n",
+ "[2023-08-30 00:10:13,539] [INFO] (runner) - Reading HAP/MAP manifest...\n",
+ "\u001b[sPreparing to copy...\u001b[?25l\u001b[u\u001b[2KCopying from container - 0B\u001b[?25h\u001b[u\u001b[2KSuccessfully copied 2.56kB to /tmp/tmpzdvb7nut/app.json\n",
+ "\u001b[sPreparing to copy...\u001b[?25l\u001b[u\u001b[2KCopying from container - 0B\u001b[?25h\u001b[u\u001b[2KSuccessfully copied 2.05kB to /tmp/tmpzdvb7nut/pkg.json\n",
+ "[2023-08-30 00:10:13,748] [INFO] (runner) - --> Verifying if \"nvidia-ctk\" is installed...\n",
+ "\n",
+ "[2023-08-30 00:10:13,942] [INFO] (common) - Launching container (0fbb33cb469e) using image 'simple_imaging_app-x64-workstation-dgpu-linux-amd64:1.0'...\n",
+ " container name: determined_leavitt\n",
+ " host name: mingq-dt\n",
+ " network: host\n",
+ " user: 1000:1000\n",
+ " ulimits: memlock=-1:-1, stack=67108864:67108864\n",
+ " cap_add: CAP_SYS_PTRACE\n",
+ " ipc mode: host\n",
+ " shared memory size: 67108864\n",
+ " devices: \n",
+ "2023-08-30 07:10:14 [INFO] Launching application python3 /opt/holoscan/app ...\n",
+ "\n",
+ "[2023-08-30 07:10:15,097] [INFO] (root) - Parsed args: Namespace(argv=['/opt/holoscan/app'], input=None, log_level=None, model=None, output=None, workdir=None)\n",
+ "\n",
+ "[2023-08-30 07:10:15,097] [INFO] (root) - AppContext object: AppContext(input_path=/var/holoscan/input, output_path=/var/holoscan/output, model_path=/opt/holoscan/models, workdir=/var/holoscan)\n",
+ "\n",
+ "[2023-08-30 07:10:15,098] [INFO] (root) - sample_data_path: /var/holoscan/input\n",
+ "\n",
+ "[info] [app_driver.cpp:1025] Launching the driver/health checking service\n",
+ "\n",
+ "[info] [gxf_executor.cpp:210] Creating context\n",
+ "\n",
+ "[info] [server.cpp:73] Health checking server listening on 0.0.0.0:8777\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1595] Loading extensions from configs...\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1741] Activating Graph...\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1771] Running Graph...\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1773] Waiting for completion...\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1774] Graph execution waiting. Fragment: \n",
+ "\n",
+ "[info] [greedy_scheduler.cpp:190] Scheduling 3 entities\n",
+ "\n",
+ "[info] [greedy_scheduler.cpp:369] Scheduler stopped: Some entities are waiting for execution, but there are no periodic or async entities to get out of the deadlock.\n",
+ "\n",
+ "[info] [greedy_scheduler.cpp:398] Scheduler finished.\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1783] Graph execution deactivating. Fragment: \n",
+ "\n",
+ "[info] [gxf_executor.cpp:1784] Deactivating Graph...\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1787] Graph execution finished. Fragment: \n",
+ "\n",
+ "[info] [gxf_executor.cpp:229] Destroying context\n",
+ "\n",
+ "Number of times operator sobel_op whose class is defined in sobel_operator called: 1\n",
+ "\n",
+ "Input from: /var/holoscan/input, whose absolute path: /var/holoscan/input\n",
+ "\n",
+ "Number of times operator median_op whose class is defined in median_operator called: 1\n",
+ "\n",
+ "Number of times operator gaussian_op whose class is defined in gaussian_operator called: 1\n",
+ "\n",
+ "Data type of output: , max = 0.35821119421406195\n",
+ "\n",
+ "Data type of output post conversion: , max = 91\n",
+ "\n",
+ "[2023-08-30 00:10:16,538] [INFO] (common) - Container 'determined_leavitt'(0fbb33cb469e) exited.\n"
]
}
],
"source": [
- "# Copy a test input file to 'input' folder\n",
- "!mkdir -p input && rm -rf input/*\n",
- "!cp {test_input_path} input/\n",
- "!echo \"MAP input folder files:\"\n",
- "!ls input\n",
- "\n",
- "# Launch the app\n",
- "!monai-deploy run simple_app:latest input output"
+ "# Clear the output folder and run the MAP container. The input is expected to be a folder\n",
+ "!rm -rf {output_path}\n",
+ "!monai-deploy run -i {test_input_folder} -o {output_path} {tag_prefix}-x64-workstation-dgpu-linux-amd64:1.0"
]
},
{
"cell_type": "code",
- "execution_count": 25,
+ "execution_count": 27,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
- ""
+ ""
]
},
- "execution_count": 25,
+ "execution_count": 27,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
- "image/png": "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",
+ "image/png": "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",
"text/plain": [
""
]
@@ -1006,7 +1879,8 @@
}
],
"source": [
- "output_image = io.imread(\"output/final_output.png\")\n",
+ "#output_image_path was set as before, output_image_path = output_path + \"/final_output.png\"\n",
+ "output_image = io.imread(output_image_path)\n",
"io.imshow(output_image)"
]
}
diff --git a/notebooks/tutorials/02_mednist_app-prebuilt.ipynb b/notebooks/tutorials/02_mednist_app-prebuilt.ipynb
index 1e817373..3647b777 100644
--- a/notebooks/tutorials/02_mednist_app-prebuilt.ipynb
+++ b/notebooks/tutorials/02_mednist_app-prebuilt.ipynb
@@ -1,21 +1,21 @@
{
"cells": [
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"# Deploying a MedNIST Classifier App with MONAI Deploy App SDK (Prebuilt Model)\n",
"\n",
- "This tutorial demos the process of packaging up a trained model using MONAI Deploy App SDK into an artifact which can be run as a local program performing inference, a workflow job doing the same, and a Docker containerized workflow execution.\n",
- "\n",
- "In this tutorial, we will use a trained model and implement & package the inference application, executing the application locally.\n"
+ "This tutorial demos the process of packaging up a trained model using MONAI Deploy App SDK into an deployable inference application which can be run as a local program, as well as an MONAI Application Package (MAP) for containerized workflow execution."
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Clone the github project (the latest version of the main branch only)\n"
+ "## Clone the github project (the latest version of the main branch only)"
]
},
{
@@ -28,12 +28,12 @@
"output_type": "stream",
"text": [
"Cloning into 'source'...\n",
- "remote: Enumerating objects: 287, done.\u001b[K\n",
- "remote: Counting objects: 100% (287/287), done.\u001b[K\n",
- "remote: Compressing objects: 100% (253/253), done.\u001b[K\n",
- "remote: Total 287 (delta 61), reused 121 (delta 20), pack-reused 0\u001b[K\n",
- "Receiving objects: 100% (287/287), 1.21 MiB | 10.01 MiB/s, done.\n",
- "Resolving deltas: 100% (61/61), done.\n"
+ "remote: Enumerating objects: 289, done.\u001b[K\n",
+ "remote: Counting objects: 100% (289/289), done.\u001b[K\n",
+ "remote: Compressing objects: 100% (255/255), done.\u001b[K\n",
+ "remote: Total 289 (delta 60), reused 126 (delta 20), pack-reused 0\u001b[K\n",
+ "Receiving objects: 100% (289/289), 1.22 MiB | 593.00 KiB/s, done.\n",
+ "Resolving deltas: 100% (60/60), done.\n"
]
}
],
@@ -45,14 +45,14 @@
},
{
"cell_type": "code",
- "execution_count": 2,
+ "execution_count": 48,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "mednist_classifier_monaideploy.py\n"
+ "app.yaml mednist_classifier_monaideploy.py requirements.txt\n"
]
}
],
@@ -61,6 +61,7 @@
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -69,29 +70,51 @@
},
{
"cell_type": "code",
- "execution_count": 3,
+ "execution_count": 49,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "Requirement already satisfied: monai-deploy-app-sdk in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (0.4.0+84.ge670e4e.dirty)\n",
- "Requirement already satisfied: numpy>=1.21.6 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from monai-deploy-app-sdk) (1.24.4)\n",
- "Requirement already satisfied: networkx>=2.4 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from monai-deploy-app-sdk) (3.1)\n",
- "Requirement already satisfied: colorama>=0.4.1 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from monai-deploy-app-sdk) (0.4.6)\n",
- "Requirement already satisfied: typeguard>=3.0.0 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from monai-deploy-app-sdk) (4.0.0)\n",
- "Requirement already satisfied: importlib-metadata>=3.6 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from typeguard>=3.0.0->monai-deploy-app-sdk) (6.8.0)\n",
- "Requirement already satisfied: typing-extensions>=4.4.0 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from typeguard>=3.0.0->monai-deploy-app-sdk) (4.7.1)\n",
- "Requirement already satisfied: zipp>=0.5 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->monai-deploy-app-sdk) (3.16.0)\n"
+ "Requirement already satisfied: monai-deploy-app-sdk in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (0.5.1+16.g23189de)\n",
+ "Requirement already satisfied: numpy>=1.21.6 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from monai-deploy-app-sdk) (1.24.4)\n",
+ "Requirement already satisfied: networkx>=2.4 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from monai-deploy-app-sdk) (3.1)\n",
+ "Requirement already satisfied: holoscan>=0.5.0 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from monai-deploy-app-sdk) (0.6.0)\n",
+ "Requirement already satisfied: colorama>=0.4.1 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from monai-deploy-app-sdk) (0.4.6)\n",
+ "Requirement already satisfied: typeguard>=3.0.0 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from monai-deploy-app-sdk) (4.1.2)\n",
+ "Requirement already satisfied: cloudpickle~=2.2 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from holoscan>=0.5.0->monai-deploy-app-sdk) (2.2.1)\n",
+ "Requirement already satisfied: python-on-whales~=0.60 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from holoscan>=0.5.0->monai-deploy-app-sdk) (0.64.2)\n",
+ "Requirement already satisfied: Jinja2~=3.1 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from holoscan>=0.5.0->monai-deploy-app-sdk) (3.1.2)\n",
+ "Requirement already satisfied: packaging~=23.1 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from holoscan>=0.5.0->monai-deploy-app-sdk) (23.1)\n",
+ "Requirement already satisfied: pyyaml~=6.0 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from holoscan>=0.5.0->monai-deploy-app-sdk) (6.0.1)\n",
+ "Requirement already satisfied: requests~=2.28 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from holoscan>=0.5.0->monai-deploy-app-sdk) (2.31.0)\n",
+ "Requirement already satisfied: pip>=20.2 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from holoscan>=0.5.0->monai-deploy-app-sdk) (23.2.1)\n",
+ "Requirement already satisfied: wheel-axle-runtime<1.0 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from holoscan>=0.5.0->monai-deploy-app-sdk) (0.0.4)\n",
+ "Requirement already satisfied: importlib-metadata>=3.6 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from typeguard>=3.0.0->monai-deploy-app-sdk) (6.8.0)\n",
+ "Requirement already satisfied: typing-extensions>=4.7.0 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from typeguard>=3.0.0->monai-deploy-app-sdk) (4.7.1)\n",
+ "Requirement already satisfied: zipp>=0.5 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->monai-deploy-app-sdk) (3.16.2)\n",
+ "Requirement already satisfied: MarkupSafe>=2.0 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from Jinja2~=3.1->holoscan>=0.5.0->monai-deploy-app-sdk) (2.1.3)\n",
+ "Requirement already satisfied: pydantic!=2.0.*,<3,>=1.5 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from python-on-whales~=0.60->holoscan>=0.5.0->monai-deploy-app-sdk) (2.2.0)\n",
+ "Requirement already satisfied: tqdm in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from python-on-whales~=0.60->holoscan>=0.5.0->monai-deploy-app-sdk) (4.66.1)\n",
+ "Requirement already satisfied: typer>=0.4.1 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from python-on-whales~=0.60->holoscan>=0.5.0->monai-deploy-app-sdk) (0.9.0)\n",
+ "Requirement already satisfied: charset-normalizer<4,>=2 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from requests~=2.28->holoscan>=0.5.0->monai-deploy-app-sdk) (3.2.0)\n",
+ "Requirement already satisfied: idna<4,>=2.5 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from requests~=2.28->holoscan>=0.5.0->monai-deploy-app-sdk) (3.4)\n",
+ "Requirement already satisfied: urllib3<3,>=1.21.1 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from requests~=2.28->holoscan>=0.5.0->monai-deploy-app-sdk) (2.0.4)\n",
+ "Requirement already satisfied: certifi>=2017.4.17 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from requests~=2.28->holoscan>=0.5.0->monai-deploy-app-sdk) (2023.7.22)\n",
+ "Requirement already satisfied: filelock in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from wheel-axle-runtime<1.0->holoscan>=0.5.0->monai-deploy-app-sdk) (3.12.2)\n",
+ "Requirement already satisfied: annotated-types>=0.4.0 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from pydantic!=2.0.*,<3,>=1.5->python-on-whales~=0.60->holoscan>=0.5.0->monai-deploy-app-sdk) (0.5.0)\n",
+ "Requirement already satisfied: pydantic-core==2.6.0 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from pydantic!=2.0.*,<3,>=1.5->python-on-whales~=0.60->holoscan>=0.5.0->monai-deploy-app-sdk) (2.6.0)\n",
+ "Requirement already satisfied: click<9.0.0,>=7.1.1 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from typer>=0.4.1->python-on-whales~=0.60->holoscan>=0.5.0->monai-deploy-app-sdk) (8.1.7)\n"
]
}
],
"source": [
- "!pip install --upgrade monai-deploy-app-sdk"
+ "!pip install monai-deploy-app-sdk"
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -100,50 +123,51 @@
},
{
"cell_type": "code",
- "execution_count": 4,
+ "execution_count": 50,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "Requirement already satisfied: monai in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (1.2.0)\n",
- "Requirement already satisfied: Pillow in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (10.0.0)\n",
- "Requirement already satisfied: torch>=1.9 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from monai) (2.0.1)\n",
- "Requirement already satisfied: numpy>=1.20 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from monai) (1.24.4)\n",
- "Requirement already satisfied: filelock in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from torch>=1.9->monai) (3.12.2)\n",
- "Requirement already satisfied: typing-extensions in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from torch>=1.9->monai) (4.7.1)\n",
- "Requirement already satisfied: sympy in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from torch>=1.9->monai) (1.12)\n",
- "Requirement already satisfied: networkx in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from torch>=1.9->monai) (3.1)\n",
- "Requirement already satisfied: jinja2 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from torch>=1.9->monai) (3.1.2)\n",
- "Requirement already satisfied: nvidia-cuda-nvrtc-cu11==11.7.99 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from torch>=1.9->monai) (11.7.99)\n",
- "Requirement already satisfied: nvidia-cuda-runtime-cu11==11.7.99 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from torch>=1.9->monai) (11.7.99)\n",
- "Requirement already satisfied: nvidia-cuda-cupti-cu11==11.7.101 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from torch>=1.9->monai) (11.7.101)\n",
- "Requirement already satisfied: nvidia-cudnn-cu11==8.5.0.96 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from torch>=1.9->monai) (8.5.0.96)\n",
- "Requirement already satisfied: nvidia-cublas-cu11==11.10.3.66 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from torch>=1.9->monai) (11.10.3.66)\n",
- "Requirement already satisfied: nvidia-cufft-cu11==10.9.0.58 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from torch>=1.9->monai) (10.9.0.58)\n",
- "Requirement already satisfied: nvidia-curand-cu11==10.2.10.91 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from torch>=1.9->monai) (10.2.10.91)\n",
- "Requirement already satisfied: nvidia-cusolver-cu11==11.4.0.1 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from torch>=1.9->monai) (11.4.0.1)\n",
- "Requirement already satisfied: nvidia-cusparse-cu11==11.7.4.91 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from torch>=1.9->monai) (11.7.4.91)\n",
- "Requirement already satisfied: nvidia-nccl-cu11==2.14.3 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from torch>=1.9->monai) (2.14.3)\n",
- "Requirement already satisfied: nvidia-nvtx-cu11==11.7.91 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from torch>=1.9->monai) (11.7.91)\n",
- "Requirement already satisfied: triton==2.0.0 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from torch>=1.9->monai) (2.0.0)\n",
- "Requirement already satisfied: setuptools in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from nvidia-cublas-cu11==11.10.3.66->torch>=1.9->monai) (68.0.0)\n",
- "Requirement already satisfied: wheel in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from nvidia-cublas-cu11==11.10.3.66->torch>=1.9->monai) (0.40.0)\n",
- "Requirement already satisfied: cmake in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from triton==2.0.0->torch>=1.9->monai) (3.26.4)\n",
- "Requirement already satisfied: lit in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from triton==2.0.0->torch>=1.9->monai) (16.0.6)\n",
- "Requirement already satisfied: MarkupSafe>=2.0 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from jinja2->torch>=1.9->monai) (2.1.3)\n",
- "Requirement already satisfied: mpmath>=0.19 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from sympy->torch>=1.9->monai) (1.3.0)\n"
+ "Requirement already satisfied: monai in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (1.2.0)\n",
+ "Requirement already satisfied: Pillow in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (10.0.0)\n",
+ "Requirement already satisfied: torch>=1.9 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from monai) (2.0.1)\n",
+ "Requirement already satisfied: numpy>=1.20 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from monai) (1.24.4)\n",
+ "Requirement already satisfied: filelock in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from torch>=1.9->monai) (3.12.2)\n",
+ "Requirement already satisfied: typing-extensions in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from torch>=1.9->monai) (4.7.1)\n",
+ "Requirement already satisfied: sympy in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from torch>=1.9->monai) (1.12)\n",
+ "Requirement already satisfied: networkx in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from torch>=1.9->monai) (3.1)\n",
+ "Requirement already satisfied: jinja2 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from torch>=1.9->monai) (3.1.2)\n",
+ "Requirement already satisfied: nvidia-cuda-nvrtc-cu11==11.7.99 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from torch>=1.9->monai) (11.7.99)\n",
+ "Requirement already satisfied: nvidia-cuda-runtime-cu11==11.7.99 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from torch>=1.9->monai) (11.7.99)\n",
+ "Requirement already satisfied: nvidia-cuda-cupti-cu11==11.7.101 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from torch>=1.9->monai) (11.7.101)\n",
+ "Requirement already satisfied: nvidia-cudnn-cu11==8.5.0.96 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from torch>=1.9->monai) (8.5.0.96)\n",
+ "Requirement already satisfied: nvidia-cublas-cu11==11.10.3.66 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from torch>=1.9->monai) (11.10.3.66)\n",
+ "Requirement already satisfied: nvidia-cufft-cu11==10.9.0.58 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from torch>=1.9->monai) (10.9.0.58)\n",
+ "Requirement already satisfied: nvidia-curand-cu11==10.2.10.91 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from torch>=1.9->monai) (10.2.10.91)\n",
+ "Requirement already satisfied: nvidia-cusolver-cu11==11.4.0.1 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from torch>=1.9->monai) (11.4.0.1)\n",
+ "Requirement already satisfied: nvidia-cusparse-cu11==11.7.4.91 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from torch>=1.9->monai) (11.7.4.91)\n",
+ "Requirement already satisfied: nvidia-nccl-cu11==2.14.3 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from torch>=1.9->monai) (2.14.3)\n",
+ "Requirement already satisfied: nvidia-nvtx-cu11==11.7.91 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from torch>=1.9->monai) (11.7.91)\n",
+ "Requirement already satisfied: triton==2.0.0 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from torch>=1.9->monai) (2.0.0)\n",
+ "Requirement already satisfied: setuptools in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from nvidia-cublas-cu11==11.10.3.66->torch>=1.9->monai) (68.1.2)\n",
+ "Requirement already satisfied: wheel in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from nvidia-cublas-cu11==11.10.3.66->torch>=1.9->monai) (0.41.2)\n",
+ "Requirement already satisfied: cmake in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from triton==2.0.0->torch>=1.9->monai) (3.27.2)\n",
+ "Requirement already satisfied: lit in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from triton==2.0.0->torch>=1.9->monai) (16.0.6)\n",
+ "Requirement already satisfied: MarkupSafe>=2.0 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from jinja2->torch>=1.9->monai) (2.1.3)\n",
+ "Requirement already satisfied: mpmath>=0.19 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from sympy->torch>=1.9->monai) (1.3.0)\n"
]
}
],
"source": [
- "!pip install monai Pillow # for MONAI transforms and Pillow\n",
+ "!pip install monai Pillow # for MONAI transforms and Pillow\n",
"!python -c \"import pydicom\" || pip install -q \"pydicom>=1.4.2\"\n",
"!python -c \"import highdicom\" || pip install -q \"highdicom>=0.18.2\" # for the use of DICOM Writer operators"
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -152,30 +176,30 @@
},
{
"cell_type": "code",
- "execution_count": 5,
+ "execution_count": 51,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "Requirement already satisfied: gdown in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (4.7.1)\n",
- "Requirement already satisfied: filelock in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from gdown) (3.12.2)\n",
- "Requirement already satisfied: requests[socks] in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from gdown) (2.31.0)\n",
- "Requirement already satisfied: six in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from gdown) (1.16.0)\n",
- "Requirement already satisfied: tqdm in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from gdown) (4.65.0)\n",
- "Requirement already satisfied: beautifulsoup4 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from gdown) (4.12.2)\n",
- "Requirement already satisfied: soupsieve>1.2 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from beautifulsoup4->gdown) (2.4.1)\n",
- "Requirement already satisfied: charset-normalizer<4,>=2 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from requests[socks]->gdown) (3.2.0)\n",
- "Requirement already satisfied: idna<4,>=2.5 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from requests[socks]->gdown) (3.4)\n",
- "Requirement already satisfied: urllib3<3,>=1.21.1 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from requests[socks]->gdown) (2.0.3)\n",
- "Requirement already satisfied: certifi>=2017.4.17 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from requests[socks]->gdown) (2023.5.7)\n",
- "Requirement already satisfied: PySocks!=1.5.7,>=1.5.6 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from requests[socks]->gdown) (1.7.1)\n",
+ "Requirement already satisfied: gdown in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (4.7.1)\n",
+ "Requirement already satisfied: filelock in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from gdown) (3.12.2)\n",
+ "Requirement already satisfied: requests[socks] in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from gdown) (2.31.0)\n",
+ "Requirement already satisfied: six in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from gdown) (1.16.0)\n",
+ "Requirement already satisfied: tqdm in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from gdown) (4.66.1)\n",
+ "Requirement already satisfied: beautifulsoup4 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from gdown) (4.12.2)\n",
+ "Requirement already satisfied: soupsieve>1.2 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from beautifulsoup4->gdown) (2.4.1)\n",
+ "Requirement already satisfied: charset-normalizer<4,>=2 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from requests[socks]->gdown) (3.2.0)\n",
+ "Requirement already satisfied: idna<4,>=2.5 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from requests[socks]->gdown) (3.4)\n",
+ "Requirement already satisfied: urllib3<3,>=1.21.1 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from requests[socks]->gdown) (2.0.4)\n",
+ "Requirement already satisfied: certifi>=2017.4.17 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from requests[socks]->gdown) (2023.7.22)\n",
+ "Requirement already satisfied: PySocks!=1.5.7,>=1.5.6 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from requests[socks]->gdown) (1.7.1)\n",
"Downloading...\n",
"From (uriginal): https://drive.google.com/uc?id=1yJ4P-xMNEfN6lIOq_u6x1eMAq1_MJu-E\n",
- "From (redirected): https://drive.google.com/uc?id=1yJ4P-xMNEfN6lIOq_u6x1eMAq1_MJu-E&confirm=t&uuid=64399e9b-2546-4500-9f28-b298c7c5c684\n",
+ "From (redirected): https://drive.google.com/uc?id=1yJ4P-xMNEfN6lIOq_u6x1eMAq1_MJu-E&confirm=t&uuid=817bd6c8-6cd7-4015-8689-f48a9825afc9\n",
"To: /home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/mednist_classifier_data.zip\n",
- "100%|██████████████████████████████████████| 28.6M/28.6M [00:00<00:00, 64.6MB/s]\n"
+ "100%|██████████████████████████████████████| 28.6M/28.6M [00:00<00:00, 56.1MB/s]\n"
]
}
],
@@ -187,7 +211,7 @@
},
{
"cell_type": "code",
- "execution_count": 6,
+ "execution_count": 52,
"metadata": {},
"outputs": [
{
@@ -196,452 +220,679 @@
"text": [
"Archive: mednist_classifier_data.zip\n",
" extracting: classifier.zip \n",
- " extracting: input/AbdomenCT_007000.jpeg \n"
+ " extracting: input/AbdomenCT_007000.jpeg \n",
+ "classifier.zip\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Unzip the downloaded mednist_classifier_data.zip from the web browser or using gdown, and set up folders\n",
+ "input_folder = \"input\"\n",
+ "output_folder = \"output\"\n",
+ "models_folder = \"models\"\n",
+ "!rm -rf {input_folder}\n",
+ "!unzip -o \"mednist_classifier_data.zip\"\n",
+ "\n",
+ "# Need to copy the model file to its own clean subfolder for pacakging, to workaround an issue in the Packager\n",
+ "models_folder = \"models\"\n",
+ "!rm -rf {models_folder} && mkdir -p {models_folder}/model && cp classifier.zip {models_folder}/model && ls {models_folder}/model"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Set up environment variables\n",
+ "The application uses well-known enviornment variables for the input/output data path, working dir, as well as AI model file path if applicable. Defaults are used if these environment variable are absent.\n",
+ "\n",
+ "Set the environment variables corresponding to the extracted data path."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 53,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "env: HOLOSCAN_INPUT_PATH=input\n",
+ "env: HOLOSCAN_OUTPUT_PATH=output\n",
+ "env: HOLOSCAN_MODEL_PATH=models\n"
]
}
],
"source": [
- "# After downloading mednist_classifier_data.zip from the web browser or using gdown,\n",
- "!unzip -o \"mednist_classifier_data.zip\""
+ "%env HOLOSCAN_INPUT_PATH {input_folder}\n",
+ "%env HOLOSCAN_OUTPUT_PATH {output_folder}\n",
+ "%env HOLOSCAN_MODEL_PATH {models_folder}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Package app (creating MAP Docker image)\n",
+ "### Package app (creating MAP container image)\n",
"\n",
- "This assumes that nvidia docker is installed in the local machine.\n",
+ "Now we can use the CLI package command to build the MONAI Application Package (MAP) container image based on a supported base image\n",
"\n",
- "Please see https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#docker to install nvidia-docker2.\n",
+ "Use `-l DEBUG` option to see progress.\n",
"\n",
- "Use `-l DEBUG` option to see progress."
+ ":::{note}\n",
+ "This assumes that NVIDIA Container Toolkit or nvidia docker is installed on the local machine.\n",
+ ":::"
]
},
{
"cell_type": "code",
- "execution_count": 7,
+ "execution_count": 54,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "Building MONAI Application Package... -\u001b[1A\u001b[1B\u001b[0G\u001b[?25l[+] Building 0.0s (0/1) \n",
- "\u001b[?25h\u001b[1A\u001b[0G\u001b[?25l[+] Building 0.1s (1/2) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m => [internal] load .dockerignore 0.1s\n",
- "\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[?25\\\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 0.2s (4/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m => [internal] load build context 0.0s\n",
- " => => transferring context: 0.0s\n",
- "\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 0.3s (4/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m => [internal] load build context 0.1s\n",
- " => => transferring context: 8.98MB 0.1s\n",
- "\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[?25|\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 0.4s (4/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m => [internal] load build context 0.2s\n",
- " => => transferring context: 20.78MB 0.2s\n",
- "\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[?25/\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 0.6s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.3s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.06MB 0.3s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s\n",
- "\u001b[0m => CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s\n",
- "\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 0.7s (13/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.3s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.06MB 0.3s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s\n",
- "\u001b[0m => [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.2s\n",
- "\u001b[?25-\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 0.9s (13/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.3s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.06MB 0.3s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s\n",
- "\u001b[0m => [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s\n",
- "\u001b[?25\\\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 1.0s (14/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.3s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.06MB 0.3s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s\n",
- "\u001b[0m\u001b[34m => [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s\n",
- "\u001b[0m => [11/15] RUN echo \"User site package location: $(python3 -m site --use 0.1s\n",
- "\u001b[?25|\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 1.2s (14/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.3s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.06MB 0.3s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s\n",
- "\u001b[0m\u001b[34m => [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s\n",
- "\u001b[0m => [11/15] RUN echo \"User site package location: $(python3 -m site --use 0.3s\n",
- "\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 1.3s (14/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.3s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.06MB 0.3s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s\n",
- "\u001b[0m\u001b[34m => [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s\n",
- "\u001b[0m => [11/15] RUN echo \"User site package location: $(python3 -m site --use 0.4s\n",
- "\u001b[?25/\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 1.4s (15/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.3s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.06MB 0.3s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s\n",
- "\u001b[0m\u001b[34m => [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s\n",
- "\u001b[0m\u001b[34m => [11/15] RUN echo \"User site package location: $(python3 -m site --use 0.6s\n",
- "\u001b[0m\u001b[?25-\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 1.5s (16/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.3s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.06MB 0.3s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s\n",
- "\u001b[0m\u001b[34m => [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s\n",
- "\u001b[0m\u001b[34m => [11/15] RUN echo \"User site package location: $(python3 -m site --use 0.6s\n",
- "\u001b[0m\u001b[34m => [12/15] COPY ./map/app.json /etc/monai/ 0.1s\n",
- "\u001b[0m\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 1.7s (17/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.3s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.06MB 0.3s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s\n",
- "\u001b[0m\u001b[34m => [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s\n",
- "\u001b[0m\u001b[34m => [11/15] RUN echo \"User site package location: $(python3 -m site --use 0.6s\n",
- "\u001b[0m\u001b[34m => [12/15] COPY ./map/app.json /etc/monai/ 0.1s\n",
- "\u001b[0m\u001b[34m => [13/15] COPY ./map/pkg.json /etc/monai/ 0.1s\n",
- "\u001b[0m\u001b[?25\\\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 1.8s (18/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.3s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.06MB 0.3s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s\n",
- "\u001b[0m\u001b[34m => [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s\n",
- "\u001b[0m\u001b[34m => [11/15] RUN echo \"User site package location: $(python3 -m site --use 0.6s\n",
- "\u001b[0m\u001b[34m => [12/15] COPY ./map/app.json /etc/monai/ 0.1s\n",
- "\u001b[0m\u001b[34m => [13/15] COPY ./map/pkg.json /etc/monai/ 0.1s\n",
- "\u001b[0m\u001b[34m => [14/15] COPY ./app /opt/monai/app 0.1s\n",
- "\u001b[0m\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 1.9s (19/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.3s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.06MB 0.3s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s\n",
- "\u001b[0m\u001b[34m => [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s\n",
- "\u001b[0m\u001b[34m => [11/15] RUN echo \"User site package location: $(python3 -m site --use 0.6s\n",
- "\u001b[0m\u001b[34m => [12/15] COPY ./map/app.json /etc/monai/ 0.1s\n",
- "\u001b[0m\u001b[34m => [13/15] COPY ./map/pkg.json /etc/monai/ 0.1s\n",
- "\u001b[0m\u001b[34m => [14/15] COPY ./app /opt/monai/app 0.1s\n",
- "\u001b[0m\u001b[34m => [15/15] WORKDIR /var/monai/ 0.1s\n",
- "\u001b[0m\u001b[?25|\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 2.0s (19/20) \n",
- "\u001b[34m => [internal] load .dockerignore 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.3s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.06MB 0.3s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s\n",
- "\u001b[0m\u001b[34m => [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s\n",
- "\u001b[0m\u001b[34m => [11/15] RUN echo \"User site package location: $(python3 -m site --use 0.6s\n",
- "\u001b[0m\u001b[34m => [12/15] COPY ./map/app.json /etc/monai/ 0.1s\n",
- "\u001b[0m\u001b[34m => [13/15] COPY ./map/pkg.json /etc/monai/ 0.1s\n",
- "\u001b[0m\u001b[34m => [14/15] COPY ./app /opt/monai/app 0.1s\n",
- "\u001b[0m\u001b[34m => [15/15] WORKDIR /var/monai/ 0.1s\n",
- "\u001b[0m => exporting to image 0.1s\n",
- " => => exporting layers 0.1s\n",
- "\u001b[?25/\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 2.2s (19/20) \n",
- "\u001b[34m => [internal] load .dockerignore 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.3s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.06MB 0.3s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s\n",
- "\u001b[0m\u001b[34m => [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s\n",
- "\u001b[0m\u001b[34m => [11/15] RUN echo \"User site package location: $(python3 -m site --use 0.6s\n",
- "\u001b[0m\u001b[34m => [12/15] COPY ./map/app.json /etc/monai/ 0.1s\n",
- "\u001b[0m\u001b[34m => [13/15] COPY ./map/pkg.json /etc/monai/ 0.1s\n",
- "\u001b[0m\u001b[34m => [14/15] COPY ./app /opt/monai/app 0.1s\n",
- "\u001b[0m\u001b[34m => [15/15] WORKDIR /var/monai/ 0.1s\n",
- "\u001b[0m => exporting to image 0.3s\n",
- "\u001b[34m => => exporting layers 0.3s\n",
- "\u001b[0m\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 2.3s (20/20) \n",
- "\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.3s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.06MB 0.3s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s\n",
- "\u001b[0m\u001b[34m => [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s\n",
- "\u001b[0m\u001b[34m => [11/15] RUN echo \"User site package location: $(python3 -m site --use 0.6s\n",
- "\u001b[0m\u001b[34m => [12/15] COPY ./map/app.json /etc/monai/ 0.1s\n",
- "\u001b[0m\u001b[34m => [13/15] COPY ./map/pkg.json /etc/monai/ 0.1s\n",
- "\u001b[0m\u001b[34m => [14/15] COPY ./app /opt/monai/app 0.1s\n",
- "\u001b[0m\u001b[34m => [15/15] WORKDIR /var/monai/ 0.1s\n",
- "\u001b[0m\u001b[34m => exporting to image 0.3s\n",
- "\u001b[0m\u001b[34m => => exporting layers 0.3s\n",
- "\u001b[0m\u001b[34m => => writing image sha256:1d85a1e712404af578bc29f3b6f407a985d51cff510bd 0.0s\n",
- "\u001b[0m\u001b[34m => => naming to docker.io/library/mednist_app:latest 0.0s\n",
- "\u001b[0m\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 2.3s (20/20) FINISHED \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.3s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.06MB 0.3s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s\n",
- "\u001b[0m\u001b[34m => [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s\n",
- "\u001b[0m\u001b[34m => [11/15] RUN echo \"User site package location: $(python3 -m site --use 0.6s\n",
- "\u001b[0m\u001b[34m => [12/15] COPY ./map/app.json /etc/monai/ 0.1s\n",
- "\u001b[0m\u001b[34m => [13/15] COPY ./map/pkg.json /etc/monai/ 0.1s\n",
- "\u001b[0m\u001b[34m => [14/15] COPY ./app /opt/monai/app 0.1s\n",
- "\u001b[0m\u001b[34m => [15/15] WORKDIR /var/monai/ 0.1s\n",
- "\u001b[0m\u001b[34m => exporting to image 0.3s\n",
- "\u001b[0m\u001b[34m => => exporting layers 0.3s\n",
- "\u001b[0m\u001b[34m => => writing image sha256:1d85a1e712404af578bc29f3b6f407a985d51cff510bd 0.0s\n",
- "\u001b[0m\u001b[34m => => naming to docker.io/library/mednist_app:latest 0.0s\n",
- "\u001b[0m\u001b[?25Done\n",
- "[2023-07-11 14:39:41,392] [INFO] (app_packager) - Successfully built mednist_app:latest\n"
+ "[2023-08-30 00:27:37,497] [INFO] (packager.parameters) - Application: /home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/source/examples/apps/mednist_classifier_monaideploy/mednist_classifier_monaideploy.py\n",
+ "[2023-08-30 00:27:37,497] [INFO] (packager.parameters) - Detected application type: Python File\n",
+ "[2023-08-30 00:27:37,498] [INFO] (packager) - Scanning for models in {models_path}...\n",
+ "[2023-08-30 00:27:37,498] [DEBUG] (packager) - Model model=/home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/models/model added.\n",
+ "[2023-08-30 00:27:37,498] [INFO] (packager) - Reading application configuration from /home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/source/examples/apps/mednist_classifier_monaideploy/app.yaml...\n",
+ "[2023-08-30 00:27:37,500] [INFO] (packager) - Generating app.json...\n",
+ "[2023-08-30 00:27:37,500] [INFO] (packager) - Generating pkg.json...\n",
+ "[2023-08-30 00:27:37,500] [DEBUG] (common) - \n",
+ "=============== Begin app.json ===============\n",
+ "{\n",
+ " \"apiVersion\": \"1.0.0\",\n",
+ " \"command\": \"[\\\"python3\\\", \\\"/opt/holoscan/app/mednist_classifier_monaideploy.py\\\"]\",\n",
+ " \"environment\": {\n",
+ " \"HOLOSCAN_APPLICATION\": \"/opt/holoscan/app\",\n",
+ " \"HOLOSCAN_INPUT_PATH\": \"input/\",\n",
+ " \"HOLOSCAN_OUTPUT_PATH\": \"output/\",\n",
+ " \"HOLOSCAN_WORKDIR\": \"/var/holoscan\",\n",
+ " \"HOLOSCAN_MODEL_PATH\": \"/opt/holoscan/models\",\n",
+ " \"HOLOSCAN_CONFIG_PATH\": \"/var/holoscan/app.yaml\",\n",
+ " \"HOLOSCAN_APP_MANIFEST_PATH\": \"/etc/holoscan/app.json\",\n",
+ " \"HOLOSCAN_PKG_MANIFEST_PATH\": \"/etc/holoscan/pkg.json\",\n",
+ " \"HOLOSCAN_DOCS_PATH\": \"/opt/holoscan/docs\",\n",
+ " \"HOLOSCAN_LOGS_PATH\": \"/var/holoscan/logs\"\n",
+ " },\n",
+ " \"input\": {\n",
+ " \"path\": \"input/\",\n",
+ " \"formats\": null\n",
+ " },\n",
+ " \"liveness\": null,\n",
+ " \"output\": {\n",
+ " \"path\": \"output/\",\n",
+ " \"formats\": null\n",
+ " },\n",
+ " \"readiness\": null,\n",
+ " \"sdk\": \"monai-deploy\",\n",
+ " \"sdkVersion\": \"0.6.0\",\n",
+ " \"timeout\": 0,\n",
+ " \"version\": 1.0,\n",
+ " \"workingDirectory\": \"/var/holoscan\"\n",
+ "}\n",
+ "================ End app.json ================\n",
+ " \n",
+ "[2023-08-30 00:27:37,501] [DEBUG] (common) - \n",
+ "=============== Begin pkg.json ===============\n",
+ "{\n",
+ " \"apiVersion\": \"1.0.0\",\n",
+ " \"applicationRoot\": \"/opt/holoscan/app\",\n",
+ " \"modelRoot\": \"/opt/holoscan/models\",\n",
+ " \"models\": {\n",
+ " \"model\": \"/opt/holoscan/models\"\n",
+ " },\n",
+ " \"resources\": {\n",
+ " \"cpu\": 1,\n",
+ " \"gpu\": 1,\n",
+ " \"memory\": \"1Gi\",\n",
+ " \"gpuMemory\": \"1Gi\"\n",
+ " },\n",
+ " \"version\": 1.0\n",
+ "}\n",
+ "================ End pkg.json ================\n",
+ " \n",
+ "[2023-08-30 00:27:37,533] [DEBUG] (packager.builder) - \n",
+ "========== Begin Dockerfile ==========\n",
+ "\n",
+ "\n",
+ "FROM nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu\n",
+ "\n",
+ "ENV DEBIAN_FRONTEND=noninteractive\n",
+ "ENV TERM=xterm-256color\n",
+ "\n",
+ "ARG UNAME\n",
+ "ARG UID\n",
+ "ARG GID\n",
+ "\n",
+ "RUN mkdir -p /etc/holoscan/ \\\n",
+ " && mkdir -p /opt/holoscan/ \\\n",
+ " && mkdir -p /var/holoscan \\\n",
+ " && mkdir -p /opt/holoscan/app \\\n",
+ " && mkdir -p /var/holoscan/input \\\n",
+ " && mkdir -p /var/holoscan/output\n",
+ "\n",
+ "LABEL base=\"nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu\"\n",
+ "LABEL tag=\"mednist_app:1.0\"\n",
+ "LABEL org.opencontainers.image.title=\"MONAI Deploy App Package - MedNIST Classifier App\"\n",
+ "LABEL org.opencontainers.image.version=\"1.0\"\n",
+ "LABEL org.nvidia.holoscan=\"0.6.0\"\n",
+ "\n",
+ "ENV HOLOSCAN_ENABLE_HEALTH_CHECK=true\n",
+ "ENV HOLOSCAN_INPUT_PATH=/var/holoscan/input\n",
+ "ENV HOLOSCAN_OUTPUT_PATH=/var/holoscan/output\n",
+ "ENV HOLOSCAN_WORKDIR=/var/holoscan\n",
+ "ENV HOLOSCAN_APPLICATION=/opt/holoscan/app\n",
+ "ENV HOLOSCAN_TIMEOUT=0\n",
+ "ENV HOLOSCAN_MODEL_PATH=/opt/holoscan/models\n",
+ "ENV HOLOSCAN_DOCS_PATH=/opt/holoscan/docs\n",
+ "ENV HOLOSCAN_CONFIG_PATH=/var/holoscan/app.yaml\n",
+ "ENV HOLOSCAN_APP_MANIFEST_PATH=/etc/holoscan/app.json\n",
+ "ENV HOLOSCAN_PKG_MANIFEST_PATH=/etc/holoscan/pkg.json\n",
+ "ENV HOLOSCAN_LOGS_PATH=/var/holoscan/logs\n",
+ "ENV PATH=/root/.local/bin:/opt/nvidia/holoscan:$PATH\n",
+ "ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/libtorch/1.13.1/lib/:/opt/nvidia/holoscan/lib\n",
+ "\n",
+ "RUN apt-get update \\\n",
+ " && apt-get install -y curl jq \\\n",
+ " && rm -rf /var/lib/apt/lists/*\n",
+ "\n",
+ "ENV PYTHONPATH=\"/opt/holoscan/app:$PYTHONPATH\"\n",
+ "\n",
+ "\n",
+ "\n",
+ "RUN groupadd -g $GID $UNAME\n",
+ "RUN useradd -rm -d /home/$UNAME -s /bin/bash -g $GID -G sudo -u $UID $UNAME\n",
+ "RUN chown -R holoscan /var/holoscan \n",
+ "RUN chown -R holoscan /var/holoscan/input \n",
+ "RUN chown -R holoscan /var/holoscan/output \n",
+ "\n",
+ "# Set the working directory\n",
+ "WORKDIR /var/holoscan\n",
+ "\n",
+ "# Copy HAP/MAP tool script\n",
+ "COPY ./tools /var/holoscan/tools\n",
+ "RUN chmod +x /var/holoscan/tools\n",
+ "\n",
+ "\n",
+ "# Copy gRPC health probe\n",
+ "\n",
+ "USER $UNAME\n",
+ "\n",
+ "ENV PATH=/root/.local/bin:/home/holoscan/.local/bin:/opt/nvidia/holoscan:$PATH\n",
+ "\n",
+ "COPY ./pip/requirements.txt /tmp/requirements.txt\n",
+ "\n",
+ "RUN pip install --upgrade pip\n",
+ "RUN pip install --no-cache-dir --user -r /tmp/requirements.txt\n",
+ "\n",
+ "# Install Holoscan from PyPI org\n",
+ "RUN pip install holoscan==0.6.0\n",
+ "\n",
+ "\n",
+ "# Copy user-specified MONAI Deploy SDK file\n",
+ "COPY ./monai_deploy_app_sdk-0.5.1+22.g029f8bc.dirty-py3-none-any.whl /tmp/monai_deploy_app_sdk-0.5.1+22.g029f8bc.dirty-py3-none-any.whl\n",
+ "RUN pip install /tmp/monai_deploy_app_sdk-0.5.1+22.g029f8bc.dirty-py3-none-any.whl\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "COPY ./models /opt/holoscan/models\n",
+ "\n",
+ "COPY ./map/app.json /etc/holoscan/app.json\n",
+ "COPY ./app.config /var/holoscan/app.yaml\n",
+ "COPY ./map/pkg.json /etc/holoscan/pkg.json\n",
+ "\n",
+ "COPY ./app /opt/holoscan/app\n",
+ "\n",
+ "ENTRYPOINT [\"/var/holoscan/tools\"]\n",
+ "=========== End Dockerfile ===========\n",
+ "\n",
+ "[2023-08-30 00:27:37,534] [INFO] (packager.builder) - \n",
+ "===============================================================================\n",
+ "Building image for: x64-workstation\n",
+ " Architecture: linux/amd64\n",
+ " Base Image: nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu\n",
+ " Build Image: N/A \n",
+ " Cache: Enabled\n",
+ " Configuration: dgpu\n",
+ " Holoiscan SDK Package: pypi.org\n",
+ " MONAI Deploy App SDK Package: /home/mqin/src/monai-deploy-app-sdk/dist/monai_deploy_app_sdk-0.5.1+22.g029f8bc.dirty-py3-none-any.whl\n",
+ " gRPC Health Probe: N/A\n",
+ " SDK Version: 0.6.0\n",
+ " SDK: monai-deploy\n",
+ " Tag: mednist_app-x64-workstation-dgpu-linux-amd64:1.0\n",
+ " \n",
+ "[2023-08-30 00:27:37,873] [INFO] (common) - Using existing Docker BuildKit builder `holoscan_app_builder`\n",
+ "[2023-08-30 00:27:37,873] [DEBUG] (packager.builder) - Building Holoscan Application Package: tag=mednist_app-x64-workstation-dgpu-linux-amd64:1.0\n",
+ "#1 [internal] load build definition from Dockerfile\n",
+ "#1 transferring dockerfile: 2.67kB done\n",
+ "#1 DONE 0.1s\n",
+ "\n",
+ "#2 [internal] load .dockerignore\n",
+ "#2 transferring context: 1.79kB done\n",
+ "#2 DONE 0.1s\n",
+ "\n",
+ "#3 [internal] load metadata for nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu\n",
+ "#3 DONE 0.7s\n",
+ "\n",
+ "#4 [internal] load build context\n",
+ "#4 DONE 0.0s\n",
+ "\n",
+ "#5 importing cache manifest from local:8636426000862419753\n",
+ "#5 DONE 0.0s\n",
+ "\n",
+ "#6 importing cache manifest from nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu\n",
+ "#6 DONE 0.7s\n",
+ "\n",
+ "#7 [ 1/22] FROM nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu@sha256:9653f80f241fd542f25afbcbcf7a0d02ed7e5941c79763e69def5b1e6d9fb7bc\n",
+ "#7 resolve nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu@sha256:9653f80f241fd542f25afbcbcf7a0d02ed7e5941c79763e69def5b1e6d9fb7bc 0.1s done\n",
+ "#7 DONE 0.1s\n",
+ "\n",
+ "#4 [internal] load build context\n",
+ "#4 transferring context: 28.74MB 0.2s done\n",
+ "#4 DONE 0.3s\n",
+ "\n",
+ "#8 [19/22] COPY ./map/app.json /etc/holoscan/app.json\n",
+ "#8 CACHED\n",
+ "\n",
+ "#9 [ 2/22] RUN mkdir -p /etc/holoscan/ && mkdir -p /opt/holoscan/ && mkdir -p /var/holoscan && mkdir -p /opt/holoscan/app && mkdir -p /var/holoscan/input && mkdir -p /var/holoscan/output\n",
+ "#9 CACHED\n",
+ "\n",
+ "#10 [15/22] RUN pip install holoscan==0.6.0\n",
+ "#10 CACHED\n",
+ "\n",
+ "#11 [ 5/22] RUN useradd -rm -d /home/holoscan -s /bin/bash -g 1000 -G sudo -u 1000 holoscan\n",
+ "#11 CACHED\n",
+ "\n",
+ "#12 [ 9/22] WORKDIR /var/holoscan\n",
+ "#12 CACHED\n",
+ "\n",
+ "#13 [14/22] RUN pip install --no-cache-dir --user -r /tmp/requirements.txt\n",
+ "#13 CACHED\n",
+ "\n",
+ "#14 [ 3/22] RUN apt-get update && apt-get install -y curl jq && rm -rf /var/lib/apt/lists/*\n",
+ "#14 CACHED\n",
+ "\n",
+ "#15 [12/22] COPY ./pip/requirements.txt /tmp/requirements.txt\n",
+ "#15 CACHED\n",
+ "\n",
+ "#16 [16/22] COPY ./monai_deploy_app_sdk-0.5.1+22.g029f8bc.dirty-py3-none-any.whl /tmp/monai_deploy_app_sdk-0.5.1+22.g029f8bc.dirty-py3-none-any.whl\n",
+ "#16 CACHED\n",
+ "\n",
+ "#17 [ 7/22] RUN chown -R holoscan /var/holoscan/input\n",
+ "#17 CACHED\n",
+ "\n",
+ "#18 [11/22] RUN chmod +x /var/holoscan/tools\n",
+ "#18 CACHED\n",
+ "\n",
+ "#19 [18/22] COPY ./models /opt/holoscan/models\n",
+ "#19 CACHED\n",
+ "\n",
+ "#20 [13/22] RUN pip install --upgrade pip\n",
+ "#20 CACHED\n",
+ "\n",
+ "#21 [ 6/22] RUN chown -R holoscan /var/holoscan\n",
+ "#21 CACHED\n",
+ "\n",
+ "#22 [ 4/22] RUN groupadd -g 1000 holoscan\n",
+ "#22 CACHED\n",
+ "\n",
+ "#23 [17/22] RUN pip install /tmp/monai_deploy_app_sdk-0.5.1+22.g029f8bc.dirty-py3-none-any.whl\n",
+ "#23 CACHED\n",
+ "\n",
+ "#24 [20/22] COPY ./app.config /var/holoscan/app.yaml\n",
+ "#24 CACHED\n",
+ "\n",
+ "#25 [21/22] COPY ./map/pkg.json /etc/holoscan/pkg.json\n",
+ "#25 CACHED\n",
+ "\n",
+ "#26 [ 8/22] RUN chown -R holoscan /var/holoscan/output\n",
+ "#26 CACHED\n",
+ "\n",
+ "#27 [10/22] COPY ./tools /var/holoscan/tools\n",
+ "#27 CACHED\n",
+ "\n",
+ "#28 [22/22] COPY ./app /opt/holoscan/app\n",
+ "#28 CACHED\n",
+ "\n",
+ "#29 exporting to docker image format\n",
+ "#29 exporting layers done\n",
+ "#29 exporting manifest sha256:d3b7e9f7074b67ee41792399d3628933430a1008bb4b0ea55a4c5bbd6f55c0ff done\n",
+ "#29 exporting config sha256:5c18974168b1fe160a2b339079dc229ca5da7436a35b371fa7e84c98bbffc41f\n",
+ "#29 exporting config sha256:5c18974168b1fe160a2b339079dc229ca5da7436a35b371fa7e84c98bbffc41f done\n",
+ "#29 sending tarball\n",
+ "#29 ...\n",
+ "\n",
+ "#30 importing to docker\n",
+ "#30 DONE 0.5s\n",
+ "\n",
+ "#29 exporting to docker image format\n",
+ "#29 sending tarball 60.0s done\n",
+ "#29 DONE 60.1s\n",
+ "\n",
+ "#31 exporting content cache\n",
+ "#31 preparing build cache for export\n",
+ "#31 writing layer sha256:0709800848b4584780b40e7e81200689870e890c38b54e96b65cd0a3b1942f2d\n",
+ "#31 preparing build cache for export 0.5s done\n",
+ "#31 writing layer sha256:0709800848b4584780b40e7e81200689870e890c38b54e96b65cd0a3b1942f2d done\n",
+ "#31 writing layer sha256:0ce020987cfa5cd1654085af3bb40779634eb3d792c4a4d6059036463ae0040d done\n",
+ "#31 writing layer sha256:0d30a78cb8a1aa805a492552b4ca85bc45495e1124639d686d75536c6a92de72 done\n",
+ "#31 writing layer sha256:0dd1cff2f3adeba05c3efdf05c6f9ca4b0b2f59c95bb3f29d713b7b30615f1e5 done\n",
+ "#31 writing layer sha256:0f65089b284381bf795d15b1a186e2a8739ea957106fa526edef0d738e7cda70 done\n",
+ "#31 writing layer sha256:12a47450a9f9cc5d4edab65d0f600dbbe8b23a1663b0b3bb2c481d40e074b580 done\n",
+ "#31 writing layer sha256:18a470321fd8787a309fd093c140e1427c4b14f6d9d775054985aeae6510eb36 done\n",
+ "#31 writing layer sha256:19c20b65326c1511f8ab02f4a41453f8c0b6d9f2bdea8bb25038b628cef67ab9 done\n",
+ "#31 writing layer sha256:1de965777e2e37c7fabe00bdbf3d0203ca83ed30a71a5479c3113fe4fc48c4bb done\n",
+ "#31 writing layer sha256:22b384cd1e678fc56dc95c82f42e7a540d055418d0f1eef8d908c88305e23a88 done\n",
+ "#31 writing layer sha256:24b5aa2448e920814dd67d7d3c0169b2cdacb13c4048d74ded3b4317843b13ff done\n",
+ "#31 writing layer sha256:2d42104dbf0a7cc962b791f6ab4f45a803f8a36d296f996aca180cfb2f3e30d0 done\n",
+ "#31 writing layer sha256:2fa1ce4fa3fec6f9723380dc0536b7c361d874add0baaddc4bbf2accac82d2ff done\n",
+ "#31 writing layer sha256:38794be1b5dc99645feabf89b22cd34fb5bdffb5164ad920e7df94f353efe9c0 done\n",
+ "#31 writing layer sha256:38f963dc57c1e7b68a738fe39ed9f9345df7188111a047e2163a46648d7f1d88 done\n",
+ "#31 writing layer sha256:3e7e4c9bc2b136814c20c04feb4eea2b2ecf972e20182d88759931130cfb4181 done\n",
+ "#31 writing layer sha256:3fd77037ad585442cd82d64e337f49a38ddba50432b2a1e563a48401d25c79e6 done\n",
+ "#31 writing layer sha256:41814ed91034b30ac9c44dfc604a4bade6138005ccf682372c02e0bead66dbc0 done\n",
+ "#31 writing layer sha256:45893188359aca643d5918c9932da995364dc62013dfa40c075298b1baabece3 done\n",
+ "#31 writing layer sha256:49bc651b19d9e46715c15c41b7c0daa007e8e25f7d9518f04f0f06592799875a done\n",
+ "#31 writing layer sha256:4c12db5118d8a7d909e4926d69a2192d2b3cd8b110d49c7504a4f701258c1ccc done\n",
+ "#31 writing layer sha256:4cc43a803109d6e9d1fd35495cef9b1257035f5341a2db54f7a1940815b6cc65 done\n",
+ "#31 writing layer sha256:4d32b49e2995210e8937f0898327f196d3fcc52486f0be920e8b2d65f150a7ab done\n",
+ "#31 writing layer sha256:4d6fe980bad9cd7b2c85a478c8033cae3d098a81f7934322fb64658b0c8f9854 done\n",
+ "#31 writing layer sha256:4e78baa7922aa440fcba2b268af798b094fdb64e4450a916c15027abc06a1123 done\n",
+ "#31 writing layer sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 done\n",
+ "#31 writing layer sha256:5150182f1ff123399b300ca469e00f6c4d82e1b9b72652fb8ee7eab370245236 done\n",
+ "#31 writing layer sha256:595c38fa102c61c3dda19bdab70dcd26a0e50465b986d022a84fa69023a05d0f done\n",
+ "#31 writing layer sha256:59d451175f6950740e26d38c322da0ef67cb59da63181eb32996f752ba8a2f17 done\n",
+ "#31 writing layer sha256:5ad1f2004580e415b998124ea394e9d4072a35d70968118c779f307204d6bd17 done\n",
+ "#31 writing layer sha256:62598eafddf023e7f22643485f4321cbd51ff7eee743b970db12454fd3c8c675 done\n",
+ "#31 writing layer sha256:63d7e616a46987136f4cc9eba95db6f6327b4854cfe3c7e20fed6db0c966e380 done\n",
+ "#31 writing layer sha256:654056fd3057d315a0066ee5f4367ed8954486493fe95c0c171c27dff8ac0ffc done\n",
+ "#31 writing layer sha256:6939d591a6b09b14a437e5cd2d6082a52b6d76bec4f72d960440f097721da34f done\n",
+ "#31 writing layer sha256:698318e5a60e5e0d48c45bf992f205a9532da567fdfe94bd59be2e192975dd6f done\n",
+ "#31 writing layer sha256:6ddc1d0f91833b36aac1c6f0c8cea005c87d94bab132d46cc06d9b060a81cca3 done\n",
+ "#31 writing layer sha256:74ac1f5a47c0926bff1e997bb99985a09926f43bd0895cb27ceb5fa9e95f8720 done\n",
+ "#31 writing layer sha256:7577973918dd30e764733a352a93f418000bc3181163ca451b2307492c1a6ba9 done\n",
+ "#31 writing layer sha256:7f038e6d9e00dcbfc90c1c97d7bb11aca6cacd2aa279d9a732f08701dafb8e8c done\n",
+ "#31 writing layer sha256:81ab55ca8bce88347661e1c1e6d58975b998017ad2e91a1040bd3f5017741d2b done\n",
+ "#31 writing layer sha256:886c886d8a09d8befb92df75dd461d4f97b77d7cff4144c4223b0d2f6f2c17f2 done\n",
+ "#31 writing layer sha256:8a7451db9b4b817b3b33904abddb7041810a4ffe8ed4a034307d45d9ae9b3f2a done\n",
+ "#31 writing layer sha256:916f4054c6e7f10de4fd7c08ffc75fa23ebecca4eceb8183cb1023b33b1696c9 done\n",
+ "#31 writing layer sha256:9463aa3f56275af97693df69478a2dc1d171f4e763ca6f7b6f370a35e605c154 done\n",
+ "#31 writing layer sha256:955fd173ed884230c2eded4542d10a97384b408537be6bbb7c4ae09ccd6fb2d0 done\n",
+ "#31 writing layer sha256:9c42a4ee99755f441251e6043b2cbba16e49818a88775e7501ec17e379ce3cfd done\n",
+ "#31 writing layer sha256:9c63be0a86e3dc4168db3814bf464e40996afda0031649d9faa8ff7568c3154f done\n",
+ "#31 writing layer sha256:9e04bda98b05554953459b5edef7b2b14d32f1a00b979a23d04b6eb5c191e66b done\n",
+ "#31 writing layer sha256:a4a0c690bc7da07e592514dccaa26098a387e8457f69095e922b6d73f7852502 done\n",
+ "#31 writing layer sha256:a4aafbc094d78a85bef41036173eb816a53bcd3e2564594a32f542facdf2aba6 done\n",
+ "#31 writing layer sha256:ae36a4d38b76948e39a5957025c984a674d2de18ce162a8caaa536e6f06fccea done\n",
+ "#31 writing layer sha256:b2fa40114a4a0725c81b327df89c0c3ed5c05ca9aa7f1157394d5096cf5460ce done\n",
+ "#31 writing layer sha256:b48a5fafcaba74eb5d7e7665601509e2889285b50a04b5b639a23f8adc818157 done\n",
+ "#31 writing layer sha256:c86976a083599e36a6441f36f553627194d05ea82bb82a78682e718fe62fccf6 done\n",
+ "#31 writing layer sha256:cb506fbdedc817e3d074f609e2edbf9655aacd7784610a1bbac52f2d7be25438 done\n",
+ "#31 writing layer sha256:d0e403a8e125a305b51fe2bd601c34c0723817079bca25fcda7679c88d8bb5b4 done\n",
+ "#31 writing layer sha256:d2a6fe65a1f84edb65b63460a75d1cac1aa48b72789006881b0bcfd54cd01ffd done\n",
+ "#31 writing layer sha256:d8d16d6af76dc7c6b539422a25fdad5efb8ada5a8188069fcd9d113e3b783304 done\n",
+ "#31 writing layer sha256:ddc2ade4f6fe866696cb638c8a102cb644fa842c2ca578392802b3e0e5e3bcb7 done\n",
+ "#31 writing layer sha256:e2cfd7f6244d6f35befa6bda1caa65f1786cecf3f00ef99d7c9a90715ce6a03c done\n",
+ "#31 writing layer sha256:e94a4481e9334ff402bf90628594f64a426672debbdfb55f1290802e52013907 done\n",
+ "#31 writing layer sha256:eaf45e9f32d1f5a9983945a1a9f8dedbb475bc0f578337610e00b4dedec87c20 done\n",
+ "#31 writing layer sha256:eb411bef39c013c9853651e68f00965dbd826d829c4e478884a2886976e9c989 done\n",
+ "#31 writing layer sha256:edfe4a95eb6bd3142aeda941ab871ffcc8c19cf50c33561c210ba8ead2424759 done\n",
+ "#31 writing layer sha256:ef4466d6f927d29d404df9c5af3ef5733c86fa14e008762c90110b963978b1e7 done\n",
+ "#31 writing layer sha256:efeed9f42c39c54037a94758f3241cba081ba3b9757cd3bb02b68236e32407a8 done\n",
+ "#31 writing layer sha256:f346e3ecdf0bee048fa1e3baf1d3128ff0283b903f03e97524944949bd8882e5 done\n",
+ "#31 writing layer sha256:f3f9a00a1ce9aadda250aacb3e66a932676badc5d8519c41517fdf7ea14c13ed done\n",
+ "#31 writing layer sha256:fd849d9bd8889edd43ae38e9f21a912430c8526b2c18f3057a3b2cd74eb27b31 done\n",
+ "#31 writing config sha256:b6fc6225c36e7934983d6d120774b3ecf31f01c91c2fa044eb6e0e577ffe6d81 done\n",
+ "#31 writing manifest sha256:7ab07233db7c57bf72e36f09b58376a67abb90cfe635ad1703b75b4416f5b983 done\n",
+ "#31 DONE 0.5s\n",
+ "[2023-08-30 00:28:41,348] [INFO] (packager) - Build Summary:\n",
+ "\n",
+ "Platform: x64-workstation/dgpu\n",
+ " Status: Succeeded\n",
+ " Docker Tag: mednist_app-x64-workstation-dgpu-linux-amd64:1.0\n",
+ " Tarball: None\n"
+ ]
+ }
+ ],
+ "source": [
+ "tag_prefix = \"mednist_app\"\n",
+ "\n",
+ "!monai-deploy package \"source/examples/apps/mednist_classifier_monaideploy/mednist_classifier_monaideploy.py\" -m {models_folder} -c \"source/examples/apps/mednist_classifier_monaideploy/app.yaml\" -t {tag_prefix}:1.0 --platform x64-workstation -l DEBUG"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "We can see that the MAP Docker image is created"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 55,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "mednist_app-x64-workstation-dgpu-linux-amd64 1.0 5c18974168b1 10 minutes ago 15.4GB\n",
+ "mednist_app-x64-workstation-dgpu-linux-amd64 latest 8aa4dbfb02fb 2 weeks ago 15.4GB\n"
]
}
],
"source": [
- "!monai-deploy package \"source/examples/apps/mednist_classifier_monaideploy/mednist_classifier_monaideploy.py\" \\\n",
- " --tag mednist_app:latest \\\n",
- " --model classifier.zip"
+ "!docker image ls | grep {tag_prefix}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "## Run the app with docker image and input file locally"
+ "We can choose to display and inspect the MAP manifests by running the container with the `show` command.\n",
+ "Furthermore, we can also extract the manifests and other contents in the MAP by using the `extract` command while mapping specific folder to the host's (we know that our MAP is compliant and supports these commands).\n",
+ "\n",
+ ":::{note}\n",
+ "The host folder for storing the extracted content must first be created by the user, and if it has been created by Docker on running the container, the folder needs to be deleted and re-created.\n",
+ ":::"
]
},
{
"cell_type": "code",
- "execution_count": 8,
+ "execution_count": 56,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "Checking dependencies...\n",
- "--> Verifying if \"docker\" is installed...\n",
- "\n",
- "--> Verifying if \"mednist_app:latest\" is available...\n",
- "\n",
- "Checking for MAP \"mednist_app:latest\" locally\n",
- "\"mednist_app:latest\" found.\n",
- "\n",
- "Reading MONAI App Package manifest...\n",
- "\u001b[sPreparing to copy...\u001b[?25l\u001b[u\u001b[2KCopying from container - 0B\u001b[?25h\u001b[u\u001b[2KSuccessfully copied 2.05kB to /tmp/tmpvdf4hnad/app.json\n",
- "\u001b[sPreparing to copy...\u001b[?25l\u001b[u\u001b[2KCopying from container - 0B\u001b[?25h\u001b[u\u001b[2KSuccessfully copied 2.05kB to /tmp/tmpvdf4hnad/pkg.json\n",
- "--> Verifying if \"nvidia-docker\" is installed...\n",
- "\n",
- "/opt/conda/lib/python3.8/site-packages/scipy/__init__.py:138: UserWarning: A NumPy version >=1.16.5 and <1.23.0 is required for this version of SciPy (detected version 1.24.3)\n",
- " warnings.warn(f\"A NumPy version >={np_minversion} and <{np_maxversion} is required for this version of \"\n",
- "\u001b[34mGoing to initiate execution of operator LoadPILOperator\u001b[39m\n",
- "\u001b[32mExecuting operator LoadPILOperator \u001b[33m(Process ID: 1, Operator ID: 5ca4fdc7-8dd0-4eb8-8550-9d92b820f2da)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator LoadPILOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator MedNISTClassifierOperator\u001b[39m\n",
- "\u001b[32mExecuting operator MedNISTClassifierOperator \u001b[33m(Process ID: 1, Operator ID: 9d624c54-86c3-48a7-b827-ef60030db8ea)\u001b[39m\n",
- "/root/.local/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:111: FutureWarning: : Class `AddChannel` has been deprecated since version 0.8. It will be removed in version 1.3. please use MetaTensor data type and monai.transforms.EnsureChannelFirst instead with `channel_dim='no_channel'`.\n",
+ "Display manifests and extract MAP contents to the host folder, ./export\n",
+ "\n",
+ "============================== app.json ==============================\n",
+ "{\n",
+ " \"apiVersion\": \"1.0.0\",\n",
+ " \"command\": \"[\\\"python3\\\", \\\"/opt/holoscan/app/mednist_classifier_monaideploy.py\\\"]\",\n",
+ " \"environment\": {\n",
+ " \"HOLOSCAN_APPLICATION\": \"/opt/holoscan/app\",\n",
+ " \"HOLOSCAN_INPUT_PATH\": \"input/\",\n",
+ " \"HOLOSCAN_OUTPUT_PATH\": \"output/\",\n",
+ " \"HOLOSCAN_WORKDIR\": \"/var/holoscan\",\n",
+ " \"HOLOSCAN_MODEL_PATH\": \"/opt/holoscan/models\",\n",
+ " \"HOLOSCAN_CONFIG_PATH\": \"/var/holoscan/app.yaml\",\n",
+ " \"HOLOSCAN_APP_MANIFEST_PATH\": \"/etc/holoscan/app.json\",\n",
+ " \"HOLOSCAN_PKG_MANIFEST_PATH\": \"/etc/holoscan/pkg.json\",\n",
+ " \"HOLOSCAN_DOCS_PATH\": \"/opt/holoscan/docs\",\n",
+ " \"HOLOSCAN_LOGS_PATH\": \"/var/holoscan/logs\"\n",
+ " },\n",
+ " \"input\": {\n",
+ " \"path\": \"input/\",\n",
+ " \"formats\": null\n",
+ " },\n",
+ " \"liveness\": null,\n",
+ " \"output\": {\n",
+ " \"path\": \"output/\",\n",
+ " \"formats\": null\n",
+ " },\n",
+ " \"readiness\": null,\n",
+ " \"sdk\": \"monai-deploy\",\n",
+ " \"sdkVersion\": \"0.6.0\",\n",
+ " \"timeout\": 0,\n",
+ " \"version\": 1,\n",
+ " \"workingDirectory\": \"/var/holoscan\"\n",
+ "}\n",
+ "\n",
+ "============================== pkg.json ==============================\n",
+ "{\n",
+ " \"apiVersion\": \"1.0.0\",\n",
+ " \"applicationRoot\": \"/opt/holoscan/app\",\n",
+ " \"modelRoot\": \"/opt/holoscan/models\",\n",
+ " \"models\": {\n",
+ " \"model\": \"/opt/holoscan/models\"\n",
+ " },\n",
+ " \"resources\": {\n",
+ " \"cpu\": 1,\n",
+ " \"gpu\": 1,\n",
+ " \"memory\": \"1Gi\",\n",
+ " \"gpuMemory\": \"1Gi\"\n",
+ " },\n",
+ " \"version\": 1\n",
+ "}\n",
+ "\n",
+ "2023-08-30 07:28:47 [INFO] Copying application from /opt/holoscan/app to /var/run/holoscan/export/app\n",
+ "\n",
+ "2023-08-30 07:28:47 [INFO] Copying application manifest file from /etc/holoscan/app.json to /var/run/holoscan/export/config/app.json\n",
+ "2023-08-30 07:28:47 [INFO] Copying pkg manifest file from /etc/holoscan/pkg.json to /var/run/holoscan/export/config/pkg.json\n",
+ "2023-08-30 07:28:47 [INFO] Copying application configuration from /var/holoscan/app.yaml to /var/run/holoscan/export/config/app.yaml\n",
+ "\n",
+ "2023-08-30 07:28:47 [INFO] Copying models from /opt/holoscan/models to /var/run/holoscan/export/models\n",
+ "\n",
+ "2023-08-30 07:28:47 [INFO] Copying documentation from /opt/holoscan/docs/ to /var/run/holoscan/export/docs\n",
+ "2023-08-30 07:28:47 [INFO] '/opt/holoscan/docs/' cannot be found.\n",
+ "\n",
+ "app config models\n"
+ ]
+ }
+ ],
+ "source": [
+ "!echo \"Display manifests and extract MAP contents to the host folder, ./export\"\n",
+ "!docker run --rm {tag_prefix}-x64-workstation-dgpu-linux-amd64:1.0 show\n",
+ "!rm -rf `pwd`/export && mkdir -p `pwd`/export\n",
+ "!docker run --rm -v `pwd`/export/:/var/run/holoscan/export/ {tag_prefix}-x64-workstation-dgpu-linux-amd64:1.0 extract\n",
+ "!ls `pwd`/export"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Executing packaged app locally\n",
+ "\n",
+ "The packaged app can be run locally through [MONAI Application Runner](/developing_with_sdk/executing_packaged_app_locally)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 57,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[2023-08-30 00:28:51,206] [INFO] (runner) - Checking dependencies...\n",
+ "[2023-08-30 00:28:51,206] [INFO] (runner) - --> Verifying if \"docker\" is installed...\n",
+ "\n",
+ "[2023-08-30 00:28:51,206] [INFO] (runner) - --> Verifying if \"docker-buildx\" is installed...\n",
+ "\n",
+ "[2023-08-30 00:28:51,207] [INFO] (runner) - --> Verifying if \"mednist_app-x64-workstation-dgpu-linux-amd64:1.0\" is available...\n",
+ "\n",
+ "[2023-08-30 00:28:51,263] [INFO] (runner) - Reading HAP/MAP manifest...\n",
+ "\u001b[sPreparing to copy...\u001b[?25l\u001b[u\u001b[2KCopying from container - 0B\u001b[?25h\u001b[u\u001b[2KSuccessfully copied 2.56kB to /tmp/tmplfd8b757/app.json\n",
+ "\u001b[sPreparing to copy...\u001b[?25l\u001b[u\u001b[2KCopying from container - 0B\u001b[?25h\u001b[u\u001b[2KSuccessfully copied 2.05kB to /tmp/tmplfd8b757/pkg.json\n",
+ "[2023-08-30 00:28:51,463] [INFO] (runner) - --> Verifying if \"nvidia-ctk\" is installed...\n",
+ "\n",
+ "[2023-08-30 00:28:51,629] [INFO] (common) - Launching container (d5b437535199) using image 'mednist_app-x64-workstation-dgpu-linux-amd64:1.0'...\n",
+ " container name: focused_jepsen\n",
+ " host name: mingq-dt\n",
+ " network: host\n",
+ " user: 1000:1000\n",
+ " ulimits: memlock=-1:-1, stack=67108864:67108864\n",
+ " cap_add: CAP_SYS_PTRACE\n",
+ " ipc mode: host\n",
+ " shared memory size: 67108864\n",
+ " devices: \n",
+ "2023-08-30 07:28:52 [INFO] Launching application python3 /opt/holoscan/app/mednist_classifier_monaideploy.py ...\n",
+ "\n",
+ "[2023-08-30 07:28:55,927] [INFO] (root) - Parsed args: Namespace(argv=['/opt/holoscan/app/mednist_classifier_monaideploy.py'], input=None, log_level=None, model=None, output=None, workdir=None)\n",
+ "\n",
+ "[2023-08-30 07:28:55,933] [INFO] (root) - AppContext object: AppContext(input_path=/var/holoscan/input, output_path=/var/holoscan/output, model_path=/opt/holoscan/models, workdir=/var/holoscan)\n",
+ "\n",
+ "[info] [app_driver.cpp:1025] Launching the driver/health checking service\n",
+ "\n",
+ "[info] [gxf_executor.cpp:210] Creating context\n",
+ "\n",
+ "[info] [server.cpp:73] Health checking server listening on 0.0.0.0:8777\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1595] Loading extensions from configs...\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1741] Activating Graph...\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1771] Running Graph...\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1773] Waiting for completion...\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1774] Graph execution waiting. Fragment: \n",
+ "\n",
+ "[info] [greedy_scheduler.cpp:190] Scheduling 3 entities\n",
+ "\n",
+ "/home/holoscan/.local/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:111: FutureWarning: : Class `AddChannel` has been deprecated since version 0.8. It will be removed in version 1.3. please use MetaTensor data type and monai.transforms.EnsureChannelFirst instead with `channel_dim='no_channel'`.\n",
+ "\n",
" warn_deprecated(obj, msg, warning_category)\n",
- "AbdomenCT\n",
- "\u001b[34mDone performing execution of operator MedNISTClassifierOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator DICOMTextSRWriterOperator\u001b[39m\n",
- "\u001b[32mExecuting operator DICOMTextSRWriterOperator \u001b[33m(Process ID: 1, Operator ID: 0e037b51-3949-4738-a827-f57d2ba082f6)\u001b[39m\n",
- "/root/.local/lib/python3.8/site-packages/pydicom/valuerep.py:443: UserWarning: Invalid value for VR UI: 'xyz'. Please see for allowed values for each VR.\n",
+ "\n",
+ "/home/holoscan/.local/lib/python3.8/site-packages/monai/data/meta_tensor.py:116: UserWarning: The given NumPy array is not writable, and PyTorch does not support non-writable tensors. This means writing to this tensor will result in undefined behavior. You may want to copy the array to protect its data or make it writable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at ../torch/csrc/utils/tensor_numpy.cpp:206.)\n",
+ "\n",
+ " return torch.as_tensor(x, *args, **_kwargs).as_subclass(cls) # type: ignore\n",
+ "\n",
+ "/home/holoscan/.local/lib/python3.8/site-packages/pydicom/valuerep.py:443: UserWarning: Invalid value for VR UI: 'xyz'. Please see for allowed values for each VR.\n",
+ "\n",
" warnings.warn(msg)\n",
- "[2023-07-11 21:39:55,214] [INFO] (root) - Finished writing DICOM instance to file /var/monai/output/1.2.826.0.1.3680043.8.498.11147135660136449723298304060083219290.dcm\n",
- "[2023-07-11 21:39:55,216] [INFO] (monai.deploy.operators.dicom_text_sr_writer_operator.DICOMTextSRWriterOperator) - DICOM SOP instance saved in /var/monai/output/1.2.826.0.1.3680043.8.498.11147135660136449723298304060083219290.dcm\n",
- "\u001b[34mDone performing execution of operator DICOMTextSRWriterOperator\n",
- "\u001b[39m\n"
+ "\n",
+ "[2023-08-30 07:29:01,433] [INFO] (root) - Finished writing DICOM instance to file /var/holoscan/output/1.2.826.0.1.3680043.8.498.13087581575145852698543141083118877098.dcm\n",
+ "\n",
+ "[2023-08-30 07:29:01,435] [INFO] (monai.deploy.operators.dicom_text_sr_writer_operator.DICOMTextSRWriterOperator) - DICOM SOP instance saved in /var/holoscan/output/1.2.826.0.1.3680043.8.498.13087581575145852698543141083118877098.dcm\n",
+ "\n",
+ "[info] [greedy_scheduler.cpp:369] Scheduler stopped: Some entities are waiting for execution, but there are no periodic or async entities to get out of the deadlock.\n",
+ "\n",
+ "[info] [greedy_scheduler.cpp:398] Scheduler finished.\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1783] Graph execution deactivating. Fragment: \n",
+ "\n",
+ "[info] [gxf_executor.cpp:1784] Deactivating Graph...\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1787] Graph execution finished. Fragment: \n",
+ "\n",
+ "[info] [gxf_executor.cpp:229] Destroying context\n",
+ "\n",
+ "AbdomenCT\n",
+ "\n",
+ "[2023-08-30 00:29:02,801] [INFO] (common) - Container 'focused_jepsen'(d5b437535199) exited.\n"
]
}
],
"source": [
- "!monai-deploy run mednist_app:latest \"input\" \"output\""
+ "# Clear the output folder and run the MAP. The input is expected to be a folder.\n",
+ "!rm -rf {ouput_folder}\n",
+ "!monai-deploy run -i $HOLOSCAN_INPUT_PATH -o $HOLOSCAN_OUTPUT_PATH mednist_app-x64-workstation-dgpu-linux-amd64:1.0"
]
},
{
"cell_type": "code",
- "execution_count": 9,
+ "execution_count": 58,
"metadata": {},
"outputs": [
{
@@ -653,27 +904,29 @@
}
],
"source": [
- "!cat output/output.json"
+ "!cat {output_folder}/output.json"
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Implementing and Packaging Application with MONAI Deploy App SDK\n",
"\n",
+ "In the following sections we will discuss the details of buildng the application that was packaged and run above.\n",
+ "\n",
"Based on the Torchscript model(`classifier.zip`), we will implement an application that process an input Jpeg image and write the prediction(classification) result as JSON file(`output.json`).\n",
"\n",
"In our inference application, we will define two operators:\n",
"\n",
"1. `LoadPILOperator` - Load a JPEG image from the input path and pass the loaded image object to the next operator.\n",
- " - This Operator does similar job with `LoadImage(image_only=True)` transform in *train_transforms*, but handles only one image.\n",
- " - **Input**: a file path ([`DataPath`](/modules/_autosummary/monai.deploy.core.domain.DataPath))\n",
+ " - **Input**: a file path (`Path`)\n",
" - **Output**: an image object in memory ([`Image`](/modules/_autosummary/monai.deploy.core.domain.Image))\n",
"2. `MedNISTClassifierOperator` - Pre-transform the given image by using MONAI's `Compose` class, feed to the Torchscript model (`classifier.zip`), and write the prediction into JSON file(`output.json`)\n",
" - Pre-transforms consist of three transforms -- `AddChannel`, `ScaleIntensity`, and `EnsureType`.\n",
" - **Input**: an image object in memory ([`Image`](/modules/_autosummary/monai.deploy.core.domain.Image))\n",
- " - **Output**: a folder path that the prediction result(`output.json`) would be written ([`DataPath`](/modules/_autosummary/monai.deploy.core.domain.DataPath))\n",
+ " - **Output**: a folder path that the prediction result(`output.json`) would be written (`Path`)\n",
"\n",
"The workflow of the application would look like this.\n",
"\n",
@@ -681,6 +934,7 @@
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -691,27 +945,27 @@
},
{
"cell_type": "code",
- "execution_count": 10,
+ "execution_count": 59,
"metadata": {},
"outputs": [],
"source": [
- "import monai.deploy.core as md\n",
- "from monai.deploy.core import (\n",
- " Application,\n",
- " DataPath,\n",
- " ExecutionContext,\n",
- " Image,\n",
- " InputContext,\n",
- " IOType,\n",
- " Operator,\n",
- " OutputContext,\n",
- ")\n",
+ "import logging\n",
+ "import os\n",
+ "from pathlib import Path\n",
+ "from typing import Optional\n",
+ "\n",
+ "import torch\n",
+ "\n",
+ "from monai.deploy.conditions import CountCondition\n",
+ "from monai.deploy.core import AppContext, Application, ConditionType, Fragment, Image, Operator, OperatorSpec\n",
+ "from monai.deploy.operators.dicom_text_sr_writer_operator import DICOMTextSRWriterOperator, EquipmentInfo, ModelInfo\n",
"from monai.transforms import AddChannel, Compose, EnsureType, ScaleIntensity\n",
"\n",
"MEDNIST_CLASSES = [\"AbdomenCT\", \"BreastMRI\", \"CXR\", \"ChestCT\", \"Hand\", \"HeadCT\"]"
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -722,33 +976,69 @@
},
{
"cell_type": "code",
- "execution_count": 11,
+ "execution_count": 60,
"metadata": {},
"outputs": [],
"source": [
- "@md.input(\"image\", DataPath, IOType.DISK)\n",
- "@md.output(\"image\", Image, IOType.IN_MEMORY)\n",
- "@md.env(pip_packages=[\"pillow\"])\n",
"class LoadPILOperator(Operator):\n",
" \"\"\"Load image from the given input (DataPath) and set numpy array to the output (Image).\"\"\"\n",
"\n",
- " def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):\n",
+ " DEFAULT_INPUT_FOLDER = Path.cwd() / \"input\"\n",
+ " DEFAULT_OUTPUT_NAME = \"image\"\n",
+ "\n",
+ " # For now, need to have the input folder as an instance attribute, set on init.\n",
+ " # If dynamically changing the input folder, per compute, then use a (optional) input port to convey the\n",
+ " # value of the input folder, which is then emitted by a upstream operator.\n",
+ " def __init__(\n",
+ " self,\n",
+ " fragment: Fragment,\n",
+ " *args,\n",
+ " input_folder: Path = DEFAULT_INPUT_FOLDER,\n",
+ " output_name: str = DEFAULT_OUTPUT_NAME,\n",
+ " **kwargs,\n",
+ " ):\n",
+ " \"\"\"Creates an loader object with the input folder and the output port name overrides as needed.\n",
+ "\n",
+ " Args:\n",
+ " fragment (Fragment): An instance of the Application class which is derived from Fragment.\n",
+ " input_folder (Path): Folder from which to load input file(s).\n",
+ " Defaults to `input` in the current working directory.\n",
+ " output_name (str): Name of the output port, which is an image object. Defaults to `image`.\n",
+ " \"\"\"\n",
+ "\n",
+ " self._logger = logging.getLogger(\"{}.{}\".format(__name__, type(self).__name__))\n",
+ " self.input_path = input_folder\n",
+ " self.index = 0\n",
+ " self.output_name_image = (\n",
+ " output_name.strip() if output_name and len(output_name.strip()) > 0 else LoadPILOperator.DEFAULT_OUTPUT_NAME\n",
+ " )\n",
+ "\n",
+ " super().__init__(fragment, *args, **kwargs)\n",
+ "\n",
+ " def setup(self, spec: OperatorSpec):\n",
+ " \"\"\"Set up the named input and output port(s)\"\"\"\n",
+ " spec.output(self.output_name_image)\n",
+ "\n",
+ " def compute(self, op_input, op_output, context):\n",
" import numpy as np\n",
" from PIL import Image as PILImage\n",
"\n",
- " input_path = op_input.get().path\n",
+ " # Input path is stored in the object attribute, but could change to use a named port if need be.\n",
+ " input_path = self.input_path\n",
" if input_path.is_dir():\n",
- " input_path = next(input_path.glob(\"*.*\")) # take the first file\n",
+ " input_path = next(self.input_path.glob(\"*.*\")) # take the first file\n",
"\n",
" image = PILImage.open(input_path)\n",
" image = image.convert(\"L\") # convert to greyscale image\n",
" image_arr = np.asarray(image)\n",
"\n",
" output_image = Image(image_arr) # create Image domain object with a numpy array\n",
- " op_output.set(output_image)"
+ " op_output.emit(output_image, self.output_name_image) # cannot omit the name even if single output.\n",
+ "\n"
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -757,53 +1047,131 @@
},
{
"cell_type": "code",
- "execution_count": 12,
+ "execution_count": 61,
"metadata": {},
"outputs": [],
"source": [
- "@md.input(\"image\", Image, IOType.IN_MEMORY)\n",
- "@md.output(\"output\", DataPath, IOType.DISK)\n",
- "@md.env(pip_packages=[\"monai\"])\n",
"class MedNISTClassifierOperator(Operator):\n",
- " \"\"\"Classifies the given image and returns the class name.\"\"\"\n",
+ " \"\"\"Classifies the given image and returns the class name.\n",
+ "\n",
+ " Named inputs:\n",
+ " image: Image object for which to generate the classification.\n",
+ " output_folder: Optional, the path to save the results JSON file, overridingthe the one set on __init__\n",
+ "\n",
+ " Named output:\n",
+ " result_text: The classification results in text.\n",
+ " \"\"\"\n",
+ "\n",
+ " DEFAULT_OUTPUT_FOLDER = Path.cwd() / \"classification_results\"\n",
+ " # For testing the app directly, the model should be at the following path.\n",
+ " MODEL_LOCAL_PATH = Path(os.environ.get(\"HOLOSCAN_MODEL_PATH\", Path.cwd() / \"model/model.ts\"))\n",
+ "\n",
+ " def __init__(\n",
+ " self,\n",
+ " frament: Fragment,\n",
+ " *args,\n",
+ " app_context: AppContext,\n",
+ " model_name: Optional[str] = \"\",\n",
+ " model_path: Path = MODEL_LOCAL_PATH,\n",
+ " output_folder: Path = DEFAULT_OUTPUT_FOLDER,\n",
+ " **kwargs,\n",
+ " ):\n",
+ " \"\"\"Creates an instance with the reference back to the containing application/fragment.\n",
+ "\n",
+ " fragment (Fragment): An instance of the Application class which is derived from Fragment.\n",
+ " model_name (str, optional): Name of the model. Default to \"\" for single model app.\n",
+ " model_path (Path): Path to the model file. Defaults to model/models.ts of current working dir.\n",
+ " output_folder (Path, optional): output folder for saving the classification results JSON file.\n",
+ " \"\"\"\n",
+ "\n",
+ " # the names used for the model inference input and output\n",
+ " self._input_dataset_key = \"image\"\n",
+ " self._pred_dataset_key = \"pred\"\n",
+ "\n",
+ " # The names used for the operator input and output\n",
+ " self.input_name_image = \"image\"\n",
+ " self.output_name_result = \"result_text\"\n",
+ "\n",
+ " # The name of the optional input port for passing data to override the output folder path.\n",
+ " self.input_name_output_folder = \"output_folder\"\n",
+ "\n",
+ " # The output folder set on the object can be overriden at each compute by data in the optional named input\n",
+ " self.output_folder = output_folder\n",
+ "\n",
+ " # Need the name when there are multiple models loaded\n",
+ " self._model_name = model_name.strip() if isinstance(model_name, str) else \"\"\n",
+ " # Need the path to load the models when they are not loaded in the execution context\n",
+ " self.model_path = model_path\n",
+ " self.app_context = app_context\n",
+ " self.model = self._get_model(self.app_context, self.model_path, self._model_name)\n",
+ "\n",
+ " # This needs to be at the end of the constructor.\n",
+ " super().__init__(frament, *args, **kwargs)\n",
+ "\n",
+ " def _get_model(self, app_context: AppContext, model_path: Path, model_name: str):\n",
+ " \"\"\"Load the model with the given name from context or model path\n",
+ "\n",
+ " Args:\n",
+ " app_context (AppContext): The application context object holding the model(s)\n",
+ " model_path (Path): The path to the model file, as a backup to load model directly\n",
+ " model_name (str): The name of the model, when multiples are loaded in the context\n",
+ " \"\"\"\n",
+ "\n",
+ " if app_context.models:\n",
+ " # `app_context.models.get(model_name)` returns a model instance if exists.\n",
+ " # If model_name is not specified and only one model exists, it returns that model.\n",
+ " model = app_context.models.get(model_name)\n",
+ " else:\n",
+ " model = torch.jit.load(\n",
+ " MedNISTClassifierOperator.MODEL_LOCAL_PATH,\n",
+ " map_location=torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\"),\n",
+ " )\n",
+ "\n",
+ " return model\n",
+ "\n",
+ " def setup(self, spec: OperatorSpec):\n",
+ " \"\"\"Set up the operator named input and named output, both are in-memory objects.\"\"\"\n",
+ "\n",
+ " spec.input(self.input_name_image)\n",
+ " spec.input(self.input_name_output_folder).condition(ConditionType.NONE) # Optional for overriding.\n",
+ " spec.output(self.output_name_result).condition(ConditionType.NONE) # Not forcing a downstream receiver.\n",
"\n",
" @property\n",
" def transform(self):\n",
" return Compose([AddChannel(), ScaleIntensity(), EnsureType()])\n",
"\n",
- " def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):\n",
+ " def compute(self, op_input, op_output, context):\n",
" import json\n",
"\n",
" import torch\n",
"\n",
- " img = op_input.get().asnumpy() # (64, 64), uint8\n",
+ " img = op_input.receive(self.input_name_image).asnumpy() # (64, 64), uint8. Input validation can be added.\n",
" image_tensor = self.transform(img) # (1, 64, 64), torch.float64\n",
" image_tensor = image_tensor[None].float() # (1, 1, 64, 64), torch.float32\n",
"\n",
" device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
" image_tensor = image_tensor.to(device)\n",
"\n",
- " model = context.models.get() # get a TorchScriptModel object\n",
- "\n",
" with torch.no_grad():\n",
- " outputs = model(image_tensor)\n",
+ " outputs = self.model(image_tensor)\n",
"\n",
" _, output_classes = outputs.max(dim=1)\n",
"\n",
" result = MEDNIST_CLASSES[output_classes[0]] # get the class name\n",
" print(result)\n",
+ " op_output.emit(result, self.output_name_result)\n",
"\n",
- " # Get output (folder) path and create the folder if not exists\n",
- " output_folder = op_output.get().path\n",
- " output_folder.mkdir(parents=True, exist_ok=True)\n",
- "\n",
- " # Write result to \"output.json\"\n",
- " output_path = output_folder / \"output.json\"\n",
+ " # Get output folder, with value in optional input port overriding the obj attribute\n",
+ " output_folder_on_compute = op_input.receive(self.input_name_output_folder) or self.output_folder\n",
+ " Path.mkdir(output_folder_on_compute, parents=True, exist_ok=True) # Let exception bubble up if raised.\n",
+ " output_path = output_folder_on_compute / \"output.json\"\n",
" with open(output_path, \"w\") as fp:\n",
- " json.dump(result, fp)"
+ " json.dump(result, fp)\n",
+ "\n"
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -818,23 +1186,41 @@
},
{
"cell_type": "code",
- "execution_count": 13,
+ "execution_count": 62,
"metadata": {},
"outputs": [],
"source": [
- "@md.resource(cpu=1, gpu=1, memory=\"1Gi\")\n",
- "@md.env(pip_packages=[\"pydicom >= 2.3.0\", \"highdicom>=0.18.2\"]) # for the use of DICOM Writer operators\n",
"class App(Application):\n",
" \"\"\"Application class for the MedNIST classifier.\"\"\"\n",
"\n",
" def compose(self):\n",
- " load_pil_op = LoadPILOperator()\n",
- " classifier_op = MedNISTClassifierOperator()\n",
- "\n",
- " self.add_flow(load_pil_op, classifier_op)"
+ " app_context = Application.init_app_context({}) # Do not pass argv in Jupyter Notebook\n",
+ " app_input_path = Path(app_context.input_path)\n",
+ " app_output_path = Path(app_context.output_path)\n",
+ " model_path = Path(app_context.model_path)\n",
+ " load_pil_op = LoadPILOperator(self, CountCondition(self, 1), input_folder=app_input_path, name=\"pil_loader_op\")\n",
+ " classifier_op = MedNISTClassifierOperator(\n",
+ " self, app_context=app_context, output_folder=app_output_path, model_path=model_path, name=\"classifier_op\"\n",
+ " )\n",
+ "\n",
+ " my_model_info = ModelInfo(\"MONAI WG Trainer\", \"MEDNIST Classifier\", \"0.1\", \"xyz\")\n",
+ " my_equipment = EquipmentInfo(manufacturer=\"MOANI Deploy App SDK\", manufacturer_model=\"DICOM SR Writer\")\n",
+ " my_special_tags = {\"SeriesDescription\": \"Not for clinical use. The result is for research use only.\"}\n",
+ " dicom_sr_operator = DICOMTextSRWriterOperator(\n",
+ " self,\n",
+ " copy_tags=False,\n",
+ " model_info=my_model_info,\n",
+ " equipment_info=my_equipment,\n",
+ " custom_tags=my_special_tags,\n",
+ " output_folder=app_output_path,\n",
+ " )\n",
+ "\n",
+ " self.add_flow(load_pil_op, classifier_op, {(\"image\", \"image\")})\n",
+ " self.add_flow(classifier_op, dicom_sr_operator, {(\"result_text\", \"text\")})\n"
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -851,59 +1237,54 @@
},
{
"cell_type": "code",
- "execution_count": 14,
- "metadata": {},
- "outputs": [],
- "source": [
- "!rm -rf output\n",
- "\n",
- "app = App()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 15,
+ "execution_count": 63,
"metadata": {},
"outputs": [
{
- "name": "stdout",
+ "name": "stderr",
"output_type": "stream",
"text": [
- "\u001b[34mGoing to initiate execution of operator LoadPILOperator\u001b[39m\n",
- "\u001b[32mExecuting operator LoadPILOperator \u001b[33m(Process ID: 409880, Operator ID: 06991530-662d-46eb-83f2-e8e1368c4bb1)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator LoadPILOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator MedNISTClassifierOperator\u001b[39m\n",
- "\u001b[32mExecuting operator MedNISTClassifierOperator \u001b[33m(Process ID: 409880, Operator ID: 1c4a4293-869f-4843-83f0-2c857c3bde96)\u001b[39m\n"
+ "[2023-08-30 00:29:04,860] [INFO] (root) - Parsed args: Namespace(argv=[], input=None, log_level=None, model=None, output=None, workdir=None)\n",
+ "[2023-08-30 00:29:04,876] [INFO] (root) - AppContext object: AppContext(input_path=input, output_path=output, model_path=models, workdir=)\n",
+ "[info] [gxf_executor.cpp:210] Creating context\n",
+ "[info] [gxf_executor.cpp:1595] Loading extensions from configs...\n",
+ "[info] [gxf_executor.cpp:1741] Activating Graph...\n",
+ "[info] [gxf_executor.cpp:1771] Running Graph...\n",
+ "[info] [gxf_executor.cpp:1773] Waiting for completion...\n",
+ "[info] [gxf_executor.cpp:1774] Graph execution waiting. Fragment: \n",
+ "[info] [greedy_scheduler.cpp:190] Scheduling 3 entities\n",
+ "[2023-08-30 00:29:05,845] [INFO] (root) - Finished writing DICOM instance to file output/1.2.826.0.1.3680043.8.498.88152747946307619191879398109230140381.dcm\n",
+ "[2023-08-30 00:29:05,847] [INFO] (monai.deploy.operators.dicom_text_sr_writer_operator.DICOMTextSRWriterOperator) - DICOM SOP instance saved in output/1.2.826.0.1.3680043.8.498.88152747946307619191879398109230140381.dcm\n"
]
},
{
- "name": "stderr",
+ "name": "stdout",
"output_type": "stream",
"text": [
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:111: FutureWarning: : Class `AddChannel` has been deprecated since version 0.8. It will be removed in version 1.3. please use MetaTensor data type and monai.transforms.EnsureChannelFirst instead with `channel_dim='no_channel'`.\n",
- " warn_deprecated(obj, msg, warning_category)\n",
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/monai/data/meta_tensor.py:116: UserWarning: The given NumPy array is not writable, and PyTorch does not support non-writable tensors. This means writing to this tensor will result in undefined behavior. You may want to copy the array to protect its data or make it writable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at ../torch/csrc/utils/tensor_numpy.cpp:206.)\n",
- " return torch.as_tensor(x, *args, **_kwargs).as_subclass(cls) # type: ignore\n"
+ "AbdomenCT\n"
]
},
{
- "name": "stdout",
+ "name": "stderr",
"output_type": "stream",
"text": [
- "AbdomenCT\n",
- "\u001b[34mDone performing execution of operator MedNISTClassifierOperator\n",
- "\u001b[39m\n"
+ "[info] [greedy_scheduler.cpp:369] Scheduler stopped: Some entities are waiting for execution, but there are no periodic or async entities to get out of the deadlock.\n",
+ "[info] [greedy_scheduler.cpp:398] Scheduler finished.\n",
+ "[info] [gxf_executor.cpp:1783] Graph execution deactivating. Fragment: \n",
+ "[info] [gxf_executor.cpp:1784] Deactivating Graph...\n",
+ "[info] [gxf_executor.cpp:1787] Graph execution finished. Fragment: \n",
+ "[info] [gxf_executor.cpp:229] Destroying context\n"
]
}
],
"source": [
- "app.run(input=\"input/AbdomenCT_007000.jpeg\", output=\"output\", model=\"classifier.zip\")"
+ "!rm -rf $HOLOSCAN_OUTPUT_PATH\n",
+ "app = App().run()"
]
},
{
"cell_type": "code",
- "execution_count": 16,
+ "execution_count": 64,
"metadata": {},
"outputs": [
{
@@ -915,10 +1296,11 @@
}
],
"source": [
- "!cat output/output.json"
+ "!cat $HOLOSCAN_OUTPUT_PATH/output.json"
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {
"tags": []
@@ -928,7 +1310,7 @@
"\n",
"```python\n",
"if __name__ == \"__main__\":\n",
- " App(do_run=True)\n",
+ " App().run()\n",
"```\n",
"\n",
"The above lines are needed to execute the application code by using `python` interpreter."
@@ -936,21 +1318,31 @@
},
{
"cell_type": "code",
- "execution_count": 17,
+ "execution_count": 65,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Create an application folder\n",
+ "!mkdir -p mednist_app && rm -rf mednist_app/*"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 66,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "Overwriting mednist_classifier_monaideploy.py\n"
+ "Writing mednist_app/mednist_classifier_monaideploy.py\n"
]
}
],
"source": [
- "%%writefile mednist_classifier_monaideploy.py\n",
+ "%%writefile mednist_app/mednist_classifier_monaideploy.py\n",
"\n",
- "# Copyright 2021 MONAI Consortium\n",
+ "# Copyright 2021-2023 MONAI Consortium\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",
"# You may obtain a copy of the License at\n",
@@ -961,189 +1353,497 @@
"# See the License for the specific language governing permissions and\n",
"# limitations under the License.\n",
"\n",
- "import monai.deploy.core as md # 'md' stands for MONAI Deploy (or can use 'core' instead)\n",
- "from monai.deploy.core import (\n",
- " Application,\n",
- " DataPath,\n",
- " ExecutionContext,\n",
- " Image,\n",
- " InputContext,\n",
- " IOType,\n",
- " Operator,\n",
- " OutputContext,\n",
- ")\n",
+ "import logging\n",
+ "import os\n",
+ "from pathlib import Path\n",
+ "from typing import Optional\n",
+ "\n",
+ "import torch\n",
+ "\n",
+ "from monai.deploy.conditions import CountCondition\n",
+ "from monai.deploy.core import AppContext, Application, ConditionType, Fragment, Image, Operator, OperatorSpec\n",
+ "from monai.deploy.operators.dicom_text_sr_writer_operator import DICOMTextSRWriterOperator, EquipmentInfo, ModelInfo\n",
"from monai.transforms import AddChannel, Compose, EnsureType, ScaleIntensity\n",
"\n",
"MEDNIST_CLASSES = [\"AbdomenCT\", \"BreastMRI\", \"CXR\", \"ChestCT\", \"Hand\", \"HeadCT\"]\n",
"\n",
"\n",
- "@md.input(\"image\", DataPath, IOType.DISK)\n",
- "@md.output(\"image\", Image, IOType.IN_MEMORY)\n",
- "@md.env(pip_packages=[\"pillow\"])\n",
+ "# @md.env(pip_packages=[\"pillow\"])\n",
"class LoadPILOperator(Operator):\n",
" \"\"\"Load image from the given input (DataPath) and set numpy array to the output (Image).\"\"\"\n",
"\n",
- " def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):\n",
+ " DEFAULT_INPUT_FOLDER = Path.cwd() / \"input\"\n",
+ " DEFAULT_OUTPUT_NAME = \"image\"\n",
+ "\n",
+ " # For now, need to have the input folder as an instance attribute, set on init.\n",
+ " # If dynamically changing the input folder, per compute, then use a (optional) input port to convey the\n",
+ " # value of the input folder, which is then emitted by a upstream operator.\n",
+ " def __init__(\n",
+ " self,\n",
+ " fragment: Fragment,\n",
+ " *args,\n",
+ " input_folder: Path = DEFAULT_INPUT_FOLDER,\n",
+ " output_name: str = DEFAULT_OUTPUT_NAME,\n",
+ " **kwargs,\n",
+ " ):\n",
+ " \"\"\"Creates an loader object with the input folder and the output port name overrides as needed.\n",
+ "\n",
+ " Args:\n",
+ " fragment (Fragment): An instance of the Application class which is derived from Fragment.\n",
+ " input_folder (Path): Folder from which to load input file(s).\n",
+ " Defaults to `input` in the current working directory.\n",
+ " output_name (str): Name of the output port, which is an image object. Defaults to `image`.\n",
+ " \"\"\"\n",
+ "\n",
+ " self._logger = logging.getLogger(\"{}.{}\".format(__name__, type(self).__name__))\n",
+ " self.input_path = input_folder\n",
+ " self.index = 0\n",
+ " self.output_name_image = (\n",
+ " output_name.strip() if output_name and len(output_name.strip()) > 0 else LoadPILOperator.DEFAULT_OUTPUT_NAME\n",
+ " )\n",
+ "\n",
+ " super().__init__(fragment, *args, **kwargs)\n",
+ "\n",
+ " def setup(self, spec: OperatorSpec):\n",
+ " \"\"\"Set up the named input and output port(s)\"\"\"\n",
+ " spec.output(self.output_name_image)\n",
+ "\n",
+ " def compute(self, op_input, op_output, context):\n",
" import numpy as np\n",
" from PIL import Image as PILImage\n",
"\n",
- " input_path = op_input.get().path\n",
+ " # Input path is stored in the object attribute, but could change to use a named port if need be.\n",
+ " input_path = self.input_path\n",
" if input_path.is_dir():\n",
- " input_path = next(input_path.glob(\"*.*\")) # take the first file\n",
+ " input_path = next(self.input_path.glob(\"*.*\")) # take the first file\n",
"\n",
" image = PILImage.open(input_path)\n",
" image = image.convert(\"L\") # convert to greyscale image\n",
" image_arr = np.asarray(image)\n",
"\n",
" output_image = Image(image_arr) # create Image domain object with a numpy array\n",
- " op_output.set(output_image)\n",
+ " op_output.emit(output_image, self.output_name_image) # cannot omit the name even if single output.\n",
"\n",
"\n",
- "@md.input(\"image\", Image, IOType.IN_MEMORY)\n",
- "@md.output(\"output\", DataPath, IOType.DISK)\n",
- "@md.env(pip_packages=[\"monai\"])\n",
+ "# @md.env(pip_packages=[\"monai\"])\n",
"class MedNISTClassifierOperator(Operator):\n",
- " \"\"\"Classifies the given image and returns the class name.\"\"\"\n",
+ " \"\"\"Classifies the given image and returns the class name.\n",
+ "\n",
+ " Named inputs:\n",
+ " image: Image object for which to generate the classification.\n",
+ " output_folder: Optional, the path to save the results JSON file, overridingthe the one set on __init__\n",
+ "\n",
+ " Named output:\n",
+ " result_text: The classification results in text.\n",
+ " \"\"\"\n",
+ "\n",
+ " DEFAULT_OUTPUT_FOLDER = Path.cwd() / \"classification_results\"\n",
+ " # For testing the app directly, the model should be at the following path.\n",
+ " MODEL_LOCAL_PATH = Path(os.environ.get(\"HOLOSCAN_MODEL_PATH\", Path.cwd() / \"model/model.ts\"))\n",
+ "\n",
+ " def __init__(\n",
+ " self,\n",
+ " frament: Fragment,\n",
+ " *args,\n",
+ " app_context: AppContext,\n",
+ " model_name: Optional[str] = \"\",\n",
+ " model_path: Path = MODEL_LOCAL_PATH,\n",
+ " output_folder: Path = DEFAULT_OUTPUT_FOLDER,\n",
+ " **kwargs,\n",
+ " ):\n",
+ " \"\"\"Creates an instance with the reference back to the containing application/fragment.\n",
+ "\n",
+ " fragment (Fragment): An instance of the Application class which is derived from Fragment.\n",
+ " model_name (str, optional): Name of the model. Default to \"\" for single model app.\n",
+ " model_path (Path): Path to the model file. Defaults to model/models.ts of current working dir.\n",
+ " output_folder (Path, optional): output folder for saving the classification results JSON file.\n",
+ " \"\"\"\n",
+ "\n",
+ " # the names used for the model inference input and output\n",
+ " self._input_dataset_key = \"image\"\n",
+ " self._pred_dataset_key = \"pred\"\n",
+ "\n",
+ " # The names used for the operator input and output\n",
+ " self.input_name_image = \"image\"\n",
+ " self.output_name_result = \"result_text\"\n",
+ "\n",
+ " # The name of the optional input port for passing data to override the output folder path.\n",
+ " self.input_name_output_folder = \"output_folder\"\n",
+ "\n",
+ " # The output folder set on the object can be overriden at each compute by data in the optional named input\n",
+ " self.output_folder = output_folder\n",
+ "\n",
+ " # Need the name when there are multiple models loaded\n",
+ " self._model_name = model_name.strip() if isinstance(model_name, str) else \"\"\n",
+ " # Need the path to load the models when they are not loaded in the execution context\n",
+ " self.model_path = model_path\n",
+ " self.app_context = app_context\n",
+ " self.model = self._get_model(self.app_context, self.model_path, self._model_name)\n",
+ "\n",
+ " # This needs to be at the end of the constructor.\n",
+ " super().__init__(frament, *args, **kwargs)\n",
+ "\n",
+ " def _get_model(self, app_context: AppContext, model_path: Path, model_name: str):\n",
+ " \"\"\"Load the model with the given name from context or model path\n",
+ "\n",
+ " Args:\n",
+ " app_context (AppContext): The application context object holding the model(s)\n",
+ " model_path (Path): The path to the model file, as a backup to load model directly\n",
+ " model_name (str): The name of the model, when multiples are loaded in the context\n",
+ " \"\"\"\n",
+ "\n",
+ " if app_context.models:\n",
+ " # `app_context.models.get(model_name)` returns a model instance if exists.\n",
+ " # If model_name is not specified and only one model exists, it returns that model.\n",
+ " model = app_context.models.get(model_name)\n",
+ " else:\n",
+ " model = torch.jit.load(\n",
+ " MedNISTClassifierOperator.MODEL_LOCAL_PATH,\n",
+ " map_location=torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\"),\n",
+ " )\n",
+ "\n",
+ " return model\n",
+ "\n",
+ " def setup(self, spec: OperatorSpec):\n",
+ " \"\"\"Set up the operator named input and named output, both are in-memory objects.\"\"\"\n",
+ "\n",
+ " spec.input(self.input_name_image)\n",
+ " spec.input(self.input_name_output_folder).condition(ConditionType.NONE) # Optional for overriding.\n",
+ " spec.output(self.output_name_result).condition(ConditionType.NONE) # Not forcing a downstream receiver.\n",
"\n",
" @property\n",
" def transform(self):\n",
" return Compose([AddChannel(), ScaleIntensity(), EnsureType()])\n",
"\n",
- " def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):\n",
+ " def compute(self, op_input, op_output, context):\n",
" import json\n",
"\n",
" import torch\n",
"\n",
- " img = op_input.get().asnumpy() # (64, 64), uint8\n",
+ " img = op_input.receive(self.input_name_image).asnumpy() # (64, 64), uint8. Input validation can be added.\n",
" image_tensor = self.transform(img) # (1, 64, 64), torch.float64\n",
" image_tensor = image_tensor[None].float() # (1, 1, 64, 64), torch.float32\n",
"\n",
" device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
" image_tensor = image_tensor.to(device)\n",
"\n",
- " model = context.models.get() # get a TorchScriptModel object\n",
- "\n",
" with torch.no_grad():\n",
- " outputs = model(image_tensor)\n",
+ " outputs = self.model(image_tensor)\n",
"\n",
" _, output_classes = outputs.max(dim=1)\n",
"\n",
" result = MEDNIST_CLASSES[output_classes[0]] # get the class name\n",
" print(result)\n",
+ " op_output.emit(result, self.output_name_result)\n",
"\n",
- " # Get output (folder) path and create the folder if not exists\n",
- " output_folder = op_output.get().path\n",
- " output_folder.mkdir(parents=True, exist_ok=True)\n",
- "\n",
- " # Write result to \"output.json\"\n",
- " output_path = output_folder / \"output.json\"\n",
+ " # Get output folder, with value in optional input port overriding the obj attribute\n",
+ " output_folder_on_compute = op_input.receive(self.input_name_output_folder) or self.output_folder\n",
+ " Path.mkdir(output_folder_on_compute, parents=True, exist_ok=True) # Let exception bubble up if raised.\n",
+ " output_path = output_folder_on_compute / \"output.json\"\n",
" with open(output_path, \"w\") as fp:\n",
" json.dump(result, fp)\n",
"\n",
"\n",
- "@md.resource(cpu=1, gpu=1, memory=\"1Gi\")\n",
- "@md.env(pip_packages=[\"pydicom >= 2.3.0\", \"highdicom>=0.18.2\"]) # for the use of DICOM Writer operators\n",
+ "# @md.resource(cpu=1, gpu=1, memory=\"1Gi\")\n",
"class App(Application):\n",
" \"\"\"Application class for the MedNIST classifier.\"\"\"\n",
"\n",
" def compose(self):\n",
- " load_pil_op = LoadPILOperator()\n",
- " classifier_op = MedNISTClassifierOperator()\n",
- "\n",
- " self.add_flow(load_pil_op, classifier_op)\n",
+ " # Use Commandline options over environment variables to init context.\n",
+ " app_context = Application.init_app_context(self.argv)\n",
+ " app_input_path = Path(app_context.input_path)\n",
+ " app_output_path = Path(app_context.output_path)\n",
+ " model_path = Path(app_context.model_path)\n",
+ " load_pil_op = LoadPILOperator(self, CountCondition(self, 1), input_folder=app_input_path, name=\"pil_loader_op\")\n",
+ " classifier_op = MedNISTClassifierOperator(\n",
+ " self, app_context=app_context, output_folder=app_output_path, model_path=model_path, name=\"classifier_op\"\n",
+ " )\n",
+ "\n",
+ " my_model_info = ModelInfo(\"MONAI WG Trainer\", \"MEDNIST Classifier\", \"0.1\", \"xyz\")\n",
+ " my_equipment = EquipmentInfo(manufacturer=\"MOANI Deploy App SDK\", manufacturer_model=\"DICOM SR Writer\")\n",
+ " my_special_tags = {\"SeriesDescription\": \"Not for clinical use. The result is for research use only.\"}\n",
+ " dicom_sr_operator = DICOMTextSRWriterOperator(\n",
+ " self,\n",
+ " copy_tags=False,\n",
+ " model_info=my_model_info,\n",
+ " equipment_info=my_equipment,\n",
+ " custom_tags=my_special_tags,\n",
+ " output_folder=app_output_path,\n",
+ " )\n",
+ "\n",
+ " self.add_flow(load_pil_op, classifier_op, {(\"image\", \"image\")})\n",
+ " self.add_flow(classifier_op, dicom_sr_operator, {(\"result_text\", \"text\")})\n",
"\n",
"\n",
"if __name__ == \"__main__\":\n",
- " App(do_run=True)"
+ " App().run()\n"
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
- "In this time, let's execute the app in the command line."
+ "This time, let's execute the app on the command line.\n",
+ "\n",
+ ":::{note}\n",
+ "Since the environment variables have been set and contain the correct paths, it is not necessary to provide the command line options on running the application, though the following demonstrates the use of the options.\n",
+ ":::"
]
},
{
"cell_type": "code",
- "execution_count": 18,
+ "execution_count": 67,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "\u001b[34mGoing to initiate execution of operator LoadPILOperator\u001b[39m\n",
- "\u001b[32mExecuting operator LoadPILOperator \u001b[33m(Process ID: 410692, Operator ID: c6ecd716-26ef-4706-8cd4-11fc7f3179bb)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator LoadPILOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator MedNISTClassifierOperator\u001b[39m\n",
- "\u001b[32mExecuting operator MedNISTClassifierOperator \u001b[33m(Process ID: 410692, Operator ID: 7b972a34-7f9b-472e-ad4c-394526e9c20b)\u001b[39m\n",
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:111: FutureWarning: : Class `AddChannel` has been deprecated since version 0.8. It will be removed in version 1.3. please use MetaTensor data type and monai.transforms.EnsureChannelFirst instead with `channel_dim='no_channel'`.\n",
+ "[2023-08-30 00:29:14,027] [INFO] (root) - Parsed args: Namespace(argv=['mednist_app/mednist_classifier_monaideploy.py', '-i', 'input', '-o', 'output', '-m', 'models', '-l', 'DEBUG'], input=PosixPath('/home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/input'), log_level='DEBUG', model=PosixPath('/home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/models'), output=PosixPath('/home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/output'), workdir=None)\n",
+ "[2023-08-30 00:29:14,033] [INFO] (root) - AppContext object: AppContext(input_path=/home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/input, output_path=/home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/output, model_path=/home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/models, workdir=)\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:210] Creating context\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1595] Loading extensions from configs...\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1741] Activating Graph...\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1771] Running Graph...\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1773] Waiting for completion...\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1774] Graph execution waiting. Fragment: \n",
+ "[\u001b[32minfo\u001b[m] [greedy_scheduler.cpp:190] Scheduling 3 entities\n",
+ "/home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:111: FutureWarning: : Class `AddChannel` has been deprecated since version 0.8. It will be removed in version 1.3. please use MetaTensor data type and monai.transforms.EnsureChannelFirst instead with `channel_dim='no_channel'`.\n",
" warn_deprecated(obj, msg, warning_category)\n",
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/monai/data/meta_tensor.py:116: UserWarning: The given NumPy array is not writable, and PyTorch does not support non-writable tensors. This means writing to this tensor will result in undefined behavior. You may want to copy the array to protect its data or make it writable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at ../torch/csrc/utils/tensor_numpy.cpp:206.)\n",
+ "/home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages/monai/data/meta_tensor.py:116: UserWarning: The given NumPy array is not writable, and PyTorch does not support non-writable tensors. This means writing to this tensor will result in undefined behavior. You may want to copy the array to protect its data or make it writable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at ../torch/csrc/utils/tensor_numpy.cpp:206.)\n",
" return torch.as_tensor(x, *args, **_kwargs).as_subclass(cls) # type: ignore\n",
"AbdomenCT\n",
- "\u001b[34mDone performing execution of operator MedNISTClassifierOperator\n",
- "\u001b[39m\n"
+ "[2023-08-30 00:29:17,180] [DEBUG] (monai.deploy.operators.dicom_text_sr_writer_operator.DICOMTextSRWriterOperator) - Writing DICOM object...\n",
+ "\n",
+ "[2023-08-30 00:29:17,180] [DEBUG] (root) - Writing DICOM common modules...\n",
+ "/home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages/pydicom/valuerep.py:443: UserWarning: Invalid value for VR UI: 'xyz'. Please see for allowed values for each VR.\n",
+ " warnings.warn(msg)\n",
+ "[2023-08-30 00:29:17,183] [DEBUG] (root) - DICOM common modules written:\n",
+ "Dataset.file_meta -------------------------------\n",
+ "(0002, 0000) File Meta Information Group Length UL: 198\n",
+ "(0002, 0001) File Meta Information Version OB: b'01'\n",
+ "(0002, 0002) Media Storage SOP Class UID UI: Basic Text SR Storage\n",
+ "(0002, 0003) Media Storage SOP Instance UID UI: 1.2.826.0.1.3680043.8.498.48571967537049939109703063489026494794\n",
+ "(0002, 0010) Transfer Syntax UID UI: Implicit VR Little Endian\n",
+ "(0002, 0012) Implementation Class UID UI: 1.2.40.0.13.1.1.1\n",
+ "(0002, 0013) Implementation Version Name SH: '0.5.1+22.g029f8'\n",
+ "-------------------------------------------------\n",
+ "(0008, 0005) Specific Character Set CS: 'ISO_IR 100'\n",
+ "(0008, 0012) Instance Creation Date DA: '20230830'\n",
+ "(0008, 0013) Instance Creation Time TM: '002917'\n",
+ "(0008, 0016) SOP Class UID UI: Basic Text SR Storage\n",
+ "(0008, 0018) SOP Instance UID UI: 1.2.826.0.1.3680043.8.498.48571967537049939109703063489026494794\n",
+ "(0008, 0020) Study Date DA: '20230830'\n",
+ "(0008, 0021) Series Date DA: '20230830'\n",
+ "(0008, 0023) Content Date DA: '20230830'\n",
+ "(0008, 002a) Acquisition DateTime DT: '20230830002917'\n",
+ "(0008, 0030) Study Time TM: '002917'\n",
+ "(0008, 0031) Series Time TM: '002917'\n",
+ "(0008, 0033) Content Time TM: '002917'\n",
+ "(0008, 0050) Accession Number SH: ''\n",
+ "(0008, 0060) Modality CS: 'SR'\n",
+ "(0008, 0070) Manufacturer LO: 'MOANI Deploy App SDK'\n",
+ "(0008, 0090) Referring Physician's Name PN: ''\n",
+ "(0008, 0201) Timezone Offset From UTC SH: '-0700'\n",
+ "(0008, 1030) Study Description LO: 'AI results.'\n",
+ "(0008, 103e) Series Description LO: 'CAUTION: Not for Diagnostic Use, for research use only.'\n",
+ "(0008, 1090) Manufacturer's Model Name LO: 'DICOM SR Writer'\n",
+ "(0010, 0010) Patient's Name PN: ''\n",
+ "(0010, 0020) Patient ID LO: ''\n",
+ "(0010, 0021) Issuer of Patient ID LO: ''\n",
+ "(0010, 0030) Patient's Birth Date DA: ''\n",
+ "(0010, 0040) Patient's Sex CS: ''\n",
+ "(0018, 0015) Body Part Examined CS: ''\n",
+ "(0018, 1020) Software Versions LO: '0.5.1+22.g029f8'\n",
+ "(0018, a001) Contributing Equipment Sequence 1 item(s) ---- \n",
+ " (0008, 0070) Manufacturer LO: 'MONAI WG Trainer'\n",
+ " (0008, 1090) Manufacturer's Model Name LO: 'MEDNIST Classifier'\n",
+ " (0018, 1002) Device UID UI: xyz\n",
+ " (0018, 1020) Software Versions LO: '0.1'\n",
+ " (0040, a170) Purpose of Reference Code Sequence 1 item(s) ---- \n",
+ " (0008, 0100) Code Value SH: 'Newcode1'\n",
+ " (0008, 0102) Coding Scheme Designator SH: '99IHE'\n",
+ " (0008, 0104) Code Meaning LO: '\"Processing Algorithm'\n",
+ " ---------\n",
+ " ---------\n",
+ "(0020, 000d) Study Instance UID UI: 1.2.826.0.1.3680043.8.498.12129058299828649912489432723605279507\n",
+ "(0020, 000e) Series Instance UID UI: 1.2.826.0.1.3680043.8.498.97786003431027375178670323563066287594\n",
+ "(0020, 0010) Study ID SH: '1'\n",
+ "(0020, 0011) Series Number IS: '1475'\n",
+ "(0020, 0013) Instance Number IS: '1'\n",
+ "(0040, 1001) Requested Procedure ID SH: ''\n",
+ "[2023-08-30 00:29:17,184] [DEBUG] (root) - DICOM dataset to be written:Dataset.file_meta -------------------------------\n",
+ "(0002, 0000) File Meta Information Group Length UL: 198\n",
+ "(0002, 0001) File Meta Information Version OB: b'01'\n",
+ "(0002, 0002) Media Storage SOP Class UID UI: Basic Text SR Storage\n",
+ "(0002, 0003) Media Storage SOP Instance UID UI: 1.2.826.0.1.3680043.8.498.48571967537049939109703063489026494794\n",
+ "(0002, 0010) Transfer Syntax UID UI: Implicit VR Little Endian\n",
+ "(0002, 0012) Implementation Class UID UI: 1.2.40.0.13.1.1.1\n",
+ "(0002, 0013) Implementation Version Name SH: '0.5.1+22.g029f8'\n",
+ "-------------------------------------------------\n",
+ "(0008, 0005) Specific Character Set CS: 'ISO_IR 100'\n",
+ "(0008, 0012) Instance Creation Date DA: '20230830'\n",
+ "(0008, 0013) Instance Creation Time TM: '002917'\n",
+ "(0008, 0016) SOP Class UID UI: Basic Text SR Storage\n",
+ "(0008, 0018) SOP Instance UID UI: 1.2.826.0.1.3680043.8.498.48571967537049939109703063489026494794\n",
+ "(0008, 0020) Study Date DA: '20230830'\n",
+ "(0008, 0021) Series Date DA: '20230830'\n",
+ "(0008, 0023) Content Date DA: '20230830'\n",
+ "(0008, 002a) Acquisition DateTime DT: '20230830002917'\n",
+ "(0008, 0030) Study Time TM: '002917'\n",
+ "(0008, 0031) Series Time TM: '002917'\n",
+ "(0008, 0033) Content Time TM: '002917'\n",
+ "(0008, 0050) Accession Number SH: ''\n",
+ "(0008, 0060) Modality CS: 'SR'\n",
+ "(0008, 0070) Manufacturer LO: 'MOANI Deploy App SDK'\n",
+ "(0008, 0090) Referring Physician's Name PN: ''\n",
+ "(0008, 0201) Timezone Offset From UTC SH: '-0700'\n",
+ "(0008, 1030) Study Description LO: 'AI results.'\n",
+ "(0008, 103e) Series Description LO: 'Not for clinical use. The result is for research use only.'\n",
+ "(0008, 1090) Manufacturer's Model Name LO: 'DICOM SR Writer'\n",
+ "(0010, 0010) Patient's Name PN: ''\n",
+ "(0010, 0020) Patient ID LO: ''\n",
+ "(0010, 0021) Issuer of Patient ID LO: ''\n",
+ "(0010, 0030) Patient's Birth Date DA: ''\n",
+ "(0010, 0040) Patient's Sex CS: ''\n",
+ "(0018, 0015) Body Part Examined CS: ''\n",
+ "(0018, 1020) Software Versions LO: '0.5.1+22.g029f8'\n",
+ "(0018, a001) Contributing Equipment Sequence 1 item(s) ---- \n",
+ " (0008, 0070) Manufacturer LO: 'MONAI WG Trainer'\n",
+ " (0008, 1090) Manufacturer's Model Name LO: 'MEDNIST Classifier'\n",
+ " (0018, 1002) Device UID UI: xyz\n",
+ " (0018, 1020) Software Versions LO: '0.1'\n",
+ " (0040, a170) Purpose of Reference Code Sequence 1 item(s) ---- \n",
+ " (0008, 0100) Code Value SH: 'Newcode1'\n",
+ " (0008, 0102) Coding Scheme Designator SH: '99IHE'\n",
+ " (0008, 0104) Code Meaning LO: '\"Processing Algorithm'\n",
+ " ---------\n",
+ " ---------\n",
+ "(0020, 000d) Study Instance UID UI: 1.2.826.0.1.3680043.8.498.12129058299828649912489432723605279507\n",
+ "(0020, 000e) Series Instance UID UI: 1.2.826.0.1.3680043.8.498.97786003431027375178670323563066287594\n",
+ "(0020, 0010) Study ID SH: '1'\n",
+ "(0020, 0011) Series Number IS: '1475'\n",
+ "(0020, 0013) Instance Number IS: '1'\n",
+ "(0040, 1001) Requested Procedure ID SH: ''\n",
+ "(0040, a040) Value Type CS: 'CONTAINER'\n",
+ "(0040, a043) Concept Name Code Sequence 1 item(s) ---- \n",
+ " (0008, 0100) Code Value SH: '18748-4'\n",
+ " (0008, 0102) Coding Scheme Designator SH: 'LN'\n",
+ " (0008, 0104) Code Meaning LO: 'Diagnostic Imaging Report'\n",
+ " ---------\n",
+ "(0040, a050) Continuity Of Content CS: 'SEPARATE'\n",
+ "(0040, a493) Verification Flag CS: 'UNVERIFIED'\n",
+ "(0040, a730) Content Sequence 1 item(s) ---- \n",
+ " (0040, a010) Relationship Type CS: 'CONTAINS'\n",
+ " (0040, a040) Value Type CS: 'TEXT'\n",
+ " (0040, a043) Concept Name Code Sequence 1 item(s) ---- \n",
+ " (0008, 0100) Code Value SH: '111412'\n",
+ " (0008, 0102) Coding Scheme Designator SH: 'DCM'\n",
+ " (0008, 0104) Code Meaning LO: 'Narrative Summary'\n",
+ " ---------\n",
+ " (0040, a160) Text Value UT: 'AbdomenCT'\n",
+ " ---------\n",
+ "[2023-08-30 00:29:17,187] [INFO] (root) - Finished writing DICOM instance to file /home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/output/1.2.826.0.1.3680043.8.498.48571967537049939109703063489026494794.dcm\n",
+ "[2023-08-30 00:29:17,188] [INFO] (monai.deploy.operators.dicom_text_sr_writer_operator.DICOMTextSRWriterOperator) - DICOM SOP instance saved in /home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/output/1.2.826.0.1.3680043.8.498.48571967537049939109703063489026494794.dcm\n",
+ "[\u001b[32minfo\u001b[m] [greedy_scheduler.cpp:369] Scheduler stopped: Some entities are waiting for execution, but there are no periodic or async entities to get out of the deadlock.\n",
+ "[\u001b[32minfo\u001b[m] [greedy_scheduler.cpp:398] Scheduler finished.\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1783] Graph execution deactivating. Fragment: \n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1784] Deactivating Graph...\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1787] Graph execution finished. Fragment: \n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:229] Destroying context\n"
]
}
],
"source": [
- "!python \"mednist_classifier_monaideploy.py\" -i \"input/AbdomenCT_007000.jpeg\" -o output -m \"classifier.zip\""
+ "!python \"mednist_app/mednist_classifier_monaideploy.py\" -i {input_folder} -o {output_folder} -m {models_folder} -l DEBUG"
]
},
{
+ "cell_type": "code",
+ "execution_count": 68,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\"AbdomenCT\""
+ ]
+ }
+ ],
+ "source": [
+ "!cat {output_folder}/output.json"
+ ]
+ },
+ {
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
- "Above command is same with the following command line:"
+ "## Additional file required for packaging the app (creating MAP Docker image)\n",
+ "\n",
+ "In this version of the App SDK, we need to write out the configuration yaml file as well as the package requirements file, in the application folder."
]
},
{
"cell_type": "code",
- "execution_count": 19,
+ "execution_count": 69,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "\u001b[34mGoing to initiate execution of operator LoadPILOperator\u001b[39m\n",
- "\u001b[32mExecuting operator LoadPILOperator \u001b[33m(Process ID: 410750, Operator ID: 91aa8bda-4a3b-47fd-b393-13181eb69e2c)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator LoadPILOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator MedNISTClassifierOperator\u001b[39m\n",
- "\u001b[32mExecuting operator MedNISTClassifierOperator \u001b[33m(Process ID: 410750, Operator ID: e085c688-f8d2-4896-899a-3905105e40e8)\u001b[39m\n",
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:111: FutureWarning: : Class `AddChannel` has been deprecated since version 0.8. It will be removed in version 1.3. please use MetaTensor data type and monai.transforms.EnsureChannelFirst instead with `channel_dim='no_channel'`.\n",
- " warn_deprecated(obj, msg, warning_category)\n",
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/monai/data/meta_tensor.py:116: UserWarning: The given NumPy array is not writable, and PyTorch does not support non-writable tensors. This means writing to this tensor will result in undefined behavior. You may want to copy the array to protect its data or make it writable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at ../torch/csrc/utils/tensor_numpy.cpp:206.)\n",
- " return torch.as_tensor(x, *args, **_kwargs).as_subclass(cls) # type: ignore\n",
- "AbdomenCT\n",
- "\u001b[34mDone performing execution of operator MedNISTClassifierOperator\n",
- "\u001b[39m\n"
+ "Writing mednist_app/app.yaml\n"
]
}
],
"source": [
- "!monai-deploy exec \"mednist_classifier_monaideploy.py\" -i \"input/AbdomenCT_007000.jpeg\" -o output -m \"classifier.zip\""
+ "%%writefile mednist_app/app.yaml\n",
+ "%YAML 1.2\n",
+ "---\n",
+ "application:\n",
+ " title: MONAI Deploy App Package - MedNIST Classifier App\n",
+ " version: 1.0\n",
+ " inputFormats: [\"file\"]\n",
+ " outputFormats: [\"file\"]\n",
+ "\n",
+ "resources:\n",
+ " cpu: 1\n",
+ " gpu: 1\n",
+ " memory: 1Gi\n",
+ " gpuMemory: 1Gi"
]
},
{
"cell_type": "code",
- "execution_count": 20,
+ "execution_count": 70,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "\"AbdomenCT\""
+ "Writing mednist_app/requirements.txt\n"
]
}
],
"source": [
- "!cat output/output.json"
+ "%%writefile mednist_app/requirements.txt\n",
+ "monai>=1.2.0\n",
+ "Pillow>=8.4.0\n",
+ "pydicom>=2.3.0\n",
+ "highdicom>=0.18.2\n",
+ "SimpleITK>=2.0.0\n",
+ "setuptools>=59.5.0 # for pkg_resources"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "By now, we have built the application and prepared all necessary files for create the MONAI Application Package (MAP)."
]
}
],
diff --git a/notebooks/tutorials/02_mednist_app.ipynb b/notebooks/tutorials/02_mednist_app.ipynb
index e9e869a0..59d017ed 100644
--- a/notebooks/tutorials/02_mednist_app.ipynb
+++ b/notebooks/tutorials/02_mednist_app.ipynb
@@ -39,7 +39,7 @@
"!python -c \"import highdicom\" || pip install -q \"highdicom>=0.18.2\" # for the use of DICOM Writer operators\n",
"\n",
"# Install MONAI Deploy App SDK package\n",
- "!python -c \"import monai.deploy\" || pip install --upgrade -q \"monai-deploy-app-sdk\""
+ "!python -c \"import monai.deploy\" || pip install -q \"monai-deploy-app-sdk\""
]
},
{
@@ -65,7 +65,7 @@
"Pytorch version: 2.0.1+cu117\n",
"MONAI flags: HAS_EXT = False, USE_COMPILED = False, USE_META_DICT = False\n",
"MONAI rev id: c33f1ba588ee00229a309000e888f9817b4f1934\n",
- "MONAI __file__: /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/monai/__init__.py\n",
+ "MONAI __file__: /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages/monai/__init__.py\n",
"\n",
"Optional dependencies:\n",
"Pytorch Ignite version: 0.4.11\n",
@@ -161,7 +161,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "/tmp/tmp00iaib5g\n"
+ "/tmp/tmp_ijj195_\n"
]
},
{
@@ -170,16 +170,18 @@
"text": [
"Downloading...\n",
"From (uriginal): https://drive.google.com/uc?id=1QsnnkvZyJPcbRoV_ArW8SnE1OTuoVbKE\n",
- "From (redirected): https://drive.google.com/uc?id=1QsnnkvZyJPcbRoV_ArW8SnE1OTuoVbKE&confirm=t&uuid=79a11612-ee21-4913-81f7-1db5840c71af\n",
- "To: /tmp/tmpgf67zvcd/MedNIST.tar.gz\n",
- "100%|██████████| 61.8M/61.8M [00:01<00:00, 58.3MB/s]"
+ "From (redirected): https://drive.google.com/uc?id=1QsnnkvZyJPcbRoV_ArW8SnE1OTuoVbKE&confirm=t&uuid=d974f3a4-5d30-48b6-9b6d-9459b32b4cac\n",
+ "To: /tmp/tmp3aa3c3k6/MedNIST.tar.gz\n",
+ "100%|██████████| 61.8M/61.8M [00:03<00:00, 19.1MB/s]"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
- "2023-07-11 12:21:48,269 - INFO - Downloaded: /tmp/tmp00iaib5g/MedNIST.tar.gz\n"
+ "2023-08-03 20:42:12,748 - INFO - Downloaded: /tmp/tmp_ijj195_/MedNIST.tar.gz\n",
+ "2023-08-03 20:42:12,856 - INFO - Verified 'MedNIST.tar.gz', md5: 0bc7306e7427e00ad1c5526a6677552d.\n",
+ "2023-08-03 20:42:12,857 - INFO - Writing into directory: /tmp/tmp_ijj195_.\n"
]
},
{
@@ -188,14 +190,6 @@
"text": [
"\n"
]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "2023-07-11 12:21:48,376 - INFO - Verified 'MedNIST.tar.gz', md5: 0bc7306e7427e00ad1c5526a6677552d.\n",
- "2023-07-11 12:21:48,377 - INFO - Writing into directory: /tmp/tmp00iaib5g.\n"
- ]
}
],
"source": [
@@ -264,7 +258,7 @@
"name": "stderr",
"output_type": "stream",
"text": [
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:111: FutureWarning: : Class `AddChannel` has been deprecated since version 0.8. It will be removed in version 1.3. please use MetaTensor data type and monai.transforms.EnsureChannelFirst instead with `channel_dim='no_channel'`.\n",
+ "/home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:111: FutureWarning: : Class `AddChannel` has been deprecated since version 0.8. It will be removed in version 1.3. please use MetaTensor data type and monai.transforms.EnsureChannelFirst instead with `channel_dim='no_channel'`.\n",
" warn_deprecated(obj, msg, warning_category)\n"
]
}
@@ -313,7 +307,7 @@
"metadata": {},
"outputs": [],
"source": [
- "device = torch.device(\"cuda:0\")\n",
+ "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
"net = DenseNet121(spatial_dims=2, in_channels=1, out_channels=len(class_names)).to(device)\n",
"loss_function = torch.nn.CrossEntropyLoss()\n",
"opt = torch.optim.Adam(net.parameters(), 1e-5)\n",
@@ -407,12 +401,12 @@
"\n",
"1. `LoadPILOperator` - Load a JPEG image from the input path and pass the loaded image object to the next operator.\n",
" - This Operator does similar job with `LoadImage(image_only=True)` transform in *train_transforms*, but handles only one image.\n",
- " - **Input**: a file path ([`DataPath`](/modules/_autosummary/monai.deploy.core.domain.DataPath))\n",
+ " - **Input**: a file path (`Path`)\n",
" - **Output**: an image object in memory ([`Image`](/modules/_autosummary/monai.deploy.core.domain.Image))\n",
"2. `MedNISTClassifierOperator` - Pre-transform the given image by using MONAI's `Compose` class, feed to the Torchscript model (`classifier.zip`), and write the prediction into JSON file(`output.json`)\n",
" - Pre-transforms consist of three transforms -- `AddChannel`, `ScaleIntensity`, and `EnsureType`.\n",
" - **Input**: an image object in memory ([`Image`](/modules/_autosummary/monai.deploy.core.domain.Image))\n",
- " - **Output**: a folder path that the prediction result(`output.json`) would be written ([`DataPath`](/modules/_autosummary/monai.deploy.core.domain.DataPath))\n",
+ " - **Output**: a folder path that the prediction result(`output.json`) would be written (`DataPath`)\n",
"\n",
"The workflow of the application would look like this.\n",
"\n",
@@ -436,6 +430,50 @@
"```\n",
"\n",
"\n",
+ "#### Set up environment variables\n",
+ "\n",
+ "Before proceeding to the application building and packaging, we first need to set the well-known environment variables, because the application parses them for the input, output, and model folders. Defaults are used if these environment variable are absent.\n",
+ "\n",
+ "Set the environment variables corresponding to the extracted data path."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "001420.jpeg\n",
+ "classifier.zip\n",
+ "env: HOLOSCAN_INPUT_PATH=input\n",
+ "env: HOLOSCAN_OUTPUT_PATH=output\n",
+ "env: HOLOSCAN_MODEL_PATH=models\n"
+ ]
+ }
+ ],
+ "source": [
+ "input_folder = \"input\"\n",
+ "output_foler = \"output\"\n",
+ "models_folder = \"models\"\n",
+ "\n",
+ "# Choose a file as test input\n",
+ "test_input_path = image_files[0][0]\n",
+ "!rm -rf {input_folder} && mkdir -p {input_folder} && cp {test_input_path} {input_folder} && ls {input_folder}\n",
+ "# Need to copy the model file to its own clean subfolder for pacakging, to workaround an issue in the Packager\n",
+ "!rm -rf {models_folder} && mkdir -p {models_folder}/model && cp classifier.zip {models_folder}/model && ls {models_folder}/model\n",
+ "\n",
+ "%env HOLOSCAN_INPUT_PATH {input_folder}\n",
+ "%env HOLOSCAN_OUTPUT_PATH {output_foler}\n",
+ "%env HOLOSCAN_MODEL_PATH {models_folder}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
"#### Setup imports\n",
"\n",
"Let's import necessary classes/decorators and define `MEDNIST_CLASSES`."
@@ -443,21 +481,20 @@
},
{
"cell_type": "code",
- "execution_count": 10,
+ "execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
- "import monai.deploy.core as md # 'md' stands for MONAI Deploy (or can use 'core' instead)\n",
- "from monai.deploy.core import (\n",
- " Application,\n",
- " DataPath,\n",
- " ExecutionContext,\n",
- " Image,\n",
- " InputContext,\n",
- " IOType,\n",
- " Operator,\n",
- " OutputContext,\n",
- ")\n",
+ "import logging\n",
+ "import os\n",
+ "from pathlib import Path\n",
+ "from typing import Optional\n",
+ "\n",
+ "import torch\n",
+ "\n",
+ "from monai.deploy.conditions import CountCondition\n",
+ "from monai.deploy.core import AppContext, Application, ConditionType, Fragment, Image, Operator, OperatorSpec\n",
+ "from monai.deploy.operators.dicom_text_sr_writer_operator import DICOMTextSRWriterOperator, EquipmentInfo, ModelInfo\n",
"from monai.transforms import AddChannel, Compose, EnsureType, ScaleIntensity\n",
"\n",
"MEDNIST_CLASSES = [\"AbdomenCT\", \"BreastMRI\", \"CXR\", \"ChestCT\", \"Hand\", \"HeadCT\"]"
@@ -474,30 +511,65 @@
},
{
"cell_type": "code",
- "execution_count": 11,
+ "execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
- "@md.input(\"image\", DataPath, IOType.DISK)\n",
- "@md.output(\"image\", Image, IOType.IN_MEMORY)\n",
- "@md.env(pip_packages=[\"pillow\"])\n",
"class LoadPILOperator(Operator):\n",
" \"\"\"Load image from the given input (DataPath) and set numpy array to the output (Image).\"\"\"\n",
"\n",
- " def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):\n",
+ " DEFAULT_INPUT_FOLDER = Path.cwd() / \"input\"\n",
+ " DEFAULT_OUTPUT_NAME = \"image\"\n",
+ "\n",
+ " # For now, need to have the input folder as an instance attribute, set on init.\n",
+ " # If dynamically changing the input folder, per compute, then use a (optional) input port to convey the\n",
+ " # value of the input folder, which is then emitted by a upstream operator.\n",
+ " def __init__(\n",
+ " self,\n",
+ " fragment: Fragment,\n",
+ " *args,\n",
+ " input_folder: Path = DEFAULT_INPUT_FOLDER,\n",
+ " output_name: str = DEFAULT_OUTPUT_NAME,\n",
+ " **kwargs,\n",
+ " ):\n",
+ " \"\"\"Creates an loader object with the input folder and the output port name overrides as needed.\n",
+ "\n",
+ " Args:\n",
+ " fragment (Fragment): An instance of the Application class which is derived from Fragment.\n",
+ " input_folder (Path): Folder from which to load input file(s).\n",
+ " Defaults to `input` in the current working directory.\n",
+ " output_name (str): Name of the output port, which is an image object. Defaults to `image`.\n",
+ " \"\"\"\n",
+ "\n",
+ " self._logger = logging.getLogger(\"{}.{}\".format(__name__, type(self).__name__))\n",
+ " self.input_path = input_folder\n",
+ " self.index = 0\n",
+ " self.output_name_image = (\n",
+ " output_name.strip() if output_name and len(output_name.strip()) > 0 else LoadPILOperator.DEFAULT_OUTPUT_NAME\n",
+ " )\n",
+ "\n",
+ " super().__init__(fragment, *args, **kwargs)\n",
+ "\n",
+ " def setup(self, spec: OperatorSpec):\n",
+ " \"\"\"Set up the named input and output port(s)\"\"\"\n",
+ " spec.output(self.output_name_image)\n",
+ "\n",
+ " def compute(self, op_input, op_output, context):\n",
" import numpy as np\n",
" from PIL import Image as PILImage\n",
"\n",
- " input_path = op_input.get().path\n",
+ " # Input path is stored in the object attribute, but could change to use a named port if need be.\n",
+ " input_path = self.input_path\n",
" if input_path.is_dir():\n",
- " input_path = next(input_path.glob(\"*.*\")) # take the first file\n",
+ " input_path = next(self.input_path.glob(\"*.*\")) # take the first file\n",
"\n",
" image = PILImage.open(input_path)\n",
" image = image.convert(\"L\") # convert to greyscale image\n",
" image_arr = np.asarray(image)\n",
"\n",
" output_image = Image(image_arr) # create Image domain object with a numpy array\n",
- " op_output.set(output_image)"
+ " op_output.emit(output_image, self.output_name_image) # cannot omit the name even if single output.\n",
+ "\n"
]
},
{
@@ -509,50 +581,127 @@
},
{
"cell_type": "code",
- "execution_count": 12,
+ "execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
- "@md.input(\"image\", Image, IOType.IN_MEMORY)\n",
- "@md.output(\"output\", DataPath, IOType.DISK)\n",
- "@md.env(pip_packages=[\"monai\"])\n",
"class MedNISTClassifierOperator(Operator):\n",
- " \"\"\"Classifies the given image and returns the class name.\"\"\"\n",
+ " \"\"\"Classifies the given image and returns the class name.\n",
+ "\n",
+ " Named inputs:\n",
+ " image: Image object for which to generate the classification.\n",
+ " output_folder: Optional, the path to save the results JSON file, overridingthe the one set on __init__\n",
+ "\n",
+ " Named output:\n",
+ " result_text: The classification results in text.\n",
+ " \"\"\"\n",
+ "\n",
+ " DEFAULT_OUTPUT_FOLDER = Path.cwd() / \"classification_results\"\n",
+ " # For testing the app directly, the model should be at the following path.\n",
+ " MODEL_LOCAL_PATH = Path(os.environ.get(\"HOLOSCAN_MODEL_PATH\", Path.cwd() / \"model/model.ts\"))\n",
+ "\n",
+ " def __init__(\n",
+ " self,\n",
+ " frament: Fragment,\n",
+ " *args,\n",
+ " app_context: AppContext,\n",
+ " model_name: Optional[str] = \"\",\n",
+ " model_path: Path = MODEL_LOCAL_PATH,\n",
+ " output_folder: Path = DEFAULT_OUTPUT_FOLDER,\n",
+ " **kwargs,\n",
+ " ):\n",
+ " \"\"\"Creates an instance with the reference back to the containing application/fragment.\n",
+ "\n",
+ " fragment (Fragment): An instance of the Application class which is derived from Fragment.\n",
+ " model_name (str, optional): Name of the model. Default to \"\" for single model app.\n",
+ " model_path (Path): Path to the model file. Defaults to model/models.ts of current working dir.\n",
+ " output_folder (Path, optional): output folder for saving the classification results JSON file.\n",
+ " \"\"\"\n",
+ "\n",
+ " # the names used for the model inference input and output\n",
+ " self._input_dataset_key = \"image\"\n",
+ " self._pred_dataset_key = \"pred\"\n",
+ "\n",
+ " # The names used for the operator input and output\n",
+ " self.input_name_image = \"image\"\n",
+ " self.output_name_result = \"result_text\"\n",
+ "\n",
+ " # The name of the optional input port for passing data to override the output folder path.\n",
+ " self.input_name_output_folder = \"output_folder\"\n",
+ "\n",
+ " # The output folder set on the object can be overriden at each compute by data in the optional named input\n",
+ " self.output_folder = output_folder\n",
+ "\n",
+ " # Need the name when there are multiple models loaded\n",
+ " self._model_name = model_name.strip() if isinstance(model_name, str) else \"\"\n",
+ " # Need the path to load the models when they are not loaded in the execution context\n",
+ " self.model_path = model_path\n",
+ " self.app_context = app_context\n",
+ " self.model = self._get_model(self.app_context, self.model_path, self._model_name)\n",
+ "\n",
+ " # This needs to be at the end of the constructor.\n",
+ " super().__init__(frament, *args, **kwargs)\n",
+ "\n",
+ " def _get_model(self, app_context: AppContext, model_path: Path, model_name: str):\n",
+ " \"\"\"Load the model with the given name from context or model path\n",
+ "\n",
+ " Args:\n",
+ " app_context (AppContext): The application context object holding the model(s)\n",
+ " model_path (Path): The path to the model file, as a backup to load model directly\n",
+ " model_name (str): The name of the model, when multiples are loaded in the context\n",
+ " \"\"\"\n",
+ "\n",
+ " if app_context.models:\n",
+ " # `app_context.models.get(model_name)` returns a model instance if exists.\n",
+ " # If model_name is not specified and only one model exists, it returns that model.\n",
+ " model = app_context.models.get(model_name)\n",
+ " else:\n",
+ " model = torch.jit.load(\n",
+ " MedNISTClassifierOperator.MODEL_LOCAL_PATH,\n",
+ " map_location=torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\"),\n",
+ " )\n",
+ "\n",
+ " return model\n",
+ "\n",
+ " def setup(self, spec: OperatorSpec):\n",
+ " \"\"\"Set up the operator named input and named output, both are in-memory objects.\"\"\"\n",
+ "\n",
+ " spec.input(self.input_name_image)\n",
+ " spec.input(self.input_name_output_folder).condition(ConditionType.NONE) # Optional for overriding.\n",
+ " spec.output(self.output_name_result).condition(ConditionType.NONE) # Not forcing a downstream receiver.\n",
"\n",
" @property\n",
" def transform(self):\n",
" return Compose([AddChannel(), ScaleIntensity(), EnsureType()])\n",
"\n",
- " def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):\n",
+ " def compute(self, op_input, op_output, context):\n",
" import json\n",
"\n",
" import torch\n",
"\n",
- " img = op_input.get().asnumpy() # (64, 64), uint8\n",
+ " img = op_input.receive(self.input_name_image).asnumpy() # (64, 64), uint8. Input validation can be added.\n",
" image_tensor = self.transform(img) # (1, 64, 64), torch.float64\n",
" image_tensor = image_tensor[None].float() # (1, 1, 64, 64), torch.float32\n",
"\n",
" device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
" image_tensor = image_tensor.to(device)\n",
"\n",
- " model = context.models.get() # get a TorchScriptModel object\n",
- "\n",
" with torch.no_grad():\n",
- " outputs = model(image_tensor)\n",
+ " outputs = self.model(image_tensor)\n",
"\n",
" _, output_classes = outputs.max(dim=1)\n",
"\n",
" result = MEDNIST_CLASSES[output_classes[0]] # get the class name\n",
" print(result)\n",
+ " op_output.emit(result, self.output_name_result)\n",
"\n",
- " # Get output (folder) path and create the folder if not exists\n",
- " output_folder = op_output.get().path\n",
- " output_folder.mkdir(parents=True, exist_ok=True)\n",
- "\n",
- " # Write result to \"output.json\"\n",
- " output_path = output_folder / \"output.json\"\n",
+ " # Get output folder, with value in optional input port overriding the obj attribute\n",
+ " output_folder_on_compute = op_input.receive(self.input_name_output_folder) or self.output_folder\n",
+ " Path.mkdir(output_folder_on_compute, parents=True, exist_ok=True) # Let exception bubble up if raised.\n",
+ " output_path = output_folder_on_compute / \"output.json\"\n",
" with open(output_path, \"w\") as fp:\n",
- " json.dump(result, fp)"
+ " json.dump(result, fp)\n",
+ "\n"
]
},
{
@@ -570,20 +719,37 @@
},
{
"cell_type": "code",
- "execution_count": 13,
+ "execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
- "@md.resource(cpu=1, gpu=1, memory=\"1Gi\")\n",
- "@md.env(pip_packages=[\"pydicom >= 2.3.0\", \"highdicom>=0.18.2\"]) # for the use of DICOM Writer operators\n",
"class App(Application):\n",
" \"\"\"Application class for the MedNIST classifier.\"\"\"\n",
"\n",
" def compose(self):\n",
- " load_pil_op = LoadPILOperator()\n",
- " classifier_op = MedNISTClassifierOperator()\n",
- "\n",
- " self.add_flow(load_pil_op, classifier_op)"
+ " app_context = Application.init_app_context({}) # Do not pass argv in Jupyter Notebook\n",
+ " app_input_path = Path(app_context.input_path)\n",
+ " app_output_path = Path(app_context.output_path)\n",
+ " model_path = Path(app_context.model_path)\n",
+ " load_pil_op = LoadPILOperator(self, CountCondition(self, 1), input_folder=app_input_path, name=\"pil_loader_op\")\n",
+ " classifier_op = MedNISTClassifierOperator(\n",
+ " self, app_context=app_context, output_folder=app_output_path, model_path=model_path, name=\"classifier_op\"\n",
+ " )\n",
+ "\n",
+ " my_model_info = ModelInfo(\"MONAI WG Trainer\", \"MEDNIST Classifier\", \"0.1\", \"xyz\")\n",
+ " my_equipment = EquipmentInfo(manufacturer=\"MOANI Deploy App SDK\", manufacturer_model=\"DICOM SR Writer\")\n",
+ " my_special_tags = {\"SeriesDescription\": \"Not for clinical use. The result is for research use only.\"}\n",
+ " dicom_sr_operator = DICOMTextSRWriterOperator(\n",
+ " self,\n",
+ " copy_tags=False,\n",
+ " model_info=my_model_info,\n",
+ " equipment_info=my_equipment,\n",
+ " custom_tags=my_special_tags,\n",
+ " output_folder=app_output_path,\n",
+ " )\n",
+ "\n",
+ " self.add_flow(load_pil_op, classifier_op, {(\"image\", \"image\")})\n",
+ " self.add_flow(classifier_op, dicom_sr_operator, {(\"result_text\", \"text\")})\n"
]
},
{
@@ -592,87 +758,59 @@
"source": [
"### Executing app locally\n",
"\n",
- "Let's find a test input file path to use."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 14,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Test input file path: /tmp/tmp00iaib5g/MedNIST/AbdomenCT/001420.jpeg\n"
- ]
- }
- ],
- "source": [
- "test_input_path = image_files[0][0]\n",
- "print(f\"Test input file path: {test_input_path}\")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We can execute the app in the Jupyter notebook."
+ "The test input file file, output path, and model have been prepared, and the paths set in the environment variables, so we can go ahead and execute the application Jupyter notebook with a clean output folder."
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
- "outputs": [],
- "source": [
- "app = App()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 16,
- "metadata": {},
"outputs": [
{
- "name": "stdout",
+ "name": "stderr",
"output_type": "stream",
"text": [
- "\u001b[34mGoing to initiate execution of operator LoadPILOperator\u001b[39m\n",
- "\u001b[32mExecuting operator LoadPILOperator \u001b[33m(Process ID: 393049, Operator ID: c60f371c-73bc-4bb7-aaa6-30d04f2ff280)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator LoadPILOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator MedNISTClassifierOperator\u001b[39m\n",
- "\u001b[32mExecuting operator MedNISTClassifierOperator \u001b[33m(Process ID: 393049, Operator ID: 6e94713f-4e1d-4ec4-ae69-8305e8b02b7f)\u001b[39m\n"
+ "[info] [gxf_executor.cpp:210] Creating context\n",
+ "[info] [gxf_executor.cpp:1595] Loading extensions from configs...\n",
+ "[info] [gxf_executor.cpp:1741] Activating Graph...\n",
+ "[info] [gxf_executor.cpp:1771] Running Graph...\n",
+ "[info] [gxf_executor.cpp:1773] Waiting for completion...\n",
+ "[info] [gxf_executor.cpp:1774] Graph execution waiting. Fragment: \n",
+ "[info] [greedy_scheduler.cpp:190] Scheduling 3 entities\n",
+ "/home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages/monai/data/meta_tensor.py:116: UserWarning: The given NumPy array is not writable, and PyTorch does not support non-writable tensors. This means writing to this tensor will result in undefined behavior. You may want to copy the array to protect its data or make it writable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at ../torch/csrc/utils/tensor_numpy.cpp:206.)\n",
+ " return torch.as_tensor(x, *args, **_kwargs).as_subclass(cls) # type: ignore\n"
]
},
{
- "name": "stderr",
+ "name": "stdout",
"output_type": "stream",
"text": [
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:111: FutureWarning: : Class `AddChannel` has been deprecated since version 0.8. It will be removed in version 1.3. please use MetaTensor data type and monai.transforms.EnsureChannelFirst instead with `channel_dim='no_channel'`.\n",
- " warn_deprecated(obj, msg, warning_category)\n",
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/monai/data/meta_tensor.py:116: UserWarning: The given NumPy array is not writable, and PyTorch does not support non-writable tensors. This means writing to this tensor will result in undefined behavior. You may want to copy the array to protect its data or make it writable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at ../torch/csrc/utils/tensor_numpy.cpp:206.)\n",
- " return torch.as_tensor(x, *args, **_kwargs).as_subclass(cls) # type: ignore\n"
+ "AbdomenCT\n"
]
},
{
- "name": "stdout",
+ "name": "stderr",
"output_type": "stream",
"text": [
- "AbdomenCT\n",
- "\u001b[34mDone performing execution of operator MedNISTClassifierOperator\n",
- "\u001b[39m\n"
+ "/home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages/pydicom/valuerep.py:443: UserWarning: Invalid value for VR UI: 'xyz'. Please see for allowed values for each VR.\n",
+ " warnings.warn(msg)\n",
+ "[info] [greedy_scheduler.cpp:369] Scheduler stopped: Some entities are waiting for execution, but there are no periodic or async entities to get out of the deadlock.\n",
+ "[info] [greedy_scheduler.cpp:398] Scheduler finished.\n",
+ "[info] [gxf_executor.cpp:1783] Graph execution deactivating. Fragment: \n",
+ "[info] [gxf_executor.cpp:1784] Deactivating Graph...\n",
+ "[info] [gxf_executor.cpp:1787] Graph execution finished. Fragment: \n",
+ "[info] [gxf_executor.cpp:229] Destroying context\n"
]
}
],
"source": [
- "app.run(input=test_input_path, output=\"output\", model=\"classifier.zip\")"
+ "!rm -rf $HOLOSCAN_OUTPUT_PATH\n",
+ "app = App().run()"
]
},
{
"cell_type": "code",
- "execution_count": 17,
+ "execution_count": 16,
"metadata": {},
"outputs": [
{
@@ -684,7 +822,7 @@
}
],
"source": [
- "!cat output/output.json"
+ "!cat $HOLOSCAN_OUTPUT_PATH/output.json"
]
},
{
@@ -695,12 +833,23 @@
"\n",
"```python\n",
"if __name__ == \"__main__\":\n",
- " App(do_run=True)\n",
+ " App()\n",
"```\n",
"\n",
"The above lines are needed to execute the application code by using `python` interpreter."
]
},
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Create an application folder\n",
+ "!mkdir -p mednist_app\n",
+ "!rm -rf mednist_app/*"
+ ]
+ },
{
"cell_type": "code",
"execution_count": 18,
@@ -710,14 +859,14 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "Overwriting mednist_classifier_monaideploy.py\n"
+ "Writing mednist_app/mednist_classifier_monaideploy.py\n"
]
}
],
"source": [
- "%%writefile mednist_classifier_monaideploy.py\n",
+ "%%writefile mednist_app/mednist_classifier_monaideploy.py\n",
"\n",
- "# Copyright 2021 MONAI Consortium\n",
+ "# Copyright 2021-2023 MONAI Consortium\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",
"# You may obtain a copy of the License at\n",
@@ -728,107 +877,236 @@
"# See the License for the specific language governing permissions and\n",
"# limitations under the License.\n",
"\n",
- "import monai.deploy.core as md # 'md' stands for MONAI Deploy (or can use 'core' instead)\n",
- "from monai.deploy.core import (\n",
- " Application,\n",
- " DataPath,\n",
- " ExecutionContext,\n",
- " Image,\n",
- " InputContext,\n",
- " IOType,\n",
- " Operator,\n",
- " OutputContext,\n",
- ")\n",
+ "import logging\n",
+ "import os\n",
+ "from pathlib import Path\n",
+ "from typing import Optional\n",
+ "\n",
+ "import torch\n",
+ "\n",
+ "from monai.deploy.conditions import CountCondition\n",
+ "from monai.deploy.core import AppContext, Application, ConditionType, Fragment, Image, Operator, OperatorSpec\n",
+ "from monai.deploy.operators.dicom_text_sr_writer_operator import DICOMTextSRWriterOperator, EquipmentInfo, ModelInfo\n",
"from monai.transforms import AddChannel, Compose, EnsureType, ScaleIntensity\n",
"\n",
"MEDNIST_CLASSES = [\"AbdomenCT\", \"BreastMRI\", \"CXR\", \"ChestCT\", \"Hand\", \"HeadCT\"]\n",
"\n",
"\n",
- "@md.input(\"image\", DataPath, IOType.DISK)\n",
- "@md.output(\"image\", Image, IOType.IN_MEMORY)\n",
- "@md.env(pip_packages=[\"pillow\"])\n",
+ "# @md.env(pip_packages=[\"pillow\"])\n",
"class LoadPILOperator(Operator):\n",
" \"\"\"Load image from the given input (DataPath) and set numpy array to the output (Image).\"\"\"\n",
"\n",
- " def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):\n",
+ " DEFAULT_INPUT_FOLDER = Path.cwd() / \"input\"\n",
+ " DEFAULT_OUTPUT_NAME = \"image\"\n",
+ "\n",
+ " # For now, need to have the input folder as an instance attribute, set on init.\n",
+ " # If dynamically changing the input folder, per compute, then use a (optional) input port to convey the\n",
+ " # value of the input folder, which is then emitted by a upstream operator.\n",
+ " def __init__(\n",
+ " self,\n",
+ " fragment: Fragment,\n",
+ " *args,\n",
+ " input_folder: Path = DEFAULT_INPUT_FOLDER,\n",
+ " output_name: str = DEFAULT_OUTPUT_NAME,\n",
+ " **kwargs,\n",
+ " ):\n",
+ " \"\"\"Creates an loader object with the input folder and the output port name overrides as needed.\n",
+ "\n",
+ " Args:\n",
+ " fragment (Fragment): An instance of the Application class which is derived from Fragment.\n",
+ " input_folder (Path): Folder from which to load input file(s).\n",
+ " Defaults to `input` in the current working directory.\n",
+ " output_name (str): Name of the output port, which is an image object. Defaults to `image`.\n",
+ " \"\"\"\n",
+ "\n",
+ " self._logger = logging.getLogger(\"{}.{}\".format(__name__, type(self).__name__))\n",
+ " self.input_path = input_folder\n",
+ " self.index = 0\n",
+ " self.output_name_image = (\n",
+ " output_name.strip() if output_name and len(output_name.strip()) > 0 else LoadPILOperator.DEFAULT_OUTPUT_NAME\n",
+ " )\n",
+ "\n",
+ " super().__init__(fragment, *args, **kwargs)\n",
+ "\n",
+ " def setup(self, spec: OperatorSpec):\n",
+ " \"\"\"Set up the named input and output port(s)\"\"\"\n",
+ " spec.output(self.output_name_image)\n",
+ "\n",
+ " def compute(self, op_input, op_output, context):\n",
" import numpy as np\n",
" from PIL import Image as PILImage\n",
"\n",
- " input_path = op_input.get().path\n",
+ " # Input path is stored in the object attribute, but could change to use a named port if need be.\n",
+ " input_path = self.input_path\n",
" if input_path.is_dir():\n",
- " input_path = next(input_path.glob(\"*.*\")) # take the first file\n",
+ " input_path = next(self.input_path.glob(\"*.*\")) # take the first file\n",
"\n",
" image = PILImage.open(input_path)\n",
" image = image.convert(\"L\") # convert to greyscale image\n",
" image_arr = np.asarray(image)\n",
"\n",
" output_image = Image(image_arr) # create Image domain object with a numpy array\n",
- " op_output.set(output_image)\n",
+ " op_output.emit(output_image, self.output_name_image) # cannot omit the name even if single output.\n",
"\n",
"\n",
- "@md.input(\"image\", Image, IOType.IN_MEMORY)\n",
- "@md.output(\"output\", DataPath, IOType.DISK)\n",
- "@md.env(pip_packages=[\"monai\"])\n",
+ "# @md.env(pip_packages=[\"monai\"])\n",
"class MedNISTClassifierOperator(Operator):\n",
- " \"\"\"Classifies the given image and returns the class name.\"\"\"\n",
+ " \"\"\"Classifies the given image and returns the class name.\n",
+ "\n",
+ " Named inputs:\n",
+ " image: Image object for which to generate the classification.\n",
+ " output_folder: Optional, the path to save the results JSON file, overridingthe the one set on __init__\n",
+ "\n",
+ " Named output:\n",
+ " result_text: The classification results in text.\n",
+ " \"\"\"\n",
+ "\n",
+ " DEFAULT_OUTPUT_FOLDER = Path.cwd() / \"classification_results\"\n",
+ " # For testing the app directly, the model should be at the following path.\n",
+ " MODEL_LOCAL_PATH = Path(os.environ.get(\"HOLOSCAN_MODEL_PATH\", Path.cwd() / \"model/model.ts\"))\n",
+ "\n",
+ " def __init__(\n",
+ " self,\n",
+ " frament: Fragment,\n",
+ " *args,\n",
+ " app_context: AppContext,\n",
+ " model_name: Optional[str] = \"\",\n",
+ " model_path: Path = MODEL_LOCAL_PATH,\n",
+ " output_folder: Path = DEFAULT_OUTPUT_FOLDER,\n",
+ " **kwargs,\n",
+ " ):\n",
+ " \"\"\"Creates an instance with the reference back to the containing application/fragment.\n",
+ "\n",
+ " fragment (Fragment): An instance of the Application class which is derived from Fragment.\n",
+ " model_name (str, optional): Name of the model. Default to \"\" for single model app.\n",
+ " model_path (Path): Path to the model file. Defaults to model/models.ts of current working dir.\n",
+ " output_folder (Path, optional): output folder for saving the classification results JSON file.\n",
+ " \"\"\"\n",
+ "\n",
+ " # the names used for the model inference input and output\n",
+ " self._input_dataset_key = \"image\"\n",
+ " self._pred_dataset_key = \"pred\"\n",
+ "\n",
+ " # The names used for the operator input and output\n",
+ " self.input_name_image = \"image\"\n",
+ " self.output_name_result = \"result_text\"\n",
+ "\n",
+ " # The name of the optional input port for passing data to override the output folder path.\n",
+ " self.input_name_output_folder = \"output_folder\"\n",
+ "\n",
+ " # The output folder set on the object can be overriden at each compute by data in the optional named input\n",
+ " self.output_folder = output_folder\n",
+ "\n",
+ " # Need the name when there are multiple models loaded\n",
+ " self._model_name = model_name.strip() if isinstance(model_name, str) else \"\"\n",
+ " # Need the path to load the models when they are not loaded in the execution context\n",
+ " self.model_path = model_path\n",
+ " self.app_context = app_context\n",
+ " self.model = self._get_model(self.app_context, self.model_path, self._model_name)\n",
+ "\n",
+ " # This needs to be at the end of the constructor.\n",
+ " super().__init__(frament, *args, **kwargs)\n",
+ "\n",
+ " def _get_model(self, app_context: AppContext, model_path: Path, model_name: str):\n",
+ " \"\"\"Load the model with the given name from context or model path\n",
+ "\n",
+ " Args:\n",
+ " app_context (AppContext): The application context object holding the model(s)\n",
+ " model_path (Path): The path to the model file, as a backup to load model directly\n",
+ " model_name (str): The name of the model, when multiples are loaded in the context\n",
+ " \"\"\"\n",
+ "\n",
+ " if app_context.models:\n",
+ " # `app_context.models.get(model_name)` returns a model instance if exists.\n",
+ " # If model_name is not specified and only one model exists, it returns that model.\n",
+ " model = app_context.models.get(model_name)\n",
+ " else:\n",
+ " model = torch.jit.load(\n",
+ " MedNISTClassifierOperator.MODEL_LOCAL_PATH,\n",
+ " map_location=torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\"),\n",
+ " )\n",
+ "\n",
+ " return model\n",
+ "\n",
+ " def setup(self, spec: OperatorSpec):\n",
+ " \"\"\"Set up the operator named input and named output, both are in-memory objects.\"\"\"\n",
+ "\n",
+ " spec.input(self.input_name_image)\n",
+ " spec.input(self.input_name_output_folder).condition(ConditionType.NONE) # Optional for overriding.\n",
+ " spec.output(self.output_name_result).condition(ConditionType.NONE) # Not forcing a downstream receiver.\n",
"\n",
" @property\n",
" def transform(self):\n",
" return Compose([AddChannel(), ScaleIntensity(), EnsureType()])\n",
"\n",
- " def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):\n",
+ " def compute(self, op_input, op_output, context):\n",
" import json\n",
"\n",
" import torch\n",
"\n",
- " img = op_input.get().asnumpy() # (64, 64), uint8\n",
+ " img = op_input.receive(self.input_name_image).asnumpy() # (64, 64), uint8. Input validation can be added.\n",
" image_tensor = self.transform(img) # (1, 64, 64), torch.float64\n",
" image_tensor = image_tensor[None].float() # (1, 1, 64, 64), torch.float32\n",
"\n",
" device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
" image_tensor = image_tensor.to(device)\n",
"\n",
- " model = context.models.get() # get a TorchScriptModel object\n",
- "\n",
" with torch.no_grad():\n",
- " outputs = model(image_tensor)\n",
+ " outputs = self.model(image_tensor)\n",
"\n",
" _, output_classes = outputs.max(dim=1)\n",
"\n",
" result = MEDNIST_CLASSES[output_classes[0]] # get the class name\n",
" print(result)\n",
+ " op_output.emit(result, self.output_name_result)\n",
"\n",
- " # Get output (folder) path and create the folder if not exists\n",
- " output_folder = op_output.get().path\n",
- " output_folder.mkdir(parents=True, exist_ok=True)\n",
- "\n",
- " # Write result to \"output.json\"\n",
- " output_path = output_folder / \"output.json\"\n",
+ " # Get output folder, with value in optional input port overriding the obj attribute\n",
+ " output_folder_on_compute = op_input.receive(self.input_name_output_folder) or self.output_folder\n",
+ " Path.mkdir(output_folder_on_compute, parents=True, exist_ok=True) # Let exception bubble up if raised.\n",
+ " output_path = output_folder_on_compute / \"output.json\"\n",
" with open(output_path, \"w\") as fp:\n",
" json.dump(result, fp)\n",
"\n",
"\n",
- "@md.resource(cpu=1, gpu=1, memory=\"1Gi\")\n",
- "@md.env(pip_packages=[\"pydicom >= 2.3.0\", \"highdicom>=0.18.2\"]) # for the use of DICOM Writer operators\n",
+ "# @md.resource(cpu=1, gpu=1, memory=\"1Gi\")\n",
"class App(Application):\n",
" \"\"\"Application class for the MedNIST classifier.\"\"\"\n",
"\n",
" def compose(self):\n",
- " load_pil_op = LoadPILOperator()\n",
- " classifier_op = MedNISTClassifierOperator()\n",
- "\n",
- " self.add_flow(load_pil_op, classifier_op)\n",
+ " app_context = AppContext({}) # Let it figure out all the attributes without overriding\n",
+ " app_input_path = Path(app_context.input_path)\n",
+ " app_output_path = Path(app_context.output_path)\n",
+ " model_path = Path(app_context.model_path)\n",
+ " load_pil_op = LoadPILOperator(self, CountCondition(self, 1), input_folder=app_input_path, name=\"pil_loader_op\")\n",
+ " classifier_op = MedNISTClassifierOperator(\n",
+ " self, app_context=app_context, output_folder=app_output_path, model_path=model_path, name=\"classifier_op\"\n",
+ " )\n",
+ "\n",
+ " my_model_info = ModelInfo(\"MONAI WG Trainer\", \"MEDNIST Classifier\", \"0.1\", \"xyz\")\n",
+ " my_equipment = EquipmentInfo(manufacturer=\"MOANI Deploy App SDK\", manufacturer_model=\"DICOM SR Writer\")\n",
+ " my_special_tags = {\"SeriesDescription\": \"Not for clinical use. The result is for research use only.\"}\n",
+ " dicom_sr_operator = DICOMTextSRWriterOperator(\n",
+ " self,\n",
+ " copy_tags=False,\n",
+ " model_info=my_model_info,\n",
+ " equipment_info=my_equipment,\n",
+ " custom_tags=my_special_tags,\n",
+ " output_folder=app_output_path,\n",
+ " )\n",
+ "\n",
+ " self.add_flow(load_pil_op, classifier_op, {(\"image\", \"image\")})\n",
+ " self.add_flow(classifier_op, dicom_sr_operator, {(\"result_text\", \"text\")})\n",
"\n",
"\n",
"if __name__ == \"__main__\":\n",
- " App(do_run=True)"
+ " App().run()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "In this time, let's execute the app in the command line."
+ "This time, let's execute the app in the command line."
]
},
{
@@ -840,31 +1118,31 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "\u001b[34mGoing to initiate execution of operator LoadPILOperator\u001b[39m\n",
- "\u001b[32mExecuting operator LoadPILOperator \u001b[33m(Process ID: 394647, Operator ID: 9502cae2-e14b-4c3f-be35-57dc9289ea89)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator LoadPILOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator MedNISTClassifierOperator\u001b[39m\n",
- "\u001b[32mExecuting operator MedNISTClassifierOperator \u001b[33m(Process ID: 394647, Operator ID: 66c5dc76-5e54-4a46-9a23-c0c6a70f36af)\u001b[39m\n",
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:111: FutureWarning: : Class `AddChannel` has been deprecated since version 0.8. It will be removed in version 1.3. please use MetaTensor data type and monai.transforms.EnsureChannelFirst instead with `channel_dim='no_channel'`.\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:210] Creating context\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1595] Loading extensions from configs...\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1741] Activating Graph...\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1771] Running Graph...\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1773] Waiting for completion...\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1774] Graph execution waiting. Fragment: \n",
+ "[\u001b[32minfo\u001b[m] [greedy_scheduler.cpp:190] Scheduling 3 entities\n",
+ "/home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:111: FutureWarning: : Class `AddChannel` has been deprecated since version 0.8. It will be removed in version 1.3. please use MetaTensor data type and monai.transforms.EnsureChannelFirst instead with `channel_dim='no_channel'`.\n",
" warn_deprecated(obj, msg, warning_category)\n",
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/monai/data/meta_tensor.py:116: UserWarning: The given NumPy array is not writable, and PyTorch does not support non-writable tensors. This means writing to this tensor will result in undefined behavior. You may want to copy the array to protect its data or make it writable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at ../torch/csrc/utils/tensor_numpy.cpp:206.)\n",
+ "/home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages/monai/data/meta_tensor.py:116: UserWarning: The given NumPy array is not writable, and PyTorch does not support non-writable tensors. This means writing to this tensor will result in undefined behavior. You may want to copy the array to protect its data or make it writable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at ../torch/csrc/utils/tensor_numpy.cpp:206.)\n",
" return torch.as_tensor(x, *args, **_kwargs).as_subclass(cls) # type: ignore\n",
"AbdomenCT\n",
- "\u001b[34mDone performing execution of operator MedNISTClassifierOperator\n",
- "\u001b[39m\n"
+ "/home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages/pydicom/valuerep.py:443: UserWarning: Invalid value for VR UI: 'xyz'. Please see for allowed values for each VR.\n",
+ " warnings.warn(msg)\n",
+ "[\u001b[32minfo\u001b[m] [greedy_scheduler.cpp:369] Scheduler stopped: Some entities are waiting for execution, but there are no periodic or async entities to get out of the deadlock.\n",
+ "[\u001b[32minfo\u001b[m] [greedy_scheduler.cpp:398] Scheduler finished.\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1783] Graph execution deactivating. Fragment: \n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1784] Deactivating Graph...\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1787] Graph execution finished. Fragment: \n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:229] Destroying context\n"
]
}
],
"source": [
- "!python mednist_classifier_monaideploy.py -i {test_input_path} -o output -m classifier.zip"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Above command is same with the following command line:"
+ "!python \"mednist_app/mednist_classifier_monaideploy.py\""
]
},
{
@@ -876,24 +1154,28 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "\u001b[34mGoing to initiate execution of operator LoadPILOperator\u001b[39m\n",
- "\u001b[32mExecuting operator LoadPILOperator \u001b[33m(Process ID: 394701, Operator ID: c0d3561c-6274-4953-a642-8265c6a65bc9)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator LoadPILOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator MedNISTClassifierOperator\u001b[39m\n",
- "\u001b[32mExecuting operator MedNISTClassifierOperator \u001b[33m(Process ID: 394701, Operator ID: 77db8991-6777-4c06-b28f-670b856193e4)\u001b[39m\n",
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:111: FutureWarning: : Class `AddChannel` has been deprecated since version 0.8. It will be removed in version 1.3. please use MetaTensor data type and monai.transforms.EnsureChannelFirst instead with `channel_dim='no_channel'`.\n",
- " warn_deprecated(obj, msg, warning_category)\n",
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/monai/data/meta_tensor.py:116: UserWarning: The given NumPy array is not writable, and PyTorch does not support non-writable tensors. This means writing to this tensor will result in undefined behavior. You may want to copy the array to protect its data or make it writable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at ../torch/csrc/utils/tensor_numpy.cpp:206.)\n",
- " return torch.as_tensor(x, *args, **_kwargs).as_subclass(cls) # type: ignore\n",
- "AbdomenCT\n",
- "\u001b[34mDone performing execution of operator MedNISTClassifierOperator\n",
- "\u001b[39m\n"
+ "\"AbdomenCT\""
]
}
],
"source": [
- "!monai-deploy exec mednist_classifier_monaideploy.py -i {test_input_path} -o output -m classifier.zip"
+ "!cat $HOLOSCAN_OUTPUT_PATH/output.json"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Packaging app"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Let's package the app with MONAI Application Packager .\n",
+ "\n",
+ "In this version of the App SDK, we need to write out the configuration yaml file as well as the package requirements file, in the application folder."
]
},
{
@@ -905,1589 +1187,486 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "\"AbdomenCT\""
+ "Writing mednist_app/app.yaml\n"
]
}
],
"source": [
- "!cat output/output.json"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Packaging app"
+ "%%writefile mednist_app/app.yaml\n",
+ "%YAML 1.2\n",
+ "---\n",
+ "application:\n",
+ " title: MONAI Deploy App Package - MedNIST Classifier App\n",
+ " version: 1.0\n",
+ " inputFormats: [\"file\"]\n",
+ " outputFormats: [\"file\"]\n",
+ "\n",
+ "resources:\n",
+ " cpu: 1\n",
+ " gpu: 1\n",
+ " memory: 1Gi\n",
+ " gpuMemory: 1Gi"
]
},
{
- "cell_type": "markdown",
+ "cell_type": "code",
+ "execution_count": 22,
"metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Writing mednist_app/requirements.txt\n"
+ ]
+ }
+ ],
"source": [
- "Let's package the app with MONAI Application Packager ."
+ "%%writefile mednist_app/requirements.txt\n",
+ "monai>=1.2.0\n",
+ "Pillow>=8.4.0\n",
+ "pydicom>=2.3.0\n",
+ "highdicom>=0.18.2\n",
+ "SimpleITK>=2.0.0\n",
+ "setuptools>=59.5.0 # for pkg_resources"
]
},
{
"cell_type": "code",
- "execution_count": 22,
+ "execution_count": 23,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "Building MONAI Application Package... -\u001b[1A\u001b[1B\u001b[0G\u001b[?25l[+] Building 0.0s (0/1) \n",
- "\u001b[?25\\\u001b[1A\u001b[0G\u001b[?25l[+] Building 0.1s (4/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m => [internal] load build context 0.1s\n",
- " => => transferring context: 23B 0.1s\n",
- "\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 0.3s (4/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m => [internal] load build context 0.2s\n",
- "\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[?25|\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 0.4s (9/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m => [ 6/15] COPY ./models /opt/monai/models 0.1s\n",
- "\u001b[?25/\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 0.5s (10/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 0.7s (11/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.1s\n",
- "\u001b[?25-\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 0.8s (11/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.3s\n",
- "\u001b[?25\\\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 1.0s (11/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.4s\n",
- "\u001b[2m => => # % Total % Received % Xferd Average Speed Time Time Time\n",
- "\u001b[0m\u001b[2m => => # Current \n",
- "\u001b[0m\u001b[2m => => # Dload Upload Total Spent Left\n",
- "\u001b[0m\u001b[2m => => # Speed \n",
- "\u001b[0m\u001b[2m => => # 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:\n",
- "\u001b[0m\u001b[2m => => # -- 0 \n",
- "\u001b[0m\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 1.1s (11/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.5s\n",
- "\u001b[2m => => # Current \n",
- "\u001b[0m\u001b[2m => => # Dload Upload Total Spent Left\n",
- "\u001b[0m\u001b[2m => => # Speed \n",
- "\u001b[0m\u001b[2m => => # 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:\n",
- "\u001b[0m\u001b[2m => => # 100 11.9M 100 11.9M 0 0 59.0M 0 --:--:-- --:--:-- --:--:\n",
- "\u001b[0m\u001b[2m => => # -- 59.0M \n",
- "\u001b[0m\u001b[?25|\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 1.3s (11/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.7s\n",
- "\u001b[2m => => # Archive: /opt/monai/executor/executor.zip \n",
- "\u001b[0m\u001b[2m => => # inflating: /opt/monai/executor/executor_pkg/_rels/.rels \n",
- "\u001b[0m\u001b[2m => => # inflating: /opt/monai/executor/executor_pkg/Monai.Deploy.Executor.nu\n",
- "\u001b[0m\u001b[2m => => # spec \n",
- "\u001b[0m\u001b[2m => => # inflating: /opt/monai/executor/executor_pkg/lib/native/linux-x64/mon\n",
- "\u001b[0m\u001b[2m => => # ai-exec \n",
- "\u001b[0m\u001b[?25/\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 1.4s (11/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.8s\n",
- "\u001b[2m => => # inflating: /opt/monai/executor/executor_pkg/lib/native/linux-x64/mon\n",
- "\u001b[0m\u001b[2m => => # ai-exec \n",
- "\u001b[0m\u001b[2m => => # inflating: /opt/monai/executor/executor_pkg/[Content_Types].xml \n",
- "\u001b[0m\u001b[2m => => # inflating: /opt/monai/executor/executor_pkg/package/services/metadat\n",
- "\u001b[0m\u001b[2m => => # a/core-properties/c09c14c8557342a7b41ac545107c1263.psmdcp \n",
- "\u001b[0m\u001b[2m => => # extracting: /opt/monai/executor/executor_pkg/.signature.p7s \n",
- "\u001b[0m\u001b[?25-\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 1.6s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 0.1s\n",
- " \n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\u001b[5A\u001b[0G\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 1.7s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 0.2s\n",
- "\u001b[?25\\\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 1.9s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 0.4s\n",
- "\u001b[?25|\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 2.0s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 0.5s\n",
- "\u001b[?25/\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 2.2s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 0.7s\n",
- "\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 2.3s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 0.8s\n",
- "\u001b[?25-\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 2.5s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 1.0s\n",
- "\u001b[2m => => # Looking in indexes: https://pypi.org/simple, https://pypi.ngc.nvidia.c\n",
- "\u001b[0m\u001b[2m => => # om \n",
- "\u001b[0m\u001b[?25\\\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 2.6s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 1.1s\n",
- "\u001b[2m => => # Looking in indexes: https://pypi.org/simple, https://pypi.ngc.nvidia.c\n",
- "\u001b[0m\u001b[2m => => # om \n",
- "\u001b[0m\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 2.7s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 1.3s\n",
- "\u001b[2m => => # Looking in indexes: https://pypi.org/simple, https://pypi.ngc.nvidia.c\n",
- "\u001b[0m\u001b[2m => => # om \n",
- "\u001b[0m\u001b[2m => => # Collecting pydicom>=2.3.0 \n",
- "\u001b[0m\u001b[2m => => # Downloading pydicom-2.4.1-py3-none-any.whl (1.8 MB) \n",
- "\u001b[0m\u001b[?25|\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 2.9s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 1.4s\n",
- "\u001b[2m => => # Looking in indexes: https://pypi.org/simple, https://pypi.ngc.nvidia.c\n",
- "\u001b[0m\u001b[2m => => # om \n",
- "\u001b[0m\u001b[2m => => # Collecting pydicom>=2.3.0 \n",
- "\u001b[0m\u001b[2m => => # Downloading pydicom-2.4.1-py3-none-any.whl (1.8 MB) \n",
- "\u001b[0m\u001b[2m => => # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.8/1.8 MB 25.5 MB/s eta\n",
- "\u001b[0m\u001b[2m => => # 0:00:00 \n",
- "\u001b[0m\u001b[?25/\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 3.0s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 1.6s\n",
- "\u001b[2m => => # Looking in indexes: https://pypi.org/simple, https://pypi.ngc.nvidia.c\n",
- "\u001b[0m\u001b[2m => => # om \n",
- "\u001b[0m\u001b[2m => => # Collecting pydicom>=2.3.0 \n",
- "\u001b[0m\u001b[2m => => # Downloading pydicom-2.4.1-py3-none-any.whl (1.8 MB) \n",
- "\u001b[0m\u001b[2m => => # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.8/1.8 MB 25.5 MB/s eta\n",
- "\u001b[0m\u001b[2m => => # 0:00:00 \n",
- "\u001b[0m\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 3.1s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 1.7s\n",
- "\u001b[2m => => # Collecting pydicom>=2.3.0 \n",
- "\u001b[0m\u001b[2m => => # Downloading pydicom-2.4.1-py3-none-any.whl (1.8 MB) \n",
- "\u001b[0m\u001b[2m => => # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.8/1.8 MB 25.5 MB/s eta\n",
- "\u001b[0m\u001b[2m => => # 0:00:00 \n",
- "\u001b[0m\u001b[2m => => # Collecting highdicom>=0.18.2 \n",
- "\u001b[0m\u001b[2m => => # Downloading highdicom-0.21.1-py3-none-any.whl (807 kB) \n",
- "\u001b[0m\u001b[?25-\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 3.3s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 1.8s\n",
- "\u001b[2m => => # Collecting highdicom>=0.18.2 \n",
- "\u001b[0m\u001b[2m => => # Downloading highdicom-0.21.1-py3-none-any.whl (807 kB) \n",
- "\u001b[0m\u001b[2m => => # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 807.1/807.1 kB 15.6 MB/s e\n",
- "\u001b[0m\u001b[2m => => # ta 0:00:00 \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: pillow in /opt/conda/lib/python3.8/site\n",
- "\u001b[0m\u001b[2m => => # -packages (from -r /opt/monai/app/requirements.txt (line 3)) (9.0.1) \n",
- "\u001b[0m\u001b[?25\\\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 3.4s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 2.0s\n",
- "\u001b[2m => => # Collecting highdicom>=0.18.2 \n",
- "\u001b[0m\u001b[2m => => # Downloading highdicom-0.21.1-py3-none-any.whl (807 kB) \n",
- "\u001b[0m\u001b[2m => => # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 807.1/807.1 kB 15.6 MB/s e\n",
- "\u001b[0m\u001b[2m => => # ta 0:00:00 \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: pillow in /opt/conda/lib/python3.8/site\n",
- "\u001b[0m\u001b[2m => => # -packages (from -r /opt/monai/app/requirements.txt (line 3)) (9.0.1) \n",
- "\u001b[0m\u001b[?25|\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 3.6s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 2.1s\n",
- "\u001b[2m => => # Requirement already satisfied: networkx>=2.4 in /opt/conda/lib/python3\n",
- "\u001b[0m\u001b[2m => => # .8/site-packages (from -r /opt/monai/app/requirements.txt (line 6)) (2\n",
- "\u001b[0m\u001b[2m => => # .6.3) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: colorama>=0.4.1 in /opt/conda/lib/pytho\n",
- "\u001b[0m\u001b[2m => => # n3.8/site-packages (from -r /opt/monai/app/requirements.txt (line 7)) \n",
- "\u001b[0m\u001b[2m => => # (0.4.5) \n",
- "\u001b[0m\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 3.7s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 2.2s\n",
- "\u001b[2m => => # .8/site-packages (from -r /opt/monai/app/requirements.txt (line 6)) (2\n",
- "\u001b[0m\u001b[2m => => # .6.3) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: colorama>=0.4.1 in /opt/conda/lib/pytho\n",
- "\u001b[0m\u001b[2m => => # n3.8/site-packages (from -r /opt/monai/app/requirements.txt (line 7)) \n",
- "\u001b[0m\u001b[2m => => # (0.4.5) \n",
- "\u001b[0m\u001b[2m => => # Collecting typeguard>=3.0.0 \n",
- "\u001b[0m\u001b[?25/\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 3.9s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 2.4s\n",
- "\u001b[2m => => # .6.3) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: colorama>=0.4.1 in /opt/conda/lib/pytho\n",
- "\u001b[0m\u001b[2m => => # n3.8/site-packages (from -r /opt/monai/app/requirements.txt (line 7)) \n",
- "\u001b[0m\u001b[2m => => # (0.4.5) \n",
- "\u001b[0m\u001b[2m => => # Collecting typeguard>=3.0.0 \n",
- "\u001b[0m\u001b[2m => => # Downloading typeguard-4.0.0-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[?25-\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 4.0s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 2.5s\n",
- "\u001b[2m => => # Requirement already satisfied: colorama>=0.4.1 in /opt/conda/lib/pytho\n",
- "\u001b[0m\u001b[2m => => # n3.8/site-packages (from -r /opt/monai/app/requirements.txt (line 7)) \n",
- "\u001b[0m\u001b[2m => => # (0.4.5) \n",
- "\u001b[0m\u001b[2m => => # Collecting typeguard>=3.0.0 \n",
- "\u001b[0m\u001b[2m => => # Downloading typeguard-4.0.0-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Collecting pillow-jpls>=1.0 \n",
- "\u001b[0m\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 4.1s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 2.6s\n",
- "\u001b[2m => => # Requirement already satisfied: torch>=1.9 in /opt/conda/lib/python3.8/\n",
- "\u001b[0m\u001b[2m => => # site-packages (from monai->-r /opt/monai/app/requirements.txt (line 4)\n",
- "\u001b[0m\u001b[2m => => # ) (1.13.0a0+d321be6) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: importlib-metadata>=3.6 in /opt/conda/l\n",
- "\u001b[0m\u001b[2m => => # ib/python3.8/site-packages (from typeguard>=3.0.0->-r /opt/monai/app/r\n",
- "\u001b[0m\u001b[2m => => # equirements.txt (line 8)) (4.12.0) \n",
- "\u001b[0m\u001b[?25\\\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 4.3s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 2.8s\n",
- "\u001b[2m => => # Requirement already satisfied: torch>=1.9 in /opt/conda/lib/python3.8/\n",
- "\u001b[0m\u001b[2m => => # site-packages (from monai->-r /opt/monai/app/requirements.txt (line 4)\n",
- "\u001b[0m\u001b[2m => => # ) (1.13.0a0+d321be6) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: importlib-metadata>=3.6 in /opt/conda/l\n",
- "\u001b[0m\u001b[2m => => # ib/python3.8/site-packages (from typeguard>=3.0.0->-r /opt/monai/app/r\n",
- "\u001b[0m\u001b[2m => => # equirements.txt (line 8)) (4.12.0) \n",
- "\u001b[0m\u001b[?25|\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 4.4s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 2.9s\n",
- "\u001b[2m => => # equirements.txt (line 8)) (4.12.0) \n",
- "\u001b[0m\u001b[2m => => # Collecting typing-extensions>=4.4.0 \n",
- "\u001b[0m\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[?25/\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 4.6s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 3.1s\n",
- "\u001b[2m => => # equirements.txt (line 8)) (4.12.0) \n",
- "\u001b[0m\u001b[2m => => # Collecting typing-extensions>=4.4.0 \n",
- "\u001b[0m\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 4.7s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 3.2s\n",
- "\u001b[2m => => # equirements.txt (line 8)) (4.12.0) \n",
- "\u001b[0m\u001b[2m => => # Collecting typing-extensions>=4.4.0 \n",
- "\u001b[0m\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[?25-\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 4.9s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 3.4s\n",
- "\u001b[2m => => # equirements.txt (line 8)) (4.12.0) \n",
- "\u001b[0m\u001b[2m => => # Collecting typing-extensions>=4.4.0 \n",
- "\u001b[0m\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[?25\\\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 5.0s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 3.5s\n",
- "\u001b[2m => => # equirements.txt (line 8)) (4.12.0) \n",
- "\u001b[0m\u001b[2m => => # Collecting typing-extensions>=4.4.0 \n",
- "\u001b[0m\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[?25|\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 5.2s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 3.7s\n",
- "\u001b[2m => => # equirements.txt (line 8)) (4.12.0) \n",
- "\u001b[0m\u001b[2m => => # Collecting typing-extensions>=4.4.0 \n",
- "\u001b[0m\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 5.3s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 3.8s\n",
- "\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[2m => => # Installing collected packages: typing-extensions, pydicom, pillow-jpls\n",
- "\u001b[0m\u001b[2m => => # , typeguard, highdicom, monai \n",
- "\u001b[0m\u001b[?25/\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 5.4s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 4.0s\n",
- "\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[2m => => # Installing collected packages: typing-extensions, pydicom, pillow-jpls\n",
- "\u001b[0m\u001b[2m => => # , typeguard, highdicom, monai \n",
- "\u001b[0m\u001b[?25-\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 5.6s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 4.1s\n",
- "\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[2m => => # Installing collected packages: typing-extensions, pydicom, pillow-jpls\n",
- "\u001b[0m\u001b[2m => => # , typeguard, highdicom, monai \n",
- "\u001b[0m\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 5.7s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 4.3s\n",
- "\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[2m => => # Installing collected packages: typing-extensions, pydicom, pillow-jpls\n",
- "\u001b[0m\u001b[2m => => # , typeguard, highdicom, monai \n",
- "\u001b[0m\u001b[?25\\\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 5.9s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 4.4s\n",
- "\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[2m => => # Installing collected packages: typing-extensions, pydicom, pillow-jpls\n",
- "\u001b[0m\u001b[2m => => # , typeguard, highdicom, monai \n",
- "\u001b[0m\u001b[?25|\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 6.0s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 4.6s\n",
- "\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[2m => => # Installing collected packages: typing-extensions, pydicom, pillow-jpls\n",
- "\u001b[0m\u001b[2m => => # , typeguard, highdicom, monai \n",
- "\u001b[0m\u001b[?25/\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 6.2s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 4.7s\n",
- "\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[2m => => # Installing collected packages: typing-extensions, pydicom, pillow-jpls\n",
- "\u001b[0m\u001b[2m => => # , typeguard, highdicom, monai \n",
- "\u001b[0m\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 6.3s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 4.9s\n",
- "\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[2m => => # Installing collected packages: typing-extensions, pydicom, pillow-jpls\n",
- "\u001b[0m\u001b[2m => => # , typeguard, highdicom, monai \n",
- "\u001b[0m\u001b[?25-\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 6.5s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 5.0s\n",
- "\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[2m => => # Installing collected packages: typing-extensions, pydicom, pillow-jpls\n",
- "\u001b[0m\u001b[2m => => # , typeguard, highdicom, monai \n",
- "\u001b[0m\u001b[?25\\\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 6.6s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 5.2s\n",
- "\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[2m => => # Installing collected packages: typing-extensions, pydicom, pillow-jpls\n",
- "\u001b[0m\u001b[2m => => # , typeguard, highdicom, monai \n",
- "\u001b[0m\u001b[?25|\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 6.8s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 5.3s\n",
- "\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[2m => => # Installing collected packages: typing-extensions, pydicom, pillow-jpls\n",
- "\u001b[0m\u001b[2m => => # , typeguard, highdicom, monai \n",
- "\u001b[0m\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 6.9s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 5.5s\n",
- "\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[2m => => # Installing collected packages: typing-extensions, pydicom, pillow-jpls\n",
- "\u001b[0m\u001b[2m => => # , typeguard, highdicom, monai \n",
- "\u001b[0m\u001b[?25/\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 7.1s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 5.6s\n",
- "\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[2m => => # Installing collected packages: typing-extensions, pydicom, pillow-jpls\n",
- "\u001b[0m\u001b[2m => => # , typeguard, highdicom, monai \n",
- "\u001b[0m\u001b[?25-\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 7.2s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 5.8s\n",
- "\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[2m => => # Installing collected packages: typing-extensions, pydicom, pillow-jpls\n",
- "\u001b[0m\u001b[2m => => # , typeguard, highdicom, monai \n",
- "\u001b[0m\u001b[?25\\\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 7.4s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 5.9s\n",
- "\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[2m => => # Installing collected packages: typing-extensions, pydicom, pillow-jpls\n",
- "\u001b[0m\u001b[2m => => # , typeguard, highdicom, monai \n",
- "\u001b[0m\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 7.5s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 6.1s\n",
- "\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[2m => => # Installing collected packages: typing-extensions, pydicom, pillow-jpls\n",
- "\u001b[0m\u001b[2m => => # , typeguard, highdicom, monai \n",
- "\u001b[0m\u001b[?25|\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 7.7s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 6.2s\n",
- "\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[2m => => # Installing collected packages: typing-extensions, pydicom, pillow-jpls\n",
- "\u001b[0m\u001b[2m => => # , typeguard, highdicom, monai \n",
- "\u001b[0m\u001b[?25/\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 7.8s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 6.4s\n",
- "\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[2m => => # Installing collected packages: typing-extensions, pydicom, pillow-jpls\n",
- "\u001b[0m\u001b[2m => => # , typeguard, highdicom, monai \n",
- "\u001b[0m\u001b[?25-\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 8.0s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 6.5s\n",
- "\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[2m => => # Installing collected packages: typing-extensions, pydicom, pillow-jpls\n",
- "\u001b[0m\u001b[2m => => # , typeguard, highdicom, monai \n",
- "\u001b[0m\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 8.1s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 6.7s\n",
- "\u001b[2m => => # Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB) \n",
- "\u001b[0m\u001b[2m => => # Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.8/s\n",
- "\u001b[0m\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[2m => => # Installing collected packages: typing-extensions, pydicom, pillow-jpls\n",
- "\u001b[0m\u001b[2m => => # , typeguard, highdicom, monai \n",
- "\u001b[0m\u001b[?25\\\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 8.3s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 6.8s\n",
- "\u001b[2m => => # ite-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->-r /opt/\n",
- "\u001b[0m\u001b[2m => => # monai/app/requirements.txt (line 8)) (3.8.1) \n",
- "\u001b[0m\u001b[2m => => # Installing collected packages: typing-extensions, pydicom, pillow-jpls\n",
- "\u001b[0m\u001b[2m => => # , typeguard, highdicom, monai \n",
- "\u001b[0m\u001b[2m => => # Successfully installed highdicom-0.21.1 monai-1.2.0 pillow-jpls-1.2.0 \n",
- "\u001b[0m\u001b[2m => => # pydicom-2.4.1 typeguard-4.0.0 typing-extensions-4.7.1 \n",
- "\u001b[0m\u001b[?25|\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 8.4s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 6.9s\n",
- "\u001b[2m => => # Successfully installed highdicom-0.21.1 monai-1.2.0 pillow-jpls-1.2.0 \n",
- "\u001b[0m\u001b[2m => => # pydicom-2.4.1 typeguard-4.0.0 typing-extensions-4.7.1 \n",
- "\u001b[0m\u001b[2m => => # WARNING: Running pip as the 'root' user can result in broken permissio\n",
- "\u001b[0m\u001b[2m => => # ns and conflicting behaviour with the system package manager. It is re\n",
- "\u001b[0m\u001b[2m => => # commended to use a virtual environment instead: https://pip.pypa.io/wa\n",
- "\u001b[0m\u001b[2m => => # rnings/venv \n",
- "\u001b[0m\u001b[?25/\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 8.6s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 7.1s\n",
- "\u001b[2m => => # Successfully installed highdicom-0.21.1 monai-1.2.0 pillow-jpls-1.2.0 \n",
- "\u001b[0m\u001b[2m => => # pydicom-2.4.1 typeguard-4.0.0 typing-extensions-4.7.1 \n",
- "\u001b[0m\u001b[2m => => # WARNING: Running pip as the 'root' user can result in broken permissio\n",
- "\u001b[0m\u001b[2m => => # ns and conflicting behaviour with the system package manager. It is re\n",
- "\u001b[0m\u001b[2m => => # commended to use a virtual environment instead: https://pip.pypa.io/wa\n",
- "\u001b[0m\u001b[2m => => # rnings/venv \n",
- "\u001b[0m\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 8.7s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 7.2s\n",
- "\u001b[2m => => # WARNING: Running pip as the 'root' user can result in broken permissio\n",
- "\u001b[0m\u001b[2m => => # ns and conflicting behaviour with the system package manager. It is re\n",
- "\u001b[0m\u001b[2m => => # commended to use a virtual environment instead: https://pip.pypa.io/wa\n",
- "\u001b[0m\u001b[2m => => # rnings/venv \n",
- "\u001b[0m\u001b[2m => => # [notice] A new release of pip available: 22.3 -> 23.1.2 \n",
- "\u001b[0m\u001b[2m => => # [notice] To update, run: pip install --upgrade pip \n",
- "\u001b[0m\u001b[?25-\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 8.8s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 7.4s\n",
- "\u001b[2m => => # WARNING: Running pip as the 'root' user can result in broken permissio\n",
- "\u001b[0m\u001b[2m => => # ns and conflicting behaviour with the system package manager. It is re\n",
- "\u001b[0m\u001b[2m => => # commended to use a virtual environment instead: https://pip.pypa.io/wa\n",
- "\u001b[0m\u001b[2m => => # rnings/venv \n",
- "\u001b[0m\u001b[2m => => # [notice] A new release of pip available: 22.3 -> 23.1.2 \n",
- "\u001b[0m\u001b[2m => => # [notice] To update, run: pip install --upgrade pip \n",
- "\u001b[0m\u001b[?25\\\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 9.0s (12/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 7.5s\n",
- "\u001b[2m => => # WARNING: Running pip as the 'root' user can result in broken permissio\n",
- "\u001b[0m\u001b[2m => => # ns and conflicting behaviour with the system package manager. It is re\n",
- "\u001b[0m\u001b[2m => => # commended to use a virtual environment instead: https://pip.pypa.io/wa\n",
- "\u001b[0m\u001b[2m => => # rnings/venv \n",
- "\u001b[0m\u001b[2m => => # [notice] A new release of pip available: 22.3 -> 23.1.2 \n",
- "\u001b[0m\u001b[2m => => # [notice] To update, run: pip install --upgrade pip \n",
- "\u001b[0m\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 9.1s (14/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m\u001b[34m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 7.5s\n",
- "\u001b[0m\u001b[34m => [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.1s\n",
- "\u001b[0m => [11/15] RUN echo \"User site package location: $(python3 -m site --use 0.1s\n",
- " \n",
- " \n",
- " \n",
- " \n",
- "\u001b[4A\u001b[0G\u001b[?25|\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 9.3s (14/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m\u001b[34m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 7.5s\n",
- "\u001b[0m\u001b[34m => [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.1s\n",
- "\u001b[0m => [11/15] RUN echo \"User site package location: $(python3 -m site --use 0.2s\n",
- "\u001b[?25/\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 9.4s (14/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m\u001b[34m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 7.5s\n",
- "\u001b[0m\u001b[34m => [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.1s\n",
- "\u001b[0m => [11/15] RUN echo \"User site package location: $(python3 -m site --use 0.4s\n",
- "\u001b[?25-\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 9.6s (14/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m\u001b[34m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 7.5s\n",
- "\u001b[0m\u001b[34m => [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.1s\n",
- "\u001b[0m => [11/15] RUN echo \"User site package location: $(python3 -m site --use 0.5s\n",
- "\u001b[2m => => # User site package location: /root/.local/lib/python3.8/site-packages \n",
- "\u001b[0m\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 9.7s (17/19) \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m\u001b[34m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 7.5s\n",
- "\u001b[0m\u001b[34m => [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.1s\n",
- "\u001b[0m\u001b[34m => [11/15] RUN echo \"User site package location: $(python3 -m site --use 0.5s\n",
- "\u001b[0m\u001b[34m => [12/15] COPY ./map/app.json /etc/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => [13/15] COPY ./map/pkg.json /etc/monai/ 0.0s\n",
- "\u001b[0m => [14/15] COPY ./app /opt/monai/app 0.0s\n",
- "\u001b[?25\\\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 9.8s (19/20) \n",
- "\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m\u001b[34m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 7.5s\n",
- "\u001b[0m\u001b[34m => [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.1s\n",
- "\u001b[0m\u001b[34m => [11/15] RUN echo \"User site package location: $(python3 -m site --use 0.5s\n",
- "\u001b[0m\u001b[34m => [12/15] COPY ./map/app.json /etc/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => [13/15] COPY ./map/pkg.json /etc/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => [14/15] COPY ./app /opt/monai/app 0.0s\n",
- "\u001b[0m\u001b[34m => [15/15] WORKDIR /var/monai/ 0.0s\n",
- "\u001b[0m => exporting to image 0.1s\n",
- " => => exporting layers 0.1s\n",
- "\u001b[?25|\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 10.0s (19/20) \n",
- "\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m\u001b[34m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 7.5s\n",
- "\u001b[0m\u001b[34m => [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.1s\n",
- "\u001b[0m\u001b[34m => [11/15] RUN echo \"User site package location: $(python3 -m site --use 0.5s\n",
- "\u001b[0m\u001b[34m => [12/15] COPY ./map/app.json /etc/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => [13/15] COPY ./map/pkg.json /etc/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => [14/15] COPY ./app /opt/monai/app 0.0s\n",
- "\u001b[0m\u001b[34m => [15/15] WORKDIR /var/monai/ 0.0s\n",
- "\u001b[0m => exporting to image 0.2s\n",
- " => => exporting layers 0.2s\n",
- "\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 10.1s (19/20) \n",
- "\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m\u001b[34m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 7.5s\n",
- "\u001b[0m\u001b[34m => [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.1s\n",
- "\u001b[0m\u001b[34m => [11/15] RUN echo \"User site package location: $(python3 -m site --use 0.5s\n",
- "\u001b[0m\u001b[34m => [12/15] COPY ./map/app.json /etc/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => [13/15] COPY ./map/pkg.json /etc/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => [14/15] COPY ./app /opt/monai/app 0.0s\n",
- "\u001b[0m\u001b[34m => [15/15] WORKDIR /var/monai/ 0.0s\n",
- "\u001b[0m => exporting to image 0.4s\n",
- " => => exporting layers 0.4s\n",
- "\u001b[?25/\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 10.3s (19/20) \n",
- "\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m\u001b[34m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 7.5s\n",
- "\u001b[0m\u001b[34m => [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.1s\n",
- "\u001b[0m\u001b[34m => [11/15] RUN echo \"User site package location: $(python3 -m site --use 0.5s\n",
- "\u001b[0m\u001b[34m => [12/15] COPY ./map/app.json /etc/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => [13/15] COPY ./map/pkg.json /etc/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => [14/15] COPY ./app /opt/monai/app 0.0s\n",
- "\u001b[0m\u001b[34m => [15/15] WORKDIR /var/monai/ 0.0s\n",
- "\u001b[0m => exporting to image 0.5s\n",
- " => => exporting layers 0.5s\n",
- "\u001b[?25-\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 10.4s (20/20) FINISHED \n",
- "\u001b[34m => [internal] load build definition from dockerfile 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load .dockerignore 0.0s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.2s\n",
- "\u001b[0m\u001b[34m => => transferring context: 29.08MB 0.2s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => [ 6/15] COPY ./models /opt/monai/models 0.2s\n",
- "\u001b[0m\u001b[34m => [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirements.txt 0.0s\n",
- "\u001b[0m\u001b[34m => [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.deploy.ex 0.9s\n",
- "\u001b[0m\u001b[34m => [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/app/requi 7.5s\n",
- "\u001b[0m\u001b[34m => [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.1s\n",
- "\u001b[0m\u001b[34m => [11/15] RUN echo \"User site package location: $(python3 -m site --use 0.5s\n",
- "\u001b[0m\u001b[34m => [12/15] COPY ./map/app.json /etc/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => [13/15] COPY ./map/pkg.json /etc/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => [14/15] COPY ./app /opt/monai/app 0.0s\n",
- "\u001b[0m\u001b[34m => [15/15] WORKDIR /var/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => exporting to image 0.6s\n",
- "\u001b[0m\u001b[34m => => exporting layers 0.6s\n",
- "\u001b[0m\u001b[34m => => writing image sha256:1eba359ad2aef41161eb2253c8ddaf172acc72bc3eaa5 0.0s\n",
- "\u001b[0m\u001b[34m => => naming to docker.io/library/mednist_app:latest 0.0s\n",
- "\u001b[0m\u001b[?25Done\n",
- "[2023-07-11 12:29:09,060] [INFO] (app_packager) - Successfully built mednist_app:latest\n"
+ "/home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages/pydantic/_internal/_config.py:269: UserWarning: Valid config keys have changed in V2:\n",
+ "* 'allow_population_by_field_name' has been renamed to 'populate_by_name'\n",
+ " warnings.warn(message, UserWarning)\n",
+ "[2023-08-03 20:49:29,599] [INFO] (packager.parameters) - Application: /home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/mednist_app/mednist_classifier_monaideploy.py\n",
+ "[2023-08-03 20:49:29,599] [INFO] (packager.parameters) - Detected application type: Python File\n",
+ "[2023-08-03 20:49:29,599] [INFO] (packager) - Scanning for models in {models_path}...\n",
+ "[2023-08-03 20:49:29,599] [DEBUG] (packager) - Model model=/home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/models/model added.\n",
+ "[2023-08-03 20:49:29,599] [INFO] (packager) - Reading application configuration from /home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/mednist_app/app.yaml...\n",
+ "[2023-08-03 20:49:29,601] [INFO] (packager) - Generating app.json...\n",
+ "[2023-08-03 20:49:29,601] [INFO] (packager) - Generating pkg.json...\n",
+ "[2023-08-03 20:49:29,601] [DEBUG] (common) - \n",
+ "=============== Begin app.json ===============\n",
+ "{\n",
+ " \"apiVersion\": \"1.0.0\",\n",
+ " \"command\": \"[\\\"python3\\\", \\\"/opt/holoscan/app/mednist_classifier_monaideploy.py\\\"]\",\n",
+ " \"environment\": {\n",
+ " \"HOLOSCAN_APPLICATION\": \"/opt/holoscan/app\",\n",
+ " \"HOLOSCAN_INPUT_PATH\": \"input/\",\n",
+ " \"HOLOSCAN_OUTPUT_PATH\": \"output/\",\n",
+ " \"HOLOSCAN_WORKDIR\": \"/var/holoscan\",\n",
+ " \"HOLOSCAN_MODEL_PATH\": \"/opt/holoscan/models\",\n",
+ " \"HOLOSCAN_CONFIG_PATH\": \"/var/holoscan/app.yaml\",\n",
+ " \"HOLOSCAN_APP_MANIFEST_PATH\": \"/etc/holoscan/app.json\",\n",
+ " \"HOLOSCAN_PKG_MANIFEST_PATH\": \"/etc/holoscan/pkg.json\",\n",
+ " \"HOLOSCAN_DOCS_PATH\": \"/opt/holoscan/docs\",\n",
+ " \"HOLOSCAN_LOGS_PATH\": \"/var/holoscan/logs\"\n",
+ " },\n",
+ " \"input\": {\n",
+ " \"path\": \"input/\",\n",
+ " \"formats\": null\n",
+ " },\n",
+ " \"liveness\": null,\n",
+ " \"output\": {\n",
+ " \"path\": \"output/\",\n",
+ " \"formats\": null\n",
+ " },\n",
+ " \"readiness\": null,\n",
+ " \"sdk\": \"monai-deploy\",\n",
+ " \"sdkVersion\": \"0.6.0\",\n",
+ " \"timeout\": 0,\n",
+ " \"version\": 1.0,\n",
+ " \"workingDirectory\": \"/var/holoscan\"\n",
+ "}\n",
+ "================ End app.json ================\n",
+ " \n",
+ "[2023-08-03 20:49:29,602] [DEBUG] (common) - \n",
+ "=============== Begin pkg.json ===============\n",
+ "{\n",
+ " \"apiVersion\": \"1.0.0\",\n",
+ " \"applicationRoot\": \"/opt/holoscan/app\",\n",
+ " \"modelRoot\": \"/opt/holoscan/models\",\n",
+ " \"models\": {\n",
+ " \"model\": \"/opt/holoscan/models\"\n",
+ " },\n",
+ " \"resources\": {\n",
+ " \"cpu\": 1,\n",
+ " \"gpu\": 1,\n",
+ " \"memory\": \"1Gi\",\n",
+ " \"gpuMemory\": \"1Gi\"\n",
+ " },\n",
+ " \"version\": 1.0\n",
+ "}\n",
+ "================ End pkg.json ================\n",
+ " \n",
+ "[2023-08-03 20:49:29,635] [DEBUG] (packager.builder) - \n",
+ "========== Begin Dockerfile ==========\n",
+ "\n",
+ "\n",
+ "FROM nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu\n",
+ "\n",
+ "ENV DEBIAN_FRONTEND=noninteractive\n",
+ "ENV TERM=xterm-256color\n",
+ "\n",
+ "ARG UNAME\n",
+ "ARG UID\n",
+ "ARG GID\n",
+ "\n",
+ "RUN mkdir -p /etc/holoscan/ \\\n",
+ " && mkdir -p /opt/holoscan/ \\\n",
+ " && mkdir -p /var/holoscan \\\n",
+ " && mkdir -p /opt/holoscan/app \\\n",
+ " && mkdir -p /var/holoscan/input \\\n",
+ " && mkdir -p /var/holoscan/output\n",
+ "\n",
+ "LABEL base=\"nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu\"\n",
+ "LABEL tag=\"mednist_app:1.0\"\n",
+ "LABEL org.opencontainers.image.title=\"MONAI Deploy App Package - MedNIST Classifier App\"\n",
+ "LABEL org.opencontainers.image.version=\"1.0\"\n",
+ "LABEL org.nvidia.holoscan=\"0.6.0\"\n",
+ "\n",
+ "ENV HOLOSCAN_ENABLE_HEALTH_CHECK=true\n",
+ "ENV HOLOSCAN_INPUT_PATH=/var/holoscan/input\n",
+ "ENV HOLOSCAN_OUTPUT_PATH=/var/holoscan/output\n",
+ "ENV HOLOSCAN_WORKDIR=/var/holoscan\n",
+ "ENV HOLOSCAN_APPLICATION=/opt/holoscan/app\n",
+ "ENV HOLOSCAN_TIMEOUT=0\n",
+ "ENV HOLOSCAN_MODEL_PATH=/opt/holoscan/models\n",
+ "ENV HOLOSCAN_DOCS_PATH=/opt/holoscan/docs\n",
+ "ENV HOLOSCAN_CONFIG_PATH=/var/holoscan/app.yaml\n",
+ "ENV HOLOSCAN_APP_MANIFEST_PATH=/etc/holoscan/app.json\n",
+ "ENV HOLOSCAN_PKG_MANIFEST_PATH=/etc/holoscan/pkg.json\n",
+ "ENV HOLOSCAN_LOGS_PATH=/var/holoscan/logs\n",
+ "ENV PATH=/root/.local/bin:/opt/nvidia/holoscan:$PATH\n",
+ "ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/libtorch/1.13.1/lib/:/opt/nvidia/holoscan/lib\n",
+ "\n",
+ "RUN apt-get update \\\n",
+ " && apt-get install -y curl jq \\\n",
+ " && rm -rf /var/lib/apt/lists/*\n",
+ "\n",
+ "ENV PYTHONPATH=\"/opt/holoscan/app:$PYTHONPATH\"\n",
+ "\n",
+ "\n",
+ "\n",
+ "RUN groupadd -g $GID $UNAME\n",
+ "RUN useradd -rm -d /home/$UNAME -s /bin/bash -g $GID -G sudo -u $UID $UNAME\n",
+ "RUN chown -R holoscan /var/holoscan \n",
+ "RUN chown -R holoscan /var/holoscan/input \n",
+ "RUN chown -R holoscan /var/holoscan/output \n",
+ "\n",
+ "# Set the working directory\n",
+ "WORKDIR /var/holoscan\n",
+ "\n",
+ "# Copy HAP/MAP tool script\n",
+ "COPY ./tools /var/holoscan/tools\n",
+ "RUN chmod +x /var/holoscan/tools\n",
+ "\n",
+ "\n",
+ "# Copy gRPC health probe\n",
+ "\n",
+ "USER $UNAME\n",
+ "\n",
+ "ENV PATH=/root/.local/bin:/home/holoscan/.local/bin:/opt/nvidia/holoscan:$PATH\n",
+ "\n",
+ "COPY ./pip/requirements.txt /tmp/requirements.txt\n",
+ "\n",
+ "RUN pip install --upgrade pip\n",
+ "RUN pip install --no-cache-dir --user -r /tmp/requirements.txt\n",
+ "\n",
+ "# Install Holoscan from PyPI org\n",
+ "RUN pip install holoscan==0.6.0\n",
+ "\n",
+ "\n",
+ "# Copy user-specified MONAI Deploy SDK file\n",
+ "COPY ./monai_deploy_app_sdk-0.5.1+7.g9fa1185.dirty-py3-none-any.whl /tmp/monai_deploy_app_sdk-0.5.1+7.g9fa1185.dirty-py3-none-any.whl\n",
+ "RUN pip install /tmp/monai_deploy_app_sdk-0.5.1+7.g9fa1185.dirty-py3-none-any.whl\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "COPY ./models /opt/holoscan/models\n",
+ "\n",
+ "COPY ./map/app.json /etc/holoscan/app.json\n",
+ "COPY ./app.config /var/holoscan/app.yaml\n",
+ "COPY ./map/pkg.json /etc/holoscan/pkg.json\n",
+ "\n",
+ "COPY ./app /opt/holoscan/app\n",
+ "\n",
+ "ENTRYPOINT [\"/var/holoscan/tools\"]\n",
+ "=========== End Dockerfile ===========\n",
+ "\n",
+ "[2023-08-03 20:49:29,636] [INFO] (packager.builder) - \n",
+ "===============================================================================\n",
+ "Building image for: x64-workstation\n",
+ " Architecture: linux/amd64\n",
+ " Base Image: nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu\n",
+ " Build Image: N/A \n",
+ " Cache: Enabled\n",
+ " Configuration: dgpu\n",
+ " Holoiscan SDK Package: pypi.org\n",
+ " MONAI Deploy App SDK Package: /home/mqin/src/monai-deploy-app-sdk/dist/monai_deploy_app_sdk-0.5.1+7.g9fa1185.dirty-py3-none-any.whl\n",
+ " gRPC Health Probe: N/A\n",
+ " SDK Version: 0.6.0\n",
+ " SDK: monai-deploy\n",
+ " Tag: mednist_app-x64-workstation-dgpu-linux-amd64:1.0\n",
+ " \n",
+ "[2023-08-03 20:49:30,337] [INFO] (common) - Using existing Docker BuildKit builder `holoscan_app_builder`\n",
+ "[2023-08-03 20:49:30,338] [DEBUG] (packager.builder) - Building Holoscan Application Package: tag=mednist_app-x64-workstation-dgpu-linux-amd64:1.0\n",
+ "#1 [internal] load .dockerignore\n",
+ "#1 transferring context: 1.79kB 0.0s done\n",
+ "#1 DONE 0.1s\n",
+ "\n",
+ "#2 [internal] load build definition from Dockerfile\n",
+ "#2 transferring dockerfile: 2.67kB done\n",
+ "#2 DONE 0.1s\n",
+ "\n",
+ "#3 [internal] load metadata for nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu\n",
+ "#3 DONE 0.8s\n",
+ "\n",
+ "#4 [internal] load build context\n",
+ "#4 DONE 0.0s\n",
+ "\n",
+ "#5 importing cache manifest from local:9585092855700183608\n",
+ "#5 DONE 0.0s\n",
+ "\n",
+ "#6 importing cache manifest from nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu\n",
+ "#6 DONE 0.9s\n",
+ "\n",
+ "#7 [ 1/22] FROM nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu@sha256:9653f80f241fd542f25afbcbcf7a0d02ed7e5941c79763e69def5b1e6d9fb7bc\n",
+ "#7 resolve nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu@sha256:9653f80f241fd542f25afbcbcf7a0d02ed7e5941c79763e69def5b1e6d9fb7bc\n",
+ "#7 resolve nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu@sha256:9653f80f241fd542f25afbcbcf7a0d02ed7e5941c79763e69def5b1e6d9fb7bc 0.1s done\n",
+ "#7 DONE 0.1s\n",
+ "\n",
+ "#4 [internal] load build context\n",
+ "#4 transferring context: 28.78MB 0.2s done\n",
+ "#4 DONE 0.3s\n",
+ "\n",
+ "#8 [ 6/22] RUN chown -R holoscan /var/holoscan\n",
+ "#8 CACHED\n",
+ "\n",
+ "#9 [12/22] COPY ./pip/requirements.txt /tmp/requirements.txt\n",
+ "#9 CACHED\n",
+ "\n",
+ "#10 [10/22] COPY ./tools /var/holoscan/tools\n",
+ "#10 CACHED\n",
+ "\n",
+ "#11 [15/22] RUN pip install holoscan==0.6.0\n",
+ "#11 CACHED\n",
+ "\n",
+ "#12 [16/22] COPY ./monai_deploy_app_sdk-0.5.1+7.g9fa1185.dirty-py3-none-any.whl /tmp/monai_deploy_app_sdk-0.5.1+7.g9fa1185.dirty-py3-none-any.whl\n",
+ "#12 CACHED\n",
+ "\n",
+ "#13 [ 7/22] RUN chown -R holoscan /var/holoscan/input\n",
+ "#13 CACHED\n",
+ "\n",
+ "#14 [ 4/22] RUN groupadd -g 1000 holoscan\n",
+ "#14 CACHED\n",
+ "\n",
+ "#15 [14/22] RUN pip install --no-cache-dir --user -r /tmp/requirements.txt\n",
+ "#15 CACHED\n",
+ "\n",
+ "#16 [11/22] RUN chmod +x /var/holoscan/tools\n",
+ "#16 CACHED\n",
+ "\n",
+ "#17 [ 5/22] RUN useradd -rm -d /home/holoscan -s /bin/bash -g 1000 -G sudo -u 1000 holoscan\n",
+ "#17 CACHED\n",
+ "\n",
+ "#18 [ 9/22] WORKDIR /var/holoscan\n",
+ "#18 CACHED\n",
+ "\n",
+ "#19 [ 8/22] RUN chown -R holoscan /var/holoscan/output\n",
+ "#19 CACHED\n",
+ "\n",
+ "#20 [ 2/22] RUN mkdir -p /etc/holoscan/ && mkdir -p /opt/holoscan/ && mkdir -p /var/holoscan && mkdir -p /opt/holoscan/app && mkdir -p /var/holoscan/input && mkdir -p /var/holoscan/output\n",
+ "#20 CACHED\n",
+ "\n",
+ "#21 [ 3/22] RUN apt-get update && apt-get install -y curl jq && rm -rf /var/lib/apt/lists/*\n",
+ "#21 CACHED\n",
+ "\n",
+ "#22 [13/22] RUN pip install --upgrade pip\n",
+ "#22 CACHED\n",
+ "\n",
+ "#23 [17/22] RUN pip install /tmp/monai_deploy_app_sdk-0.5.1+7.g9fa1185.dirty-py3-none-any.whl\n",
+ "#23 sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523 6.29MB / 2.40GB 0.2s\n",
+ "#23 sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523 130.02MB / 2.40GB 2.7s\n",
+ "#23 sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523 251.66MB / 2.40GB 5.1s\n",
+ "#23 sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523 374.34MB / 2.40GB 7.7s\n",
+ "#23 sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523 497.03MB / 2.40GB 10.2s\n",
+ "#23 sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523 629.15MB / 2.40GB 12.9s\n",
+ "#23 sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523 758.12MB / 2.40GB 15.5s\n",
+ "#23 sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523 880.80MB / 2.40GB 18.0s\n",
+ "#23 sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523 1.00GB / 2.40GB 20.6s\n",
+ "#23 sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523 1.13GB / 2.40GB 23.1s\n",
+ "#23 sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523 1.26GB / 2.40GB 25.4s\n",
+ "#23 sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523 1.38GB / 2.40GB 27.9s\n",
+ "#23 sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523 1.51GB / 2.40GB 30.3s\n",
+ "#23 sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523 1.63GB / 2.40GB 32.9s\n",
+ "#23 sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523 1.76GB / 2.40GB 35.7s\n",
+ "#23 sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523 1.89GB / 2.40GB 38.4s\n",
+ "#23 sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523 2.02GB / 2.40GB 41.0s\n",
+ "#23 sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523 2.14GB / 2.40GB 43.4s\n",
+ "#23 sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523 2.26GB / 2.40GB 45.8s\n",
+ "#23 sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523 2.38GB / 2.40GB 48.2s\n",
+ "#23 sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523 2.40GB / 2.40GB 49.8s done\n",
+ "#23 extracting sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523\n",
+ "#23 extracting sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523 57.5s done\n",
+ "#23 sha256:f20d17e4fd485b1a37bb580c6b5e8b8d707b382d387df57004086b8036ddaded 5.24MB / 105.68MB 0.2s\n",
+ "#23 sha256:f20d17e4fd485b1a37bb580c6b5e8b8d707b382d387df57004086b8036ddaded 13.63MB / 105.68MB 0.3s\n",
+ "#23 sha256:f20d17e4fd485b1a37bb580c6b5e8b8d707b382d387df57004086b8036ddaded 22.02MB / 105.68MB 0.5s\n",
+ "#23 sha256:f20d17e4fd485b1a37bb580c6b5e8b8d707b382d387df57004086b8036ddaded 29.36MB / 105.68MB 0.6s\n",
+ "#23 sha256:f20d17e4fd485b1a37bb580c6b5e8b8d707b382d387df57004086b8036ddaded 35.65MB / 105.68MB 0.8s\n",
+ "#23 sha256:f20d17e4fd485b1a37bb580c6b5e8b8d707b382d387df57004086b8036ddaded 44.04MB / 105.68MB 0.9s\n",
+ "#23 sha256:f20d17e4fd485b1a37bb580c6b5e8b8d707b382d387df57004086b8036ddaded 51.38MB / 105.68MB 1.1s\n",
+ "#23 sha256:f20d17e4fd485b1a37bb580c6b5e8b8d707b382d387df57004086b8036ddaded 59.77MB / 105.68MB 1.2s\n",
+ "#23 sha256:f20d17e4fd485b1a37bb580c6b5e8b8d707b382d387df57004086b8036ddaded 67.15MB / 105.68MB 1.4s\n",
+ "#23 sha256:f20d17e4fd485b1a37bb580c6b5e8b8d707b382d387df57004086b8036ddaded 75.50MB / 105.68MB 1.5s\n",
+ "#23 sha256:f20d17e4fd485b1a37bb580c6b5e8b8d707b382d387df57004086b8036ddaded 82.84MB / 105.68MB 1.7s\n",
+ "#23 sha256:f20d17e4fd485b1a37bb580c6b5e8b8d707b382d387df57004086b8036ddaded 89.13MB / 105.68MB 1.8s\n",
+ "#23 sha256:f20d17e4fd485b1a37bb580c6b5e8b8d707b382d387df57004086b8036ddaded 97.52MB / 105.68MB 2.0s\n",
+ "#23 sha256:f20d17e4fd485b1a37bb580c6b5e8b8d707b382d387df57004086b8036ddaded 105.68MB / 105.68MB 2.1s\n",
+ "#23 sha256:f20d17e4fd485b1a37bb580c6b5e8b8d707b382d387df57004086b8036ddaded 105.68MB / 105.68MB 2.4s done\n",
+ "#23 extracting sha256:f20d17e4fd485b1a37bb580c6b5e8b8d707b382d387df57004086b8036ddaded\n",
+ "#23 extracting sha256:f20d17e4fd485b1a37bb580c6b5e8b8d707b382d387df57004086b8036ddaded 2.9s done\n",
+ "#23 sha256:55e32cef42f992f9c914515dc95457ad65a501d20fb8face7a82d51a620e8d0c 149.04kB / 149.04kB 0.0s done\n",
+ "#23 extracting sha256:55e32cef42f992f9c914515dc95457ad65a501d20fb8face7a82d51a620e8d0c 0.0s done\n",
+ "#23 sha256:806c67c703b35fc283718dc9a3a7062a0303aabbea1395b138e66c10cd915f56 6.29MB / 48.57MB 0.2s\n",
+ "#23 sha256:806c67c703b35fc283718dc9a3a7062a0303aabbea1395b138e66c10cd915f56 13.63MB / 48.57MB 0.3s\n",
+ "#23 sha256:806c67c703b35fc283718dc9a3a7062a0303aabbea1395b138e66c10cd915f56 22.02MB / 48.57MB 0.5s\n",
+ "#23 sha256:806c67c703b35fc283718dc9a3a7062a0303aabbea1395b138e66c10cd915f56 29.36MB / 48.57MB 0.6s\n",
+ "#23 sha256:806c67c703b35fc283718dc9a3a7062a0303aabbea1395b138e66c10cd915f56 35.65MB / 48.57MB 0.8s\n",
+ "#23 sha256:806c67c703b35fc283718dc9a3a7062a0303aabbea1395b138e66c10cd915f56 42.99MB / 48.57MB 0.9s\n",
+ "#23 sha256:806c67c703b35fc283718dc9a3a7062a0303aabbea1395b138e66c10cd915f56 48.57MB / 48.57MB 1.1s\n",
+ "#23 sha256:806c67c703b35fc283718dc9a3a7062a0303aabbea1395b138e66c10cd915f56 48.57MB / 48.57MB 1.1s done\n",
+ "#23 extracting sha256:806c67c703b35fc283718dc9a3a7062a0303aabbea1395b138e66c10cd915f56\n",
+ "#23 extracting sha256:806c67c703b35fc283718dc9a3a7062a0303aabbea1395b138e66c10cd915f56 2.2s done\n",
+ "#23 CACHED\n",
+ "\n",
+ "#24 [18/22] COPY ./models /opt/holoscan/models\n",
+ "#24 DONE 3.1s\n",
+ "\n",
+ "#25 [19/22] COPY ./map/app.json /etc/holoscan/app.json\n",
+ "#25 DONE 0.1s\n",
+ "\n",
+ "#26 [20/22] COPY ./app.config /var/holoscan/app.yaml\n",
+ "#26 DONE 0.1s\n",
+ "\n",
+ "#27 [21/22] COPY ./map/pkg.json /etc/holoscan/pkg.json\n",
+ "#27 DONE 0.1s\n",
+ "\n",
+ "#28 [22/22] COPY ./app /opt/holoscan/app\n",
+ "#28 DONE 0.1s\n",
+ "\n",
+ "#29 exporting to docker image format\n",
+ "#29 exporting layers\n",
+ "#29 exporting layers 1.1s done\n",
+ "#29 exporting manifest sha256:c788c08ceb970d2b6c8a36eaf5d5809a959ed6ac92e387bf964a3b4998d3f2af 0.0s done\n",
+ "#29 exporting config sha256:d22d232013f038d48c43d4caa2246268674e9c6c81083f7ab6c3f37ec7ce31e2 0.0s done\n",
+ "#29 sending tarball\n",
+ "#29 ...\n",
+ "\n",
+ "#30 importing to docker\n",
+ "#30 DONE 1.3s\n",
+ "\n",
+ "#29 exporting to docker image format\n",
+ "#29 sending tarball 52.6s done\n",
+ "#29 DONE 53.8s\n",
+ "\n",
+ "#31 exporting content cache\n",
+ "#31 preparing build cache for export\n",
+ "#31 writing layer sha256:0709800848b4584780b40e7e81200689870e890c38b54e96b65cd0a3b1942f2d done\n",
+ "#31 writing layer sha256:0ce020987cfa5cd1654085af3bb40779634eb3d792c4a4d6059036463ae0040d done\n",
+ "#31 writing layer sha256:0f65089b284381bf795d15b1a186e2a8739ea957106fa526edef0d738e7cda70 done\n",
+ "#31 writing layer sha256:12a47450a9f9cc5d4edab65d0f600dbbe8b23a1663b0b3bb2c481d40e074b580 done\n",
+ "#31 writing layer sha256:1338fe24653eba781a71bd79902b5b905624589983ce80c816a09bda7b89e3bd\n",
+ "#31 writing layer sha256:1338fe24653eba781a71bd79902b5b905624589983ce80c816a09bda7b89e3bd 0.6s done\n",
+ "#31 writing layer sha256:1477e9e55f1216fe4085565e21baa742149b480d35141f298402b1e766fb58d3 0.0s done\n",
+ "#31 writing layer sha256:1de965777e2e37c7fabe00bdbf3d0203ca83ed30a71a5479c3113fe4fc48c4bb done\n",
+ "#31 writing layer sha256:24b5aa2448e920814dd67d7d3c0169b2cdacb13c4048d74ded3b4317843b13ff done\n",
+ "#31 writing layer sha256:2d42104dbf0a7cc962b791f6ab4f45a803f8a36d296f996aca180cfb2f3e30d0 done\n",
+ "#31 writing layer sha256:2fa1ce4fa3fec6f9723380dc0536b7c361d874add0baaddc4bbf2accac82d2ff\n",
+ "#31 writing layer sha256:2fa1ce4fa3fec6f9723380dc0536b7c361d874add0baaddc4bbf2accac82d2ff done\n",
+ "#31 writing layer sha256:38794be1b5dc99645feabf89b22cd34fb5bdffb5164ad920e7df94f353efe9c0 done\n",
+ "#31 writing layer sha256:38f963dc57c1e7b68a738fe39ed9f9345df7188111a047e2163a46648d7f1d88 done\n",
+ "#31 writing layer sha256:3e7e4c9bc2b136814c20c04feb4eea2b2ecf972e20182d88759931130cfb4181 done\n",
+ "#31 writing layer sha256:3fd77037ad585442cd82d64e337f49a38ddba50432b2a1e563a48401d25c79e6 done\n",
+ "#31 writing layer sha256:41814ed91034b30ac9c44dfc604a4bade6138005ccf682372c02e0bead66dbc0 done\n",
+ "#31 writing layer sha256:45893188359aca643d5918c9932da995364dc62013dfa40c075298b1baabece3 done\n",
+ "#31 writing layer sha256:49bc651b19d9e46715c15c41b7c0daa007e8e25f7d9518f04f0f06592799875a done\n",
+ "#31 writing layer sha256:4aeb0049534a685f9b8d851171ca3ee850fc1609d85e651ebdb0508d8d1e9403 0.0s done\n",
+ "#31 writing layer sha256:4c12db5118d8a7d909e4926d69a2192d2b3cd8b110d49c7504a4f701258c1ccc done\n",
+ "#31 writing layer sha256:4cc43a803109d6e9d1fd35495cef9b1257035f5341a2db54f7a1940815b6cc65 done\n",
+ "#31 writing layer sha256:4d32b49e2995210e8937f0898327f196d3fcc52486f0be920e8b2d65f150a7ab done\n",
+ "#31 writing layer sha256:4d6fe980bad9cd7b2c85a478c8033cae3d098a81f7934322fb64658b0c8f9854 done\n",
+ "#31 writing layer sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 done\n",
+ "#31 writing layer sha256:5150182f1ff123399b300ca469e00f6c4d82e1b9b72652fb8ee7eab370245236 done\n",
+ "#31 writing layer sha256:55e32cef42f992f9c914515dc95457ad65a501d20fb8face7a82d51a620e8d0c done\n",
+ "#31 writing layer sha256:595c38fa102c61c3dda19bdab70dcd26a0e50465b986d022a84fa69023a05d0f done\n",
+ "#31 writing layer sha256:59d451175f6950740e26d38c322da0ef67cb59da63181eb32996f752ba8a2f17 done\n",
+ "#31 writing layer sha256:5ad1f2004580e415b998124ea394e9d4072a35d70968118c779f307204d6bd17 done\n",
+ "#31 writing layer sha256:62598eafddf023e7f22643485f4321cbd51ff7eee743b970db12454fd3c8c675 done\n",
+ "#31 writing layer sha256:63d7e616a46987136f4cc9eba95db6f6327b4854cfe3c7e20fed6db0c966e380 done\n",
+ "#31 writing layer sha256:6939d591a6b09b14a437e5cd2d6082a52b6d76bec4f72d960440f097721da34f done\n",
+ "#31 writing layer sha256:698318e5a60e5e0d48c45bf992f205a9532da567fdfe94bd59be2e192975dd6f done\n",
+ "#31 writing layer sha256:6ddc1d0f91833b36aac1c6f0c8cea005c87d94bab132d46cc06d9b060a81cca3 done\n",
+ "#31 writing layer sha256:74ac1f5a47c0926bff1e997bb99985a09926f43bd0895cb27ceb5fa9e95f8720 done\n",
+ "#31 writing layer sha256:7577973918dd30e764733a352a93f418000bc3181163ca451b2307492c1a6ba9 done\n",
+ "#31 writing layer sha256:806c67c703b35fc283718dc9a3a7062a0303aabbea1395b138e66c10cd915f56 done\n",
+ "#31 writing layer sha256:886c886d8a09d8befb92df75dd461d4f97b77d7cff4144c4223b0d2f6f2c17f2 done\n",
+ "#31 writing layer sha256:8a7451db9b4b817b3b33904abddb7041810a4ffe8ed4a034307d45d9ae9b3f2a done\n",
+ "#31 writing layer sha256:916f4054c6e7f10de4fd7c08ffc75fa23ebecca4eceb8183cb1023b33b1696c9 done\n",
+ "#31 writing layer sha256:9463aa3f56275af97693df69478a2dc1d171f4e763ca6f7b6f370a35e605c154 done\n",
+ "#31 writing layer sha256:955fd173ed884230c2eded4542d10a97384b408537be6bbb7c4ae09ccd6fb2d0 done\n",
+ "#31 writing layer sha256:99ef644a0c84a569b9692a76e0c6a1c3e9dedae5d551087be684b6bc1bea6f22 done\n",
+ "#31 writing layer sha256:9c42a4ee99755f441251e6043b2cbba16e49818a88775e7501ec17e379ce3cfd done\n",
+ "#31 writing layer sha256:9c63be0a86e3dc4168db3814bf464e40996afda0031649d9faa8ff7568c3154f done\n",
+ "#31 writing layer sha256:9e04bda98b05554953459b5edef7b2b14d32f1a00b979a23d04b6eb5c191e66b done\n",
+ "#31 writing layer sha256:a4a0c690bc7da07e592514dccaa26098a387e8457f69095e922b6d73f7852502 done\n",
+ "#31 writing layer sha256:a4aafbc094d78a85bef41036173eb816a53bcd3e2564594a32f542facdf2aba6 done\n",
+ "#31 writing layer sha256:ae36a4d38b76948e39a5957025c984a674d2de18ce162a8caaa536e6f06fccea done\n",
+ "#31 writing layer sha256:b2fa40114a4a0725c81b327df89c0c3ed5c05ca9aa7f1157394d5096cf5460ce done\n",
+ "#31 writing layer sha256:b48a5fafcaba74eb5d7e7665601509e2889285b50a04b5b639a23f8adc818157 done\n",
+ "#31 writing layer sha256:b8ec9058cfc8057a4989af89add416b6d4c425cb3e3a4542281d3b188ef8d97f 0.0s done\n",
+ "#31 writing layer sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523\n",
+ "#31 preparing build cache for export 1.3s done\n",
+ "#31 writing layer sha256:b9874c0e107000cd0157c2f6c12f6b095ec79e92b293ef581984b94c75080523 done\n",
+ "#31 writing layer sha256:c86976a083599e36a6441f36f553627194d05ea82bb82a78682e718fe62fccf6 done\n",
+ "#31 writing layer sha256:cb506fbdedc817e3d074f609e2edbf9655aacd7784610a1bbac52f2d7be25438 done\n",
+ "#31 writing layer sha256:d2a6fe65a1f84edb65b63460a75d1cac1aa48b72789006881b0bcfd54cd01ffd done\n",
+ "#31 writing layer sha256:d674572cae0440d01b016bd1a6cf88924f6067f38858706ad4856d78993a0a6e done\n",
+ "#31 writing layer sha256:d709c3fc82181d7bc3561f087363554add07059d1fc1fa014d3da3f9092a7524 0.0s done\n",
+ "#31 writing layer sha256:d8d16d6af76dc7c6b539422a25fdad5efb8ada5a8188069fcd9d113e3b783304 done\n",
+ "#31 writing layer sha256:ddc2ade4f6fe866696cb638c8a102cb644fa842c2ca578392802b3e0e5e3bcb7 done\n",
+ "#31 writing layer sha256:e2cfd7f6244d6f35befa6bda1caa65f1786cecf3f00ef99d7c9a90715ce6a03c done\n",
+ "#31 writing layer sha256:e94a4481e9334ff402bf90628594f64a426672debbdfb55f1290802e52013907 done\n",
+ "#31 writing layer sha256:eaf45e9f32d1f5a9983945a1a9f8dedbb475bc0f578337610e00b4dedec87c20 done\n",
+ "#31 writing layer sha256:eb411bef39c013c9853651e68f00965dbd826d829c4e478884a2886976e9c989 done\n",
+ "#31 writing layer sha256:edfe4a95eb6bd3142aeda941ab871ffcc8c19cf50c33561c210ba8ead2424759 done\n",
+ "#31 writing layer sha256:ef4466d6f927d29d404df9c5af3ef5733c86fa14e008762c90110b963978b1e7 done\n",
+ "#31 writing layer sha256:f20d17e4fd485b1a37bb580c6b5e8b8d707b382d387df57004086b8036ddaded done\n",
+ "#31 writing layer sha256:f346e3ecdf0bee048fa1e3baf1d3128ff0283b903f03e97524944949bd8882e5 done\n",
+ "#31 writing layer sha256:f3f9a00a1ce9aadda250aacb3e66a932676badc5d8519c41517fdf7ea14c13ed done\n",
+ "#31 writing layer sha256:fd849d9bd8889edd43ae38e9f21a912430c8526b2c18f3057a3b2cd74eb27b31 done\n",
+ "#31 writing config sha256:23fbbd00b006000bbd87f5dfe7e12fe71203e710a83580e1ee63125c214ff4d5 0.0s done\n",
+ "#31 writing manifest sha256:7b8dadf0182c3fbe7dede6a29963defd6eff4efa3a6b8e81e5f2dceaaf023210 0.0s done\n",
+ "#31 DONE 1.3s\n",
+ "[2023-08-03 20:52:32,339] [INFO] (packager) - Build Summary:\n",
+ "\n",
+ "Platform: x64-workstation/dgpu\n",
+ " Status: Succeeded\n",
+ " Docker Tag: mednist_app-x64-workstation-dgpu-linux-amd64:1.0\n",
+ " Tarball: None\n"
]
}
],
"source": [
- "!monai-deploy package mednist_classifier_monaideploy.py --tag mednist_app:latest --model classifier.zip # -l DEBUG"
+ "tag_prefix = \"mednist_app\"\n",
+ "\n",
+ "!monai-deploy package \"mednist_app/mednist_classifier_monaideploy.py\" -m {models_folder} -c \"mednist_app/app.yaml\" -t {tag_prefix}:1.0 --platform x64-workstation -l DEBUG"
]
},
{
@@ -2504,19 +1683,19 @@
},
{
"cell_type": "code",
- "execution_count": 23,
+ "execution_count": 24,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "mednist_app latest 1eba359ad2ae 3 seconds ago 15GB\n"
+ "mednist_app-x64-workstation-dgpu-linux-amd64 1.0 d22d232013f0 59 seconds ago 15.4GB\n"
]
}
],
"source": [
- "!docker image ls | grep mednist_app"
+ "!docker image ls | grep {tag_prefix}"
]
},
{
@@ -2525,65 +1704,102 @@
"source": [
"### Executing packaged app locally\n",
"\n",
- "The packaged app can be run locally through MONAI Application Runner ."
+ "We can choose to display and export the MAP manifests, but in this example, we will just run the MAP through MONAI Application Runner ."
]
},
{
"cell_type": "code",
- "execution_count": 24,
+ "execution_count": 25,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "Test Input Path: /tmp/tmp00iaib5g/MedNIST/AbdomenCT/001420.jpeg\n",
- "MAP input folder files:\n",
- "001420.jpeg\n",
- "Checking dependencies...\n",
- "--> Verifying if \"docker\" is installed...\n",
- "\n",
- "--> Verifying if \"mednist_app:latest\" is available...\n",
- "\n",
- "Checking for MAP \"mednist_app:latest\" locally\n",
- "\"mednist_app:latest\" found.\n",
- "\n",
- "Reading MONAI App Package manifest...\n",
- "\u001b[sPreparing to copy...\u001b[?25l\u001b[u\u001b[2KCopying from container - 0B\u001b[?25h\u001b[u\u001b[2KSuccessfully copied 2.05kB to /tmp/tmp0_zu2d_p/app.json\n",
- "\u001b[sPreparing to copy...\u001b[?25l\u001b[u\u001b[2KCopying from container - 0B\u001b[?25h\u001b[u\u001b[2KSuccessfully copied 2.05kB to /tmp/tmp0_zu2d_p/pkg.json\n",
- "--> Verifying if \"nvidia-docker\" is installed...\n",
- "\n",
- "/opt/conda/lib/python3.8/site-packages/scipy/__init__.py:138: UserWarning: A NumPy version >=1.16.5 and <1.23.0 is required for this version of SciPy (detected version 1.24.3)\n",
- " warnings.warn(f\"A NumPy version >={np_minversion} and <{np_maxversion} is required for this version of \"\n",
- "\u001b[34mGoing to initiate execution of operator LoadPILOperator\u001b[39m\n",
- "\u001b[32mExecuting operator LoadPILOperator \u001b[33m(Process ID: 1, Operator ID: ffdb9a34-3aab-42c7-b850-1e807d4abc42)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator LoadPILOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator MedNISTClassifierOperator\u001b[39m\n",
- "\u001b[32mExecuting operator MedNISTClassifierOperator \u001b[33m(Process ID: 1, Operator ID: 0ed76555-578f-4b9e-8d41-4629eca56630)\u001b[39m\n",
- "/root/.local/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:111: FutureWarning: : Class `AddChannel` has been deprecated since version 0.8. It will be removed in version 1.3. please use MetaTensor data type and monai.transforms.EnsureChannelFirst instead with `channel_dim='no_channel'`.\n",
+ "/home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages/pydantic/_internal/_config.py:269: UserWarning: Valid config keys have changed in V2:\n",
+ "* 'allow_population_by_field_name' has been renamed to 'populate_by_name'\n",
+ " warnings.warn(message, UserWarning)\n",
+ "[2023-08-03 20:52:37,269] [INFO] (runner) - Checking dependencies...\n",
+ "[2023-08-03 20:52:37,269] [INFO] (runner) - --> Verifying if \"docker\" is installed...\n",
+ "\n",
+ "[2023-08-03 20:52:37,270] [INFO] (runner) - --> Verifying if \"docker-buildx\" is installed...\n",
+ "\n",
+ "[2023-08-03 20:52:37,270] [INFO] (runner) - --> Verifying if \"mednist_app-x64-workstation-dgpu-linux-amd64:1.0\" is available...\n",
+ "\n",
+ "[2023-08-03 20:52:37,348] [INFO] (runner) - Reading HAP/MAP manifest...\n",
+ "\u001b[sPreparing to copy...\u001b[?25l\u001b[u\u001b[2KCopying from container - 0B\u001b[?25h\u001b[u\u001b[2KSuccessfully copied 2.56kB to /tmp/tmp4dplyjgr/app.json\n",
+ "\u001b[sPreparing to copy...\u001b[?25l\u001b[u\u001b[2KCopying from container - 0B\u001b[?25h\u001b[u\u001b[2KSuccessfully copied 2.05kB to /tmp/tmp4dplyjgr/pkg.json\n",
+ "[2023-08-03 20:52:37,733] [INFO] (runner) - --> Verifying if \"nvidia-ctk\" is installed...\n",
+ "\n",
+ "[2023-08-03 20:52:37,954] [INFO] (common) - Launching container (96d09cbab602) using image 'mednist_app-x64-workstation-dgpu-linux-amd64:1.0'...\n",
+ " container name: determined_maxwell\n",
+ " host name: mingq-dt\n",
+ " network: host\n",
+ " user: 1000:1000\n",
+ " ulimits: memlock=-1:-1, stack=67108864:67108864\n",
+ " cap_add: CAP_SYS_PTRACE\n",
+ " ipc mode: host\n",
+ " shared memory size: 67108864\n",
+ " devices: \n",
+ "2023-08-04 03:52:38 [INFO] Launching application python3 /opt/holoscan/app/mednist_classifier_monaideploy.py ...\n",
+ "\n",
+ "[info] [app_driver.cpp:1025] Launching the driver/health checking service\n",
+ "\n",
+ "[info] [gxf_executor.cpp:210] Creating context\n",
+ "\n",
+ "[info] [server.cpp:73] Health checking server listening on 0.0.0.0:8777\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1595] Loading extensions from configs...\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1741] Activating Graph...\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1771] Running Graph...\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1773] Waiting for completion...\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1774] Graph execution waiting. Fragment: \n",
+ "\n",
+ "[info] [greedy_scheduler.cpp:190] Scheduling 3 entities\n",
+ "\n",
+ "[info] [greedy_scheduler.cpp:369] Scheduler stopped: Some entities are waiting for execution, but there are no periodic or async entities to get out of the deadlock.\n",
+ "\n",
+ "[info] [greedy_scheduler.cpp:398] Scheduler finished.\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1783] Graph execution deactivating. Fragment: \n",
+ "\n",
+ "[info] [gxf_executor.cpp:1784] Deactivating Graph...\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1787] Graph execution finished. Fragment: \n",
+ "\n",
+ "[info] [gxf_executor.cpp:229] Destroying context\n",
+ "\n",
+ "/home/holoscan/.local/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:111: FutureWarning: : Class `AddChannel` has been deprecated since version 0.8. It will be removed in version 1.3. please use MetaTensor data type and monai.transforms.EnsureChannelFirst instead with `channel_dim='no_channel'`.\n",
+ "\n",
" warn_deprecated(obj, msg, warning_category)\n",
+ "\n",
+ "/home/holoscan/.local/lib/python3.8/site-packages/monai/data/meta_tensor.py:116: UserWarning: The given NumPy array is not writable, and PyTorch does not support non-writable tensors. This means writing to this tensor will result in undefined behavior. You may want to copy the array to protect its data or make it writable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at ../torch/csrc/utils/tensor_numpy.cpp:206.)\n",
+ "\n",
+ " return torch.as_tensor(x, *args, **_kwargs).as_subclass(cls) # type: ignore\n",
+ "\n",
+ "/home/holoscan/.local/lib/python3.8/site-packages/pydicom/valuerep.py:443: UserWarning: Invalid value for VR UI: 'xyz'. Please see for allowed values for each VR.\n",
+ "\n",
+ " warnings.warn(msg)\n",
+ "\n",
"AbdomenCT\n",
- "\u001b[34mDone performing execution of operator MedNISTClassifierOperator\n",
- "\u001b[39m\n"
+ "\n",
+ "[2023-08-03 20:52:51,293] [INFO] (common) - Container 'determined_maxwell'(96d09cbab602) exited.\n"
]
}
],
"source": [
- "# Copy a test input file to 'input' folder\n",
- "!mkdir -p input && rm -rf input/*\n",
- "!echo \"Test Input Path: \" {test_input_path}\n",
- "!cp {test_input_path} input/\n",
- "!echo \"MAP input folder files:\"\n",
- "!ls input\n",
- "\n",
- "# Launch the app\n",
- "!monai-deploy run mednist_app:latest input output"
+ "# Clear the output folder and run the MAP. The input is expected to be a folder.\n",
+ "!rm -rf $HOLOSCAN_OUTPUT_PATH\n",
+ "!monai-deploy run -i$HOLOSCAN_INPUT_PATH -o $HOLOSCAN_OUTPUT_PATH mednist_app-x64-workstation-dgpu-linux-amd64:1.0"
]
},
{
"cell_type": "code",
- "execution_count": 25,
+ "execution_count": 26,
"metadata": {},
"outputs": [
{
@@ -2595,7 +1811,7 @@
}
],
"source": [
- "!cat output/output.json"
+ "!cat $HOLOSCAN_OUTPUT_PATH/output.json"
]
},
{
@@ -2607,7 +1823,7 @@
},
{
"cell_type": "code",
- "execution_count": 26,
+ "execution_count": 27,
"metadata": {},
"outputs": [],
"source": [
diff --git a/notebooks/tutorials/03_segmentation_app.ipynb b/notebooks/tutorials/03_segmentation_app.ipynb
index 9028141b..11fc08ce 100644
--- a/notebooks/tutorials/03_segmentation_app.ipynb
+++ b/notebooks/tutorials/03_segmentation_app.ipynb
@@ -6,13 +6,13 @@
"source": [
"# Creating a Segmentation App with MONAI Deploy App SDK\n",
"\n",
- "This tutorial shows how to create an organ segmentation application for a PyTorch model that has been trained with MONAI. Please note that this tutorial is based on the [earlier version](https://github.com/Project-MONAI/monai-deploy-app-sdk/blob/7615d73f6ec2125ba5d2e3480f85b060e95b81e4/examples/apps/ai_spleen_seg_app/app.py) of the Spleen Segmentation Application.\n",
+ "This tutorial shows how to create an organ segmentation application for a PyTorch model that has been trained with MONAI. Please note that this one does not require the model be a MONAI Bundle.\n",
"\n",
- "Deploying AI models requires the integration with clinical imaging network, even if in a for-research-use setting. This means that the AI deploy application will need to support standards-based imaging protocols, and specifically for Radiological imaging, DICOM protocol.\n",
+ "Deploying AI models requires the integration with clinical imaging network, even if just in a for-research-use setting. This means that the AI deploy application will need to support standards-based imaging protocols, and specifically for Radiological imaging, DICOM protocol.\n",
"\n",
- "Typically, DICOM network communication, either in DICOM TCP/IP network protocol or DICOMWeb, would be handled by DICOM devices or services, e.g. MONAI Deploy Informatics Gateway, so the deploy application itself would only need to use DICOM Part 10 files as input and save the AI result in DICOM Part10 file(s). For segmentation use cases, the DICOM instance file could be a DICOM Segmentation object or a DICOM RT Structure Set, and for classification, DICOM Structure Report and/or DICOM Encapsulated PDF.\n",
+ "Typically, DICOM network communication, either in DICOM TCP/IP network protocol or DICOMWeb, would be handled by DICOM devices or services, e.g. MONAI Deploy Informatics Gateway, so the deploy application itself would only need to use DICOM Part 10 files as input and save the AI result in DICOM Part10 file(s). For segmentation use cases, the DICOM instance file for AI results could be a DICOM Segmentation object or a DICOM RT Structure Set, and for classification, DICOM Structure Report and/or DICOM Encapsulated PDF.\n",
"\n",
- "During model training, input and label images are typically in non-DICOM volumetric image format, e.g., NIfTI and PNG, converted from a specific DICOM study series. Furthermore, the voxel spacings most likely have been re-sampled to be uniform for all images. When integrated with imaging networks and receiving DICOM instances from modalities and Picture Archiving and Communications System, PACS, an AI deploy application may have to deal with a whole DICOM study with multiple series, whose images' spacing may not be the same as expected by the trained model. To address these cases consistently and efficiently, MONAI Deploy Application SDK provides classes, called operators, to parse DICOM studies, select specific series with application-defined rules, and convert the selected DICOM series into domain-specific image format along with meta-data representing the pertinent DICOM attributes.\n",
+ "During model training, input and label images are typically in non-DICOM volumetric image format, e.g., NIfTI and PNG, converted from a specific DICOM study series. Furthermore, the voxel spacings most likely have been re-sampled to be uniform for all images. When integrated with imaging networks and receiving DICOM instances from modalities and Picture Archiving and Communications System, PACS, an AI deploy application has to deal with a whole DICOM study with multiple series, whose images' spacing may not be the same as expected by the trained model. To address these cases consistently and efficiently, MONAI Deploy Application SDK provides classes, called operators, to parse DICOM studies, select specific series with application-defined rules, and convert the selected DICOM series into domain-specific image format along with meta-data representing the pertinent DICOM attributes. The image is then further processed in the pre-processing stage to normalize spacing, orientation, intensity, etc., before pixel data as Tensors are used for inference.\n",
"\n",
"In the following sections, we will demonstrate how to create a MONAI Deploy application package using the MONAI Deploy App SDK.\n",
"\n",
@@ -26,7 +26,7 @@
"We will implement an application that consists of five Operators:\n",
"\n",
"- **DICOMDataLoaderOperator**:\n",
- " - **Input(dicom_files)**: a folder path ([`DataPath`](/modules/_autosummary/monai.deploy.core.domain.DataPath))\n",
+ " - **Input(dicom_files)**: a folder path (`Path`)\n",
" - **Output(dicom_study_list)**: a list of DICOM studies in memory (List[[`DICOMStudy`](/modules/_autosummary/monai.deploy.core.domain.DICOMStudy)])\n",
"- **DICOMSeriesSelectorOperator**:\n",
" - **Input(dicom_study_list)**: a list of DICOM studies in memory (List[[`DICOMStudy`](/modules/_autosummary/monai.deploy.core.domain.DICOMStudy)])\n",
@@ -41,7 +41,7 @@
"- **DICOMSegmentationWriterOperator**:\n",
" - **Input(seg_image)**: a segmentation image object in memory ([`Image`](/modules/_autosummary/monai.deploy.core.domain.Image))\n",
" - **Input(study_selected_series_list)**: a DICOM series object in memory ([`StudySelectedSeries`](/modules/_autosummary/monai.deploy.core.domain.StudySelectedSeries))\n",
- " - **Output(dicom_seg_instance)**: a file path ([`DataPath`](/modules/_autosummary/monai.deploy.core.domain.DataPath))\n",
+ " - **Output(dicom_seg_instance)**: a file path (`Path`)\n",
"\n",
"\n",
":::{note}\n",
@@ -106,7 +106,7 @@
"!python -c \"import SimpleITK\" || pip install -q \"SimpleITK>=2.0.0\"\n",
"\n",
"# Install MONAI Deploy App SDK package\n",
- "!python -c \"import monai.deploy\" || pip install --upgrade -q \"monai-deploy-app-sdk\""
+ "!python -c \"import monai.deploy\" || pip install --upgrade \"monai-deploy-app-sdk\""
]
},
{
@@ -132,23 +132,23 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "Requirement already satisfied: gdown in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (4.7.1)\n",
- "Requirement already satisfied: filelock in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from gdown) (3.12.2)\n",
- "Requirement already satisfied: requests[socks] in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from gdown) (2.31.0)\n",
- "Requirement already satisfied: six in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from gdown) (1.16.0)\n",
- "Requirement already satisfied: tqdm in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from gdown) (4.65.0)\n",
- "Requirement already satisfied: beautifulsoup4 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from gdown) (4.12.2)\n",
- "Requirement already satisfied: soupsieve>1.2 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from beautifulsoup4->gdown) (2.4.1)\n",
- "Requirement already satisfied: charset-normalizer<4,>=2 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from requests[socks]->gdown) (3.2.0)\n",
- "Requirement already satisfied: idna<4,>=2.5 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from requests[socks]->gdown) (3.4)\n",
- "Requirement already satisfied: urllib3<3,>=1.21.1 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from requests[socks]->gdown) (2.0.3)\n",
- "Requirement already satisfied: certifi>=2017.4.17 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from requests[socks]->gdown) (2023.5.7)\n",
- "Requirement already satisfied: PySocks!=1.5.7,>=1.5.6 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from requests[socks]->gdown) (1.7.1)\n",
+ "Requirement already satisfied: gdown in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (4.7.1)\n",
+ "Requirement already satisfied: filelock in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from gdown) (3.12.2)\n",
+ "Requirement already satisfied: requests[socks] in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from gdown) (2.31.0)\n",
+ "Requirement already satisfied: six in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from gdown) (1.16.0)\n",
+ "Requirement already satisfied: tqdm in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from gdown) (4.66.1)\n",
+ "Requirement already satisfied: beautifulsoup4 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from gdown) (4.12.2)\n",
+ "Requirement already satisfied: soupsieve>1.2 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from beautifulsoup4->gdown) (2.4.1)\n",
+ "Requirement already satisfied: charset-normalizer<4,>=2 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from requests[socks]->gdown) (3.2.0)\n",
+ "Requirement already satisfied: idna<4,>=2.5 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from requests[socks]->gdown) (3.4)\n",
+ "Requirement already satisfied: urllib3<3,>=1.21.1 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from requests[socks]->gdown) (2.0.4)\n",
+ "Requirement already satisfied: certifi>=2017.4.17 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from requests[socks]->gdown) (2023.7.22)\n",
+ "Requirement already satisfied: PySocks!=1.5.7,>=1.5.6 in /home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages (from requests[socks]->gdown) (1.7.1)\n",
"Downloading...\n",
"From (uriginal): https://drive.google.com/uc?id=1Uds8mEvdGNYUuvFpTtCQ8gNU97bAPCaQ\n",
- "From (redirected): https://drive.google.com/uc?id=1Uds8mEvdGNYUuvFpTtCQ8gNU97bAPCaQ&confirm=t&uuid=acc94cb9-5b71-4f4c-8148-50021b56a2b2\n",
+ "From (redirected): https://drive.google.com/uc?id=1Uds8mEvdGNYUuvFpTtCQ8gNU97bAPCaQ&confirm=t&uuid=583abdda-51b2-449f-b609-992374b4ac1a\n",
"To: /home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/ai_spleen_seg_bundle_data.zip\n",
- "100%|██████████████████████████████████████| 79.4M/79.4M [00:01<00:00, 46.0MB/s]\n",
+ "100%|██████████████████████████████████████| 79.4M/79.4M [00:01<00:00, 56.1MB/s]\n",
"Archive: ai_spleen_seg_bundle_data.zip\n",
" inflating: dcm/1-001.dcm \n",
" inflating: dcm/1-002.dcm \n",
@@ -354,7 +354,8 @@
" inflating: dcm/1-202.dcm \n",
" inflating: dcm/1-203.dcm \n",
" inflating: dcm/1-204.dcm \n",
- " inflating: model.ts \n"
+ " inflating: model.ts \n",
+ "model.ts\n"
]
}
],
@@ -364,7 +365,32 @@
"!gdown \"https://drive.google.com/uc?id=1Uds8mEvdGNYUuvFpTtCQ8gNU97bAPCaQ\"\n",
"\n",
"# After downloading ai_spleen_bundle_data zip file from the web browser or using gdown,\n",
- "!unzip -o \"ai_spleen_seg_bundle_data.zip\""
+ "!unzip -o \"ai_spleen_seg_bundle_data.zip\"\n",
+ "\n",
+ "# Need to copy the model.ts file to its own clean subfolder for packaging, to work around an issue in the Packager\n",
+ "models_folder = \"models\"\n",
+ "!rm -rf {models_folder} && mkdir -p {models_folder}/model && cp model.ts {models_folder}/model && ls {models_folder}/model"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "env: HOLOSCAN_INPUT_PATH=dcm\n",
+ "env: HOLOSCAN_MODEL_PATH=models\n",
+ "env: HOLOSCAN_OUTPUT_PATH=output\n"
+ ]
+ }
+ ],
+ "source": [
+ "%env HOLOSCAN_INPUT_PATH dcm\n",
+ "%env HOLOSCAN_MODEL_PATH {models_folder}\n",
+ "%env HOLOSCAN_OUTPUT_PATH output"
]
},
{
@@ -378,18 +404,27 @@
},
{
"cell_type": "code",
- "execution_count": 3,
+ "execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"import logging\n",
- "from os import path\n",
+ "from numpy import uint8 # Needed if SaveImaged is enabled\n",
+ "from pathlib import Path\n",
"\n",
- "from numpy import uint8\n",
+ "# Required for setting SegmentDescription attributes. Direct import as this is not part of App SDK package.\n",
+ "from pydicom.sr.codedict import codes\n",
+ "\n",
+ "from monai.deploy.conditions import CountCondition\n",
+ "from monai.deploy.core import AppContext, Application, ConditionType, Fragment, Operator, OperatorSpec\n",
+ "from monai.deploy.core.domain import Image\n",
+ "from monai.deploy.core.io_type import IOType\n",
+ "from monai.deploy.operators.dicom_data_loader_operator import DICOMDataLoaderOperator\n",
+ "from monai.deploy.operators.dicom_seg_writer_operator import DICOMSegmentationWriterOperator, SegmentDescription\n",
+ "from monai.deploy.operators.dicom_series_selector_operator import DICOMSeriesSelectorOperator\n",
+ "from monai.deploy.operators.dicom_series_to_volume_operator import DICOMSeriesToVolumeOperator\n",
+ "from monai.deploy.operators.monai_seg_inference_operator import InfererType, InMemImageReader, MonaiSegInferenceOperator\n",
"\n",
- "import monai.deploy.core as md\n",
- "from monai.deploy.core import ExecutionContext, Image, InputContext, IOType, Operator, OutputContext\n",
- "from monai.deploy.operators.monai_seg_inference_operator import InMemImageReader, MonaiSegInferenceOperator\n",
"from monai.transforms import (\n",
" Activationsd,\n",
" AsDiscreted,\n",
@@ -402,16 +437,7 @@
" SaveImaged,\n",
" ScaleIntensityRanged,\n",
" Spacingd,\n",
- ")\n",
- "\n",
- "# Required for setting SegmentDescription attributes. Direct import as this is not part of App SDK package.\n",
- "from pydicom.sr.codedict import codes\n",
- "\n",
- "from monai.deploy.core import Application, resource\n",
- "from monai.deploy.operators.dicom_data_loader_operator import DICOMDataLoaderOperator\n",
- "from monai.deploy.operators.dicom_seg_writer_operator import DICOMSegmentationWriterOperator, SegmentDescription\n",
- "from monai.deploy.operators.dicom_series_selector_operator import DICOMSeriesSelectorOperator\n",
- "from monai.deploy.operators.dicom_series_to_volume_operator import DICOMSeriesToVolumeOperator\n"
+ ")\n"
]
},
{
@@ -420,11 +446,9 @@
"source": [
"### Creating Model Specific Inference Operator classes\n",
"\n",
- "Each Operator class inherits [Operator](/modules/_autosummary/monai.deploy.core.Operator) class and input/output properties are specified by using [@input](/modules/_autosummary/monai.deploy.core.input)/[@output](/modules/_autosummary/monai.deploy.core.output) decorators.\n",
+ "Each Operator class inherits the base `Operator` class. The input/output properties are specified by implementing the `setup()` method, and the business logic implemented in the `compute()` method.\n",
"\n",
- "Business logic would be implemented in the compute() method.\n",
- "\n",
- "The App SDK provides a `MonaiSegInferenceOperator` class to perform segmentation prediction with a Torch Script model. For consistency, this class uses MONAI dictionary-based transforms, as `Compose` object, for pre and post transforms. The model-specific inference operator will then only need to create the pre and post transform `Compose` based on what has been used in the model training and validation. Note that for deploy application, `ignite` is not needed nor supported.\n",
+ "The App SDK provides a `MonaiSegInferenceOperator` class to perform segmentation prediction with a Torch Script model. For consistency, this class uses MONAI dictionary-based transforms, as `Compose` object, for pre and post transforms. The model-specific inference operator will then only need to create the pre and post transform `Compose` based on what has been used in the model during training and validation. Note that for deploy application, `ignite` is not needed nor supported.\n",
"\n",
"#### SpleenSegOperator\n",
"\n",
@@ -436,68 +460,110 @@
"\n",
"When the `MonaiSegInferenceOperator` object is created, the `ROI` size is specified, as well as the transform `Compose` objects. Furthermore, the dataset image key names are set accordingly.\n",
"\n",
- "Loading of the model and performing the prediction are encapsulated in the `MonaiSegInferenceOperator` and other SDK classes. Once the inference is completed, the segmentation [Image](/modules/_autosummary/monai.deploy.core.domain.Image) object is created and set to the output (op_output.set(value, label) ), by the `MonaiSegInferenceOperator`."
+ "Loading of the model and performing the prediction are encapsulated in the `MonaiSegInferenceOperator` and other SDK classes. Once the inference is completed, the segmentation [Image](/modules/_autosummary/monai.deploy.core.domain.Image) object is created and set to the output by the `SpleenSegOperator`."
]
},
{
"cell_type": "code",
- "execution_count": 4,
+ "execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
- "@md.input(\"image\", Image, IOType.IN_MEMORY)\n",
- "@md.output(\"seg_image\", Image, IOType.IN_MEMORY)\n",
- "@md.env(pip_packages=[\"monai>=0.8.1\", \"torch>=1.10.2\", \"numpy>=1.21\", \"nibabel\"])\n",
"class SpleenSegOperator(Operator):\n",
" \"\"\"Performs Spleen segmentation with a 3D image converted from a DICOM CT series.\n",
" \"\"\"\n",
"\n",
- " def __init__(self):\n",
+ " DEFAULT_OUTPUT_FOLDER = Path.cwd() / \"output/saved_images_folder\"\n",
+ "\n",
+ " def __init__(\n",
+ " self,\n",
+ " fragment: Fragment,\n",
+ " *args,\n",
+ " app_context: AppContext,\n",
+ " model_path: Path,\n",
+ " output_folder: Path = DEFAULT_OUTPUT_FOLDER,\n",
+ " **kwargs,\n",
+ " ):\n",
"\n",
" self.logger = logging.getLogger(\"{}.{}\".format(__name__, type(self).__name__))\n",
- " super().__init__()\n",
" self._input_dataset_key = \"image\"\n",
" self._pred_dataset_key = \"pred\"\n",
"\n",
- " def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):\n",
- "\n",
- " input_image = op_input.get(\"image\")\n",
+ " self.model_path = model_path\n",
+ " self.output_folder = output_folder\n",
+ " self.output_folder.mkdir(parents=True, exist_ok=True)\n",
+ " self.app_context = app_context\n",
+ " self.input_name_image = \"image\"\n",
+ " self.output_name_seg = \"seg_image\"\n",
+ " self.output_name_saved_images_folder = \"saved_images_folder\"\n",
+ "\n",
+ " # The base class has an attribute called fragment to hold the reference to the fragment object\n",
+ " super().__init__(fragment, *args, **kwargs)\n",
+ "\n",
+ " def setup(self, spec: OperatorSpec):\n",
+ " spec.input(self.input_name_image)\n",
+ " spec.output(self.output_name_seg)\n",
+ " spec.output(self.output_name_saved_images_folder).condition(\n",
+ " ConditionType.NONE\n",
+ " ) # Output not requiring a receiver\n",
+ "\n",
+ " def compute(self, op_input, op_output, context):\n",
+ " input_image = op_input.receive(self.input_name_image)\n",
" if not input_image:\n",
" raise ValueError(\"Input image is not found.\")\n",
"\n",
- " output_path = context.output.get().path\n",
- "\n",
" # This operator gets an in-memory Image object, so a specialized ImageReader is needed.\n",
" _reader = InMemImageReader(input_image)\n",
- " pre_transforms = self.pre_process(_reader)\n",
- " post_transforms = self.post_process(pre_transforms, path.join(output_path, \"prediction_output\"))\n",
+ "\n",
+ " pre_transforms = self.pre_process(_reader, str(self.output_folder))\n",
+ " post_transforms = self.post_process(pre_transforms, str(self.output_folder))\n",
"\n",
" # Delegates inference and saving output to the built-in operator.\n",
" infer_operator = MonaiSegInferenceOperator(\n",
- " (\n",
+ " self.fragment,\n",
+ " roi_size=(\n",
" 96,\n",
" 96,\n",
" 96,\n",
" ),\n",
- " pre_transforms,\n",
- " post_transforms,\n",
+ " pre_transforms=pre_transforms,\n",
+ " post_transforms=post_transforms,\n",
+ " overlap=0.6,\n",
+ " app_context=self.app_context,\n",
+ " model_name=\"\",\n",
+ " inferer=InfererType.SLIDING_WINDOW,\n",
+ " sw_batch_size=4,\n",
+ " model_path=self.model_path,\n",
+ " name=\"monai_seg_inference_op\",\n",
" )\n",
"\n",
- " # Setting the keys used in the dictironary based transforms may change.\n",
+ " # Setting the keys used in the dictionary based transforms may change.\n",
" infer_operator.input_dataset_key = self._input_dataset_key\n",
" infer_operator.pred_dataset_key = self._pred_dataset_key\n",
"\n",
- " # Now let the built-in operator handles the work with the I/O spec and execution context.\n",
- " infer_operator.compute(op_input, op_output, context)\n",
+ " # Now emit data to the output ports of this operator\n",
+ " op_output.emit(infer_operator.compute_impl(input_image, context), self.output_name_seg)\n",
+ " op_output.emit(self.output_folder, self.output_name_saved_images_folder)\n",
"\n",
- " def pre_process(self, img_reader) -> Compose:\n",
+ " def pre_process(self, img_reader, out_dir: str = \"./input_images\") -> Compose:\n",
" \"\"\"Composes transforms for preprocessing input before predicting on a model.\"\"\"\n",
"\n",
+ " Path(out_dir).mkdir(parents=True, exist_ok=True)\n",
" my_key = self._input_dataset_key\n",
+ "\n",
" return Compose(\n",
" [\n",
" LoadImaged(keys=my_key, reader=img_reader),\n",
" EnsureChannelFirstd(keys=my_key),\n",
+ " # The SaveImaged transform can be commented out to save 5 seconds.\n",
+ " # Uncompress NIfTI file, nii, is used favoring speed over size, but can be changed to nii.gz\n",
+ " SaveImaged(\n",
+ " keys=my_key,\n",
+ " output_dir=out_dir,\n",
+ " output_postfix=\"\",\n",
+ " resample=False,\n",
+ " output_ext=\".nii\",\n",
+ " ),\n",
" Orientationd(keys=my_key, axcodes=\"RAS\"),\n",
" Spacingd(keys=my_key, pixdim=[1.5, 1.5, 2.9], mode=[\"bilinear\"]),\n",
" ScaleIntensityRanged(keys=my_key, a_min=-57, a_max=164, b_min=0.0, b_max=1.0, clip=True),\n",
@@ -508,7 +574,9 @@
" def post_process(self, pre_transforms: Compose, out_dir: str = \"./prediction_output\") -> Compose:\n",
" \"\"\"Composes transforms for postprocessing the prediction results.\"\"\"\n",
"\n",
+ " Path(out_dir).mkdir(parents=True, exist_ok=True)\n",
" pred_key = self._pred_dataset_key\n",
+ "\n",
" return Compose(\n",
" [\n",
" Activationsd(keys=pred_key, softmax=True),\n",
@@ -520,11 +588,15 @@
" to_tensor=True,\n",
" ),\n",
" AsDiscreted(keys=pred_key, argmax=True),\n",
+ " # The SaveImaged transform can be commented out to save 5 seconds.\n",
+ " # Uncompress NIfTI file, nii, is used favoring speed over size, but can be changed to nii.gz\n",
" SaveImaged(\n",
" keys=pred_key,\n",
" output_dir=out_dir,\n",
" output_postfix=\"seg\",\n",
" output_dtype=uint8,\n",
+ " resample=False,\n",
+ " output_ext=\".nii\",\n",
" ),\n",
" ]\n",
" )\n"
@@ -538,45 +610,50 @@
"\n",
"Our application class would look like below.\n",
"\n",
- "It defines `App` class, inheriting [Application](/modules/_autosummary/monai.deploy.core.Application) class.\n",
- "\n",
- "The requirements (resource and package dependency) for the App can be specified by using [@resource](/modules/_autosummary/monai.deploy.core.resource) and [@env](/modules/_autosummary/monai.deploy.core.env) decorators.\n",
+ "It defines `App` class, inheriting the base `Application` class.\n",
"\n",
- "The base class method, `compose`, is overridden. Objects required for DICOM parsing, series selection (selecting the first series for the current release), pixel data conversion to volume image, and segmentation instance creation are created, so is the model-specific `SpleenSegOperator`. The execution pipeline, as a Directed Acyclic Graph, is created by connecting these objects through self.add_flow() ."
+ "The base class method, `compose`, is overridden. Objects required for DICOM parsing, series selection, pixel data conversion to volume image, and segmentation instance creation are created, so is the model-specific `SpleenSegOperator`. The execution pipeline, as a Directed Acyclic Graph (DAG), is created by connecting these objects through the `add_flow` method."
]
},
{
"cell_type": "code",
- "execution_count": 5,
+ "execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
- "@resource(cpu=1, gpu=1, memory=\"7Gi\")\n",
"class AISpleenSegApp(Application):\n",
" def __init__(self, *args, **kwargs):\n",
" \"\"\"Creates an application instance.\"\"\"\n",
"\n",
- " self._logger = logging.getLogger(\"{}.{}\".format(__name__, type(self).__name__))\n",
" super().__init__(*args, **kwargs)\n",
+ " self._logger = logging.getLogger(\"{}.{}\".format(__name__, type(self).__name__))\n",
"\n",
" def run(self, *args, **kwargs):\n",
" # This method calls the base class to run. Can be omitted if simply calling through.\n",
- " self._logger.debug(f\"Begin {self.run.__name__}\")\n",
+ " self._logger.info(f\"Begin {self.run.__name__}\")\n",
" super().run(*args, **kwargs)\n",
- " self._logger.debug(f\"End {self.run.__name__}\")\n",
+ " self._logger.info(f\"End {self.run.__name__}\")\n",
"\n",
" def compose(self):\n",
" \"\"\"Creates the app specific operators and chain them up in the processing DAG.\"\"\"\n",
"\n",
" self._logger.debug(f\"Begin {self.compose.__name__}\")\n",
- " # Creates the custom operator(s) as well as SDK built-in operator(s).\n",
- " study_loader_op = DICOMDataLoaderOperator()\n",
- " series_selector_op = DICOMSeriesSelectorOperator(rules=Sample_Rules_Text)\n",
- " series_to_vol_op = DICOMSeriesToVolumeOperator()\n",
- " # Model specific inference operator, supporting MONAI transforms.\n",
+ " app_context = Application.init_app_context({}) # Do not pass argv in Jupyter Notebook\n",
+ " app_input_path = Path(app_context.input_path)\n",
+ " app_output_path = Path(app_context.output_path)\n",
+ " model_path = Path(app_context.model_path)\n",
"\n",
- " # Creates the model specific segmentation operator\n",
- " spleen_seg_op = SpleenSegOperator()\n",
+ " self._logger.info(f\"App input and output path: {app_input_path}, {app_output_path}\")\n",
+ "\n",
+ " # instantiates the SDK built-in operator(s).\n",
+ " study_loader_op = DICOMDataLoaderOperator(\n",
+ " self, CountCondition(self, 1), input_folder=app_input_path, name=\"dcm_loader_op\"\n",
+ " )\n",
+ " series_selector_op = DICOMSeriesSelectorOperator(self, rules=Sample_Rules_Text, name=\"series_selector_op\")\n",
+ " series_to_vol_op = DICOMSeriesToVolumeOperator(self, name=\"series_to_vol_op\")\n",
+ "\n",
+ " # Model specific inference operator, supporting MONAI transforms.\n",
+ " spleen_seg_op = SpleenSegOperator(self, app_context=app_context, model_path=model_path, name=\"seg_op\")\n",
"\n",
" # Create DICOM Seg writer providing the required segment description for each segment with\n",
" # the actual algorithm and the pertinent organ/tissue.\n",
@@ -591,9 +668,9 @@
"\n",
" segment_descriptions = [\n",
" SegmentDescription(\n",
- " segment_label=\"Lung\",\n",
+ " segment_label=\"Spleen\",\n",
" segmented_property_category=codes.SCT.Organ,\n",
- " segmented_property_type=codes.SCT.Lung,\n",
+ " segmented_property_type=codes.SCT.Spleen,\n",
" algorithm_name=_algorithm_name,\n",
" algorithm_family=_algorithm_family,\n",
" algorithm_version=_algorithm_version,\n",
@@ -603,22 +680,26 @@
" custom_tags = {\"SeriesDescription\": \"AI generated Seg, not for clinical use.\"}\n",
"\n",
" dicom_seg_writer = DICOMSegmentationWriterOperator(\n",
- " segment_descriptions=segment_descriptions, custom_tags=custom_tags\n",
+ " self,\n",
+ " segment_descriptions=segment_descriptions,\n",
+ " custom_tags=custom_tags,\n",
+ " output_folder=app_output_path,\n",
+ " name=\"dcm_seg_writer_op\",\n",
" )\n",
"\n",
" # Create the processing pipeline, by specifying the source and destination operators, and\n",
" # ensuring the output from the former matches the input of the latter, in both name and type.\n",
- " self.add_flow(study_loader_op, series_selector_op, {\"dicom_study_list\": \"dicom_study_list\"})\n",
+ " self.add_flow(study_loader_op, series_selector_op, {(\"dicom_study_list\", \"dicom_study_list\")})\n",
" self.add_flow(\n",
- " series_selector_op, series_to_vol_op, {\"study_selected_series_list\": \"study_selected_series_list\"}\n",
+ " series_selector_op, series_to_vol_op, {(\"study_selected_series_list\", \"study_selected_series_list\")}\n",
" )\n",
- " self.add_flow(series_to_vol_op, spleen_seg_op, {\"image\": \"image\"})\n",
+ " self.add_flow(series_to_vol_op, spleen_seg_op, {(\"image\", \"image\")})\n",
"\n",
" # Note below the dicom_seg_writer requires two inputs, each coming from a source operator.\n",
" self.add_flow(\n",
- " series_selector_op, dicom_seg_writer, {\"study_selected_series_list\": \"study_selected_series_list\"}\n",
+ " series_selector_op, dicom_seg_writer, {(\"study_selected_series_list\", \"study_selected_series_list\")}\n",
" )\n",
- " self.add_flow(spleen_seg_op, dicom_seg_writer, {\"seg_image\": \"seg_image\"})\n",
+ " self.add_flow(spleen_seg_op, dicom_seg_writer, {(\"seg_image\", \"seg_image\")})\n",
"\n",
" self._logger.debug(f\"End {self.compose.__name__}\")\n",
"\n",
@@ -652,238 +733,208 @@
"source": [
"## Executing app locally\n",
"\n",
- "We can execute the app in the Jupyter notebook. Note that the DICOM files of the CT Abdomen series must be present in the `dcm` and the Torch Script model at `model.ts`. Please use the actual path in your environment.\n"
+ "We can execute the app in Jupyter notebook. Note that the DICOM files of the CT Abdomen series must be present in the `dcm` folder and the TorchScript, `model.ts`, in the folder pointed to by the environment variables.\n"
]
},
{
"cell_type": "code",
- "execution_count": 6,
+ "execution_count": 7,
"metadata": {},
"outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\u001b[34mGoing to initiate execution of operator DICOMDataLoaderOperator\u001b[39m\n",
- "\u001b[32mExecuting operator DICOMDataLoaderOperator \u001b[33m(Process ID: 411090, Operator ID: e3b86e86-9f94-4ef1-bf1f-ba8506f3835d)\u001b[39m\n"
- ]
- },
{
"name": "stderr",
"output_type": "stream",
"text": [
- "[2023-07-11 14:43:41,365] [INFO] (root) - Finding series for Selection named: CT Series\n",
- "[2023-07-11 14:43:41,365] [INFO] (root) - Searching study, : 1.3.6.1.4.1.14519.5.2.1.7085.2626.822645453932810382886582736291\n",
+ "[2023-08-30 00:58:15,457] [INFO] (root) - Parsed args: Namespace(argv=[], input=None, log_level=None, model=None, output=None, workdir=None)\n",
+ "[2023-08-30 00:58:15,465] [INFO] (root) - AppContext object: AppContext(input_path=dcm, output_path=output, model_path=models, workdir=)\n",
+ "[2023-08-30 00:58:15,466] [INFO] (__main__.AISpleenSegApp) - App input and output path: dcm, output\n",
+ "[info] [gxf_executor.cpp:210] Creating context\n",
+ "[info] [gxf_executor.cpp:1595] Loading extensions from configs...\n",
+ "[info] [gxf_executor.cpp:1741] Activating Graph...\n",
+ "[info] [gxf_executor.cpp:1771] Running Graph...\n",
+ "[info] [gxf_executor.cpp:1773] Waiting for completion...\n",
+ "[info] [gxf_executor.cpp:1774] Graph execution waiting. Fragment: \n",
+ "[info] [greedy_scheduler.cpp:190] Scheduling 6 entities\n",
+ "[2023-08-30 00:58:15,557] [INFO] (monai.deploy.operators.dicom_data_loader_operator.DICOMDataLoaderOperator) - No or invalid input path from the optional input port: None\n",
+ "[2023-08-30 00:58:15,886] [INFO] (root) - Finding series for Selection named: CT Series\n",
+ "[2023-08-30 00:58:15,887] [INFO] (root) - Searching study, : 1.3.6.1.4.1.14519.5.2.1.7085.2626.822645453932810382886582736291\n",
" # of series: 1\n",
- "[2023-07-11 14:43:41,366] [INFO] (root) - Working on series, instance UID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.119403521930927333027265674239\n",
- "[2023-07-11 14:43:41,367] [INFO] (root) - On attribute: 'StudyDescription' to match value: '(.*?)'\n",
- "[2023-07-11 14:43:41,367] [INFO] (root) - Series attribute StudyDescription value: CT ABDOMEN W IV CONTRAST\n",
- "[2023-07-11 14:43:41,368] [INFO] (root) - Series attribute string value did not match. Try regEx.\n",
- "[2023-07-11 14:43:41,369] [INFO] (root) - On attribute: 'Modality' to match value: '(?i)CT'\n",
- "[2023-07-11 14:43:41,369] [INFO] (root) - Series attribute Modality value: CT\n",
- "[2023-07-11 14:43:41,370] [INFO] (root) - Series attribute string value did not match. Try regEx.\n",
- "[2023-07-11 14:43:41,370] [INFO] (root) - On attribute: 'SeriesDescription' to match value: '(.*?)'\n",
- "[2023-07-11 14:43:41,371] [INFO] (root) - Series attribute SeriesDescription value: ABD/PANC 3.0 B31f\n",
- "[2023-07-11 14:43:41,371] [INFO] (root) - Series attribute string value did not match. Try regEx.\n",
- "[2023-07-11 14:43:41,372] [INFO] (root) - On attribute: 'ImageType' to match value: ['PRIMARY', 'ORIGINAL']\n",
- "[2023-07-11 14:43:41,373] [INFO] (root) - Series attribute ImageType value: None\n",
- "[2023-07-11 14:43:41,373] [INFO] (root) - Selected Series, UID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.119403521930927333027265674239\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\u001b[34mDone performing execution of operator DICOMDataLoaderOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator DICOMSeriesSelectorOperator\u001b[39m\n",
- "\u001b[32mExecuting operator DICOMSeriesSelectorOperator \u001b[33m(Process ID: 411090, Operator ID: 8f7cf878-8975-46f6-9428-a48da67f76d0)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator DICOMSeriesSelectorOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator DICOMSeriesToVolumeOperator\u001b[39m\n",
- "\u001b[32mExecuting operator DICOMSeriesToVolumeOperator \u001b[33m(Process ID: 411090, Operator ID: 31fd2f9c-e161-4600-9c0d-1148dae474dd)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator DICOMSeriesToVolumeOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator SpleenSegOperator\u001b[39m\n",
- "\u001b[32mExecuting operator SpleenSegOperator \u001b[33m(Process ID: 411090, Operator ID: dba9a5f1-7017-43fc-b55b-f5b31af9bcea)\u001b[39m\n",
- "Converted Image object metadata:\n",
- "SeriesInstanceUID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.119403521930927333027265674239, type \n",
- "SeriesDate: 20090831, type \n",
- "SeriesTime: 101721.452, type \n",
- "Modality: CT, type \n",
- "SeriesDescription: ABD/PANC 3.0 B31f, type \n",
- "PatientPosition: HFS, type \n",
- "SeriesNumber: 8, type \n",
- "row_pixel_spacing: 0.7890625, type \n",
- "col_pixel_spacing: 0.7890625, type \n",
- "depth_pixel_spacing: 1.5, type \n",
- "row_direction_cosine: [1.0, 0.0, 0.0], type \n",
- "col_direction_cosine: [0.0, 1.0, 0.0], type \n",
- "depth_direction_cosine: [0.0, 0.0, 1.0], type \n",
- "dicom_affine_transform: [[ 0.7890625 0. 0. -197.60547 ]\n",
+ "[2023-08-30 00:58:15,888] [INFO] (root) - Working on series, instance UID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.119403521930927333027265674239\n",
+ "[2023-08-30 00:58:15,889] [INFO] (root) - On attribute: 'StudyDescription' to match value: '(.*?)'\n",
+ "[2023-08-30 00:58:15,889] [INFO] (root) - Series attribute StudyDescription value: CT ABDOMEN W IV CONTRAST\n",
+ "[2023-08-30 00:58:15,890] [INFO] (root) - Series attribute string value did not match. Try regEx.\n",
+ "[2023-08-30 00:58:15,891] [INFO] (root) - On attribute: 'Modality' to match value: '(?i)CT'\n",
+ "[2023-08-30 00:58:15,891] [INFO] (root) - Series attribute Modality value: CT\n",
+ "[2023-08-30 00:58:15,892] [INFO] (root) - Series attribute string value did not match. Try regEx.\n",
+ "[2023-08-30 00:58:15,892] [INFO] (root) - On attribute: 'SeriesDescription' to match value: '(.*?)'\n",
+ "[2023-08-30 00:58:15,893] [INFO] (root) - Series attribute SeriesDescription value: ABD/PANC 3.0 B31f\n",
+ "[2023-08-30 00:58:15,893] [INFO] (root) - Series attribute string value did not match. Try regEx.\n",
+ "[2023-08-30 00:58:15,894] [INFO] (root) - On attribute: 'ImageType' to match value: ['PRIMARY', 'ORIGINAL']\n",
+ "[2023-08-30 00:58:15,894] [INFO] (root) - Series attribute ImageType value: None\n",
+ "[2023-08-30 00:58:15,895] [INFO] (root) - Selected Series, UID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.119403521930927333027265674239\n",
+ "/home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:321: FutureWarning: monai.transforms.io.dictionary LoadImaged.__init__:image_only: Current default value of argument `image_only=False` has been deprecated since version 1.1. It will be changed to `image_only=True` in version 1.3.\n",
+ " warn_deprecated(argname, msg, warning_category)\n",
+ "[2023-08-30 00:58:16,110] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - Converted Image object metadata:\n",
+ "[2023-08-30 00:58:16,111] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - SeriesInstanceUID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.119403521930927333027265674239, type \n",
+ "[2023-08-30 00:58:16,112] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - SeriesDate: 20090831, type \n",
+ "[2023-08-30 00:58:16,112] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - SeriesTime: 101721.452, type \n",
+ "[2023-08-30 00:58:16,113] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - Modality: CT, type \n",
+ "[2023-08-30 00:58:16,114] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - SeriesDescription: ABD/PANC 3.0 B31f, type \n",
+ "[2023-08-30 00:58:16,115] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - PatientPosition: HFS, type \n",
+ "[2023-08-30 00:58:16,116] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - SeriesNumber: 8, type \n",
+ "[2023-08-30 00:58:16,116] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - row_pixel_spacing: 0.7890625, type \n",
+ "[2023-08-30 00:58:16,117] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - col_pixel_spacing: 0.7890625, type \n",
+ "[2023-08-30 00:58:16,117] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - depth_pixel_spacing: 1.5, type \n",
+ "[2023-08-30 00:58:16,118] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - row_direction_cosine: [1.0, 0.0, 0.0], type \n",
+ "[2023-08-30 00:58:16,119] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - col_direction_cosine: [0.0, 1.0, 0.0], type \n",
+ "[2023-08-30 00:58:16,119] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - depth_direction_cosine: [0.0, 0.0, 1.0], type \n",
+ "[2023-08-30 00:58:16,120] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - dicom_affine_transform: [[ 0.7890625 0. 0. -197.60547 ]\n",
" [ 0. 0.7890625 0. -398.60547 ]\n",
" [ 0. 0. 1.5 -383. ]\n",
" [ 0. 0. 0. 1. ]], type \n",
- "nifti_affine_transform: [[ -0.7890625 -0. -0. 197.60547 ]\n",
+ "[2023-08-30 00:58:16,121] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - nifti_affine_transform: [[ -0.7890625 -0. -0. 197.60547 ]\n",
" [ -0. -0.7890625 -0. 398.60547 ]\n",
" [ 0. 0. 1.5 -383. ]\n",
" [ 0. 0. 0. 1. ]], type \n",
- "StudyInstanceUID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.822645453932810382886582736291, type \n",
- "StudyID: , type \n",
- "StudyDate: 20090831, type \n",
- "StudyTime: 095948.599, type \n",
- "StudyDescription: CT ABDOMEN W IV CONTRAST, type \n",
- "AccessionNumber: 5471978513296937, type \n",
- "selection_name: CT Series, type \n"
- ]
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:321: FutureWarning: monai.transforms.io.dictionary LoadImaged.__init__:image_only: Current default value of argument `image_only=False` has been deprecated since version 1.1. It will be changed to `image_only=True` in version 1.3.\n",
- " warn_deprecated(argname, msg, warning_category)\n",
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:321: FutureWarning: monai.transforms.io.dictionary SaveImaged.__init__:resample: Current default value of argument `resample=True` has been deprecated since version 1.1. It will be changed to `resample=False` in version 1.3.\n",
- " warn_deprecated(argname, msg, warning_category)\n"
+ "[2023-08-30 00:58:16,122] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - StudyInstanceUID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.822645453932810382886582736291, type \n",
+ "[2023-08-30 00:58:16,123] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - StudyID: , type \n",
+ "[2023-08-30 00:58:16,123] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - StudyDate: 20090831, type \n",
+ "[2023-08-30 00:58:16,124] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - StudyTime: 095948.599, type \n",
+ "[2023-08-30 00:58:16,124] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - StudyDescription: CT ABDOMEN W IV CONTRAST, type \n",
+ "[2023-08-30 00:58:16,125] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - AccessionNumber: 5471978513296937, type \n",
+ "[2023-08-30 00:58:16,125] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - selection_name: CT Series, type \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
- "2023-07-11 14:43:48,110 INFO image_writer.py:197 - writing: /home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/output/prediction_output/1.3.6.1.4.1.14519.5.2.1.7085.2626/1.3.6.1.4.1.14519.5.2.1.7085.2626_seg.nii.gz\n",
- "Output Seg image numpy array shaped: (204, 512, 512)\n",
- "Output Seg image pixel max value: 1\n",
- "Output Seg image pixel min value: 0\n",
- "\u001b[34mDone performing execution of operator SpleenSegOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator DICOMSegmentationWriterOperator\u001b[39m\n",
- "\u001b[32mExecuting operator DICOMSegmentationWriterOperator \u001b[33m(Process ID: 411090, Operator ID: 6102deaa-bfb9-4075-a3ce-49ed532c4be5)\u001b[39m\n"
+ "2023-08-30 00:58:16,933 INFO image_writer.py:197 - writing: /home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/output/saved_images_folder/1.3.6.1.4.1.14519.5.2.1.7085.2626/1.3.6.1.4.1.14519.5.2.1.7085.2626.nii\n",
+ "2023-08-30 00:58:23,738 INFO image_writer.py:197 - writing: /home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/output/saved_images_folder/1.3.6.1.4.1.14519.5.2.1.7085.2626/1.3.6.1.4.1.14519.5.2.1.7085.2626_seg.nii\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/highdicom/valuerep.py:54: UserWarning: The string \"C3N-00198\" is unlikely to represent the intended person name since it contains only a single component. Construct a person name according to the format in described in http://dicom.nema.org/dicom/2013/output/chtml/part05/sect_6.2.html#sect_6.2.1.2, or, in pydicom 2.2.0 or later, use the pydicom.valuerep.PersonName.from_named_components() method to construct the person name correctly. If a single-component name is really intended, add a trailing caret character to disambiguate the name.\n",
+ "[2023-08-30 00:58:25,340] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - Output Seg image numpy array shaped: (204, 512, 512)\n",
+ "[2023-08-30 00:58:25,348] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - Output Seg image pixel max value: 1\n",
+ "/home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages/highdicom/valuerep.py:54: UserWarning: The string \"C3N-00198\" is unlikely to represent the intended person name since it contains only a single component. Construct a person name according to the format in described in http://dicom.nema.org/dicom/2013/output/chtml/part05/sect_6.2.html#sect_6.2.1.2, or, in pydicom 2.2.0 or later, use the pydicom.valuerep.PersonName.from_named_components() method to construct the person name correctly. If a single-component name is really intended, add a trailing caret character to disambiguate the name.\n",
" warnings.warn(\n",
- "[2023-07-11 14:43:52,338] [INFO] (highdicom.seg.sop) - add plane #0 for segment #1\n",
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/pydicom/valuerep.py:443: UserWarning: A value of type 'int64' cannot be assigned to a tag with VR UL.\n",
+ "[2023-08-30 00:58:27,813] [INFO] (highdicom.seg.sop) - add plane #0 for segment #1\n",
+ "/home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages/pydicom/valuerep.py:443: UserWarning: A value of type 'int64' cannot be assigned to a tag with VR UL.\n",
" warnings.warn(msg)\n",
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/pydicom/valuerep.py:443: UserWarning: A value of type 'int64' cannot be assigned to a tag with VR US.\n",
+ "/home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages/pydicom/valuerep.py:443: UserWarning: A value of type 'int64' cannot be assigned to a tag with VR US.\n",
" warnings.warn(msg)\n",
- "[2023-07-11 14:43:52,340] [INFO] (highdicom.seg.sop) - add plane #1 for segment #1\n",
- "[2023-07-11 14:43:52,342] [INFO] (highdicom.seg.sop) - add plane #2 for segment #1\n",
- "[2023-07-11 14:43:52,343] [INFO] (highdicom.seg.sop) - add plane #3 for segment #1\n",
- "[2023-07-11 14:43:52,344] [INFO] (highdicom.seg.sop) - add plane #4 for segment #1\n",
- "[2023-07-11 14:43:52,345] [INFO] (highdicom.seg.sop) - add plane #5 for segment #1\n",
- "[2023-07-11 14:43:52,347] [INFO] (highdicom.seg.sop) - add plane #6 for segment #1\n",
- "[2023-07-11 14:43:52,348] [INFO] (highdicom.seg.sop) - add plane #7 for segment #1\n",
- "[2023-07-11 14:43:52,349] [INFO] (highdicom.seg.sop) - add plane #8 for segment #1\n",
- "[2023-07-11 14:43:52,350] [INFO] (highdicom.seg.sop) - add plane #9 for segment #1\n",
- "[2023-07-11 14:43:52,351] [INFO] (highdicom.seg.sop) - add plane #10 for segment #1\n",
- "[2023-07-11 14:43:52,353] [INFO] (highdicom.seg.sop) - add plane #11 for segment #1\n",
- "[2023-07-11 14:43:52,354] [INFO] (highdicom.seg.sop) - add plane #12 for segment #1\n",
- "[2023-07-11 14:43:52,355] [INFO] (highdicom.seg.sop) - add plane #13 for segment #1\n",
- "[2023-07-11 14:43:52,356] [INFO] (highdicom.seg.sop) - add plane #14 for segment #1\n",
- "[2023-07-11 14:43:52,357] [INFO] (highdicom.seg.sop) - add plane #15 for segment #1\n",
- "[2023-07-11 14:43:52,359] [INFO] (highdicom.seg.sop) - add plane #16 for segment #1\n",
- "[2023-07-11 14:43:52,360] [INFO] (highdicom.seg.sop) - add plane #17 for segment #1\n",
- "[2023-07-11 14:43:52,361] [INFO] (highdicom.seg.sop) - add plane #18 for segment #1\n",
- "[2023-07-11 14:43:52,362] [INFO] (highdicom.seg.sop) - add plane #19 for segment #1\n",
- "[2023-07-11 14:43:52,363] [INFO] (highdicom.seg.sop) - add plane #20 for segment #1\n",
- "[2023-07-11 14:43:52,365] [INFO] (highdicom.seg.sop) - add plane #21 for segment #1\n",
- "[2023-07-11 14:43:52,366] [INFO] (highdicom.seg.sop) - add plane #22 for segment #1\n",
- "[2023-07-11 14:43:52,367] [INFO] (highdicom.seg.sop) - add plane #23 for segment #1\n",
- "[2023-07-11 14:43:52,368] [INFO] (highdicom.seg.sop) - add plane #24 for segment #1\n",
- "[2023-07-11 14:43:52,369] [INFO] (highdicom.seg.sop) - add plane #25 for segment #1\n",
- "[2023-07-11 14:43:52,371] [INFO] (highdicom.seg.sop) - add plane #26 for segment #1\n",
- "[2023-07-11 14:43:52,372] [INFO] (highdicom.seg.sop) - add plane #27 for segment #1\n",
- "[2023-07-11 14:43:52,373] [INFO] (highdicom.seg.sop) - add plane #28 for segment #1\n",
- "[2023-07-11 14:43:52,374] [INFO] (highdicom.seg.sop) - add plane #29 for segment #1\n",
- "[2023-07-11 14:43:52,376] [INFO] (highdicom.seg.sop) - add plane #30 for segment #1\n",
- "[2023-07-11 14:43:52,377] [INFO] (highdicom.seg.sop) - add plane #31 for segment #1\n",
- "[2023-07-11 14:43:52,378] [INFO] (highdicom.seg.sop) - add plane #32 for segment #1\n",
- "[2023-07-11 14:43:52,379] [INFO] (highdicom.seg.sop) - add plane #33 for segment #1\n",
- "[2023-07-11 14:43:52,381] [INFO] (highdicom.seg.sop) - add plane #34 for segment #1\n",
- "[2023-07-11 14:43:52,382] [INFO] (highdicom.seg.sop) - add plane #35 for segment #1\n",
- "[2023-07-11 14:43:52,383] [INFO] (highdicom.seg.sop) - add plane #36 for segment #1\n",
- "[2023-07-11 14:43:52,385] [INFO] (highdicom.seg.sop) - add plane #37 for segment #1\n",
- "[2023-07-11 14:43:52,386] [INFO] (highdicom.seg.sop) - add plane #38 for segment #1\n",
- "[2023-07-11 14:43:52,387] [INFO] (highdicom.seg.sop) - add plane #39 for segment #1\n",
- "[2023-07-11 14:43:52,388] [INFO] (highdicom.seg.sop) - add plane #40 for segment #1\n",
- "[2023-07-11 14:43:52,390] [INFO] (highdicom.seg.sop) - add plane #41 for segment #1\n",
- "[2023-07-11 14:43:52,394] [INFO] (highdicom.seg.sop) - add plane #42 for segment #1\n",
- "[2023-07-11 14:43:52,403] [INFO] (highdicom.seg.sop) - add plane #43 for segment #1\n",
- "[2023-07-11 14:43:52,406] [INFO] (highdicom.seg.sop) - add plane #44 for segment #1\n",
- "[2023-07-11 14:43:52,408] [INFO] (highdicom.seg.sop) - add plane #45 for segment #1\n",
- "[2023-07-11 14:43:52,411] [INFO] (highdicom.seg.sop) - add plane #46 for segment #1\n",
- "[2023-07-11 14:43:52,413] [INFO] (highdicom.seg.sop) - add plane #47 for segment #1\n",
- "[2023-07-11 14:43:52,416] [INFO] (highdicom.seg.sop) - add plane #48 for segment #1\n",
- "[2023-07-11 14:43:52,419] [INFO] (highdicom.seg.sop) - add plane #49 for segment #1\n",
- "[2023-07-11 14:43:52,421] [INFO] (highdicom.seg.sop) - add plane #50 for segment #1\n",
- "[2023-07-11 14:43:52,423] [INFO] (highdicom.seg.sop) - add plane #51 for segment #1\n",
- "[2023-07-11 14:43:52,425] [INFO] (highdicom.seg.sop) - add plane #52 for segment #1\n",
- "[2023-07-11 14:43:52,428] [INFO] (highdicom.seg.sop) - add plane #53 for segment #1\n",
- "[2023-07-11 14:43:52,430] [INFO] (highdicom.seg.sop) - add plane #54 for segment #1\n",
- "[2023-07-11 14:43:52,432] [INFO] (highdicom.seg.sop) - add plane #55 for segment #1\n",
- "[2023-07-11 14:43:52,434] [INFO] (highdicom.seg.sop) - add plane #56 for segment #1\n",
- "[2023-07-11 14:43:52,436] [INFO] (highdicom.seg.sop) - add plane #57 for segment #1\n",
- "[2023-07-11 14:43:52,438] [INFO] (highdicom.seg.sop) - add plane #58 for segment #1\n",
- "[2023-07-11 14:43:52,440] [INFO] (highdicom.seg.sop) - add plane #59 for segment #1\n",
- "[2023-07-11 14:43:52,442] [INFO] (highdicom.seg.sop) - add plane #60 for segment #1\n",
- "[2023-07-11 14:43:52,444] [INFO] (highdicom.seg.sop) - add plane #61 for segment #1\n",
- "[2023-07-11 14:43:52,447] [INFO] (highdicom.seg.sop) - add plane #62 for segment #1\n",
- "[2023-07-11 14:43:52,449] [INFO] (highdicom.seg.sop) - add plane #63 for segment #1\n",
- "[2023-07-11 14:43:52,451] [INFO] (highdicom.seg.sop) - add plane #64 for segment #1\n",
- "[2023-07-11 14:43:52,453] [INFO] (highdicom.seg.sop) - add plane #65 for segment #1\n",
- "[2023-07-11 14:43:52,455] [INFO] (highdicom.seg.sop) - add plane #66 for segment #1\n",
- "[2023-07-11 14:43:52,457] [INFO] (highdicom.seg.sop) - add plane #67 for segment #1\n",
- "[2023-07-11 14:43:52,459] [INFO] (highdicom.seg.sop) - add plane #68 for segment #1\n",
- "[2023-07-11 14:43:52,461] [INFO] (highdicom.seg.sop) - add plane #69 for segment #1\n",
- "[2023-07-11 14:43:52,463] [INFO] (highdicom.seg.sop) - add plane #70 for segment #1\n",
- "[2023-07-11 14:43:52,465] [INFO] (highdicom.seg.sop) - add plane #71 for segment #1\n",
- "[2023-07-11 14:43:52,467] [INFO] (highdicom.seg.sop) - add plane #72 for segment #1\n",
- "[2023-07-11 14:43:52,469] [INFO] (highdicom.seg.sop) - add plane #73 for segment #1\n",
- "[2023-07-11 14:43:52,471] [INFO] (highdicom.seg.sop) - add plane #74 for segment #1\n",
- "[2023-07-11 14:43:52,473] [INFO] (highdicom.seg.sop) - add plane #75 for segment #1\n",
- "[2023-07-11 14:43:52,475] [INFO] (highdicom.seg.sop) - add plane #76 for segment #1\n",
- "[2023-07-11 14:43:52,477] [INFO] (highdicom.seg.sop) - add plane #77 for segment #1\n",
- "[2023-07-11 14:43:52,479] [INFO] (highdicom.seg.sop) - add plane #78 for segment #1\n",
- "[2023-07-11 14:43:52,481] [INFO] (highdicom.seg.sop) - add plane #79 for segment #1\n",
- "[2023-07-11 14:43:52,483] [INFO] (highdicom.seg.sop) - add plane #80 for segment #1\n",
- "[2023-07-11 14:43:52,484] [INFO] (highdicom.seg.sop) - add plane #81 for segment #1\n",
- "[2023-07-11 14:43:52,487] [INFO] (highdicom.seg.sop) - add plane #82 for segment #1\n",
- "[2023-07-11 14:43:52,489] [INFO] (highdicom.seg.sop) - add plane #83 for segment #1\n",
- "[2023-07-11 14:43:52,491] [INFO] (highdicom.seg.sop) - add plane #84 for segment #1\n",
- "[2023-07-11 14:43:52,493] [INFO] (highdicom.seg.sop) - add plane #85 for segment #1\n",
- "[2023-07-11 14:43:52,496] [INFO] (highdicom.seg.sop) - add plane #86 for segment #1\n",
- "[2023-07-11 14:43:52,497] [INFO] (highdicom.seg.sop) - add plane #87 for segment #1\n",
- "[2023-07-11 14:43:52,499] [INFO] (highdicom.seg.sop) - add plane #88 for segment #1\n",
- "[2023-07-11 14:43:52,559] [INFO] (highdicom.base) - copy Image-related attributes from dataset \"1.3.6.1.4.1.14519.5.2.1.7085.2626.936983343951485811186213470191\"\n",
- "[2023-07-11 14:43:52,560] [INFO] (highdicom.base) - copy attributes of module \"Specimen\"\n",
- "[2023-07-11 14:43:52,561] [INFO] (highdicom.base) - copy Patient-related attributes from dataset \"1.3.6.1.4.1.14519.5.2.1.7085.2626.936983343951485811186213470191\"\n",
- "[2023-07-11 14:43:52,562] [INFO] (highdicom.base) - copy attributes of module \"Patient\"\n",
- "[2023-07-11 14:43:52,563] [INFO] (highdicom.base) - copy attributes of module \"Clinical Trial Subject\"\n",
- "[2023-07-11 14:43:52,564] [INFO] (highdicom.base) - copy Study-related attributes from dataset \"1.3.6.1.4.1.14519.5.2.1.7085.2626.936983343951485811186213470191\"\n",
- "[2023-07-11 14:43:52,564] [INFO] (highdicom.base) - copy attributes of module \"General Study\"\n",
- "[2023-07-11 14:43:52,565] [INFO] (highdicom.base) - copy attributes of module \"Patient Study\"\n",
- "[2023-07-11 14:43:52,566] [INFO] (highdicom.base) - copy attributes of module \"Clinical Trial Study\"\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\u001b[34mDone performing execution of operator DICOMSegmentationWriterOperator\n",
- "\u001b[39m\n"
+ "[2023-08-30 00:58:27,816] [INFO] (highdicom.seg.sop) - add plane #1 for segment #1\n",
+ "[2023-08-30 00:58:27,818] [INFO] (highdicom.seg.sop) - add plane #2 for segment #1\n",
+ "[2023-08-30 00:58:27,819] [INFO] (highdicom.seg.sop) - add plane #3 for segment #1\n",
+ "[2023-08-30 00:58:27,820] [INFO] (highdicom.seg.sop) - add plane #4 for segment #1\n",
+ "[2023-08-30 00:58:27,821] [INFO] (highdicom.seg.sop) - add plane #5 for segment #1\n",
+ "[2023-08-30 00:58:27,822] [INFO] (highdicom.seg.sop) - add plane #6 for segment #1\n",
+ "[2023-08-30 00:58:27,823] [INFO] (highdicom.seg.sop) - add plane #7 for segment #1\n",
+ "[2023-08-30 00:58:27,825] [INFO] (highdicom.seg.sop) - add plane #8 for segment #1\n",
+ "[2023-08-30 00:58:27,826] [INFO] (highdicom.seg.sop) - add plane #9 for segment #1\n",
+ "[2023-08-30 00:58:27,827] [INFO] (highdicom.seg.sop) - add plane #10 for segment #1\n",
+ "[2023-08-30 00:58:27,828] [INFO] (highdicom.seg.sop) - add plane #11 for segment #1\n",
+ "[2023-08-30 00:58:27,829] [INFO] (highdicom.seg.sop) - add plane #12 for segment #1\n",
+ "[2023-08-30 00:58:27,830] [INFO] (highdicom.seg.sop) - add plane #13 for segment #1\n",
+ "[2023-08-30 00:58:27,833] [INFO] (highdicom.seg.sop) - add plane #14 for segment #1\n",
+ "[2023-08-30 00:58:27,834] [INFO] (highdicom.seg.sop) - add plane #15 for segment #1\n",
+ "[2023-08-30 00:58:27,836] [INFO] (highdicom.seg.sop) - add plane #16 for segment #1\n",
+ "[2023-08-30 00:58:27,837] [INFO] (highdicom.seg.sop) - add plane #17 for segment #1\n",
+ "[2023-08-30 00:58:27,838] [INFO] (highdicom.seg.sop) - add plane #18 for segment #1\n",
+ "[2023-08-30 00:58:27,839] [INFO] (highdicom.seg.sop) - add plane #19 for segment #1\n",
+ "[2023-08-30 00:58:27,841] [INFO] (highdicom.seg.sop) - add plane #20 for segment #1\n",
+ "[2023-08-30 00:58:27,842] [INFO] (highdicom.seg.sop) - add plane #21 for segment #1\n",
+ "[2023-08-30 00:58:27,843] [INFO] (highdicom.seg.sop) - add plane #22 for segment #1\n",
+ "[2023-08-30 00:58:27,845] [INFO] (highdicom.seg.sop) - add plane #23 for segment #1\n",
+ "[2023-08-30 00:58:27,846] [INFO] (highdicom.seg.sop) - add plane #24 for segment #1\n",
+ "[2023-08-30 00:58:27,848] [INFO] (highdicom.seg.sop) - add plane #25 for segment #1\n",
+ "[2023-08-30 00:58:27,849] [INFO] (highdicom.seg.sop) - add plane #26 for segment #1\n",
+ "[2023-08-30 00:58:27,850] [INFO] (highdicom.seg.sop) - add plane #27 for segment #1\n",
+ "[2023-08-30 00:58:27,851] [INFO] (highdicom.seg.sop) - add plane #28 for segment #1\n",
+ "[2023-08-30 00:58:27,853] [INFO] (highdicom.seg.sop) - add plane #29 for segment #1\n",
+ "[2023-08-30 00:58:27,854] [INFO] (highdicom.seg.sop) - add plane #30 for segment #1\n",
+ "[2023-08-30 00:58:27,856] [INFO] (highdicom.seg.sop) - add plane #31 for segment #1\n",
+ "[2023-08-30 00:58:27,857] [INFO] (highdicom.seg.sop) - add plane #32 for segment #1\n",
+ "[2023-08-30 00:58:27,858] [INFO] (highdicom.seg.sop) - add plane #33 for segment #1\n",
+ "[2023-08-30 00:58:27,860] [INFO] (highdicom.seg.sop) - add plane #34 for segment #1\n",
+ "[2023-08-30 00:58:27,861] [INFO] (highdicom.seg.sop) - add plane #35 for segment #1\n",
+ "[2023-08-30 00:58:27,863] [INFO] (highdicom.seg.sop) - add plane #36 for segment #1\n",
+ "[2023-08-30 00:58:27,864] [INFO] (highdicom.seg.sop) - add plane #37 for segment #1\n",
+ "[2023-08-30 00:58:27,866] [INFO] (highdicom.seg.sop) - add plane #38 for segment #1\n",
+ "[2023-08-30 00:58:27,867] [INFO] (highdicom.seg.sop) - add plane #39 for segment #1\n",
+ "[2023-08-30 00:58:27,869] [INFO] (highdicom.seg.sop) - add plane #40 for segment #1\n",
+ "[2023-08-30 00:58:27,871] [INFO] (highdicom.seg.sop) - add plane #41 for segment #1\n",
+ "[2023-08-30 00:58:27,872] [INFO] (highdicom.seg.sop) - add plane #42 for segment #1\n",
+ "[2023-08-30 00:58:27,874] [INFO] (highdicom.seg.sop) - add plane #43 for segment #1\n",
+ "[2023-08-30 00:58:27,875] [INFO] (highdicom.seg.sop) - add plane #44 for segment #1\n",
+ "[2023-08-30 00:58:27,877] [INFO] (highdicom.seg.sop) - add plane #45 for segment #1\n",
+ "[2023-08-30 00:58:27,879] [INFO] (highdicom.seg.sop) - add plane #46 for segment #1\n",
+ "[2023-08-30 00:58:27,881] [INFO] (highdicom.seg.sop) - add plane #47 for segment #1\n",
+ "[2023-08-30 00:58:27,882] [INFO] (highdicom.seg.sop) - add plane #48 for segment #1\n",
+ "[2023-08-30 00:58:27,884] [INFO] (highdicom.seg.sop) - add plane #49 for segment #1\n",
+ "[2023-08-30 00:58:27,886] [INFO] (highdicom.seg.sop) - add plane #50 for segment #1\n",
+ "[2023-08-30 00:58:27,888] [INFO] (highdicom.seg.sop) - add plane #51 for segment #1\n",
+ "[2023-08-30 00:58:27,890] [INFO] (highdicom.seg.sop) - add plane #52 for segment #1\n",
+ "[2023-08-30 00:58:27,892] [INFO] (highdicom.seg.sop) - add plane #53 for segment #1\n",
+ "[2023-08-30 00:58:27,894] [INFO] (highdicom.seg.sop) - add plane #54 for segment #1\n",
+ "[2023-08-30 00:58:27,896] [INFO] (highdicom.seg.sop) - add plane #55 for segment #1\n",
+ "[2023-08-30 00:58:27,898] [INFO] (highdicom.seg.sop) - add plane #56 for segment #1\n",
+ "[2023-08-30 00:58:27,900] [INFO] (highdicom.seg.sop) - add plane #57 for segment #1\n",
+ "[2023-08-30 00:58:27,903] [INFO] (highdicom.seg.sop) - add plane #58 for segment #1\n",
+ "[2023-08-30 00:58:27,908] [INFO] (highdicom.seg.sop) - add plane #59 for segment #1\n",
+ "[2023-08-30 00:58:27,912] [INFO] (highdicom.seg.sop) - add plane #60 for segment #1\n",
+ "[2023-08-30 00:58:27,916] [INFO] (highdicom.seg.sop) - add plane #61 for segment #1\n",
+ "[2023-08-30 00:58:27,918] [INFO] (highdicom.seg.sop) - add plane #62 for segment #1\n",
+ "[2023-08-30 00:58:27,921] [INFO] (highdicom.seg.sop) - add plane #63 for segment #1\n",
+ "[2023-08-30 00:58:27,923] [INFO] (highdicom.seg.sop) - add plane #64 for segment #1\n",
+ "[2023-08-30 00:58:27,925] [INFO] (highdicom.seg.sop) - add plane #65 for segment #1\n",
+ "[2023-08-30 00:58:27,927] [INFO] (highdicom.seg.sop) - add plane #66 for segment #1\n",
+ "[2023-08-30 00:58:27,929] [INFO] (highdicom.seg.sop) - add plane #67 for segment #1\n",
+ "[2023-08-30 00:58:27,931] [INFO] (highdicom.seg.sop) - add plane #68 for segment #1\n",
+ "[2023-08-30 00:58:27,934] [INFO] (highdicom.seg.sop) - add plane #69 for segment #1\n",
+ "[2023-08-30 00:58:27,936] [INFO] (highdicom.seg.sop) - add plane #70 for segment #1\n",
+ "[2023-08-30 00:58:27,938] [INFO] (highdicom.seg.sop) - add plane #71 for segment #1\n",
+ "[2023-08-30 00:58:27,940] [INFO] (highdicom.seg.sop) - add plane #72 for segment #1\n",
+ "[2023-08-30 00:58:27,942] [INFO] (highdicom.seg.sop) - add plane #73 for segment #1\n",
+ "[2023-08-30 00:58:27,944] [INFO] (highdicom.seg.sop) - add plane #74 for segment #1\n",
+ "[2023-08-30 00:58:27,946] [INFO] (highdicom.seg.sop) - add plane #75 for segment #1\n",
+ "[2023-08-30 00:58:27,948] [INFO] (highdicom.seg.sop) - add plane #76 for segment #1\n",
+ "[2023-08-30 00:58:27,950] [INFO] (highdicom.seg.sop) - add plane #77 for segment #1\n",
+ "[2023-08-30 00:58:27,952] [INFO] (highdicom.seg.sop) - add plane #78 for segment #1\n",
+ "[2023-08-30 00:58:27,956] [INFO] (highdicom.seg.sop) - add plane #79 for segment #1\n",
+ "[2023-08-30 00:58:27,957] [INFO] (highdicom.seg.sop) - add plane #80 for segment #1\n",
+ "[2023-08-30 00:58:27,959] [INFO] (highdicom.seg.sop) - add plane #81 for segment #1\n",
+ "[2023-08-30 00:58:27,960] [INFO] (highdicom.seg.sop) - add plane #82 for segment #1\n",
+ "[2023-08-30 00:58:27,962] [INFO] (highdicom.seg.sop) - add plane #83 for segment #1\n",
+ "[2023-08-30 00:58:27,964] [INFO] (highdicom.seg.sop) - add plane #84 for segment #1\n",
+ "[2023-08-30 00:58:27,965] [INFO] (highdicom.seg.sop) - add plane #85 for segment #1\n",
+ "[2023-08-30 00:58:27,967] [INFO] (highdicom.seg.sop) - add plane #86 for segment #1\n",
+ "[2023-08-30 00:58:27,968] [INFO] (highdicom.seg.sop) - add plane #87 for segment #1\n",
+ "[2023-08-30 00:58:28,028] [INFO] (highdicom.base) - copy Image-related attributes from dataset \"1.3.6.1.4.1.14519.5.2.1.7085.2626.936983343951485811186213470191\"\n",
+ "[2023-08-30 00:58:28,029] [INFO] (highdicom.base) - copy attributes of module \"Specimen\"\n",
+ "[2023-08-30 00:58:28,030] [INFO] (highdicom.base) - copy Patient-related attributes from dataset \"1.3.6.1.4.1.14519.5.2.1.7085.2626.936983343951485811186213470191\"\n",
+ "[2023-08-30 00:58:28,031] [INFO] (highdicom.base) - copy attributes of module \"Patient\"\n",
+ "[2023-08-30 00:58:28,032] [INFO] (highdicom.base) - copy attributes of module \"Clinical Trial Subject\"\n",
+ "[2023-08-30 00:58:28,033] [INFO] (highdicom.base) - copy Study-related attributes from dataset \"1.3.6.1.4.1.14519.5.2.1.7085.2626.936983343951485811186213470191\"\n",
+ "[2023-08-30 00:58:28,034] [INFO] (highdicom.base) - copy attributes of module \"General Study\"\n",
+ "[2023-08-30 00:58:28,035] [INFO] (highdicom.base) - copy attributes of module \"Patient Study\"\n",
+ "[2023-08-30 00:58:28,036] [INFO] (highdicom.base) - copy attributes of module \"Clinical Trial Study\"\n",
+ "[info] [greedy_scheduler.cpp:369] Scheduler stopped: Some entities are waiting for execution, but there are no periodic or async entities to get out of the deadlock.\n",
+ "[info] [greedy_scheduler.cpp:398] Scheduler finished.\n",
+ "[info] [gxf_executor.cpp:1783] Graph execution deactivating. Fragment: \n",
+ "[info] [gxf_executor.cpp:1784] Deactivating Graph...\n",
+ "[2023-08-30 00:58:28,138] [INFO] (__main__.AISpleenSegApp) - End run\n",
+ "[info] [gxf_executor.cpp:1787] Graph execution finished. Fragment: \n"
]
}
],
"source": [
+ "!rm -rf $HOLOSCAN_OUTPUT_PATH\n",
"app = AISpleenSegApp()\n",
- "\n",
- "app.run(input=\"dcm\", output=\"output\", model=\"model.ts\")"
+ "app.run()"
]
},
{
@@ -909,12 +960,12 @@
},
{
"cell_type": "code",
- "execution_count": 7,
+ "execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"# Create an application folder\n",
- "!mkdir -p my_app"
+ "!mkdir -p my_app && rm -rf my_app/*"
]
},
{
@@ -926,7 +977,7 @@
},
{
"cell_type": "code",
- "execution_count": 8,
+ "execution_count": 9,
"metadata": {},
"outputs": [
{
@@ -940,13 +991,12 @@
"source": [
"%%writefile my_app/spleen_seg_operator.py\n",
"import logging\n",
- "from os import path\n",
"\n",
"from numpy import uint8\n",
+ "from pathlib import Path\n",
"\n",
- "import monai.deploy.core as md\n",
- "from monai.deploy.core import ExecutionContext, Image, InputContext, IOType, Operator, OutputContext\n",
- "from monai.deploy.operators.monai_seg_inference_operator import InMemImageReader, MonaiSegInferenceOperator\n",
+ "from monai.deploy.core import AppContext, ConditionType, Fragment, Operator, OperatorSpec\n",
+ "from monai.deploy.operators.monai_seg_inference_operator import InfererType, InMemImageReader, MonaiSegInferenceOperator\n",
"from monai.transforms import (\n",
" Activationsd,\n",
" AsDiscreted,\n",
@@ -961,60 +1011,101 @@
" Spacingd,\n",
")\n",
"\n",
- "\n",
- "@md.input(\"image\", Image, IOType.IN_MEMORY)\n",
- "@md.output(\"seg_image\", Image, IOType.IN_MEMORY)\n",
- "@md.env(pip_packages=[\"monai>=0.8.1\", \"torch>=1.10.2\", \"numpy>=1.21\", \"nibabel\"])\n",
"class SpleenSegOperator(Operator):\n",
" \"\"\"Performs Spleen segmentation with a 3D image converted from a DICOM CT series.\n",
" \"\"\"\n",
"\n",
- " def __init__(self):\n",
+ " DEFAULT_OUTPUT_FOLDER = Path.cwd() / \"output/saved_images_folder\"\n",
+ "\n",
+ " def __init__(\n",
+ " self,\n",
+ " fragment: Fragment,\n",
+ " *args,\n",
+ " app_context: AppContext,\n",
+ " model_path: Path,\n",
+ " output_folder: Path = DEFAULT_OUTPUT_FOLDER,\n",
+ " **kwargs,\n",
+ " ):\n",
"\n",
" self.logger = logging.getLogger(\"{}.{}\".format(__name__, type(self).__name__))\n",
- " super().__init__()\n",
" self._input_dataset_key = \"image\"\n",
" self._pred_dataset_key = \"pred\"\n",
"\n",
- " def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):\n",
- "\n",
- " input_image = op_input.get(\"image\")\n",
+ " self.model_path = model_path\n",
+ " self.output_folder = output_folder\n",
+ " self.output_folder.mkdir(parents=True, exist_ok=True)\n",
+ " self.app_context = app_context\n",
+ " self.input_name_image = \"image\"\n",
+ " self.output_name_seg = \"seg_image\"\n",
+ " self.output_name_saved_images_folder = \"saved_images_folder\"\n",
+ "\n",
+ " # The base class has an attribute called fragment to hold the reference to the fragment object\n",
+ " super().__init__(fragment, *args, **kwargs)\n",
+ "\n",
+ " def setup(self, spec: OperatorSpec):\n",
+ " spec.input(self.input_name_image)\n",
+ " spec.output(self.output_name_seg)\n",
+ " spec.output(self.output_name_saved_images_folder).condition(\n",
+ " ConditionType.NONE\n",
+ " ) # Output not requiring a receiver\n",
+ "\n",
+ " def compute(self, op_input, op_output, context):\n",
+ " input_image = op_input.receive(self.input_name_image)\n",
" if not input_image:\n",
" raise ValueError(\"Input image is not found.\")\n",
"\n",
- " output_path = context.output.get().path\n",
- "\n",
" # This operator gets an in-memory Image object, so a specialized ImageReader is needed.\n",
" _reader = InMemImageReader(input_image)\n",
- " pre_transforms = self.pre_process(_reader)\n",
- " post_transforms = self.post_process(pre_transforms, path.join(output_path, \"prediction_output\"))\n",
+ "\n",
+ " pre_transforms = self.pre_process(_reader, str(self.output_folder))\n",
+ " post_transforms = self.post_process(pre_transforms, str(self.output_folder))\n",
"\n",
" # Delegates inference and saving output to the built-in operator.\n",
" infer_operator = MonaiSegInferenceOperator(\n",
- " (\n",
+ " self.fragment,\n",
+ " roi_size=(\n",
" 96,\n",
" 96,\n",
" 96,\n",
" ),\n",
- " pre_transforms,\n",
- " post_transforms,\n",
+ " pre_transforms=pre_transforms,\n",
+ " post_transforms=post_transforms,\n",
+ " overlap=0.6,\n",
+ " app_context=self.app_context,\n",
+ " model_name=\"\",\n",
+ " inferer=InfererType.SLIDING_WINDOW,\n",
+ " sw_batch_size=4,\n",
+ " model_path=self.model_path,\n",
+ " name=\"monai_seg_inference_op\",\n",
" )\n",
"\n",
- " # Setting the keys used in the dictironary based transforms may change.\n",
+ " # Setting the keys used in the dictionary based transforms may change.\n",
" infer_operator.input_dataset_key = self._input_dataset_key\n",
" infer_operator.pred_dataset_key = self._pred_dataset_key\n",
"\n",
- " # Now let the built-in operator handles the work with the I/O spec and execution context.\n",
- " infer_operator.compute(op_input, op_output, context)\n",
+ " # Now emit data to the output ports of this operator\n",
+ " op_output.emit(infer_operator.compute_impl(input_image, context), self.output_name_seg)\n",
+ " op_output.emit(self.output_folder, self.output_name_saved_images_folder)\n",
"\n",
- " def pre_process(self, img_reader) -> Compose:\n",
+ " def pre_process(self, img_reader, out_dir: str = \"./input_images\") -> Compose:\n",
" \"\"\"Composes transforms for preprocessing input before predicting on a model.\"\"\"\n",
"\n",
+ " Path(out_dir).mkdir(parents=True, exist_ok=True)\n",
" my_key = self._input_dataset_key\n",
+ "\n",
" return Compose(\n",
" [\n",
" LoadImaged(keys=my_key, reader=img_reader),\n",
" EnsureChannelFirstd(keys=my_key),\n",
+ " # The SaveImaged transform can be commented out to save 5 seconds.\n",
+ " # Uncompress NIfTI file, nii, is used favoring speed over size, but can be changed to nii.gz\n",
+ " SaveImaged(\n",
+ " keys=my_key,\n",
+ " output_dir=out_dir,\n",
+ " output_postfix=\"\",\n",
+ " resample=False,\n",
+ " output_ext=\".nii\",\n",
+ " ),\n",
" Orientationd(keys=my_key, axcodes=\"RAS\"),\n",
" Spacingd(keys=my_key, pixdim=[1.5, 1.5, 2.9], mode=[\"bilinear\"]),\n",
" ScaleIntensityRanged(keys=my_key, a_min=-57, a_max=164, b_min=0.0, b_max=1.0, clip=True),\n",
@@ -1025,7 +1116,9 @@
" def post_process(self, pre_transforms: Compose, out_dir: str = \"./prediction_output\") -> Compose:\n",
" \"\"\"Composes transforms for postprocessing the prediction results.\"\"\"\n",
"\n",
+ " Path(out_dir).mkdir(parents=True, exist_ok=True)\n",
" pred_key = self._pred_dataset_key\n",
+ "\n",
" return Compose(\n",
" [\n",
" Activationsd(keys=pred_key, softmax=True),\n",
@@ -1037,11 +1130,15 @@
" to_tensor=True,\n",
" ),\n",
" AsDiscreted(keys=pred_key, argmax=True),\n",
+ " # The SaveImaged transform can be commented out to save 5 seconds.\n",
+ " # Uncompress NIfTI file, nii, is used favoring speed over size, but can be changed to nii.gz\n",
" SaveImaged(\n",
" keys=pred_key,\n",
" output_dir=out_dir,\n",
" output_postfix=\"seg\",\n",
" output_dtype=uint8,\n",
+ " resample=False,\n",
+ " output_ext=\".nii\",\n",
" ),\n",
" ]\n",
" )\n"
@@ -1056,7 +1153,7 @@
},
{
"cell_type": "code",
- "execution_count": 9,
+ "execution_count": 10,
"metadata": {},
"outputs": [
{
@@ -1070,63 +1167,54 @@
"source": [
"%%writefile my_app/app.py\n",
"import logging\n",
+ "from pathlib import Path\n",
"\n",
"from spleen_seg_operator import SpleenSegOperator\n",
"\n",
- "# Required for setting SegmentDescription attributes. Direct import as this is not part of App SDK package.\n",
- "from pydicom.sr.codedict import codes\n",
+ "from pydicom.sr.codedict import codes # Required for setting SegmentDescription attributes.\n",
"\n",
- "from monai.deploy.core import Application, resource\n",
+ "from monai.deploy.conditions import CountCondition\n",
+ "from monai.deploy.core import AppContext, Application\n",
"from monai.deploy.operators.dicom_data_loader_operator import DICOMDataLoaderOperator\n",
"from monai.deploy.operators.dicom_seg_writer_operator import DICOMSegmentationWriterOperator, SegmentDescription\n",
"from monai.deploy.operators.dicom_series_selector_operator import DICOMSeriesSelectorOperator\n",
"from monai.deploy.operators.dicom_series_to_volume_operator import DICOMSeriesToVolumeOperator\n",
+ "from monai.deploy.operators.stl_conversion_operator import STLConversionOperator\n",
"\n",
- "# This is a sample series selection rule in JSON, simply selecting CT series.\n",
- "# If the study has more than 1 CT series, then all of them will be selected.\n",
- "# Please see more detail in DICOMSeriesSelectorOperator.\n",
- "Sample_Rules_Text = \"\"\"\n",
- "{\n",
- " \"selections\": [\n",
- " {\n",
- " \"name\": \"CT Series\",\n",
- " \"conditions\": {\n",
- " \"StudyDescription\": \"(.*?)\",\n",
- " \"Modality\": \"(?i)CT\",\n",
- " \"SeriesDescription\": \"(.*?)\",\n",
- " \"ImageType\": [\"PRIMARY\", \"ORIGINAL\"]\n",
- " }\n",
- " }\n",
- " ]\n",
- "}\n",
- "\"\"\"\n",
- "\n",
- "@resource(cpu=1, gpu=1, memory=\"7Gi\")\n",
"class AISpleenSegApp(Application):\n",
" def __init__(self, *args, **kwargs):\n",
" \"\"\"Creates an application instance.\"\"\"\n",
"\n",
- " self._logger = logging.getLogger(\"{}.{}\".format(__name__, type(self).__name__))\n",
" super().__init__(*args, **kwargs)\n",
+ " self._logger = logging.getLogger(\"{}.{}\".format(__name__, type(self).__name__))\n",
"\n",
" def run(self, *args, **kwargs):\n",
" # This method calls the base class to run. Can be omitted if simply calling through.\n",
- " self._logger.debug(f\"Begin {self.run.__name__}\")\n",
+ " self._logger.info(f\"Begin {self.run.__name__}\")\n",
" super().run(*args, **kwargs)\n",
- " self._logger.debug(f\"End {self.run.__name__}\")\n",
+ " self._logger.info(f\"End {self.run.__name__}\")\n",
"\n",
" def compose(self):\n",
" \"\"\"Creates the app specific operators and chain them up in the processing DAG.\"\"\"\n",
"\n",
+ " # Use Commandline options over environment variables to init context.\n",
+ " app_context = Application.init_app_context(self.argv)\n",
" self._logger.debug(f\"Begin {self.compose.__name__}\")\n",
- " # Creates the custom operator(s) as well as SDK built-in operator(s).\n",
- " study_loader_op = DICOMDataLoaderOperator()\n",
- " series_selector_op = DICOMSeriesSelectorOperator(rules=Sample_Rules_Text)\n",
- " series_to_vol_op = DICOMSeriesToVolumeOperator()\n",
- " # Model specific inference operator, supporting MONAI transforms.\n",
+ " app_input_path = Path(app_context.input_path)\n",
+ " app_output_path = Path(app_context.output_path)\n",
+ " model_path = Path(app_context.model_path)\n",
"\n",
- " # Creates the model specific segmentation operator\n",
- " spleen_seg_op = SpleenSegOperator()\n",
+ " self._logger.info(f\"App input and output path: {app_input_path}, {app_output_path}\")\n",
+ "\n",
+ " # instantiates the SDK built-in operator(s).\n",
+ " study_loader_op = DICOMDataLoaderOperator(\n",
+ " self, CountCondition(self, 1), input_folder=app_input_path, name=\"dcm_loader_op\"\n",
+ " )\n",
+ " series_selector_op = DICOMSeriesSelectorOperator(self, rules=Sample_Rules_Text, name=\"series_selector_op\")\n",
+ " series_to_vol_op = DICOMSeriesToVolumeOperator(self, name=\"series_to_vol_op\")\n",
+ "\n",
+ " # Model specific inference operator, supporting MONAI transforms.\n",
+ " spleen_seg_op = SpleenSegOperator(self, app_context=app_context, model_path=model_path, name=\"seg_op\")\n",
"\n",
" # Create DICOM Seg writer providing the required segment description for each segment with\n",
" # the actual algorithm and the pertinent organ/tissue.\n",
@@ -1141,9 +1229,9 @@
"\n",
" segment_descriptions = [\n",
" SegmentDescription(\n",
- " segment_label=\"Lung\",\n",
+ " segment_label=\"Spleen\",\n",
" segmented_property_category=codes.SCT.Organ,\n",
- " segmented_property_type=codes.SCT.Lung,\n",
+ " segmented_property_type=codes.SCT.Spleen,\n",
" algorithm_name=_algorithm_name,\n",
" algorithm_family=_algorithm_family,\n",
" algorithm_version=_algorithm_version,\n",
@@ -1153,34 +1241,55 @@
" custom_tags = {\"SeriesDescription\": \"AI generated Seg, not for clinical use.\"}\n",
"\n",
" dicom_seg_writer = DICOMSegmentationWriterOperator(\n",
- " segment_descriptions=segment_descriptions, custom_tags=custom_tags\n",
+ " self,\n",
+ " segment_descriptions=segment_descriptions,\n",
+ " custom_tags=custom_tags,\n",
+ " output_folder=app_output_path,\n",
+ " name=\"dcm_seg_writer_op\",\n",
" )\n",
"\n",
" # Create the processing pipeline, by specifying the source and destination operators, and\n",
" # ensuring the output from the former matches the input of the latter, in both name and type.\n",
- " self.add_flow(study_loader_op, series_selector_op, {\"dicom_study_list\": \"dicom_study_list\"})\n",
+ " self.add_flow(study_loader_op, series_selector_op, {(\"dicom_study_list\", \"dicom_study_list\")})\n",
" self.add_flow(\n",
- " series_selector_op, series_to_vol_op, {\"study_selected_series_list\": \"study_selected_series_list\"}\n",
+ " series_selector_op, series_to_vol_op, {(\"study_selected_series_list\", \"study_selected_series_list\")}\n",
" )\n",
- " self.add_flow(series_to_vol_op, spleen_seg_op, {\"image\": \"image\"})\n",
+ " self.add_flow(series_to_vol_op, spleen_seg_op, {(\"image\", \"image\")})\n",
"\n",
" # Note below the dicom_seg_writer requires two inputs, each coming from a source operator.\n",
" self.add_flow(\n",
- " series_selector_op, dicom_seg_writer, {\"study_selected_series_list\": \"study_selected_series_list\"}\n",
+ " series_selector_op, dicom_seg_writer, {(\"study_selected_series_list\", \"study_selected_series_list\")}\n",
" )\n",
- " self.add_flow(spleen_seg_op, dicom_seg_writer, {\"seg_image\": \"seg_image\"})\n",
+ " self.add_flow(spleen_seg_op, dicom_seg_writer, {(\"seg_image\", \"seg_image\")})\n",
"\n",
" self._logger.debug(f\"End {self.compose.__name__}\")\n",
"\n",
+ "\n",
+ "# This is a sample series selection rule in JSON, simply selecting CT series.\n",
+ "# If the study has more than 1 CT series, then all of them will be selected.\n",
+ "# Please see more detail in DICOMSeriesSelectorOperator.\n",
+ "# For list of string values, e.g. \"ImageType\": [\"PRIMARY\", \"ORIGINAL\"], it is a match if all elements\n",
+ "# are all in the multi-value attribute of the DICOM series.\n",
+ "\n",
+ "Sample_Rules_Text = \"\"\"\n",
+ "{\n",
+ " \"selections\": [\n",
+ " {\n",
+ " \"name\": \"CT Series\",\n",
+ " \"conditions\": {\n",
+ " \"StudyDescription\": \"(.*?)\",\n",
+ " \"Modality\": \"(?i)CT\",\n",
+ " \"SeriesDescription\": \"(.*?)\",\n",
+ " \"ImageType\": [\"PRIMARY\", \"ORIGINAL\"]\n",
+ " }\n",
+ " }\n",
+ " ]\n",
+ "}\n",
+ "\"\"\"\n",
+ "\n",
"if __name__ == \"__main__\":\n",
- " # Creates the app and test it standalone. When running is this mode, please note the following:\n",
- " # -i , for input DICOM CT series folder\n",
- " # -o , for the output folder, default $PWD/output\n",
- " # -m , for model file path\n",
- " # e.g.\n",
- " # python3 app.py -i input -m model.ts\n",
- " #\n",
- " AISpleenSegApp(do_run=True)"
+ " # Creates the app and test it standalone.\n",
+ " AISpleenSegApp().run()"
]
},
{
@@ -1189,7 +1298,7 @@
"source": [
"```python\n",
"if __name__ == \"__main__\":\n",
- " AISpleenSegApp(do_run=True)\n",
+ " AISpleenSegApp().run()\n",
"```\n",
"\n",
"The above lines are needed to execute the application code by using `python` interpreter.\n",
@@ -1201,7 +1310,7 @@
},
{
"cell_type": "code",
- "execution_count": 10,
+ "execution_count": 11,
"metadata": {},
"outputs": [
{
@@ -1217,12 +1326,12 @@
"from app import AISpleenSegApp\n",
"\n",
"if __name__ == \"__main__\":\n",
- " AISpleenSegApp(do_run=True)"
+ " AISpleenSegApp().run()"
]
},
{
"cell_type": "code",
- "execution_count": 11,
+ "execution_count": 12,
"metadata": {},
"outputs": [
{
@@ -1241,556 +1350,820 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "In this time, let's execute the app in the command line."
+ "In this time, let's execute the app in the command line.\n",
+ "\n",
+ ":::{note}\n",
+ "Since the environment variables have been set and contain the correct paths, it is not necessary to provide the command line options on running the application.\n",
+ ":::"
]
},
{
"cell_type": "code",
- "execution_count": 12,
+ "execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "\u001b[34mGoing to initiate execution of operator DICOMDataLoaderOperator\u001b[39m\n",
- "\u001b[32mExecuting operator DICOMDataLoaderOperator \u001b[33m(Process ID: 411375, Operator ID: 2dbbf9a7-2218-4484-b283-10daed825d96)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator DICOMDataLoaderOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator DICOMSeriesSelectorOperator\u001b[39m\n",
- "\u001b[32mExecuting operator DICOMSeriesSelectorOperator \u001b[33m(Process ID: 411375, Operator ID: 392a230d-6efc-4b74-9e73-fead8907d62a)\u001b[39m\n",
- "[2023-07-11 14:43:58,265] [INFO] (root) - Finding series for Selection named: CT Series\n",
- "[2023-07-11 14:43:58,265] [INFO] (root) - Searching study, : 1.3.6.1.4.1.14519.5.2.1.7085.2626.822645453932810382886582736291\n",
+ "[2023-08-30 00:58:35,056] [INFO] (root) - Parsed args: Namespace(argv=['my_app'], input=None, log_level=None, model=None, output=None, workdir=None)\n",
+ "[2023-08-30 00:58:35,058] [INFO] (root) - AppContext object: AppContext(input_path=dcm, output_path=output, model_path=models, workdir=)\n",
+ "[2023-08-30 00:58:35,058] [INFO] (app.AISpleenSegApp) - App input and output path: dcm, output\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:210] Creating context\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1595] Loading extensions from configs...\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1741] Activating Graph...\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1771] Running Graph...\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1773] Waiting for completion...\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1774] Graph execution waiting. Fragment: \n",
+ "[\u001b[32minfo\u001b[m] [greedy_scheduler.cpp:190] Scheduling 6 entities\n",
+ "[2023-08-30 00:58:35,114] [INFO] (monai.deploy.operators.dicom_data_loader_operator.DICOMDataLoaderOperator) - No or invalid input path from the optional input port: None\n",
+ "[2023-08-30 00:58:35,624] [INFO] (root) - Finding series for Selection named: CT Series\n",
+ "[2023-08-30 00:58:35,624] [INFO] (root) - Searching study, : 1.3.6.1.4.1.14519.5.2.1.7085.2626.822645453932810382886582736291\n",
" # of series: 1\n",
- "[2023-07-11 14:43:58,265] [INFO] (root) - Working on series, instance UID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.119403521930927333027265674239\n",
- "[2023-07-11 14:43:58,265] [INFO] (root) - On attribute: 'StudyDescription' to match value: '(.*?)'\n",
- "[2023-07-11 14:43:58,265] [INFO] (root) - Series attribute StudyDescription value: CT ABDOMEN W IV CONTRAST\n",
- "[2023-07-11 14:43:58,265] [INFO] (root) - Series attribute string value did not match. Try regEx.\n",
- "[2023-07-11 14:43:58,265] [INFO] (root) - On attribute: 'Modality' to match value: '(?i)CT'\n",
- "[2023-07-11 14:43:58,265] [INFO] (root) - Series attribute Modality value: CT\n",
- "[2023-07-11 14:43:58,265] [INFO] (root) - Series attribute string value did not match. Try regEx.\n",
- "[2023-07-11 14:43:58,265] [INFO] (root) - On attribute: 'SeriesDescription' to match value: '(.*?)'\n",
- "[2023-07-11 14:43:58,265] [INFO] (root) - Series attribute SeriesDescription value: ABD/PANC 3.0 B31f\n",
- "[2023-07-11 14:43:58,265] [INFO] (root) - Series attribute string value did not match. Try regEx.\n",
- "[2023-07-11 14:43:58,265] [INFO] (root) - On attribute: 'ImageType' to match value: ['PRIMARY', 'ORIGINAL']\n",
- "[2023-07-11 14:43:58,265] [INFO] (root) - Series attribute ImageType value: None\n",
- "[2023-07-11 14:43:58,266] [INFO] (root) - Selected Series, UID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.119403521930927333027265674239\n",
- "\u001b[34mDone performing execution of operator DICOMSeriesSelectorOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator DICOMSeriesToVolumeOperator\u001b[39m\n",
- "\u001b[32mExecuting operator DICOMSeriesToVolumeOperator \u001b[33m(Process ID: 411375, Operator ID: 14e0e3e6-280f-44ce-841e-4c2df573e3a4)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator DICOMSeriesToVolumeOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator SpleenSegOperator\u001b[39m\n",
- "\u001b[32mExecuting operator SpleenSegOperator \u001b[33m(Process ID: 411375, Operator ID: 2efe7071-fd74-4238-aaec-65b7dbe272a8)\u001b[39m\n",
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:321: FutureWarning: monai.transforms.io.dictionary LoadImaged.__init__:image_only: Current default value of argument `image_only=False` has been deprecated since version 1.1. It will be changed to `image_only=True` in version 1.3.\n",
+ "[2023-08-30 00:58:35,624] [INFO] (root) - Working on series, instance UID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.119403521930927333027265674239\n",
+ "[2023-08-30 00:58:35,625] [INFO] (root) - On attribute: 'StudyDescription' to match value: '(.*?)'\n",
+ "[2023-08-30 00:58:35,625] [INFO] (root) - Series attribute StudyDescription value: CT ABDOMEN W IV CONTRAST\n",
+ "[2023-08-30 00:58:35,625] [INFO] (root) - Series attribute string value did not match. Try regEx.\n",
+ "[2023-08-30 00:58:35,625] [INFO] (root) - On attribute: 'Modality' to match value: '(?i)CT'\n",
+ "[2023-08-30 00:58:35,625] [INFO] (root) - Series attribute Modality value: CT\n",
+ "[2023-08-30 00:58:35,625] [INFO] (root) - Series attribute string value did not match. Try regEx.\n",
+ "[2023-08-30 00:58:35,625] [INFO] (root) - On attribute: 'SeriesDescription' to match value: '(.*?)'\n",
+ "[2023-08-30 00:58:35,625] [INFO] (root) - Series attribute SeriesDescription value: ABD/PANC 3.0 B31f\n",
+ "[2023-08-30 00:58:35,625] [INFO] (root) - Series attribute string value did not match. Try regEx.\n",
+ "[2023-08-30 00:58:35,625] [INFO] (root) - On attribute: 'ImageType' to match value: ['PRIMARY', 'ORIGINAL']\n",
+ "[2023-08-30 00:58:35,625] [INFO] (root) - Series attribute ImageType value: None\n",
+ "[2023-08-30 00:58:35,625] [INFO] (root) - Selected Series, UID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.119403521930927333027265674239\n",
+ "/home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:321: FutureWarning: monai.transforms.io.dictionary LoadImaged.__init__:image_only: Current default value of argument `image_only=False` has been deprecated since version 1.1. It will be changed to `image_only=True` in version 1.3.\n",
" warn_deprecated(argname, msg, warning_category)\n",
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:321: FutureWarning: monai.transforms.io.dictionary SaveImaged.__init__:resample: Current default value of argument `resample=True` has been deprecated since version 1.1. It will be changed to `resample=False` in version 1.3.\n",
- " warn_deprecated(argname, msg, warning_category)\n",
- "Converted Image object metadata:\n",
- "SeriesInstanceUID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.119403521930927333027265674239, type \n",
- "SeriesDate: 20090831, type \n",
- "SeriesTime: 101721.452, type \n",
- "Modality: CT, type \n",
- "SeriesDescription: ABD/PANC 3.0 B31f, type \n",
- "PatientPosition: HFS, type \n",
- "SeriesNumber: 8, type \n",
- "row_pixel_spacing: 0.7890625, type \n",
- "col_pixel_spacing: 0.7890625, type \n",
- "depth_pixel_spacing: 1.5, type \n",
- "row_direction_cosine: [1.0, 0.0, 0.0], type \n",
- "col_direction_cosine: [0.0, 1.0, 0.0], type \n",
- "depth_direction_cosine: [0.0, 0.0, 1.0], type \n",
- "dicom_affine_transform: [[ 0.7890625 0. 0. -197.60547 ]\n",
+ "[2023-08-30 00:58:35,841] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - Converted Image object metadata:\n",
+ "[2023-08-30 00:58:35,841] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - SeriesInstanceUID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.119403521930927333027265674239, type \n",
+ "[2023-08-30 00:58:35,841] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - SeriesDate: 20090831, type \n",
+ "[2023-08-30 00:58:35,841] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - SeriesTime: 101721.452, type \n",
+ "[2023-08-30 00:58:35,841] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - Modality: CT, type \n",
+ "[2023-08-30 00:58:35,841] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - SeriesDescription: ABD/PANC 3.0 B31f, type \n",
+ "[2023-08-30 00:58:35,841] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - PatientPosition: HFS, type \n",
+ "[2023-08-30 00:58:35,841] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - SeriesNumber: 8, type \n",
+ "[2023-08-30 00:58:35,841] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - row_pixel_spacing: 0.7890625, type \n",
+ "[2023-08-30 00:58:35,841] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - col_pixel_spacing: 0.7890625, type \n",
+ "[2023-08-30 00:58:35,841] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - depth_pixel_spacing: 1.5, type \n",
+ "[2023-08-30 00:58:35,841] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - row_direction_cosine: [1.0, 0.0, 0.0], type \n",
+ "[2023-08-30 00:58:35,841] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - col_direction_cosine: [0.0, 1.0, 0.0], type \n",
+ "[2023-08-30 00:58:35,841] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - depth_direction_cosine: [0.0, 0.0, 1.0], type \n",
+ "[2023-08-30 00:58:35,842] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - dicom_affine_transform: [[ 0.7890625 0. 0. -197.60547 ]\n",
" [ 0. 0.7890625 0. -398.60547 ]\n",
" [ 0. 0. 1.5 -383. ]\n",
" [ 0. 0. 0. 1. ]], type \n",
- "nifti_affine_transform: [[ -0.7890625 -0. -0. 197.60547 ]\n",
+ "[2023-08-30 00:58:35,842] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - nifti_affine_transform: [[ -0.7890625 -0. -0. 197.60547 ]\n",
" [ -0. -0.7890625 -0. 398.60547 ]\n",
" [ 0. 0. 1.5 -383. ]\n",
" [ 0. 0. 0. 1. ]], type \n",
- "StudyInstanceUID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.822645453932810382886582736291, type \n",
- "StudyID: , type \n",
- "StudyDate: 20090831, type \n",
- "StudyTime: 095948.599, type \n",
- "StudyDescription: CT ABDOMEN W IV CONTRAST, type \n",
- "AccessionNumber: 5471978513296937, type \n",
- "selection_name: CT Series, type \n",
- "2023-07-11 14:44:03,657 INFO image_writer.py:197 - writing: /home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/output/prediction_output/1.3.6.1.4.1.14519.5.2.1.7085.2626/1.3.6.1.4.1.14519.5.2.1.7085.2626_seg.nii.gz\n",
- "Output Seg image numpy array shaped: (204, 512, 512)\n",
- "Output Seg image pixel max value: 1\n",
- "Output Seg image pixel min value: 0\n",
- "\u001b[34mDone performing execution of operator SpleenSegOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator DICOMSegmentationWriterOperator\u001b[39m\n",
- "\u001b[32mExecuting operator DICOMSegmentationWriterOperator \u001b[33m(Process ID: 411375, Operator ID: 1cda89fb-a6b7-42aa-a280-4fbf757cc87d)\u001b[39m\n",
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/highdicom/valuerep.py:54: UserWarning: The string \"C3N-00198\" is unlikely to represent the intended person name since it contains only a single component. Construct a person name according to the format in described in http://dicom.nema.org/dicom/2013/output/chtml/part05/sect_6.2.html#sect_6.2.1.2, or, in pydicom 2.2.0 or later, use the pydicom.valuerep.PersonName.from_named_components() method to construct the person name correctly. If a single-component name is really intended, add a trailing caret character to disambiguate the name.\n",
+ "[2023-08-30 00:58:35,842] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - StudyInstanceUID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.822645453932810382886582736291, type \n",
+ "[2023-08-30 00:58:35,842] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - StudyID: , type \n",
+ "[2023-08-30 00:58:35,842] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - StudyDate: 20090831, type \n",
+ "[2023-08-30 00:58:35,842] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - StudyTime: 095948.599, type \n",
+ "[2023-08-30 00:58:35,842] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - StudyDescription: CT ABDOMEN W IV CONTRAST, type \n",
+ "[2023-08-30 00:58:35,842] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - AccessionNumber: 5471978513296937, type \n",
+ "[2023-08-30 00:58:35,842] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - selection_name: CT Series, type \n",
+ "2023-08-30 00:58:36,678 INFO image_writer.py:197 - writing: /home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/output/saved_images_folder/1.3.6.1.4.1.14519.5.2.1.7085.2626/1.3.6.1.4.1.14519.5.2.1.7085.2626.nii\n",
+ "2023-08-30 00:58:42,872 INFO image_writer.py:197 - writing: /home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/output/saved_images_folder/1.3.6.1.4.1.14519.5.2.1.7085.2626/1.3.6.1.4.1.14519.5.2.1.7085.2626_seg.nii\n",
+ "[2023-08-30 00:58:44,629] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - Output Seg image numpy array shaped: (204, 512, 512)\n",
+ "[2023-08-30 00:58:44,635] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - Output Seg image pixel max value: 1\n",
+ "/home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages/highdicom/valuerep.py:54: UserWarning: The string \"C3N-00198\" is unlikely to represent the intended person name since it contains only a single component. Construct a person name according to the format in described in http://dicom.nema.org/dicom/2013/output/chtml/part05/sect_6.2.html#sect_6.2.1.2, or, in pydicom 2.2.0 or later, use the pydicom.valuerep.PersonName.from_named_components() method to construct the person name correctly. If a single-component name is really intended, add a trailing caret character to disambiguate the name.\n",
" warnings.warn(\n",
- "[2023-07-11 14:44:07,732] [INFO] (highdicom.seg.sop) - add plane #0 for segment #1\n",
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/pydicom/valuerep.py:443: UserWarning: A value of type 'int64' cannot be assigned to a tag with VR UL.\n",
+ "[2023-08-30 00:58:47,369] [INFO] (highdicom.seg.sop) - add plane #0 for segment #1\n",
+ "/home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages/pydicom/valuerep.py:443: UserWarning: A value of type 'int64' cannot be assigned to a tag with VR UL.\n",
" warnings.warn(msg)\n",
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/pydicom/valuerep.py:443: UserWarning: A value of type 'int64' cannot be assigned to a tag with VR US.\n",
+ "/home/mqin/src/monai-deploy-app-sdk/.venv/lib/python3.8/site-packages/pydicom/valuerep.py:443: UserWarning: A value of type 'int64' cannot be assigned to a tag with VR US.\n",
" warnings.warn(msg)\n",
- "[2023-07-11 14:44:07,733] [INFO] (highdicom.seg.sop) - add plane #1 for segment #1\n",
- "[2023-07-11 14:44:07,734] [INFO] (highdicom.seg.sop) - add plane #2 for segment #1\n",
- "[2023-07-11 14:44:07,735] [INFO] (highdicom.seg.sop) - add plane #3 for segment #1\n",
- "[2023-07-11 14:44:07,736] [INFO] (highdicom.seg.sop) - add plane #4 for segment #1\n",
- "[2023-07-11 14:44:07,736] [INFO] (highdicom.seg.sop) - add plane #5 for segment #1\n",
- "[2023-07-11 14:44:07,737] [INFO] (highdicom.seg.sop) - add plane #6 for segment #1\n",
- "[2023-07-11 14:44:07,737] [INFO] (highdicom.seg.sop) - add plane #7 for segment #1\n",
- "[2023-07-11 14:44:07,738] [INFO] (highdicom.seg.sop) - add plane #8 for segment #1\n",
- "[2023-07-11 14:44:07,739] [INFO] (highdicom.seg.sop) - add plane #9 for segment #1\n",
- "[2023-07-11 14:44:07,739] [INFO] (highdicom.seg.sop) - add plane #10 for segment #1\n",
- "[2023-07-11 14:44:07,740] [INFO] (highdicom.seg.sop) - add plane #11 for segment #1\n",
- "[2023-07-11 14:44:07,741] [INFO] (highdicom.seg.sop) - add plane #12 for segment #1\n",
- "[2023-07-11 14:44:07,742] [INFO] (highdicom.seg.sop) - add plane #13 for segment #1\n",
- "[2023-07-11 14:44:07,742] [INFO] (highdicom.seg.sop) - add plane #14 for segment #1\n",
- "[2023-07-11 14:44:07,743] [INFO] (highdicom.seg.sop) - add plane #15 for segment #1\n",
- "[2023-07-11 14:44:07,744] [INFO] (highdicom.seg.sop) - add plane #16 for segment #1\n",
- "[2023-07-11 14:44:07,744] [INFO] (highdicom.seg.sop) - add plane #17 for segment #1\n",
- "[2023-07-11 14:44:07,745] [INFO] (highdicom.seg.sop) - add plane #18 for segment #1\n",
- "[2023-07-11 14:44:07,745] [INFO] (highdicom.seg.sop) - add plane #19 for segment #1\n",
- "[2023-07-11 14:44:07,746] [INFO] (highdicom.seg.sop) - add plane #20 for segment #1\n",
- "[2023-07-11 14:44:07,747] [INFO] (highdicom.seg.sop) - add plane #21 for segment #1\n",
- "[2023-07-11 14:44:07,748] [INFO] (highdicom.seg.sop) - add plane #22 for segment #1\n",
- "[2023-07-11 14:44:07,748] [INFO] (highdicom.seg.sop) - add plane #23 for segment #1\n",
- "[2023-07-11 14:44:07,749] [INFO] (highdicom.seg.sop) - add plane #24 for segment #1\n",
- "[2023-07-11 14:44:07,750] [INFO] (highdicom.seg.sop) - add plane #25 for segment #1\n",
- "[2023-07-11 14:44:07,750] [INFO] (highdicom.seg.sop) - add plane #26 for segment #1\n",
- "[2023-07-11 14:44:07,751] [INFO] (highdicom.seg.sop) - add plane #27 for segment #1\n",
- "[2023-07-11 14:44:07,752] [INFO] (highdicom.seg.sop) - add plane #28 for segment #1\n",
- "[2023-07-11 14:44:07,752] [INFO] (highdicom.seg.sop) - add plane #29 for segment #1\n",
- "[2023-07-11 14:44:07,753] [INFO] (highdicom.seg.sop) - add plane #30 for segment #1\n",
- "[2023-07-11 14:44:07,753] [INFO] (highdicom.seg.sop) - add plane #31 for segment #1\n",
- "[2023-07-11 14:44:07,754] [INFO] (highdicom.seg.sop) - add plane #32 for segment #1\n",
- "[2023-07-11 14:44:07,755] [INFO] (highdicom.seg.sop) - add plane #33 for segment #1\n",
- "[2023-07-11 14:44:07,756] [INFO] (highdicom.seg.sop) - add plane #34 for segment #1\n",
- "[2023-07-11 14:44:07,756] [INFO] (highdicom.seg.sop) - add plane #35 for segment #1\n",
- "[2023-07-11 14:44:07,757] [INFO] (highdicom.seg.sop) - add plane #36 for segment #1\n",
- "[2023-07-11 14:44:07,757] [INFO] (highdicom.seg.sop) - add plane #37 for segment #1\n",
- "[2023-07-11 14:44:07,758] [INFO] (highdicom.seg.sop) - add plane #38 for segment #1\n",
- "[2023-07-11 14:44:07,759] [INFO] (highdicom.seg.sop) - add plane #39 for segment #1\n",
- "[2023-07-11 14:44:07,759] [INFO] (highdicom.seg.sop) - add plane #40 for segment #1\n",
- "[2023-07-11 14:44:07,760] [INFO] (highdicom.seg.sop) - add plane #41 for segment #1\n",
- "[2023-07-11 14:44:07,761] [INFO] (highdicom.seg.sop) - add plane #42 for segment #1\n",
- "[2023-07-11 14:44:07,761] [INFO] (highdicom.seg.sop) - add plane #43 for segment #1\n",
- "[2023-07-11 14:44:07,762] [INFO] (highdicom.seg.sop) - add plane #44 for segment #1\n",
- "[2023-07-11 14:44:07,763] [INFO] (highdicom.seg.sop) - add plane #45 for segment #1\n",
- "[2023-07-11 14:44:07,763] [INFO] (highdicom.seg.sop) - add plane #46 for segment #1\n",
- "[2023-07-11 14:44:07,764] [INFO] (highdicom.seg.sop) - add plane #47 for segment #1\n",
- "[2023-07-11 14:44:07,765] [INFO] (highdicom.seg.sop) - add plane #48 for segment #1\n",
- "[2023-07-11 14:44:07,766] [INFO] (highdicom.seg.sop) - add plane #49 for segment #1\n",
- "[2023-07-11 14:44:07,766] [INFO] (highdicom.seg.sop) - add plane #50 for segment #1\n",
- "[2023-07-11 14:44:07,767] [INFO] (highdicom.seg.sop) - add plane #51 for segment #1\n",
- "[2023-07-11 14:44:07,768] [INFO] (highdicom.seg.sop) - add plane #52 for segment #1\n",
- "[2023-07-11 14:44:07,768] [INFO] (highdicom.seg.sop) - add plane #53 for segment #1\n",
- "[2023-07-11 14:44:07,769] [INFO] (highdicom.seg.sop) - add plane #54 for segment #1\n",
- "[2023-07-11 14:44:07,770] [INFO] (highdicom.seg.sop) - add plane #55 for segment #1\n",
- "[2023-07-11 14:44:07,770] [INFO] (highdicom.seg.sop) - add plane #56 for segment #1\n",
- "[2023-07-11 14:44:07,771] [INFO] (highdicom.seg.sop) - add plane #57 for segment #1\n",
- "[2023-07-11 14:44:07,772] [INFO] (highdicom.seg.sop) - add plane #58 for segment #1\n",
- "[2023-07-11 14:44:07,772] [INFO] (highdicom.seg.sop) - add plane #59 for segment #1\n",
- "[2023-07-11 14:44:07,773] [INFO] (highdicom.seg.sop) - add plane #60 for segment #1\n",
- "[2023-07-11 14:44:07,773] [INFO] (highdicom.seg.sop) - add plane #61 for segment #1\n",
- "[2023-07-11 14:44:07,774] [INFO] (highdicom.seg.sop) - add plane #62 for segment #1\n",
- "[2023-07-11 14:44:07,775] [INFO] (highdicom.seg.sop) - add plane #63 for segment #1\n",
- "[2023-07-11 14:44:07,776] [INFO] (highdicom.seg.sop) - add plane #64 for segment #1\n",
- "[2023-07-11 14:44:07,776] [INFO] (highdicom.seg.sop) - add plane #65 for segment #1\n",
- "[2023-07-11 14:44:07,777] [INFO] (highdicom.seg.sop) - add plane #66 for segment #1\n",
- "[2023-07-11 14:44:07,777] [INFO] (highdicom.seg.sop) - add plane #67 for segment #1\n",
- "[2023-07-11 14:44:07,778] [INFO] (highdicom.seg.sop) - add plane #68 for segment #1\n",
- "[2023-07-11 14:44:07,779] [INFO] (highdicom.seg.sop) - add plane #69 for segment #1\n",
- "[2023-07-11 14:44:07,779] [INFO] (highdicom.seg.sop) - add plane #70 for segment #1\n",
- "[2023-07-11 14:44:07,780] [INFO] (highdicom.seg.sop) - add plane #71 for segment #1\n",
- "[2023-07-11 14:44:07,781] [INFO] (highdicom.seg.sop) - add plane #72 for segment #1\n",
- "[2023-07-11 14:44:07,782] [INFO] (highdicom.seg.sop) - add plane #73 for segment #1\n",
- "[2023-07-11 14:44:07,782] [INFO] (highdicom.seg.sop) - add plane #74 for segment #1\n",
- "[2023-07-11 14:44:07,783] [INFO] (highdicom.seg.sop) - add plane #75 for segment #1\n",
- "[2023-07-11 14:44:07,784] [INFO] (highdicom.seg.sop) - add plane #76 for segment #1\n",
- "[2023-07-11 14:44:07,784] [INFO] (highdicom.seg.sop) - add plane #77 for segment #1\n",
- "[2023-07-11 14:44:07,785] [INFO] (highdicom.seg.sop) - add plane #78 for segment #1\n",
- "[2023-07-11 14:44:07,786] [INFO] (highdicom.seg.sop) - add plane #79 for segment #1\n",
- "[2023-07-11 14:44:07,787] [INFO] (highdicom.seg.sop) - add plane #80 for segment #1\n",
- "[2023-07-11 14:44:07,787] [INFO] (highdicom.seg.sop) - add plane #81 for segment #1\n",
- "[2023-07-11 14:44:07,788] [INFO] (highdicom.seg.sop) - add plane #82 for segment #1\n",
- "[2023-07-11 14:44:07,788] [INFO] (highdicom.seg.sop) - add plane #83 for segment #1\n",
- "[2023-07-11 14:44:07,789] [INFO] (highdicom.seg.sop) - add plane #84 for segment #1\n",
- "[2023-07-11 14:44:07,790] [INFO] (highdicom.seg.sop) - add plane #85 for segment #1\n",
- "[2023-07-11 14:44:07,790] [INFO] (highdicom.seg.sop) - add plane #86 for segment #1\n",
- "[2023-07-11 14:44:07,791] [INFO] (highdicom.seg.sop) - add plane #87 for segment #1\n",
- "[2023-07-11 14:44:07,792] [INFO] (highdicom.seg.sop) - add plane #88 for segment #1\n",
- "[2023-07-11 14:44:07,832] [INFO] (highdicom.base) - copy Image-related attributes from dataset \"1.3.6.1.4.1.14519.5.2.1.7085.2626.936983343951485811186213470191\"\n",
- "[2023-07-11 14:44:07,832] [INFO] (highdicom.base) - copy attributes of module \"Specimen\"\n",
- "[2023-07-11 14:44:07,832] [INFO] (highdicom.base) - copy Patient-related attributes from dataset \"1.3.6.1.4.1.14519.5.2.1.7085.2626.936983343951485811186213470191\"\n",
- "[2023-07-11 14:44:07,832] [INFO] (highdicom.base) - copy attributes of module \"Patient\"\n",
- "[2023-07-11 14:44:07,832] [INFO] (highdicom.base) - copy attributes of module \"Clinical Trial Subject\"\n",
- "[2023-07-11 14:44:07,833] [INFO] (highdicom.base) - copy Study-related attributes from dataset \"1.3.6.1.4.1.14519.5.2.1.7085.2626.936983343951485811186213470191\"\n",
- "[2023-07-11 14:44:07,833] [INFO] (highdicom.base) - copy attributes of module \"General Study\"\n",
- "[2023-07-11 14:44:07,833] [INFO] (highdicom.base) - copy attributes of module \"Patient Study\"\n",
- "[2023-07-11 14:44:07,833] [INFO] (highdicom.base) - copy attributes of module \"Clinical Trial Study\"\n",
- "\u001b[34mDone performing execution of operator DICOMSegmentationWriterOperator\n",
- "\u001b[39m\n"
+ "[2023-08-30 00:58:47,371] [INFO] (highdicom.seg.sop) - add plane #1 for segment #1\n",
+ "[2023-08-30 00:58:47,372] [INFO] (highdicom.seg.sop) - add plane #2 for segment #1\n",
+ "[2023-08-30 00:58:47,373] [INFO] (highdicom.seg.sop) - add plane #3 for segment #1\n",
+ "[2023-08-30 00:58:47,374] [INFO] (highdicom.seg.sop) - add plane #4 for segment #1\n",
+ "[2023-08-30 00:58:47,374] [INFO] (highdicom.seg.sop) - add plane #5 for segment #1\n",
+ "[2023-08-30 00:58:47,375] [INFO] (highdicom.seg.sop) - add plane #6 for segment #1\n",
+ "[2023-08-30 00:58:47,376] [INFO] (highdicom.seg.sop) - add plane #7 for segment #1\n",
+ "[2023-08-30 00:58:47,377] [INFO] (highdicom.seg.sop) - add plane #8 for segment #1\n",
+ "[2023-08-30 00:58:47,378] [INFO] (highdicom.seg.sop) - add plane #9 for segment #1\n",
+ "[2023-08-30 00:58:47,378] [INFO] (highdicom.seg.sop) - add plane #10 for segment #1\n",
+ "[2023-08-30 00:58:47,379] [INFO] (highdicom.seg.sop) - add plane #11 for segment #1\n",
+ "[2023-08-30 00:58:47,380] [INFO] (highdicom.seg.sop) - add plane #12 for segment #1\n",
+ "[2023-08-30 00:58:47,381] [INFO] (highdicom.seg.sop) - add plane #13 for segment #1\n",
+ "[2023-08-30 00:58:47,382] [INFO] (highdicom.seg.sop) - add plane #14 for segment #1\n",
+ "[2023-08-30 00:58:47,382] [INFO] (highdicom.seg.sop) - add plane #15 for segment #1\n",
+ "[2023-08-30 00:58:47,383] [INFO] (highdicom.seg.sop) - add plane #16 for segment #1\n",
+ "[2023-08-30 00:58:47,384] [INFO] (highdicom.seg.sop) - add plane #17 for segment #1\n",
+ "[2023-08-30 00:58:47,385] [INFO] (highdicom.seg.sop) - add plane #18 for segment #1\n",
+ "[2023-08-30 00:58:47,385] [INFO] (highdicom.seg.sop) - add plane #19 for segment #1\n",
+ "[2023-08-30 00:58:47,386] [INFO] (highdicom.seg.sop) - add plane #20 for segment #1\n",
+ "[2023-08-30 00:58:47,387] [INFO] (highdicom.seg.sop) - add plane #21 for segment #1\n",
+ "[2023-08-30 00:58:47,387] [INFO] (highdicom.seg.sop) - add plane #22 for segment #1\n",
+ "[2023-08-30 00:58:47,388] [INFO] (highdicom.seg.sop) - add plane #23 for segment #1\n",
+ "[2023-08-30 00:58:47,389] [INFO] (highdicom.seg.sop) - add plane #24 for segment #1\n",
+ "[2023-08-30 00:58:47,390] [INFO] (highdicom.seg.sop) - add plane #25 for segment #1\n",
+ "[2023-08-30 00:58:47,390] [INFO] (highdicom.seg.sop) - add plane #26 for segment #1\n",
+ "[2023-08-30 00:58:47,391] [INFO] (highdicom.seg.sop) - add plane #27 for segment #1\n",
+ "[2023-08-30 00:58:47,392] [INFO] (highdicom.seg.sop) - add plane #28 for segment #1\n",
+ "[2023-08-30 00:58:47,393] [INFO] (highdicom.seg.sop) - add plane #29 for segment #1\n",
+ "[2023-08-30 00:58:47,393] [INFO] (highdicom.seg.sop) - add plane #30 for segment #1\n",
+ "[2023-08-30 00:58:47,394] [INFO] (highdicom.seg.sop) - add plane #31 for segment #1\n",
+ "[2023-08-30 00:58:47,395] [INFO] (highdicom.seg.sop) - add plane #32 for segment #1\n",
+ "[2023-08-30 00:58:47,396] [INFO] (highdicom.seg.sop) - add plane #33 for segment #1\n",
+ "[2023-08-30 00:58:47,397] [INFO] (highdicom.seg.sop) - add plane #34 for segment #1\n",
+ "[2023-08-30 00:58:47,398] [INFO] (highdicom.seg.sop) - add plane #35 for segment #1\n",
+ "[2023-08-30 00:58:47,399] [INFO] (highdicom.seg.sop) - add plane #36 for segment #1\n",
+ "[2023-08-30 00:58:47,400] [INFO] (highdicom.seg.sop) - add plane #37 for segment #1\n",
+ "[2023-08-30 00:58:47,401] [INFO] (highdicom.seg.sop) - add plane #38 for segment #1\n",
+ "[2023-08-30 00:58:47,401] [INFO] (highdicom.seg.sop) - add plane #39 for segment #1\n",
+ "[2023-08-30 00:58:47,402] [INFO] (highdicom.seg.sop) - add plane #40 for segment #1\n",
+ "[2023-08-30 00:58:47,403] [INFO] (highdicom.seg.sop) - add plane #41 for segment #1\n",
+ "[2023-08-30 00:58:47,403] [INFO] (highdicom.seg.sop) - add plane #42 for segment #1\n",
+ "[2023-08-30 00:58:47,404] [INFO] (highdicom.seg.sop) - add plane #43 for segment #1\n",
+ "[2023-08-30 00:58:47,404] [INFO] (highdicom.seg.sop) - add plane #44 for segment #1\n",
+ "[2023-08-30 00:58:47,405] [INFO] (highdicom.seg.sop) - add plane #45 for segment #1\n",
+ "[2023-08-30 00:58:47,405] [INFO] (highdicom.seg.sop) - add plane #46 for segment #1\n",
+ "[2023-08-30 00:58:47,406] [INFO] (highdicom.seg.sop) - add plane #47 for segment #1\n",
+ "[2023-08-30 00:58:47,407] [INFO] (highdicom.seg.sop) - add plane #48 for segment #1\n",
+ "[2023-08-30 00:58:47,407] [INFO] (highdicom.seg.sop) - add plane #49 for segment #1\n",
+ "[2023-08-30 00:58:47,408] [INFO] (highdicom.seg.sop) - add plane #50 for segment #1\n",
+ "[2023-08-30 00:58:47,409] [INFO] (highdicom.seg.sop) - add plane #51 for segment #1\n",
+ "[2023-08-30 00:58:47,410] [INFO] (highdicom.seg.sop) - add plane #52 for segment #1\n",
+ "[2023-08-30 00:58:47,410] [INFO] (highdicom.seg.sop) - add plane #53 for segment #1\n",
+ "[2023-08-30 00:58:47,411] [INFO] (highdicom.seg.sop) - add plane #54 for segment #1\n",
+ "[2023-08-30 00:58:47,411] [INFO] (highdicom.seg.sop) - add plane #55 for segment #1\n",
+ "[2023-08-30 00:58:47,412] [INFO] (highdicom.seg.sop) - add plane #56 for segment #1\n",
+ "[2023-08-30 00:58:47,413] [INFO] (highdicom.seg.sop) - add plane #57 for segment #1\n",
+ "[2023-08-30 00:58:47,413] [INFO] (highdicom.seg.sop) - add plane #58 for segment #1\n",
+ "[2023-08-30 00:58:47,414] [INFO] (highdicom.seg.sop) - add plane #59 for segment #1\n",
+ "[2023-08-30 00:58:47,414] [INFO] (highdicom.seg.sop) - add plane #60 for segment #1\n",
+ "[2023-08-30 00:58:47,415] [INFO] (highdicom.seg.sop) - add plane #61 for segment #1\n",
+ "[2023-08-30 00:58:47,415] [INFO] (highdicom.seg.sop) - add plane #62 for segment #1\n",
+ "[2023-08-30 00:58:47,416] [INFO] (highdicom.seg.sop) - add plane #63 for segment #1\n",
+ "[2023-08-30 00:58:47,417] [INFO] (highdicom.seg.sop) - add plane #64 for segment #1\n",
+ "[2023-08-30 00:58:47,417] [INFO] (highdicom.seg.sop) - add plane #65 for segment #1\n",
+ "[2023-08-30 00:58:47,418] [INFO] (highdicom.seg.sop) - add plane #66 for segment #1\n",
+ "[2023-08-30 00:58:47,418] [INFO] (highdicom.seg.sop) - add plane #67 for segment #1\n",
+ "[2023-08-30 00:58:47,419] [INFO] (highdicom.seg.sop) - add plane #68 for segment #1\n",
+ "[2023-08-30 00:58:47,420] [INFO] (highdicom.seg.sop) - add plane #69 for segment #1\n",
+ "[2023-08-30 00:58:47,420] [INFO] (highdicom.seg.sop) - add plane #70 for segment #1\n",
+ "[2023-08-30 00:58:47,421] [INFO] (highdicom.seg.sop) - add plane #71 for segment #1\n",
+ "[2023-08-30 00:58:47,421] [INFO] (highdicom.seg.sop) - add plane #72 for segment #1\n",
+ "[2023-08-30 00:58:47,422] [INFO] (highdicom.seg.sop) - add plane #73 for segment #1\n",
+ "[2023-08-30 00:58:47,423] [INFO] (highdicom.seg.sop) - add plane #74 for segment #1\n",
+ "[2023-08-30 00:58:47,423] [INFO] (highdicom.seg.sop) - add plane #75 for segment #1\n",
+ "[2023-08-30 00:58:47,424] [INFO] (highdicom.seg.sop) - add plane #76 for segment #1\n",
+ "[2023-08-30 00:58:47,424] [INFO] (highdicom.seg.sop) - add plane #77 for segment #1\n",
+ "[2023-08-30 00:58:47,425] [INFO] (highdicom.seg.sop) - add plane #78 for segment #1\n",
+ "[2023-08-30 00:58:47,426] [INFO] (highdicom.seg.sop) - add plane #79 for segment #1\n",
+ "[2023-08-30 00:58:47,426] [INFO] (highdicom.seg.sop) - add plane #80 for segment #1\n",
+ "[2023-08-30 00:58:47,427] [INFO] (highdicom.seg.sop) - add plane #81 for segment #1\n",
+ "[2023-08-30 00:58:47,428] [INFO] (highdicom.seg.sop) - add plane #82 for segment #1\n",
+ "[2023-08-30 00:58:47,429] [INFO] (highdicom.seg.sop) - add plane #83 for segment #1\n",
+ "[2023-08-30 00:58:47,430] [INFO] (highdicom.seg.sop) - add plane #84 for segment #1\n",
+ "[2023-08-30 00:58:47,430] [INFO] (highdicom.seg.sop) - add plane #85 for segment #1\n",
+ "[2023-08-30 00:58:47,431] [INFO] (highdicom.seg.sop) - add plane #86 for segment #1\n",
+ "[2023-08-30 00:58:47,432] [INFO] (highdicom.seg.sop) - add plane #87 for segment #1\n",
+ "[2023-08-30 00:58:47,528] [INFO] (highdicom.base) - copy Image-related attributes from dataset \"1.3.6.1.4.1.14519.5.2.1.7085.2626.936983343951485811186213470191\"\n",
+ "[2023-08-30 00:58:47,528] [INFO] (highdicom.base) - copy attributes of module \"Specimen\"\n",
+ "[2023-08-30 00:58:47,528] [INFO] (highdicom.base) - copy Patient-related attributes from dataset \"1.3.6.1.4.1.14519.5.2.1.7085.2626.936983343951485811186213470191\"\n",
+ "[2023-08-30 00:58:47,528] [INFO] (highdicom.base) - copy attributes of module \"Patient\"\n",
+ "[2023-08-30 00:58:47,529] [INFO] (highdicom.base) - copy attributes of module \"Clinical Trial Subject\"\n",
+ "[2023-08-30 00:58:47,529] [INFO] (highdicom.base) - copy Study-related attributes from dataset \"1.3.6.1.4.1.14519.5.2.1.7085.2626.936983343951485811186213470191\"\n",
+ "[2023-08-30 00:58:47,529] [INFO] (highdicom.base) - copy attributes of module \"General Study\"\n",
+ "[2023-08-30 00:58:47,529] [INFO] (highdicom.base) - copy attributes of module \"Patient Study\"\n",
+ "[2023-08-30 00:58:47,529] [INFO] (highdicom.base) - copy attributes of module \"Clinical Trial Study\"\n",
+ "[\u001b[32minfo\u001b[m] [greedy_scheduler.cpp:369] Scheduler stopped: Some entities are waiting for execution, but there are no periodic or async entities to get out of the deadlock.\n",
+ "[\u001b[32minfo\u001b[m] [greedy_scheduler.cpp:398] Scheduler finished.\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1783] Graph execution deactivating. Fragment: \n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1784] Deactivating Graph...\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:1787] Graph execution finished. Fragment: \n",
+ "[2023-08-30 00:58:47,626] [INFO] (app.AISpleenSegApp) - End run\n",
+ "[\u001b[32minfo\u001b[m] [gxf_executor.cpp:229] Destroying context\n"
+ ]
+ }
+ ],
+ "source": [
+ "!rm -rf $HOLOSCAN_OUTPUT_PATH\n",
+ "!python my_app"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "output:\n",
+ "1.2.826.0.1.3680043.10.511.3.70000117896150756142576971005940679.dcm\n",
+ "saved_images_folder\n",
+ "\n",
+ "output/saved_images_folder:\n",
+ "1.3.6.1.4.1.14519.5.2.1.7085.2626\n",
+ "\n",
+ "output/saved_images_folder/1.3.6.1.4.1.14519.5.2.1.7085.2626:\n",
+ "1.3.6.1.4.1.14519.5.2.1.7085.2626.nii\n",
+ "1.3.6.1.4.1.14519.5.2.1.7085.2626_seg.nii\n"
]
}
],
"source": [
- "!python my_app -i dcm -o output -m model.ts"
+ "!ls -R $HOLOSCAN_OUTPUT_PATH"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "Above command is same with the following command line:"
+ "## Packaging app"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Let's package the app with [MONAI Application Packager](/developing_with_sdk/packaging_app).\n",
+ "\n",
+ "In this version of the App SDK, we need to write out the configuration yaml file as well as the package requirements file, in the application folder."
]
},
{
"cell_type": "code",
- "execution_count": 13,
+ "execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "\u001b[34mGoing to initiate execution of operator DICOMDataLoaderOperator\u001b[39m\n",
- "\u001b[32mExecuting operator DICOMDataLoaderOperator \u001b[33m(Process ID: 411461, Operator ID: 638cc085-772b-440c-9b73-9a786bb50875)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator DICOMDataLoaderOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator DICOMSeriesSelectorOperator\u001b[39m\n",
- "\u001b[32mExecuting operator DICOMSeriesSelectorOperator \u001b[33m(Process ID: 411461, Operator ID: bcaa782b-e6b6-4259-b98f-e7ecf1d62c10)\u001b[39m\n",
- "[2023-07-11 14:44:13,012] [INFO] (root) - Finding series for Selection named: CT Series\n",
- "[2023-07-11 14:44:13,012] [INFO] (root) - Searching study, : 1.3.6.1.4.1.14519.5.2.1.7085.2626.822645453932810382886582736291\n",
- " # of series: 1\n",
- "[2023-07-11 14:44:13,012] [INFO] (root) - Working on series, instance UID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.119403521930927333027265674239\n",
- "[2023-07-11 14:44:13,012] [INFO] (root) - On attribute: 'StudyDescription' to match value: '(.*?)'\n",
- "[2023-07-11 14:44:13,012] [INFO] (root) - Series attribute StudyDescription value: CT ABDOMEN W IV CONTRAST\n",
- "[2023-07-11 14:44:13,012] [INFO] (root) - Series attribute string value did not match. Try regEx.\n",
- "[2023-07-11 14:44:13,012] [INFO] (root) - On attribute: 'Modality' to match value: '(?i)CT'\n",
- "[2023-07-11 14:44:13,012] [INFO] (root) - Series attribute Modality value: CT\n",
- "[2023-07-11 14:44:13,012] [INFO] (root) - Series attribute string value did not match. Try regEx.\n",
- "[2023-07-11 14:44:13,013] [INFO] (root) - On attribute: 'SeriesDescription' to match value: '(.*?)'\n",
- "[2023-07-11 14:44:13,013] [INFO] (root) - Series attribute SeriesDescription value: ABD/PANC 3.0 B31f\n",
- "[2023-07-11 14:44:13,013] [INFO] (root) - Series attribute string value did not match. Try regEx.\n",
- "[2023-07-11 14:44:13,013] [INFO] (root) - On attribute: 'ImageType' to match value: ['PRIMARY', 'ORIGINAL']\n",
- "[2023-07-11 14:44:13,013] [INFO] (root) - Series attribute ImageType value: None\n",
- "[2023-07-11 14:44:13,013] [INFO] (root) - Selected Series, UID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.119403521930927333027265674239\n",
- "\u001b[34mDone performing execution of operator DICOMSeriesSelectorOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator DICOMSeriesToVolumeOperator\u001b[39m\n",
- "\u001b[32mExecuting operator DICOMSeriesToVolumeOperator \u001b[33m(Process ID: 411461, Operator ID: 99760221-c8f0-4176-a6b6-8228d73c36fb)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator DICOMSeriesToVolumeOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator SpleenSegOperator\u001b[39m\n",
- "\u001b[32mExecuting operator SpleenSegOperator \u001b[33m(Process ID: 411461, Operator ID: bf5184b8-3e43-4c37-8bbd-aaf9d855602a)\u001b[39m\n",
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:321: FutureWarning: monai.transforms.io.dictionary LoadImaged.__init__:image_only: Current default value of argument `image_only=False` has been deprecated since version 1.1. It will be changed to `image_only=True` in version 1.3.\n",
- " warn_deprecated(argname, msg, warning_category)\n",
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:321: FutureWarning: monai.transforms.io.dictionary SaveImaged.__init__:resample: Current default value of argument `resample=True` has been deprecated since version 1.1. It will be changed to `resample=False` in version 1.3.\n",
- " warn_deprecated(argname, msg, warning_category)\n",
- "Converted Image object metadata:\n",
- "SeriesInstanceUID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.119403521930927333027265674239, type \n",
- "SeriesDate: 20090831, type \n",
- "SeriesTime: 101721.452, type \n",
- "Modality: CT, type \n",
- "SeriesDescription: ABD/PANC 3.0 B31f, type \n",
- "PatientPosition: HFS, type \n",
- "SeriesNumber: 8, type \n",
- "row_pixel_spacing: 0.7890625, type \n",
- "col_pixel_spacing: 0.7890625, type \n",
- "depth_pixel_spacing: 1.5, type \n",
- "row_direction_cosine: [1.0, 0.0, 0.0], type \n",
- "col_direction_cosine: [0.0, 1.0, 0.0], type \n",
- "depth_direction_cosine: [0.0, 0.0, 1.0], type \n",
- "dicom_affine_transform: [[ 0.7890625 0. 0. -197.60547 ]\n",
- " [ 0. 0.7890625 0. -398.60547 ]\n",
- " [ 0. 0. 1.5 -383. ]\n",
- " [ 0. 0. 0. 1. ]], type \n",
- "nifti_affine_transform: [[ -0.7890625 -0. -0. 197.60547 ]\n",
- " [ -0. -0.7890625 -0. 398.60547 ]\n",
- " [ 0. 0. 1.5 -383. ]\n",
- " [ 0. 0. 0. 1. ]], type \n",
- "StudyInstanceUID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.822645453932810382886582736291, type \n",
- "StudyID: , type \n",
- "StudyDate: 20090831, type \n",
- "StudyTime: 095948.599, type \n",
- "StudyDescription: CT ABDOMEN W IV CONTRAST, type \n",
- "AccessionNumber: 5471978513296937, type \n",
- "selection_name: CT Series, type \n",
- "2023-07-11 14:44:18,262 INFO image_writer.py:197 - writing: /home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/output/prediction_output/1.3.6.1.4.1.14519.5.2.1.7085.2626/1.3.6.1.4.1.14519.5.2.1.7085.2626_seg.nii.gz\n",
- "Output Seg image numpy array shaped: (204, 512, 512)\n",
- "Output Seg image pixel max value: 1\n",
- "Output Seg image pixel min value: 0\n",
- "\u001b[34mDone performing execution of operator SpleenSegOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator DICOMSegmentationWriterOperator\u001b[39m\n",
- "\u001b[32mExecuting operator DICOMSegmentationWriterOperator \u001b[33m(Process ID: 411461, Operator ID: 6288b216-c567-41cd-9347-0a71620e29a6)\u001b[39m\n",
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/highdicom/valuerep.py:54: UserWarning: The string \"C3N-00198\" is unlikely to represent the intended person name since it contains only a single component. Construct a person name according to the format in described in http://dicom.nema.org/dicom/2013/output/chtml/part05/sect_6.2.html#sect_6.2.1.2, or, in pydicom 2.2.0 or later, use the pydicom.valuerep.PersonName.from_named_components() method to construct the person name correctly. If a single-component name is really intended, add a trailing caret character to disambiguate the name.\n",
- " warnings.warn(\n",
- "[2023-07-11 14:44:22,408] [INFO] (highdicom.seg.sop) - add plane #0 for segment #1\n",
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/pydicom/valuerep.py:443: UserWarning: A value of type 'int64' cannot be assigned to a tag with VR UL.\n",
- " warnings.warn(msg)\n",
- "/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/pydicom/valuerep.py:443: UserWarning: A value of type 'int64' cannot be assigned to a tag with VR US.\n",
- " warnings.warn(msg)\n",
- "[2023-07-11 14:44:22,409] [INFO] (highdicom.seg.sop) - add plane #1 for segment #1\n",
- "[2023-07-11 14:44:22,410] [INFO] (highdicom.seg.sop) - add plane #2 for segment #1\n",
- "[2023-07-11 14:44:22,410] [INFO] (highdicom.seg.sop) - add plane #3 for segment #1\n",
- "[2023-07-11 14:44:22,411] [INFO] (highdicom.seg.sop) - add plane #4 for segment #1\n",
- "[2023-07-11 14:44:22,412] [INFO] (highdicom.seg.sop) - add plane #5 for segment #1\n",
- "[2023-07-11 14:44:22,412] [INFO] (highdicom.seg.sop) - add plane #6 for segment #1\n",
- "[2023-07-11 14:44:22,413] [INFO] (highdicom.seg.sop) - add plane #7 for segment #1\n",
- "[2023-07-11 14:44:22,414] [INFO] (highdicom.seg.sop) - add plane #8 for segment #1\n",
- "[2023-07-11 14:44:22,414] [INFO] (highdicom.seg.sop) - add plane #9 for segment #1\n",
- "[2023-07-11 14:44:22,415] [INFO] (highdicom.seg.sop) - add plane #10 for segment #1\n",
- "[2023-07-11 14:44:22,416] [INFO] (highdicom.seg.sop) - add plane #11 for segment #1\n",
- "[2023-07-11 14:44:22,416] [INFO] (highdicom.seg.sop) - add plane #12 for segment #1\n",
- "[2023-07-11 14:44:22,417] [INFO] (highdicom.seg.sop) - add plane #13 for segment #1\n",
- "[2023-07-11 14:44:22,418] [INFO] (highdicom.seg.sop) - add plane #14 for segment #1\n",
- "[2023-07-11 14:44:22,418] [INFO] (highdicom.seg.sop) - add plane #15 for segment #1\n",
- "[2023-07-11 14:44:22,419] [INFO] (highdicom.seg.sop) - add plane #16 for segment #1\n",
- "[2023-07-11 14:44:22,420] [INFO] (highdicom.seg.sop) - add plane #17 for segment #1\n",
- "[2023-07-11 14:44:22,420] [INFO] (highdicom.seg.sop) - add plane #18 for segment #1\n",
- "[2023-07-11 14:44:22,421] [INFO] (highdicom.seg.sop) - add plane #19 for segment #1\n",
- "[2023-07-11 14:44:22,422] [INFO] (highdicom.seg.sop) - add plane #20 for segment #1\n",
- "[2023-07-11 14:44:22,423] [INFO] (highdicom.seg.sop) - add plane #21 for segment #1\n",
- "[2023-07-11 14:44:22,424] [INFO] (highdicom.seg.sop) - add plane #22 for segment #1\n",
- "[2023-07-11 14:44:22,424] [INFO] (highdicom.seg.sop) - add plane #23 for segment #1\n",
- "[2023-07-11 14:44:22,425] [INFO] (highdicom.seg.sop) - add plane #24 for segment #1\n",
- "[2023-07-11 14:44:22,426] [INFO] (highdicom.seg.sop) - add plane #25 for segment #1\n",
- "[2023-07-11 14:44:22,426] [INFO] (highdicom.seg.sop) - add plane #26 for segment #1\n",
- "[2023-07-11 14:44:22,427] [INFO] (highdicom.seg.sop) - add plane #27 for segment #1\n",
- "[2023-07-11 14:44:22,428] [INFO] (highdicom.seg.sop) - add plane #28 for segment #1\n",
- "[2023-07-11 14:44:22,428] [INFO] (highdicom.seg.sop) - add plane #29 for segment #1\n",
- "[2023-07-11 14:44:22,429] [INFO] (highdicom.seg.sop) - add plane #30 for segment #1\n",
- "[2023-07-11 14:44:22,429] [INFO] (highdicom.seg.sop) - add plane #31 for segment #1\n",
- "[2023-07-11 14:44:22,430] [INFO] (highdicom.seg.sop) - add plane #32 for segment #1\n",
- "[2023-07-11 14:44:22,431] [INFO] (highdicom.seg.sop) - add plane #33 for segment #1\n",
- "[2023-07-11 14:44:22,432] [INFO] (highdicom.seg.sop) - add plane #34 for segment #1\n",
- "[2023-07-11 14:44:22,433] [INFO] (highdicom.seg.sop) - add plane #35 for segment #1\n",
- "[2023-07-11 14:44:22,433] [INFO] (highdicom.seg.sop) - add plane #36 for segment #1\n",
- "[2023-07-11 14:44:22,434] [INFO] (highdicom.seg.sop) - add plane #37 for segment #1\n",
- "[2023-07-11 14:44:22,435] [INFO] (highdicom.seg.sop) - add plane #38 for segment #1\n",
- "[2023-07-11 14:44:22,435] [INFO] (highdicom.seg.sop) - add plane #39 for segment #1\n",
- "[2023-07-11 14:44:22,436] [INFO] (highdicom.seg.sop) - add plane #40 for segment #1\n",
- "[2023-07-11 14:44:22,436] [INFO] (highdicom.seg.sop) - add plane #41 for segment #1\n",
- "[2023-07-11 14:44:22,437] [INFO] (highdicom.seg.sop) - add plane #42 for segment #1\n",
- "[2023-07-11 14:44:22,438] [INFO] (highdicom.seg.sop) - add plane #43 for segment #1\n",
- "[2023-07-11 14:44:22,438] [INFO] (highdicom.seg.sop) - add plane #44 for segment #1\n",
- "[2023-07-11 14:44:22,439] [INFO] (highdicom.seg.sop) - add plane #45 for segment #1\n",
- "[2023-07-11 14:44:22,440] [INFO] (highdicom.seg.sop) - add plane #46 for segment #1\n",
- "[2023-07-11 14:44:22,441] [INFO] (highdicom.seg.sop) - add plane #47 for segment #1\n",
- "[2023-07-11 14:44:22,442] [INFO] (highdicom.seg.sop) - add plane #48 for segment #1\n",
- "[2023-07-11 14:44:22,443] [INFO] (highdicom.seg.sop) - add plane #49 for segment #1\n",
- "[2023-07-11 14:44:22,443] [INFO] (highdicom.seg.sop) - add plane #50 for segment #1\n",
- "[2023-07-11 14:44:22,444] [INFO] (highdicom.seg.sop) - add plane #51 for segment #1\n",
- "[2023-07-11 14:44:22,445] [INFO] (highdicom.seg.sop) - add plane #52 for segment #1\n",
- "[2023-07-11 14:44:22,445] [INFO] (highdicom.seg.sop) - add plane #53 for segment #1\n",
- "[2023-07-11 14:44:22,446] [INFO] (highdicom.seg.sop) - add plane #54 for segment #1\n",
- "[2023-07-11 14:44:22,447] [INFO] (highdicom.seg.sop) - add plane #55 for segment #1\n",
- "[2023-07-11 14:44:22,447] [INFO] (highdicom.seg.sop) - add plane #56 for segment #1\n",
- "[2023-07-11 14:44:22,448] [INFO] (highdicom.seg.sop) - add plane #57 for segment #1\n",
- "[2023-07-11 14:44:22,449] [INFO] (highdicom.seg.sop) - add plane #58 for segment #1\n",
- "[2023-07-11 14:44:22,449] [INFO] (highdicom.seg.sop) - add plane #59 for segment #1\n",
- "[2023-07-11 14:44:22,450] [INFO] (highdicom.seg.sop) - add plane #60 for segment #1\n",
- "[2023-07-11 14:44:22,451] [INFO] (highdicom.seg.sop) - add plane #61 for segment #1\n",
- "[2023-07-11 14:44:22,452] [INFO] (highdicom.seg.sop) - add plane #62 for segment #1\n",
- "[2023-07-11 14:44:22,452] [INFO] (highdicom.seg.sop) - add plane #63 for segment #1\n",
- "[2023-07-11 14:44:22,453] [INFO] (highdicom.seg.sop) - add plane #64 for segment #1\n",
- "[2023-07-11 14:44:22,454] [INFO] (highdicom.seg.sop) - add plane #65 for segment #1\n",
- "[2023-07-11 14:44:22,454] [INFO] (highdicom.seg.sop) - add plane #66 for segment #1\n",
- "[2023-07-11 14:44:22,455] [INFO] (highdicom.seg.sop) - add plane #67 for segment #1\n",
- "[2023-07-11 14:44:22,456] [INFO] (highdicom.seg.sop) - add plane #68 for segment #1\n",
- "[2023-07-11 14:44:22,457] [INFO] (highdicom.seg.sop) - add plane #69 for segment #1\n",
- "[2023-07-11 14:44:22,457] [INFO] (highdicom.seg.sop) - add plane #70 for segment #1\n",
- "[2023-07-11 14:44:22,458] [INFO] (highdicom.seg.sop) - add plane #71 for segment #1\n",
- "[2023-07-11 14:44:22,459] [INFO] (highdicom.seg.sop) - add plane #72 for segment #1\n",
- "[2023-07-11 14:44:22,459] [INFO] (highdicom.seg.sop) - add plane #73 for segment #1\n",
- "[2023-07-11 14:44:22,460] [INFO] (highdicom.seg.sop) - add plane #74 for segment #1\n",
- "[2023-07-11 14:44:22,460] [INFO] (highdicom.seg.sop) - add plane #75 for segment #1\n",
- "[2023-07-11 14:44:22,461] [INFO] (highdicom.seg.sop) - add plane #76 for segment #1\n",
- "[2023-07-11 14:44:22,462] [INFO] (highdicom.seg.sop) - add plane #77 for segment #1\n",
- "[2023-07-11 14:44:22,462] [INFO] (highdicom.seg.sop) - add plane #78 for segment #1\n",
- "[2023-07-11 14:44:22,463] [INFO] (highdicom.seg.sop) - add plane #79 for segment #1\n",
- "[2023-07-11 14:44:22,464] [INFO] (highdicom.seg.sop) - add plane #80 for segment #1\n",
- "[2023-07-11 14:44:22,464] [INFO] (highdicom.seg.sop) - add plane #81 for segment #1\n",
- "[2023-07-11 14:44:22,465] [INFO] (highdicom.seg.sop) - add plane #82 for segment #1\n",
- "[2023-07-11 14:44:22,465] [INFO] (highdicom.seg.sop) - add plane #83 for segment #1\n",
- "[2023-07-11 14:44:22,466] [INFO] (highdicom.seg.sop) - add plane #84 for segment #1\n",
- "[2023-07-11 14:44:22,467] [INFO] (highdicom.seg.sop) - add plane #85 for segment #1\n",
- "[2023-07-11 14:44:22,467] [INFO] (highdicom.seg.sop) - add plane #86 for segment #1\n",
- "[2023-07-11 14:44:22,468] [INFO] (highdicom.seg.sop) - add plane #87 for segment #1\n",
- "[2023-07-11 14:44:22,468] [INFO] (highdicom.seg.sop) - add plane #88 for segment #1\n",
- "[2023-07-11 14:44:22,511] [INFO] (highdicom.base) - copy Image-related attributes from dataset \"1.3.6.1.4.1.14519.5.2.1.7085.2626.936983343951485811186213470191\"\n",
- "[2023-07-11 14:44:22,511] [INFO] (highdicom.base) - copy attributes of module \"Specimen\"\n",
- "[2023-07-11 14:44:22,511] [INFO] (highdicom.base) - copy Patient-related attributes from dataset \"1.3.6.1.4.1.14519.5.2.1.7085.2626.936983343951485811186213470191\"\n",
- "[2023-07-11 14:44:22,511] [INFO] (highdicom.base) - copy attributes of module \"Patient\"\n",
- "[2023-07-11 14:44:22,511] [INFO] (highdicom.base) - copy attributes of module \"Clinical Trial Subject\"\n",
- "[2023-07-11 14:44:22,511] [INFO] (highdicom.base) - copy Study-related attributes from dataset \"1.3.6.1.4.1.14519.5.2.1.7085.2626.936983343951485811186213470191\"\n",
- "[2023-07-11 14:44:22,511] [INFO] (highdicom.base) - copy attributes of module \"General Study\"\n",
- "[2023-07-11 14:44:22,511] [INFO] (highdicom.base) - copy attributes of module \"Patient Study\"\n",
- "[2023-07-11 14:44:22,512] [INFO] (highdicom.base) - copy attributes of module \"Clinical Trial Study\"\n",
- "\u001b[34mDone performing execution of operator DICOMSegmentationWriterOperator\n",
- "\u001b[39m\n"
+ "Writing my_app/app.yaml\n"
]
}
],
"source": [
- "import os\n",
- "os.environ['MKL_THREADING_LAYER'] = 'GNU'\n",
- "!monai-deploy exec my_app -i dcm -o output -m model.ts"
+ "%%writefile my_app/app.yaml\n",
+ "%YAML 1.2\n",
+ "---\n",
+ "application:\n",
+ " title: MONAI Deploy App Package - MONAI Bundle AI App\n",
+ " version: 1.0\n",
+ " inputFormats: [\"file\"]\n",
+ " outputFormats: [\"file\"]\n",
+ "\n",
+ "resources:\n",
+ " cpu: 1\n",
+ " gpu: 1\n",
+ " memory: 1Gi\n",
+ " gpuMemory: 6Gi"
]
},
{
"cell_type": "code",
- "execution_count": 14,
+ "execution_count": 16,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "1.2.826.0.1.3680043.10.511.3.10571558318884637420522234320485669.dcm\n",
- "1.2.826.0.1.3680043.10.511.3.12144237274469875262273877398595532.dcm\n",
- "1.2.826.0.1.3680043.10.511.3.15663327658863063131906751270244328.dcm\n",
- "prediction_output\n"
+ "Writing my_app/requirements.txt\n"
]
}
],
"source": [
- "!ls output"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Packaging app"
+ "%%writefile my_app/requirements.txt\n",
+ "highdicom>=0.18.2\n",
+ "monai>=1.0\n",
+ "nibabel>=3.2.1\n",
+ "numpy>=1.21.6\n",
+ "pydicom>=2.3.0\n",
+ "setuptools>=59.5.0 # for pkg_resources\n",
+ "SimpleITK>=2.0.0\n",
+ "torch>=1.12.0"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "Let's package the app with [MONAI Application Packager](/developing_with_sdk/packaging_app)."
+ "Now we can use the CLI package command to build the MONAI Application Package (MAP) container image based on a supported base image.\n",
+ "\n",
+ ":::{note}\n",
+ "Building a MONAI Application Package (Docker image) can take time. Use `-l DEBUG` option to see the progress.\n",
+ ":::"
]
},
{
"cell_type": "code",
- "execution_count": 15,
+ "execution_count": 21,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "Building MONAI Application Package... -\u001b[1A\u001b[1B\u001b[0G\u001b[?25l[+] Building 0.0s (0/1) \n",
- "\u001b[?25h\u001b[1A\u001b[0G\u001b[?25l[+] Building 0.1s (2/2) \n",
- "\u001b[34m => [internal] load .dockerignore 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build definition from dockerfile 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[?25\\\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 0.3s (4/19) \n",
- "\u001b[34m => [internal] load .dockerignore 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build definition from dockerfile 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m => [internal] load build context 0.1s\n",
- " => => transferring context: 23B 0.1s\n",
- "\u001b[?25|\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 0.4s (4/19) \n",
- "\u001b[34m => [internal] load .dockerignore 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build definition from dockerfile 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m => [internal] load build context 0.2s\n",
- "\u001b[34m => => transferring context: 19.90MB 0.2s\n",
- "\u001b[0m\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 0.6s (20/20) \n",
- "\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.3s\n",
- "\u001b[0m\u001b[34m => => transferring context: 19.90MB 0.2s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [11/15] RUN echo \"User site package location: $(python3 -m sit 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [12/15] COPY ./map/app.json /etc/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [13/15] COPY ./map/pkg.json /etc/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [14/15] COPY ./app /opt/monai/app 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [15/15] WORKDIR /var/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => exporting to image 0.0s\n",
- "\u001b[0m\u001b[34m => => exporting layers 0.0s\n",
- "\u001b[0m\u001b[34m => => writing image sha256:9485f50a4d6282edc928dd97251ffa765623ecf212846 0.0s\n",
- "\u001b[0m\u001b[34m => => naming to docker.io/library/my_app:latest 0.0s\n",
- "\u001b[0m\u001b[?25/\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Building 0.6s (20/20) FINISHED \n",
- "\u001b[34m => [internal] load .dockerignore 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring context: 1.11kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build definition from dockerfile 0.1s\n",
- "\u001b[0m\u001b[34m => => transferring dockerfile: 2.58kB 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s\n",
- "\u001b[0m\u001b[34m => [internal] load build context 0.3s\n",
- "\u001b[0m\u001b[34m => => transferring context: 19.90MB 0.2s\n",
- "\u001b[0m\u001b[34m => CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [11/15] RUN echo \"User site package location: $(python3 -m sit 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [12/15] COPY ./map/app.json /etc/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [13/15] COPY ./map/pkg.json /etc/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [14/15] COPY ./app /opt/monai/app 0.0s\n",
- "\u001b[0m\u001b[34m => CACHED [15/15] WORKDIR /var/monai/ 0.0s\n",
- "\u001b[0m\u001b[34m => exporting to image 0.0s\n",
- "\u001b[0m\u001b[34m => => exporting layers 0.0s\n",
- "\u001b[0m\u001b[34m => => writing image sha256:9485f50a4d6282edc928dd97251ffa765623ecf212846 0.0s\n",
- "\u001b[0m\u001b[34m => => naming to docker.io/library/my_app:latest 0.0s\n",
- "\u001b[0m\u001b[?25Done\n",
- "[2023-07-11 14:44:28,987] [INFO] (app_packager) - Successfully built my_app:latest\n"
+ "[2023-08-30 00:59:31,113] [INFO] (packager.parameters) - Application: /home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/my_app\n",
+ "[2023-08-30 00:59:31,114] [INFO] (packager.parameters) - Detected application type: Python Module\n",
+ "[2023-08-30 00:59:31,114] [INFO] (packager) - Scanning for models in {models_path}...\n",
+ "[2023-08-30 00:59:31,115] [DEBUG] (packager) - Model model=/home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/models/model added.\n",
+ "[2023-08-30 00:59:31,115] [INFO] (packager) - Reading application configuration from /home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/my_app/app.yaml...\n",
+ "[2023-08-30 00:59:31,117] [INFO] (packager) - Generating app.json...\n",
+ "[2023-08-30 00:59:31,117] [INFO] (packager) - Generating pkg.json...\n",
+ "[2023-08-30 00:59:31,118] [DEBUG] (common) - \n",
+ "=============== Begin app.json ===============\n",
+ "{\n",
+ " \"apiVersion\": \"1.0.0\",\n",
+ " \"command\": \"[\\\"python3\\\", \\\"/opt/holoscan/app\\\"]\",\n",
+ " \"environment\": {\n",
+ " \"HOLOSCAN_APPLICATION\": \"/opt/holoscan/app\",\n",
+ " \"HOLOSCAN_INPUT_PATH\": \"input/\",\n",
+ " \"HOLOSCAN_OUTPUT_PATH\": \"output/\",\n",
+ " \"HOLOSCAN_WORKDIR\": \"/var/holoscan\",\n",
+ " \"HOLOSCAN_MODEL_PATH\": \"/opt/holoscan/models\",\n",
+ " \"HOLOSCAN_CONFIG_PATH\": \"/var/holoscan/app.yaml\",\n",
+ " \"HOLOSCAN_APP_MANIFEST_PATH\": \"/etc/holoscan/app.json\",\n",
+ " \"HOLOSCAN_PKG_MANIFEST_PATH\": \"/etc/holoscan/pkg.json\",\n",
+ " \"HOLOSCAN_DOCS_PATH\": \"/opt/holoscan/docs\",\n",
+ " \"HOLOSCAN_LOGS_PATH\": \"/var/holoscan/logs\"\n",
+ " },\n",
+ " \"input\": {\n",
+ " \"path\": \"input/\",\n",
+ " \"formats\": null\n",
+ " },\n",
+ " \"liveness\": null,\n",
+ " \"output\": {\n",
+ " \"path\": \"output/\",\n",
+ " \"formats\": null\n",
+ " },\n",
+ " \"readiness\": null,\n",
+ " \"sdk\": \"monai-deploy\",\n",
+ " \"sdkVersion\": \"0.6.0\",\n",
+ " \"timeout\": 0,\n",
+ " \"version\": 1.0,\n",
+ " \"workingDirectory\": \"/var/holoscan\"\n",
+ "}\n",
+ "================ End app.json ================\n",
+ " \n",
+ "[2023-08-30 00:59:31,118] [DEBUG] (common) - \n",
+ "=============== Begin pkg.json ===============\n",
+ "{\n",
+ " \"apiVersion\": \"1.0.0\",\n",
+ " \"applicationRoot\": \"/opt/holoscan/app\",\n",
+ " \"modelRoot\": \"/opt/holoscan/models\",\n",
+ " \"models\": {\n",
+ " \"model\": \"/opt/holoscan/models\"\n",
+ " },\n",
+ " \"resources\": {\n",
+ " \"cpu\": 1,\n",
+ " \"gpu\": 1,\n",
+ " \"memory\": \"1Gi\",\n",
+ " \"gpuMemory\": \"6Gi\"\n",
+ " },\n",
+ " \"version\": 1.0\n",
+ "}\n",
+ "================ End pkg.json ================\n",
+ " \n",
+ "[2023-08-30 00:59:31,179] [DEBUG] (packager.builder) - \n",
+ "========== Begin Dockerfile ==========\n",
+ "\n",
+ "\n",
+ "FROM nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu\n",
+ "\n",
+ "ENV DEBIAN_FRONTEND=noninteractive\n",
+ "ENV TERM=xterm-256color\n",
+ "\n",
+ "ARG UNAME\n",
+ "ARG UID\n",
+ "ARG GID\n",
+ "\n",
+ "RUN mkdir -p /etc/holoscan/ \\\n",
+ " && mkdir -p /opt/holoscan/ \\\n",
+ " && mkdir -p /var/holoscan \\\n",
+ " && mkdir -p /opt/holoscan/app \\\n",
+ " && mkdir -p /var/holoscan/input \\\n",
+ " && mkdir -p /var/holoscan/output\n",
+ "\n",
+ "LABEL base=\"nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu\"\n",
+ "LABEL tag=\"my_app:1.0\"\n",
+ "LABEL org.opencontainers.image.title=\"MONAI Deploy App Package - MONAI Bundle AI App\"\n",
+ "LABEL org.opencontainers.image.version=\"1.0\"\n",
+ "LABEL org.nvidia.holoscan=\"0.6.0\"\n",
+ "\n",
+ "ENV HOLOSCAN_ENABLE_HEALTH_CHECK=true\n",
+ "ENV HOLOSCAN_INPUT_PATH=/var/holoscan/input\n",
+ "ENV HOLOSCAN_OUTPUT_PATH=/var/holoscan/output\n",
+ "ENV HOLOSCAN_WORKDIR=/var/holoscan\n",
+ "ENV HOLOSCAN_APPLICATION=/opt/holoscan/app\n",
+ "ENV HOLOSCAN_TIMEOUT=0\n",
+ "ENV HOLOSCAN_MODEL_PATH=/opt/holoscan/models\n",
+ "ENV HOLOSCAN_DOCS_PATH=/opt/holoscan/docs\n",
+ "ENV HOLOSCAN_CONFIG_PATH=/var/holoscan/app.yaml\n",
+ "ENV HOLOSCAN_APP_MANIFEST_PATH=/etc/holoscan/app.json\n",
+ "ENV HOLOSCAN_PKG_MANIFEST_PATH=/etc/holoscan/pkg.json\n",
+ "ENV HOLOSCAN_LOGS_PATH=/var/holoscan/logs\n",
+ "ENV PATH=/root/.local/bin:/opt/nvidia/holoscan:$PATH\n",
+ "ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/libtorch/1.13.1/lib/:/opt/nvidia/holoscan/lib\n",
+ "\n",
+ "RUN apt-get update \\\n",
+ " && apt-get install -y curl jq \\\n",
+ " && rm -rf /var/lib/apt/lists/*\n",
+ "\n",
+ "ENV PYTHONPATH=\"/opt/holoscan/app:$PYTHONPATH\"\n",
+ "\n",
+ "\n",
+ "\n",
+ "RUN groupadd -g $GID $UNAME\n",
+ "RUN useradd -rm -d /home/$UNAME -s /bin/bash -g $GID -G sudo -u $UID $UNAME\n",
+ "RUN chown -R holoscan /var/holoscan \n",
+ "RUN chown -R holoscan /var/holoscan/input \n",
+ "RUN chown -R holoscan /var/holoscan/output \n",
+ "\n",
+ "# Set the working directory\n",
+ "WORKDIR /var/holoscan\n",
+ "\n",
+ "# Copy HAP/MAP tool script\n",
+ "COPY ./tools /var/holoscan/tools\n",
+ "RUN chmod +x /var/holoscan/tools\n",
+ "\n",
+ "\n",
+ "# Copy gRPC health probe\n",
+ "\n",
+ "USER $UNAME\n",
+ "\n",
+ "ENV PATH=/root/.local/bin:/home/holoscan/.local/bin:/opt/nvidia/holoscan:$PATH\n",
+ "\n",
+ "COPY ./pip/requirements.txt /tmp/requirements.txt\n",
+ "\n",
+ "RUN pip install --upgrade pip\n",
+ "RUN pip install --no-cache-dir --user -r /tmp/requirements.txt\n",
+ "\n",
+ "# Install Holoscan from PyPI org\n",
+ "RUN pip install holoscan==0.6.0\n",
+ "\n",
+ "\n",
+ "# Copy user-specified MONAI Deploy SDK file\n",
+ "COPY ./monai_deploy_app_sdk-0.5.1+22.g029f8bc.dirty-py3-none-any.whl /tmp/monai_deploy_app_sdk-0.5.1+22.g029f8bc.dirty-py3-none-any.whl\n",
+ "RUN pip install /tmp/monai_deploy_app_sdk-0.5.1+22.g029f8bc.dirty-py3-none-any.whl\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "COPY ./models /opt/holoscan/models\n",
+ "\n",
+ "COPY ./map/app.json /etc/holoscan/app.json\n",
+ "COPY ./app.config /var/holoscan/app.yaml\n",
+ "COPY ./map/pkg.json /etc/holoscan/pkg.json\n",
+ "\n",
+ "COPY ./app /opt/holoscan/app\n",
+ "\n",
+ "ENTRYPOINT [\"/var/holoscan/tools\"]\n",
+ "=========== End Dockerfile ===========\n",
+ "\n",
+ "[2023-08-30 00:59:31,179] [INFO] (packager.builder) - \n",
+ "===============================================================================\n",
+ "Building image for: x64-workstation\n",
+ " Architecture: linux/amd64\n",
+ " Base Image: nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu\n",
+ " Build Image: N/A \n",
+ " Cache: Enabled\n",
+ " Configuration: dgpu\n",
+ " Holoiscan SDK Package: pypi.org\n",
+ " MONAI Deploy App SDK Package: /home/mqin/src/monai-deploy-app-sdk/dist/monai_deploy_app_sdk-0.5.1+22.g029f8bc.dirty-py3-none-any.whl\n",
+ " gRPC Health Probe: N/A\n",
+ " SDK Version: 0.6.0\n",
+ " SDK: monai-deploy\n",
+ " Tag: my_app-x64-workstation-dgpu-linux-amd64:1.0\n",
+ " \n",
+ "[2023-08-30 00:59:31,807] [INFO] (common) - Using existing Docker BuildKit builder `holoscan_app_builder`\n",
+ "[2023-08-30 00:59:31,808] [DEBUG] (packager.builder) - Building Holoscan Application Package: tag=my_app-x64-workstation-dgpu-linux-amd64:1.0\n",
+ "#1 [internal] load build definition from Dockerfile\n",
+ "#1 transferring dockerfile: 2.67kB done\n",
+ "#1 DONE 0.1s\n",
+ "\n",
+ "#2 [internal] load .dockerignore\n",
+ "#2 transferring context: 1.79kB 0.0s done\n",
+ "#2 DONE 0.1s\n",
+ "\n",
+ "#3 [internal] load metadata for nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu\n",
+ "#3 DONE 0.6s\n",
+ "\n",
+ "#4 [internal] load build context\n",
+ "#4 DONE 0.0s\n",
+ "\n",
+ "#5 importing cache manifest from local:8636426000862419753\n",
+ "#5 DONE 0.0s\n",
+ "\n",
+ "#6 [ 1/22] FROM nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu@sha256:9653f80f241fd542f25afbcbcf7a0d02ed7e5941c79763e69def5b1e6d9fb7bc\n",
+ "#6 resolve nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu@sha256:9653f80f241fd542f25afbcbcf7a0d02ed7e5941c79763e69def5b1e6d9fb7bc 0.0s done\n",
+ "#6 DONE 0.0s\n",
+ "\n",
+ "#7 importing cache manifest from nvcr.io/nvidia/clara-holoscan/holoscan:v0.6.0-dgpu\n",
+ "#7 DONE 0.9s\n",
+ "\n",
+ "#4 [internal] load build context\n",
+ "#4 transferring context: 19.57MB 0.1s done\n",
+ "#4 DONE 0.2s\n",
+ "\n",
+ "#8 [ 7/22] RUN chown -R holoscan /var/holoscan/input\n",
+ "#8 CACHED\n",
+ "\n",
+ "#9 [12/22] COPY ./pip/requirements.txt /tmp/requirements.txt\n",
+ "#9 CACHED\n",
+ "\n",
+ "#10 [10/22] COPY ./tools /var/holoscan/tools\n",
+ "#10 CACHED\n",
+ "\n",
+ "#11 [14/22] RUN pip install --no-cache-dir --user -r /tmp/requirements.txt\n",
+ "#11 CACHED\n",
+ "\n",
+ "#12 [ 5/22] RUN useradd -rm -d /home/holoscan -s /bin/bash -g 1000 -G sudo -u 1000 holoscan\n",
+ "#12 CACHED\n",
+ "\n",
+ "#13 [13/22] RUN pip install --upgrade pip\n",
+ "#13 CACHED\n",
+ "\n",
+ "#14 [ 6/22] RUN chown -R holoscan /var/holoscan\n",
+ "#14 CACHED\n",
+ "\n",
+ "#15 [ 9/22] WORKDIR /var/holoscan\n",
+ "#15 CACHED\n",
+ "\n",
+ "#16 [ 4/22] RUN groupadd -g 1000 holoscan\n",
+ "#16 CACHED\n",
+ "\n",
+ "#17 [ 3/22] RUN apt-get update && apt-get install -y curl jq && rm -rf /var/lib/apt/lists/*\n",
+ "#17 CACHED\n",
+ "\n",
+ "#18 [ 8/22] RUN chown -R holoscan /var/holoscan/output\n",
+ "#18 CACHED\n",
+ "\n",
+ "#19 [ 2/22] RUN mkdir -p /etc/holoscan/ && mkdir -p /opt/holoscan/ && mkdir -p /var/holoscan && mkdir -p /opt/holoscan/app && mkdir -p /var/holoscan/input && mkdir -p /var/holoscan/output\n",
+ "#19 CACHED\n",
+ "\n",
+ "#20 [11/22] RUN chmod +x /var/holoscan/tools\n",
+ "#20 CACHED\n",
+ "\n",
+ "#21 [15/22] RUN pip install holoscan==0.6.0\n",
+ "#21 CACHED\n",
+ "\n",
+ "#22 [16/22] COPY ./monai_deploy_app_sdk-0.5.1+22.g029f8bc.dirty-py3-none-any.whl /tmp/monai_deploy_app_sdk-0.5.1+22.g029f8bc.dirty-py3-none-any.whl\n",
+ "#22 DONE 0.3s\n",
+ "\n",
+ "#23 [17/22] RUN pip install /tmp/monai_deploy_app_sdk-0.5.1+22.g029f8bc.dirty-py3-none-any.whl\n",
+ "#23 0.878 Defaulting to user installation because normal site-packages is not writeable\n",
+ "#23 0.949 Processing /tmp/monai_deploy_app_sdk-0.5.1+22.g029f8bc.dirty-py3-none-any.whl\n",
+ "#23 1.347 Collecting numpy>=1.21.6 (from monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty)\n",
+ "#23 1.347 Obtaining dependency information for numpy>=1.21.6 from https://files.pythonhosted.org/packages/98/5d/5738903efe0ecb73e51eb44feafba32bdba2081263d40c5043568ff60faf/numpy-1.24.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata\n",
+ "#23 1.394 Downloading numpy-1.24.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (5.6 kB)\n",
+ "#23 1.409 Requirement already satisfied: networkx>=2.4 in /home/holoscan/.local/lib/python3.8/site-packages (from monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty) (3.1)\n",
+ "#23 1.411 Requirement already satisfied: holoscan>=0.5.0 in /home/holoscan/.local/lib/python3.8/site-packages (from monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty) (0.6.0)\n",
+ "#23 1.475 Collecting colorama>=0.4.1 (from monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty)\n",
+ "#23 1.484 Downloading colorama-0.4.6-py2.py3-none-any.whl (25 kB)\n",
+ "#23 1.557 Collecting typeguard>=3.0.0 (from monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty)\n",
+ "#23 1.557 Obtaining dependency information for typeguard>=3.0.0 from https://files.pythonhosted.org/packages/84/99/bfa960dcc0386e240f823f7f4b1b028a18126a72216febf892f84b872444/typeguard-4.1.3-py3-none-any.whl.metadata\n",
+ "#23 1.566 Downloading typeguard-4.1.3-py3-none-any.whl.metadata (3.7 kB)\n",
+ "#23 1.634 Collecting cloudpickle~=2.2 (from holoscan>=0.5.0->monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty)\n",
+ "#23 1.642 Downloading cloudpickle-2.2.1-py3-none-any.whl (25 kB)\n",
+ "#23 1.738 Collecting python-on-whales~=0.60 (from holoscan>=0.5.0->monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty)\n",
+ "#23 1.738 Obtaining dependency information for python-on-whales~=0.60 from https://files.pythonhosted.org/packages/b1/3b/84494b632d8964e51cb06db89988f2155e1ea62537ba0d70d974fc2a8967/python_on_whales-0.64.2-py3-none-any.whl.metadata\n",
+ "#23 1.751 Downloading python_on_whales-0.64.2-py3-none-any.whl.metadata (16 kB)\n",
+ "#23 1.825 Collecting Jinja2~=3.1 (from holoscan>=0.5.0->monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty)\n",
+ "#23 1.835 Downloading Jinja2-3.1.2-py3-none-any.whl (133 kB)\n",
+ "#23 1.854 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 133.1/133.1 kB 8.7 MB/s eta 0:00:00\n",
+ "#23 1.914 Collecting packaging~=23.1 (from holoscan>=0.5.0->monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty)\n",
+ "#23 1.923 Downloading packaging-23.1-py3-none-any.whl (48 kB)\n",
+ "#23 1.936 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 48.9/48.9 kB 3.9 MB/s eta 0:00:00\n",
+ "#23 2.019 Collecting pyyaml~=6.0 (from holoscan>=0.5.0->monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty)\n",
+ "#23 2.019 Obtaining dependency information for pyyaml~=6.0 from https://files.pythonhosted.org/packages/c8/6b/6600ac24725c7388255b2f5add93f91e58a5d7efaf4af244fdbcc11a541b/PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata\n",
+ "#23 2.035 Downloading PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (2.1 kB)\n",
+ "#23 2.116 Collecting requests~=2.28 (from holoscan>=0.5.0->monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty)\n",
+ "#23 2.117 Obtaining dependency information for requests~=2.28 from https://files.pythonhosted.org/packages/70/8e/0e2d847013cb52cd35b38c009bb167a1a26b2ce6cd6965bf26b47bc0bf44/requests-2.31.0-py3-none-any.whl.metadata\n",
+ "#23 2.125 Downloading requests-2.31.0-py3-none-any.whl.metadata (4.6 kB)\n",
+ "#23 2.134 Requirement already satisfied: pip>=20.2 in /home/holoscan/.local/lib/python3.8/site-packages (from holoscan>=0.5.0->monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty) (23.2.1)\n",
+ "#23 2.135 Requirement already satisfied: wheel-axle-runtime<1.0 in /home/holoscan/.local/lib/python3.8/site-packages (from holoscan>=0.5.0->monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty) (0.0.4)\n",
+ "#23 2.253 Collecting importlib-metadata>=3.6 (from typeguard>=3.0.0->monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty)\n",
+ "#23 2.254 Obtaining dependency information for importlib-metadata>=3.6 from https://files.pythonhosted.org/packages/cc/37/db7ba97e676af155f5fcb1a35466f446eadc9104e25b83366e8088c9c926/importlib_metadata-6.8.0-py3-none-any.whl.metadata\n",
+ "#23 2.262 Downloading importlib_metadata-6.8.0-py3-none-any.whl.metadata (5.1 kB)\n",
+ "#23 2.317 Collecting typing-extensions>=4.7.0 (from typeguard>=3.0.0->monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty)\n",
+ "#23 2.318 Obtaining dependency information for typing-extensions>=4.7.0 from https://files.pythonhosted.org/packages/ec/6b/63cc3df74987c36fe26157ee12e09e8f9db4de771e0f3404263117e75b95/typing_extensions-4.7.1-py3-none-any.whl.metadata\n",
+ "#23 2.331 Downloading typing_extensions-4.7.1-py3-none-any.whl.metadata (3.1 kB)\n",
+ "#23 2.365 Requirement already satisfied: zipp>=0.5 in /home/holoscan/.local/lib/python3.8/site-packages (from importlib-metadata>=3.6->typeguard>=3.0.0->monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty) (3.16.2)\n",
+ "#23 2.458 Collecting MarkupSafe>=2.0 (from Jinja2~=3.1->holoscan>=0.5.0->monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty)\n",
+ "#23 2.459 Obtaining dependency information for MarkupSafe>=2.0 from https://files.pythonhosted.org/packages/de/e2/32c14301bb023986dff527a49325b6259cab4ebb4633f69de54af312fc45/MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata\n",
+ "#23 2.467 Downloading MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (3.0 kB)\n",
+ "#23 2.706 Collecting pydantic!=2.0.*,<3,>=1.5 (from python-on-whales~=0.60->holoscan>=0.5.0->monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty)\n",
+ "#23 2.707 Obtaining dependency information for pydantic!=2.0.*,<3,>=1.5 from https://files.pythonhosted.org/packages/82/06/fafdc75e48b248eff364b4249af4bcc6952225e8f20e8205820afc66e88e/pydantic-2.3.0-py3-none-any.whl.metadata\n",
+ "#23 2.720 Downloading pydantic-2.3.0-py3-none-any.whl.metadata (148 kB)\n",
+ "#23 2.734 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 148.8/148.8 kB 14.8 MB/s eta 0:00:00\n",
+ "#23 2.832 Collecting tqdm (from python-on-whales~=0.60->holoscan>=0.5.0->monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty)\n",
+ "#23 2.832 Obtaining dependency information for tqdm from https://files.pythonhosted.org/packages/00/e5/f12a80907d0884e6dff9c16d0c0114d81b8cd07dc3ae54c5e962cc83037e/tqdm-4.66.1-py3-none-any.whl.metadata\n",
+ "#23 2.840 Downloading tqdm-4.66.1-py3-none-any.whl.metadata (57 kB)\n",
+ "#23 2.856 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 57.6/57.6 kB 4.5 MB/s eta 0:00:00\n",
+ "#23 2.926 Collecting typer>=0.4.1 (from python-on-whales~=0.60->holoscan>=0.5.0->monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty)\n",
+ "#23 2.933 Downloading typer-0.9.0-py3-none-any.whl (45 kB)\n",
+ "#23 2.945 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 45.9/45.9 kB 4.4 MB/s eta 0:00:00\n",
+ "#23 3.107 Collecting charset-normalizer<4,>=2 (from requests~=2.28->holoscan>=0.5.0->monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty)\n",
+ "#23 3.107 Obtaining dependency information for charset-normalizer<4,>=2 from https://files.pythonhosted.org/packages/cb/e7/5e43745003bf1f90668c7be23fc5952b3a2b9c2558f16749411c18039b36/charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata\n",
+ "#23 3.115 Downloading charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (31 kB)\n",
+ "#23 3.166 Collecting idna<4,>=2.5 (from requests~=2.28->holoscan>=0.5.0->monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty)\n",
+ "#23 3.174 Downloading idna-3.4-py3-none-any.whl (61 kB)\n",
+ "#23 3.186 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 61.5/61.5 kB 6.2 MB/s eta 0:00:00\n",
+ "#23 3.254 Collecting urllib3<3,>=1.21.1 (from requests~=2.28->holoscan>=0.5.0->monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty)\n",
+ "#23 3.254 Obtaining dependency information for urllib3<3,>=1.21.1 from https://files.pythonhosted.org/packages/9b/81/62fd61001fa4b9d0df6e31d47ff49cfa9de4af03adecf339c7bc30656b37/urllib3-2.0.4-py3-none-any.whl.metadata\n",
+ "#23 3.264 Downloading urllib3-2.0.4-py3-none-any.whl.metadata (6.6 kB)\n",
+ "#23 3.326 Collecting certifi>=2017.4.17 (from requests~=2.28->holoscan>=0.5.0->monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty)\n",
+ "#23 3.326 Obtaining dependency information for certifi>=2017.4.17 from https://files.pythonhosted.org/packages/4c/dd/2234eab22353ffc7d94e8d13177aaa050113286e93e7b40eae01fbf7c3d9/certifi-2023.7.22-py3-none-any.whl.metadata\n",
+ "#23 3.334 Downloading certifi-2023.7.22-py3-none-any.whl.metadata (2.2 kB)\n",
+ "#23 3.352 Requirement already satisfied: filelock in /home/holoscan/.local/lib/python3.8/site-packages (from wheel-axle-runtime<1.0->holoscan>=0.5.0->monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty) (3.12.2)\n",
+ "#23 3.415 Collecting annotated-types>=0.4.0 (from pydantic!=2.0.*,<3,>=1.5->python-on-whales~=0.60->holoscan>=0.5.0->monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty)\n",
+ "#23 3.415 Obtaining dependency information for annotated-types>=0.4.0 from https://files.pythonhosted.org/packages/d8/f0/a2ee543a96cc624c35a9086f39b1ed2aa403c6d355dfe47a11ee5c64a164/annotated_types-0.5.0-py3-none-any.whl.metadata\n",
+ "#23 3.423 Downloading annotated_types-0.5.0-py3-none-any.whl.metadata (11 kB)\n",
+ "#23 4.197 Collecting pydantic-core==2.6.3 (from pydantic!=2.0.*,<3,>=1.5->python-on-whales~=0.60->holoscan>=0.5.0->monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty)\n",
+ "#23 4.198 Obtaining dependency information for pydantic-core==2.6.3 from https://files.pythonhosted.org/packages/b0/88/43c79099fe0bcf6680c0782eb1b08069f024a08e114121b6704c9b26355a/pydantic_core-2.6.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata\n",
+ "#23 4.208 Downloading pydantic_core-2.6.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (6.5 kB)\n",
+ "#23 4.301 Collecting click<9.0.0,>=7.1.1 (from typer>=0.4.1->python-on-whales~=0.60->holoscan>=0.5.0->monai-deploy-app-sdk==0.5.1+22.g029f8bc.dirty)\n",
+ "#23 4.301 Obtaining dependency information for click<9.0.0,>=7.1.1 from https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl.metadata\n",
+ "#23 4.309 Downloading click-8.1.7-py3-none-any.whl.metadata (3.0 kB)\n",
+ "#23 4.455 Downloading numpy-1.24.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (17.3 MB)\n",
+ "#23 4.699 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 17.3/17.3 MB 57.3 MB/s eta 0:00:00\n",
+ "#23 4.709 Downloading typeguard-4.1.3-py3-none-any.whl (33 kB)\n",
+ "#23 4.725 Downloading importlib_metadata-6.8.0-py3-none-any.whl (22 kB)\n",
+ "#23 4.748 Downloading python_on_whales-0.64.2-py3-none-any.whl (104 kB)\n",
+ "#23 4.763 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 104.9/104.9 kB 9.1 MB/s eta 0:00:00\n",
+ "#23 4.776 Downloading PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (736 kB)\n",
+ "#23 4.803 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 736.6/736.6 kB 32.5 MB/s eta 0:00:00\n",
+ "#23 4.812 Downloading requests-2.31.0-py3-none-any.whl (62 kB)\n",
+ "#23 4.823 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 62.6/62.6 kB 6.3 MB/s eta 0:00:00\n",
+ "#23 4.836 Downloading typing_extensions-4.7.1-py3-none-any.whl (33 kB)\n",
+ "#23 4.867 Downloading certifi-2023.7.22-py3-none-any.whl (158 kB)\n",
+ "#23 4.879 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 158.3/158.3 kB 15.7 MB/s eta 0:00:00\n",
+ "#23 4.896 Downloading charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (199 kB)\n",
+ "#23 4.909 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 199.1/199.1 kB 19.5 MB/s eta 0:00:00\n",
+ "#23 4.917 Downloading MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (25 kB)\n",
+ "#23 4.944 Downloading pydantic-2.3.0-py3-none-any.whl (374 kB)\n",
+ "#23 4.958 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 374.5/374.5 kB 31.9 MB/s eta 0:00:00\n",
+ "#23 4.982 Downloading pydantic_core-2.6.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.9 MB)\n",
+ "#23 5.022 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.9/1.9 MB 51.7 MB/s eta 0:00:00\n",
+ "#23 5.032 Downloading urllib3-2.0.4-py3-none-any.whl (123 kB)\n",
+ "#23 5.047 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 123.9/123.9 kB 10.8 MB/s eta 0:00:00\n",
+ "#23 5.061 Downloading tqdm-4.66.1-py3-none-any.whl (78 kB)\n",
+ "#23 5.074 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 78.3/78.3 kB 7.8 MB/s eta 0:00:00\n",
+ "#23 5.082 Downloading annotated_types-0.5.0-py3-none-any.whl (11 kB)\n",
+ "#23 5.098 Downloading click-8.1.7-py3-none-any.whl (97 kB)\n",
+ "#23 5.109 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 97.9/97.9 kB 10.0 MB/s eta 0:00:00\n",
+ "#23 5.502 Installing collected packages: urllib3, typing-extensions, tqdm, pyyaml, packaging, numpy, MarkupSafe, importlib-metadata, idna, colorama, cloudpickle, click, charset-normalizer, certifi, typer, typeguard, requests, pydantic-core, Jinja2, annotated-types, pydantic, python-on-whales, monai-deploy-app-sdk\n",
+ "#23 8.455 Successfully installed Jinja2-3.1.2 MarkupSafe-2.1.3 annotated-types-0.5.0 certifi-2023.7.22 charset-normalizer-3.2.0 click-8.1.7 cloudpickle-2.2.1 colorama-0.4.6 idna-3.4 importlib-metadata-6.8.0 monai-deploy-app-sdk-0.5.1+22.g029f8bc.dirty numpy-1.24.4 packaging-23.1 pydantic-2.3.0 pydantic-core-2.6.3 python-on-whales-0.64.2 pyyaml-6.0.1 requests-2.31.0 tqdm-4.66.1 typeguard-4.1.3 typer-0.9.0 typing-extensions-4.7.1 urllib3-2.0.4\n",
+ "#23 DONE 9.2s\n",
+ "\n",
+ "#24 [18/22] COPY ./models /opt/holoscan/models\n",
+ "#24 DONE 0.2s\n",
+ "\n",
+ "#25 [19/22] COPY ./map/app.json /etc/holoscan/app.json\n",
+ "#25 DONE 0.1s\n",
+ "\n",
+ "#26 [20/22] COPY ./app.config /var/holoscan/app.yaml\n",
+ "#26 DONE 0.1s\n",
+ "\n",
+ "#27 [21/22] COPY ./map/pkg.json /etc/holoscan/pkg.json\n",
+ "#27 DONE 0.1s\n",
+ "\n",
+ "#28 [22/22] COPY ./app /opt/holoscan/app\n",
+ "#28 DONE 0.1s\n",
+ "\n",
+ "#29 exporting to docker image format\n",
+ "#29 exporting layers\n",
+ "#29 exporting layers 3.9s done\n",
+ "#29 exporting manifest sha256:f5c67a40a66fa6ccdc2781d51051812f7717c694918f109890a1198817c43f22 0.0s done\n",
+ "#29 exporting config sha256:17be984e3846abefdab5e9fc77950d42632ca87ff47628da66e67a2dff7ebd81 0.0s done\n",
+ "#29 sending tarball\n",
+ "#29 ...\n",
+ "\n",
+ "#30 importing to docker\n",
+ "#30 DONE 2.8s\n",
+ "\n",
+ "#29 exporting to docker image format\n",
+ "#29 sending tarball 62.0s done\n",
+ "#29 DONE 66.0s\n",
+ "\n",
+ "#31 exporting content cache\n",
+ "#31 preparing build cache for export\n",
+ "#31 writing layer sha256:0709800848b4584780b40e7e81200689870e890c38b54e96b65cd0a3b1942f2d\n",
+ "#31 writing layer sha256:0709800848b4584780b40e7e81200689870e890c38b54e96b65cd0a3b1942f2d 0.0s done\n",
+ "#31 writing layer sha256:0ce020987cfa5cd1654085af3bb40779634eb3d792c4a4d6059036463ae0040d done\n",
+ "#31 writing layer sha256:0f4bc5775dfef844ad94316d6cba08f7430019a5986278e18978fdf8fd6370d0 0.0s done\n",
+ "#31 writing layer sha256:0f65089b284381bf795d15b1a186e2a8739ea957106fa526edef0d738e7cda70 done\n",
+ "#31 writing layer sha256:12a47450a9f9cc5d4edab65d0f600dbbe8b23a1663b0b3bb2c481d40e074b580 done\n",
+ "#31 writing layer sha256:1de965777e2e37c7fabe00bdbf3d0203ca83ed30a71a5479c3113fe4fc48c4bb done\n",
+ "#31 writing layer sha256:1e6d878a29f0eee28390766120813fdf36893f516bcc029e698cd941eeb79616 0.0s done\n",
+ "#31 writing layer sha256:24b5aa2448e920814dd67d7d3c0169b2cdacb13c4048d74ded3b4317843b13ff done\n",
+ "#31 writing layer sha256:2789e1f0e19719b047679b4b490cab1edb9e151cd286aed22df08022c249f040\n",
+ "#31 writing layer sha256:2789e1f0e19719b047679b4b490cab1edb9e151cd286aed22df08022c249f040 1.0s done\n",
+ "#31 writing layer sha256:2d42104dbf0a7cc962b791f6ab4f45a803f8a36d296f996aca180cfb2f3e30d0 done\n",
+ "#31 writing layer sha256:2fa1ce4fa3fec6f9723380dc0536b7c361d874add0baaddc4bbf2accac82d2ff done\n",
+ "#31 writing layer sha256:38794be1b5dc99645feabf89b22cd34fb5bdffb5164ad920e7df94f353efe9c0 done\n",
+ "#31 writing layer sha256:38f963dc57c1e7b68a738fe39ed9f9345df7188111a047e2163a46648d7f1d88 done\n",
+ "#31 writing layer sha256:3e7e4c9bc2b136814c20c04feb4eea2b2ecf972e20182d88759931130cfb4181 done\n",
+ "#31 writing layer sha256:3fd77037ad585442cd82d64e337f49a38ddba50432b2a1e563a48401d25c79e6 done\n",
+ "#31 writing layer sha256:41814ed91034b30ac9c44dfc604a4bade6138005ccf682372c02e0bead66dbc0 done\n",
+ "#31 writing layer sha256:45893188359aca643d5918c9932da995364dc62013dfa40c075298b1baabece3 done\n",
+ "#31 writing layer sha256:49bc651b19d9e46715c15c41b7c0daa007e8e25f7d9518f04f0f06592799875a done\n",
+ "#31 writing layer sha256:4c12db5118d8a7d909e4926d69a2192d2b3cd8b110d49c7504a4f701258c1ccc done\n",
+ "#31 writing layer sha256:4cc43a803109d6e9d1fd35495cef9b1257035f5341a2db54f7a1940815b6cc65 done\n",
+ "#31 writing layer sha256:4d32b49e2995210e8937f0898327f196d3fcc52486f0be920e8b2d65f150a7ab done\n",
+ "#31 writing layer sha256:4d6fe980bad9cd7b2c85a478c8033cae3d098a81f7934322fb64658b0c8f9854 done\n",
+ "#31 writing layer sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 done\n",
+ "#31 writing layer sha256:50b2500ad4a5ad2f73d71f4dedecabff852c74ea78a97dab0fc86b2ed44ddc77 done\n",
+ "#31 writing layer sha256:5150182f1ff123399b300ca469e00f6c4d82e1b9b72652fb8ee7eab370245236 done\n",
+ "#31 writing layer sha256:595c38fa102c61c3dda19bdab70dcd26a0e50465b986d022a84fa69023a05d0f done\n",
+ "#31 writing layer sha256:59d451175f6950740e26d38c322da0ef67cb59da63181eb32996f752ba8a2f17 done\n",
+ "#31 writing layer sha256:5ad1f2004580e415b998124ea394e9d4072a35d70968118c779f307204d6bd17 done\n",
+ "#31 writing layer sha256:5e2c1cbc09286c26c04d5b4257b11940ecdb161330319d54feadc7ef9a8dc8f6 done\n",
+ "#31 writing layer sha256:62598eafddf023e7f22643485f4321cbd51ff7eee743b970db12454fd3c8c675 done\n",
+ "#31 writing layer sha256:63d7e616a46987136f4cc9eba95db6f6327b4854cfe3c7e20fed6db0c966e380 done\n",
+ "#31 writing layer sha256:6939d591a6b09b14a437e5cd2d6082a52b6d76bec4f72d960440f097721da34f done\n",
+ "#31 writing layer sha256:698318e5a60e5e0d48c45bf992f205a9532da567fdfe94bd59be2e192975dd6f done\n",
+ "#31 writing layer sha256:6ddc1d0f91833b36aac1c6f0c8cea005c87d94bab132d46cc06d9b060a81cca3 done\n",
+ "#31 writing layer sha256:74ac1f5a47c0926bff1e997bb99985a09926f43bd0895cb27ceb5fa9e95f8720 done\n",
+ "#31 writing layer sha256:7577973918dd30e764733a352a93f418000bc3181163ca451b2307492c1a6ba9 done\n",
+ "#31 writing layer sha256:886c886d8a09d8befb92df75dd461d4f97b77d7cff4144c4223b0d2f6f2c17f2 done\n",
+ "#31 writing layer sha256:8a7451db9b4b817b3b33904abddb7041810a4ffe8ed4a034307d45d9ae9b3f2a done\n",
+ "#31 writing layer sha256:916f4054c6e7f10de4fd7c08ffc75fa23ebecca4eceb8183cb1023b33b1696c9 done\n",
+ "#31 writing layer sha256:9463aa3f56275af97693df69478a2dc1d171f4e763ca6f7b6f370a35e605c154 done\n",
+ "#31 writing layer sha256:955fd173ed884230c2eded4542d10a97384b408537be6bbb7c4ae09ccd6fb2d0 done\n",
+ "#31 writing layer sha256:9c42a4ee99755f441251e6043b2cbba16e49818a88775e7501ec17e379ce3cfd done\n",
+ "#31 writing layer sha256:9c63be0a86e3dc4168db3814bf464e40996afda0031649d9faa8ff7568c3154f done\n",
+ "#31 writing layer sha256:9e04bda98b05554953459b5edef7b2b14d32f1a00b979a23d04b6eb5c191e66b done\n",
+ "#31 writing layer sha256:a4a0c690bc7da07e592514dccaa26098a387e8457f69095e922b6d73f7852502 done\n",
+ "#31 writing layer sha256:a4aafbc094d78a85bef41036173eb816a53bcd3e2564594a32f542facdf2aba6 done\n",
+ "#31 writing layer sha256:ae36a4d38b76948e39a5957025c984a674d2de18ce162a8caaa536e6f06fccea done\n",
+ "#31 writing layer sha256:b2fa40114a4a0725c81b327df89c0c3ed5c05ca9aa7f1157394d5096cf5460ce done\n",
+ "#31 writing layer sha256:b48a5fafcaba74eb5d7e7665601509e2889285b50a04b5b639a23f8adc818157 done\n",
+ "#31 writing layer sha256:c657dd855c8726b050f2b5bd6f4999883fff6803fe9f22add96f6d3ff89cd477 done\n",
+ "#31 writing layer sha256:c86976a083599e36a6441f36f553627194d05ea82bb82a78682e718fe62fccf6 done\n",
+ "#31 writing layer sha256:cb506fbdedc817e3d074f609e2edbf9655aacd7784610a1bbac52f2d7be25438 done\n",
+ "#31 writing layer sha256:d2a6fe65a1f84edb65b63460a75d1cac1aa48b72789006881b0bcfd54cd01ffd done\n",
+ "#31 writing layer sha256:d2cafa18c788d3e44592cf8dcabf80e138db8389aa89e765550691199861d4fe 0.0s done\n",
+ "#31 writing layer sha256:d6a198fd2a224cb803248e86953a164439f1a64889df0861dc5cc7eef4c66664 0.0s done\n",
+ "#31 writing layer sha256:d8d16d6af76dc7c6b539422a25fdad5efb8ada5a8188069fcd9d113e3b783304\n",
+ "#31 writing layer sha256:d8d16d6af76dc7c6b539422a25fdad5efb8ada5a8188069fcd9d113e3b783304 done\n",
+ "#31 writing layer sha256:ddc2ade4f6fe866696cb638c8a102cb644fa842c2ca578392802b3e0e5e3bcb7 done\n",
+ "#31 writing layer sha256:e2cfd7f6244d6f35befa6bda1caa65f1786cecf3f00ef99d7c9a90715ce6a03c done\n",
+ "#31 writing layer sha256:e3d62e9dfa6b71c784d14517790438fabbc4adfca340fc7e2c2fa3ae76eb6917 0.0s done\n",
+ "#31 writing layer sha256:e42e7ccc889dd8eabf5148a4e91eb843e32688cf109fa7c074d87862f8da5da0\n",
+ "#31 writing layer sha256:e42e7ccc889dd8eabf5148a4e91eb843e32688cf109fa7c074d87862f8da5da0 0.4s done\n",
+ "#31 writing layer sha256:e94a4481e9334ff402bf90628594f64a426672debbdfb55f1290802e52013907 done\n",
+ "#31 writing layer sha256:eaf45e9f32d1f5a9983945a1a9f8dedbb475bc0f578337610e00b4dedec87c20 done\n",
+ "#31 writing layer sha256:eb411bef39c013c9853651e68f00965dbd826d829c4e478884a2886976e9c989 done\n",
+ "#31 writing layer sha256:edfe4a95eb6bd3142aeda941ab871ffcc8c19cf50c33561c210ba8ead2424759 done\n",
+ "#31 writing layer sha256:ef4466d6f927d29d404df9c5af3ef5733c86fa14e008762c90110b963978b1e7 done\n",
+ "#31 writing layer sha256:f346e3ecdf0bee048fa1e3baf1d3128ff0283b903f03e97524944949bd8882e5 done\n",
+ "#31 writing layer sha256:f3f9a00a1ce9aadda250aacb3e66a932676badc5d8519c41517fdf7ea14c13ed done\n",
+ "#31 writing layer sha256:f7a50dafd51c2bcaad0ede31fbf29c38fe66776ade008a7fbdb07dba39de7f97 done\n",
+ "#31 writing layer sha256:fd849d9bd8889edd43ae38e9f21a912430c8526b2c18f3057a3b2cd74eb27b31 done\n",
+ "#31 writing config sha256:b3ecef29d7ecd014606ec1a5bc12ec4a44ab5cdaedc016d07e70d0bebbaf471a 0.0s done\n",
+ "#31 preparing build cache for export 2.2s done\n",
+ "#31 writing manifest sha256:41770de5232f0f9ed1171d161204bcf55abf5a318aa784a38c8de9e07d4b7c3d 0.0s done\n",
+ "#31 DONE 2.2s\n",
+ "[2023-08-30 01:00:53,452] [INFO] (packager) - Build Summary:\n",
+ "\n",
+ "Platform: x64-workstation/dgpu\n",
+ " Status: Succeeded\n",
+ " Docker Tag: my_app-x64-workstation-dgpu-linux-amd64:1.0\n",
+ " Tarball: None\n"
]
}
],
"source": [
- "!monai-deploy package -b nvcr.io/nvidia/pytorch:22.08-py3 my_app --tag my_app:latest -m model.ts"
+ "tag_prefix = \"my_app\"\n",
+ "\n",
+ "!monai-deploy package my_app -m {models_folder} -c my_app/app.yaml -t {tag_prefix}:1.0 --platform x64-workstation -l DEBUG"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- ":::{note}\n",
- "Building a MONAI Application Package (Docker image) can take time. Use `-l DEBUG` option if you want to see the progress.\n",
- ":::\n",
+ "We can see that the MAP Docker image is created.\n",
"\n",
- "We can see that the Docker image is created."
+ "We can choose to display and inspect the MAP manifests by running the container with the `show` command, as well as extracting the manifests and other contents in the MAP by using the `extract` command, but not demonstrated in this example."
]
},
{
"cell_type": "code",
- "execution_count": 16,
+ "execution_count": 22,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "my_app latest 9485f50a4d62 3 hours ago 15GB\n"
+ "my_app-x64-workstation-dgpu-linux-amd64 1.0 17be984e3846 About a minute ago 15.4GB\n"
]
}
],
"source": [
- "!docker image ls | grep my_app"
+ "!docker image ls | grep {tag_prefix}"
]
},
{
@@ -1804,234 +2177,419 @@
},
{
"cell_type": "code",
- "execution_count": 17,
+ "execution_count": 23,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "Checking dependencies...\n",
- "--> Verifying if \"docker\" is installed...\n",
- "\n",
- "--> Verifying if \"my_app:latest\" is available...\n",
- "\n",
- "Checking for MAP \"my_app:latest\" locally\n",
- "\"my_app:latest\" found.\n",
- "\n",
- "Reading MONAI App Package manifest...\n",
- "\u001b[sPreparing to copy...\u001b[?25l\u001b[u\u001b[2KCopying from container - 0B\u001b[?25h\u001b[u\u001b[2KSuccessfully copied 2.05kB to /tmp/tmphnopey6n/app.json\n",
- "\u001b[sPreparing to copy...\u001b[?25l\u001b[u\u001b[2KCopying from container - 0B\u001b[?25h\u001b[u\u001b[2KSuccessfully copied 2.05kB to /tmp/tmphnopey6n/pkg.json\n",
- "--> Verifying if \"nvidia-docker\" is installed...\n",
- "\n",
- "/opt/conda/lib/python3.8/site-packages/scipy/__init__.py:138: UserWarning: A NumPy version >=1.16.5 and <1.23.0 is required for this version of SciPy (detected version 1.24.3)\n",
- " warnings.warn(f\"A NumPy version >={np_minversion} and <{np_maxversion} is required for this version of \"\n",
- "\u001b[34mGoing to initiate execution of operator DICOMDataLoaderOperator\u001b[39m\n",
- "\u001b[32mExecuting operator DICOMDataLoaderOperator \u001b[33m(Process ID: 1, Operator ID: d1c5089b-3071-4485-9bb2-95dca8253064)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator DICOMDataLoaderOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator DICOMSeriesSelectorOperator\u001b[39m\n",
- "\u001b[32mExecuting operator DICOMSeriesSelectorOperator \u001b[33m(Process ID: 1, Operator ID: cc2cd155-67df-4121-9066-0321ea6d9f5a)\u001b[39m\n",
- "[2023-07-11 21:44:39,915] [INFO] (root) - Finding series for Selection named: CT Series\n",
- "[2023-07-11 21:44:39,915] [INFO] (root) - Searching study, : 1.3.6.1.4.1.14519.5.2.1.7085.2626.822645453932810382886582736291\n",
+ "[2023-08-30 01:00:57,619] [INFO] (runner) - Checking dependencies...\n",
+ "[2023-08-30 01:00:57,619] [INFO] (runner) - --> Verifying if \"docker\" is installed...\n",
+ "\n",
+ "[2023-08-30 01:00:57,620] [INFO] (runner) - --> Verifying if \"docker-buildx\" is installed...\n",
+ "\n",
+ "[2023-08-30 01:00:57,620] [INFO] (runner) - --> Verifying if \"my_app-x64-workstation-dgpu-linux-amd64:1.0\" is available...\n",
+ "\n",
+ "[2023-08-30 01:00:57,670] [INFO] (runner) - Reading HAP/MAP manifest...\n",
+ "\u001b[sPreparing to copy...\u001b[?25l\u001b[u\u001b[2KCopying from container - 0B\u001b[?25h\u001b[u\u001b[2KSuccessfully copied 2.56kB to /tmp/tmpah05b7ex/app.json\n",
+ "\u001b[sPreparing to copy...\u001b[?25l\u001b[u\u001b[2KCopying from container - 0B\u001b[?25h\u001b[u\u001b[2KSuccessfully copied 2.05kB to /tmp/tmpah05b7ex/pkg.json\n",
+ "[2023-08-30 01:00:58,237] [INFO] (runner) - --> Verifying if \"nvidia-ctk\" is installed...\n",
+ "\n",
+ "[2023-08-30 01:00:58,414] [INFO] (common) - Launching container (8ca19e2ad332) using image 'my_app-x64-workstation-dgpu-linux-amd64:1.0'...\n",
+ " container name: peaceful_goldstine\n",
+ " host name: mingq-dt\n",
+ " network: host\n",
+ " user: 1000:1000\n",
+ " ulimits: memlock=-1:-1, stack=67108864:67108864\n",
+ " cap_add: CAP_SYS_PTRACE\n",
+ " ipc mode: host\n",
+ " shared memory size: 67108864\n",
+ " devices: \n",
+ "2023-08-30 08:00:59 [INFO] Launching application python3 /opt/holoscan/app ...\n",
+ "\n",
+ "[2023-08-30 08:01:03,315] [INFO] (root) - Parsed args: Namespace(argv=['/opt/holoscan/app'], input=None, log_level=None, model=None, output=None, workdir=None)\n",
+ "\n",
+ "[2023-08-30 08:01:03,318] [INFO] (root) - AppContext object: AppContext(input_path=/var/holoscan/input, output_path=/var/holoscan/output, model_path=/opt/holoscan/models, workdir=/var/holoscan)\n",
+ "\n",
+ "[2023-08-30 08:01:03,318] [INFO] (app.AISpleenSegApp) - App input and output path: /var/holoscan/input, /var/holoscan/output\n",
+ "\n",
+ "[info] [app_driver.cpp:1025] Launching the driver/health checking service\n",
+ "\n",
+ "[info] [gxf_executor.cpp:210] Creating context\n",
+ "\n",
+ "[info] [server.cpp:73] Health checking server listening on 0.0.0.0:8777\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1595] Loading extensions from configs...\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1741] Activating Graph...\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1771] Running Graph...\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1773] Waiting for completion...\n",
+ "\n",
+ "[info] [gxf_executor.cpp:1774] Graph execution waiting. Fragment: \n",
+ "\n",
+ "[info] [greedy_scheduler.cpp:190] Scheduling 6 entities\n",
+ "\n",
+ "[2023-08-30 08:01:03,434] [INFO] (monai.deploy.operators.dicom_data_loader_operator.DICOMDataLoaderOperator) - No or invalid input path from the optional input port: None\n",
+ "\n",
+ "[2023-08-30 08:01:04,283] [INFO] (root) - Finding series for Selection named: CT Series\n",
+ "\n",
+ "[2023-08-30 08:01:04,284] [INFO] (root) - Searching study, : 1.3.6.1.4.1.14519.5.2.1.7085.2626.822645453932810382886582736291\n",
+ "\n",
" # of series: 1\n",
- "[2023-07-11 21:44:39,915] [INFO] (root) - Working on series, instance UID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.119403521930927333027265674239\n",
- "[2023-07-11 21:44:39,915] [INFO] (root) - On attribute: 'StudyDescription' to match value: '(.*?)'\n",
- "[2023-07-11 21:44:39,915] [INFO] (root) - Series attribute StudyDescription value: CT ABDOMEN W IV CONTRAST\n",
- "[2023-07-11 21:44:39,916] [INFO] (root) - Series attribute string value did not match. Try regEx.\n",
- "[2023-07-11 21:44:39,916] [INFO] (root) - On attribute: 'Modality' to match value: '(?i)CT'\n",
- "[2023-07-11 21:44:39,916] [INFO] (root) - Series attribute Modality value: CT\n",
- "[2023-07-11 21:44:39,916] [INFO] (root) - Series attribute string value did not match. Try regEx.\n",
- "[2023-07-11 21:44:39,916] [INFO] (root) - On attribute: 'SeriesDescription' to match value: '(.*?)'\n",
- "[2023-07-11 21:44:39,916] [INFO] (root) - Series attribute SeriesDescription value: ABD/PANC 3.0 B31f\n",
- "[2023-07-11 21:44:39,916] [INFO] (root) - Series attribute string value did not match. Try regEx.\n",
- "[2023-07-11 21:44:39,916] [INFO] (root) - On attribute: 'ImageType' to match value: ['PRIMARY', 'ORIGINAL']\n",
- "[2023-07-11 21:44:39,916] [INFO] (root) - Series attribute ImageType value: None\n",
- "[2023-07-11 21:44:39,916] [INFO] (root) - Selected Series, UID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.119403521930927333027265674239\n",
- "\u001b[34mDone performing execution of operator DICOMSeriesSelectorOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator DICOMSeriesToVolumeOperator\u001b[39m\n",
- "\u001b[32mExecuting operator DICOMSeriesToVolumeOperator \u001b[33m(Process ID: 1, Operator ID: 2e5584b8-02ca-428a-afee-d33228cb029a)\u001b[39m\n",
- "\u001b[34mDone performing execution of operator DICOMSeriesToVolumeOperator\n",
- "\u001b[39m\n",
- "\u001b[34mGoing to initiate execution of operator SpleenSegOperator\u001b[39m\n",
- "\u001b[32mExecuting operator SpleenSegOperator \u001b[33m(Process ID: 1, Operator ID: bbf3d7b1-a956-4612-a767-806aeb15f7a5)\u001b[39m\n",
- "/root/.local/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:321: FutureWarning: monai.transforms.io.dictionary LoadImaged.__init__:image_only: Current default value of argument `image_only=False` has been deprecated since version 1.1. It will be changed to `image_only=True` in version 1.3.\n",
- " warn_deprecated(argname, msg, warning_category)\n",
- "/root/.local/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:321: FutureWarning: monai.transforms.io.dictionary SaveImaged.__init__:resample: Current default value of argument `resample=True` has been deprecated since version 1.1. It will be changed to `resample=False` in version 1.3.\n",
+ "\n",
+ "[2023-08-30 08:01:04,284] [INFO] (root) - Working on series, instance UID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.119403521930927333027265674239\n",
+ "\n",
+ "[2023-08-30 08:01:04,284] [INFO] (root) - On attribute: 'StudyDescription' to match value: '(.*?)'\n",
+ "\n",
+ "[2023-08-30 08:01:04,284] [INFO] (root) - Series attribute StudyDescription value: CT ABDOMEN W IV CONTRAST\n",
+ "\n",
+ "[2023-08-30 08:01:04,284] [INFO] (root) - Series attribute string value did not match. Try regEx.\n",
+ "\n",
+ "[2023-08-30 08:01:04,284] [INFO] (root) - On attribute: 'Modality' to match value: '(?i)CT'\n",
+ "\n",
+ "[2023-08-30 08:01:04,284] [INFO] (root) - Series attribute Modality value: CT\n",
+ "\n",
+ "[2023-08-30 08:01:04,284] [INFO] (root) - Series attribute string value did not match. Try regEx.\n",
+ "\n",
+ "[2023-08-30 08:01:04,284] [INFO] (root) - On attribute: 'SeriesDescription' to match value: '(.*?)'\n",
+ "\n",
+ "[2023-08-30 08:01:04,284] [INFO] (root) - Series attribute SeriesDescription value: ABD/PANC 3.0 B31f\n",
+ "\n",
+ "[2023-08-30 08:01:04,284] [INFO] (root) - Series attribute string value did not match. Try regEx.\n",
+ "\n",
+ "[2023-08-30 08:01:04,284] [INFO] (root) - On attribute: 'ImageType' to match value: ['PRIMARY', 'ORIGINAL']\n",
+ "\n",
+ "[2023-08-30 08:01:04,284] [INFO] (root) - Series attribute ImageType value: None\n",
+ "\n",
+ "[2023-08-30 08:01:04,285] [INFO] (root) - Selected Series, UID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.119403521930927333027265674239\n",
+ "\n",
+ "/home/holoscan/.local/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:321: FutureWarning: monai.transforms.io.dictionary LoadImaged.__init__:image_only: Current default value of argument `image_only=False` has been deprecated since version 1.1. It will be changed to `image_only=True` in version 1.3.\n",
+ "\n",
" warn_deprecated(argname, msg, warning_category)\n",
- "Converted Image object metadata:\n",
- "SeriesInstanceUID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.119403521930927333027265674239, type \n",
- "SeriesDate: 20090831, type \n",
- "SeriesTime: 101721.452, type \n",
- "Modality: CT, type \n",
- "SeriesDescription: ABD/PANC 3.0 B31f, type \n",
- "PatientPosition: HFS, type \n",
- "SeriesNumber: 8, type \n",
- "row_pixel_spacing: 0.7890625, type \n",
- "col_pixel_spacing: 0.7890625, type \n",
- "depth_pixel_spacing: 1.5, type \n",
- "row_direction_cosine: [1.0, 0.0, 0.0], type \n",
- "col_direction_cosine: [0.0, 1.0, 0.0], type \n",
- "depth_direction_cosine: [0.0, 0.0, 1.0], type \n",
- "dicom_affine_transform: [[ 0.7890625 0. 0. -197.60547 ]\n",
+ "\n",
+ "[2023-08-30 08:01:04,713] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - Converted Image object metadata:\n",
+ "\n",
+ "[2023-08-30 08:01:04,713] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - SeriesInstanceUID: 1.3.6.1.4.1.14519.5.2.1.7085.2626.119403521930927333027265674239, type \n",
+ "\n",
+ "[2023-08-30 08:01:04,713] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - SeriesDate: 20090831, type \n",
+ "\n",
+ "[2023-08-30 08:01:04,713] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - SeriesTime: 101721.452, type \n",
+ "\n",
+ "[2023-08-30 08:01:04,713] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - Modality: CT, type \n",
+ "\n",
+ "[2023-08-30 08:01:04,713] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - SeriesDescription: ABD/PANC 3.0 B31f, type \n",
+ "\n",
+ "[2023-08-30 08:01:04,713] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - PatientPosition: HFS, type \n",
+ "\n",
+ "[2023-08-30 08:01:04,713] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - SeriesNumber: 8, type \n",
+ "\n",
+ "[2023-08-30 08:01:04,713] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - row_pixel_spacing: 0.7890625, type \n",
+ "\n",
+ "[2023-08-30 08:01:04,713] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - col_pixel_spacing: 0.7890625, type \n",
+ "\n",
+ "[2023-08-30 08:01:04,713] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - depth_pixel_spacing: 1.5, type \n",
+ "\n",
+ "[2023-08-30 08:01:04,713] [INFO] (monai.deploy.operators.monai_seg_inference_operator.MonaiSegInferenceOperator) - row_direction_cosine: [1.0, 0.0, 0.0], type