Deploying a MedNIST Classifier App with MONAI Deploy App SDK (Prebuilt Model)¶
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.
In this tutorial, we will use a trained model and implement & package the inference application, executing the application locally.
Clone the github project (the latest version of the main branch only)¶
!rm -rf source \
&& git clone --branch main --depth 1 https://github.com/Project-MONAI/monai-deploy-app-sdk.git source \
&& rm -rf source/.git
Cloning into 'source'...
remote: Enumerating objects: 287, done.
remote: Counting objects: 100% (287/287), done.
remote: Compressing objects: 100% (253/253), done.
remote: Total 287 (delta 61), reused 121 (delta 20), pack-reused 0
Receiving objects: 100% (287/287), 1.21 MiB | 10.01 MiB/s, done.
Resolving deltas: 100% (61/61), done.
!ls source/examples/apps/mednist_classifier_monaideploy/
mednist_classifier_monaideploy.py
Install monai-deploy-app-sdk package¶
!pip install --upgrade monai-deploy-app-sdk
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)
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)
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)
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)
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)
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)
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)
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)
Install necessary packages for the app¶
!pip install monai Pillow # for MONAI transforms and Pillow
!python -c "import pydicom" || pip install -q "pydicom>=1.4.2"
!python -c "import highdicom" || pip install -q "highdicom>=0.18.2" # for the use of DICOM Writer operators
Requirement already satisfied: monai in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (1.2.0)
Requirement already satisfied: Pillow in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (10.0.0)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
Download/Extract mednist_classifier_data.zip from Google Drive¶
# Download mednist_classifier_data.zip
!pip install gdown
!gdown "https://drive.google.com/uc?id=1yJ4P-xMNEfN6lIOq_u6x1eMAq1_MJu-E"
Requirement already satisfied: gdown in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (4.7.1)
Requirement already satisfied: filelock in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from gdown) (3.12.2)
Requirement already satisfied: requests[socks] in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from gdown) (2.31.0)
Requirement already satisfied: six in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from gdown) (1.16.0)
Requirement already satisfied: tqdm in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from gdown) (4.65.0)
Requirement already satisfied: beautifulsoup4 in /home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages (from gdown) (4.12.2)
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)
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)
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)
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)
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)
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)
Downloading...
From (uriginal): https://drive.google.com/uc?id=1yJ4P-xMNEfN6lIOq_u6x1eMAq1_MJu-E
From (redirected): https://drive.google.com/uc?id=1yJ4P-xMNEfN6lIOq_u6x1eMAq1_MJu-E&confirm=t&uuid=64399e9b-2546-4500-9f28-b298c7c5c684
To: /home/mqin/src/monai-deploy-app-sdk/notebooks/tutorials/mednist_classifier_data.zip
100%|██████████████████████████████████████| 28.6M/28.6M [00:00<00:00, 64.6MB/s]
# After downloading mednist_classifier_data.zip from the web browser or using gdown,
!unzip -o "mednist_classifier_data.zip"
Archive: mednist_classifier_data.zip
extracting: classifier.zip
extracting: input/AbdomenCT_007000.jpeg
Package app (creating MAP Docker image)¶
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.
Use -l DEBUG option to see progress.
!monai-deploy package "source/examples/apps/mednist_classifier_monaideploy/mednist_classifier_monaideploy.py" \
--tag mednist_app:latest \
--model classifier.zip
Building MONAI Application Package... -?25l[+] Building 0.0s (0/1)
?25h?25l[+] Building 0.1s (1/2)
=> [internal] load build definition from dockerfile 0.1s
=> => transferring dockerfile: 2.58kB 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 1.11kB 0.0s
?25\?25l[+] Building 0.2s (4/19)
=> [internal] load build definition from dockerfile 0.1s
=> => transferring dockerfile: 2.58kB 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 1.11kB 0.0s
=> [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 0.0s
=> [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s
?25h?25l[+] Building 0.3s (4/19)
=> [internal] load build definition from dockerfile 0.1s
=> => transferring dockerfile: 2.58kB 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 1.11kB 0.0s
=> [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> [internal] load build context 0.1s
=> => transferring context: 8.98MB 0.1s
=> [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s
?25|?25l[+] Building 0.4s (4/19)
=> [internal] load build definition from dockerfile 0.1s
=> => transferring dockerfile: 2.58kB 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 1.11kB 0.0s
=> [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> [internal] load build context 0.2s
=> => transferring context: 20.78MB 0.2s
=> [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s
?25/?25l[+] Building 0.6s (12/19)
=> [internal] load build definition from dockerfile 0.1s
=> => transferring dockerfile: 2.58kB 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 1.11kB 0.0s
=> [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> [internal] load build context 0.3s
=> => transferring context: 29.06MB 0.3s
=> [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s
=> CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s
=> CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s
=> CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s
=> CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s
=> CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s
=> CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s
=> CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s
?25h?25l[+] Building 0.7s (13/19)
=> [internal] load build definition from dockerfile 0.1s
=> => transferring dockerfile: 2.58kB 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 1.11kB 0.0s
=> [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> [internal] load build context 0.3s
=> => transferring context: 29.06MB 0.3s
=> [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s
=> CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s
=> CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s
=> CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s
=> CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s
=> CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s
=> CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s
=> CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s
=> [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.2s
?25-?25l[+] Building 0.9s (13/19)
=> [internal] load build definition from dockerfile 0.1s
=> => transferring dockerfile: 2.58kB 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 1.11kB 0.0s
=> [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> [internal] load build context 0.3s
=> => transferring context: 29.06MB 0.3s
=> [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s
=> CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s
=> CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s
=> CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s
=> CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s
=> CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s
=> CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s
=> CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s
=> [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s
?25\?25l[+] Building 1.0s (14/19)
=> [internal] load build definition from dockerfile 0.1s
=> => transferring dockerfile: 2.58kB 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 1.11kB 0.0s
=> [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> [internal] load build context 0.3s
=> => transferring context: 29.06MB 0.3s
=> [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s
=> CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s
=> CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s
=> CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s
=> CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s
=> CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s
=> CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s
=> CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s
=> [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s
=> [11/15] RUN echo "User site package location: $(python3 -m site --use 0.1s
?25|?25l[+] Building 1.2s (14/19)
=> [internal] load build definition from dockerfile 0.1s
=> => transferring dockerfile: 2.58kB 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 1.11kB 0.0s
=> [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> [internal] load build context 0.3s
=> => transferring context: 29.06MB 0.3s
=> [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s
=> CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s
=> CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s
=> CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s
=> CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s
=> CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s
=> CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s
=> CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s
=> [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s
=> [11/15] RUN echo "User site package location: $(python3 -m site --use 0.3s
?25h?25l[+] Building 1.3s (14/19)
=> [internal] load build definition from dockerfile 0.1s
=> => transferring dockerfile: 2.58kB 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 1.11kB 0.0s
=> [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> [internal] load build context 0.3s
=> => transferring context: 29.06MB 0.3s
=> [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s
=> CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s
=> CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s
=> CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s
=> CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s
=> CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s
=> CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s
=> CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s
=> [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s
=> [11/15] RUN echo "User site package location: $(python3 -m site --use 0.4s
?25/?25l[+] Building 1.4s (15/19)
=> [internal] load build definition from dockerfile 0.1s
=> => transferring dockerfile: 2.58kB 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 1.11kB 0.0s
=> [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> [internal] load build context 0.3s
=> => transferring context: 29.06MB 0.3s
=> [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s
=> CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s
=> CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s
=> CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s
=> CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s
=> CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s
=> CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s
=> CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s
=> [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s
=> [11/15] RUN echo "User site package location: $(python3 -m site --use 0.6s
?25-?25l[+] Building 1.5s (16/19)
=> [internal] load build definition from dockerfile 0.1s
=> => transferring dockerfile: 2.58kB 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 1.11kB 0.0s
=> [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> [internal] load build context 0.3s
=> => transferring context: 29.06MB 0.3s
=> [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s
=> CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s
=> CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s
=> CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s
=> CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s
=> CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s
=> CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s
=> CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s
=> [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s
=> [11/15] RUN echo "User site package location: $(python3 -m site --use 0.6s
=> [12/15] COPY ./map/app.json /etc/monai/ 0.1s
?25h?25l[+] Building 1.7s (17/19)
=> [internal] load build definition from dockerfile 0.1s
=> => transferring dockerfile: 2.58kB 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 1.11kB 0.0s
=> [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> [internal] load build context 0.3s
=> => transferring context: 29.06MB 0.3s
=> [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s
=> CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s
=> CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s
=> CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s
=> CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s
=> CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s
=> CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s
=> CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s
=> [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s
=> [11/15] RUN echo "User site package location: $(python3 -m site --use 0.6s
=> [12/15] COPY ./map/app.json /etc/monai/ 0.1s
=> [13/15] COPY ./map/pkg.json /etc/monai/ 0.1s
?25\?25l[+] Building 1.8s (18/19)
=> [internal] load build definition from dockerfile 0.1s
=> => transferring dockerfile: 2.58kB 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 1.11kB 0.0s
=> [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> [internal] load build context 0.3s
=> => transferring context: 29.06MB 0.3s
=> [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s
=> CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s
=> CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s
=> CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s
=> CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s
=> CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s
=> CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s
=> CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s
=> [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s
=> [11/15] RUN echo "User site package location: $(python3 -m site --use 0.6s
=> [12/15] COPY ./map/app.json /etc/monai/ 0.1s
=> [13/15] COPY ./map/pkg.json /etc/monai/ 0.1s
=> [14/15] COPY ./app /opt/monai/app 0.1s
?25h?25l[+] Building 1.9s (19/19)
=> [internal] load build definition from dockerfile 0.1s
=> => transferring dockerfile: 2.58kB 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 1.11kB 0.0s
=> [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> [internal] load build context 0.3s
=> => transferring context: 29.06MB 0.3s
=> [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s
=> CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s
=> CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s
=> CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s
=> CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s
=> CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s
=> CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s
=> CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s
=> [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s
=> [11/15] RUN echo "User site package location: $(python3 -m site --use 0.6s
=> [12/15] COPY ./map/app.json /etc/monai/ 0.1s
=> [13/15] COPY ./map/pkg.json /etc/monai/ 0.1s
=> [14/15] COPY ./app /opt/monai/app 0.1s
=> [15/15] WORKDIR /var/monai/ 0.1s
?25|?25l[+] Building 2.0s (19/20)
=> [internal] load .dockerignore 0.1s
=> => transferring context: 1.11kB 0.0s
=> [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> [internal] load build context 0.3s
=> => transferring context: 29.06MB 0.3s
=> [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s
=> CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s
=> CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s
=> CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s
=> CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s
=> CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s
=> CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s
=> CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s
=> [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s
=> [11/15] RUN echo "User site package location: $(python3 -m site --use 0.6s
=> [12/15] COPY ./map/app.json /etc/monai/ 0.1s
=> [13/15] COPY ./map/pkg.json /etc/monai/ 0.1s
=> [14/15] COPY ./app /opt/monai/app 0.1s
=> [15/15] WORKDIR /var/monai/ 0.1s
=> exporting to image 0.1s
=> => exporting layers 0.1s
?25/?25l[+] Building 2.2s (19/20)
=> [internal] load .dockerignore 0.1s
=> => transferring context: 1.11kB 0.0s
=> [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> [internal] load build context 0.3s
=> => transferring context: 29.06MB 0.3s
=> [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s
=> CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s
=> CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s
=> CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s
=> CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s
=> CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s
=> CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s
=> CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s
=> [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s
=> [11/15] RUN echo "User site package location: $(python3 -m site --use 0.6s
=> [12/15] COPY ./map/app.json /etc/monai/ 0.1s
=> [13/15] COPY ./map/pkg.json /etc/monai/ 0.1s
=> [14/15] COPY ./app /opt/monai/app 0.1s
=> [15/15] WORKDIR /var/monai/ 0.1s
=> exporting to image 0.3s
=> => exporting layers 0.3s
?25h?25l[+] Building 2.3s (20/20)
=> [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> [internal] load build context 0.3s
=> => transferring context: 29.06MB 0.3s
=> [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s
=> CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s
=> CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s
=> CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s
=> CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s
=> CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s
=> CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s
=> CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s
=> [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s
=> [11/15] RUN echo "User site package location: $(python3 -m site --use 0.6s
=> [12/15] COPY ./map/app.json /etc/monai/ 0.1s
=> [13/15] COPY ./map/pkg.json /etc/monai/ 0.1s
=> [14/15] COPY ./app /opt/monai/app 0.1s
=> [15/15] WORKDIR /var/monai/ 0.1s
=> exporting to image 0.3s
=> => exporting layers 0.3s
=> => writing image sha256:1d85a1e712404af578bc29f3b6f407a985d51cff510bd 0.0s
=> => naming to docker.io/library/mednist_app:latest 0.0s
?25h?25l[+] Building 2.3s (20/20) FINISHED
=> [internal] load build definition from dockerfile 0.1s
=> => transferring dockerfile: 2.58kB 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 1.11kB 0.0s
=> [internal] load metadata for nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> [internal] load build context 0.3s
=> => transferring context: 29.06MB 0.3s
=> [ 1/15] FROM nvcr.io/nvidia/pytorch:22.08-py3 0.0s
=> CACHED [ 2/15] RUN apt update && apt upgrade -y --no-install-rec 0.0s
=> CACHED [ 3/15] RUN pip install --no-cache-dir --upgrade setuptools==5 0.0s
=> CACHED [ 4/15] RUN mkdir -p /etc/monai/ && mkdir -p /opt/monai/ 0.0s
=> CACHED [ 5/15] RUN mkdir -p /opt/monai/models 0.0s
=> CACHED [ 6/15] COPY ./models /opt/monai/models 0.0s
=> CACHED [ 7/15] COPY ./pip/requirements.txt /opt/monai/app/requirement 0.0s
=> CACHED [ 8/15] RUN curl https://globalcdn.nuget.org/packages/monai.de 0.0s
=> CACHED [ 9/15] RUN pip install --no-cache-dir --user -r /opt/monai/ap 0.0s
=> [10/15] COPY ./monai-deploy-app-sdk /root/.local/lib/python3.8/site-p 0.3s
=> [11/15] RUN echo "User site package location: $(python3 -m site --use 0.6s
=> [12/15] COPY ./map/app.json /etc/monai/ 0.1s
=> [13/15] COPY ./map/pkg.json /etc/monai/ 0.1s
=> [14/15] COPY ./app /opt/monai/app 0.1s
=> [15/15] WORKDIR /var/monai/ 0.1s
=> exporting to image 0.3s
=> => exporting layers 0.3s
=> => writing image sha256:1d85a1e712404af578bc29f3b6f407a985d51cff510bd 0.0s
=> => naming to docker.io/library/mednist_app:latest 0.0s
?25Done
[2023-07-11 14:39:41,392] [INFO] (app_packager) - Successfully built mednist_app:latest
Run the app with docker image and input file locally¶
!monai-deploy run mednist_app:latest "input" "output"
Checking dependencies...
--> Verifying if "docker" is installed...
--> Verifying if "mednist_app:latest" is available...
Checking for MAP "mednist_app:latest" locally
"mednist_app:latest" found.
Reading MONAI App Package manifest...
Preparing to copy...?25lCopying from container - 0B?25hSuccessfully copied 2.05kB to /tmp/tmpvdf4hnad/app.json
Preparing to copy...?25lCopying from container - 0B?25hSuccessfully copied 2.05kB to /tmp/tmpvdf4hnad/pkg.json
--> Verifying if "nvidia-docker" is installed...
/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)
warnings.warn(f"A NumPy version >={np_minversion} and <{np_maxversion} is required for this version of "
Going to initiate execution of operator LoadPILOperator
Executing operator LoadPILOperator (Process ID: 1, Operator ID: 5ca4fdc7-8dd0-4eb8-8550-9d92b820f2da)
Done performing execution of operator LoadPILOperator
Going to initiate execution of operator MedNISTClassifierOperator
Executing operator MedNISTClassifierOperator (Process ID: 1, Operator ID: 9d624c54-86c3-48a7-b827-ef60030db8ea)
/root/.local/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:111: FutureWarning: <class 'monai.transforms.utility.array.AddChannel'>: 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'`.
warn_deprecated(obj, msg, warning_category)
AbdomenCT
Done performing execution of operator MedNISTClassifierOperator
Going to initiate execution of operator DICOMTextSRWriterOperator
Executing operator DICOMTextSRWriterOperator (Process ID: 1, Operator ID: 0e037b51-3949-4738-a827-f57d2ba082f6)
/root/.local/lib/python3.8/site-packages/pydicom/valuerep.py:443: UserWarning: Invalid value for VR UI: 'xyz'. Please see <https://dicom.nema.org/medical/dicom/current/output/html/part05.html#table_6.2-1> for allowed values for each VR.
warnings.warn(msg)
[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
[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
Done performing execution of operator DICOMTextSRWriterOperator
!cat output/output.json
"AbdomenCT"
Implementing and Packaging Application with MONAI Deploy App SDK¶
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).
In our inference application, we will define two operators:
LoadPILOperator- Load a JPEG image from the input path and pass the loaded image object to the next operator.MedNISTClassifierOperator- Pre-transform the given image by using MONAI’sComposeclass, feed to the Torchscript model (classifier.zip), and write the prediction into JSON file(output.json)
The workflow of the application would look like this.
Setup imports¶
Let’s import necessary classes/decorators and define MEDNIST_CLASSES.
import monai.deploy.core as md
from monai.deploy.core import (
Application,
DataPath,
ExecutionContext,
Image,
InputContext,
IOType,
Operator,
OutputContext,
)
from monai.transforms import AddChannel, Compose, EnsureType, ScaleIntensity
MEDNIST_CLASSES = ["AbdomenCT", "BreastMRI", "CXR", "ChestCT", "Hand", "HeadCT"]
Creating Operator classes¶
LoadPILOperator¶
@md.input("image", DataPath, IOType.DISK)
@md.output("image", Image, IOType.IN_MEMORY)
@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):
import numpy as np
from PIL import Image as PILImage
input_path = op_input.get().path
if input_path.is_dir():
input_path = next(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)
MedNISTClassifierOperator¶
@md.input("image", Image, IOType.IN_MEMORY)
@md.output("output", DataPath, IOType.DISK)
@md.env(pip_packages=["monai"])
class MedNISTClassifierOperator(Operator):
"""Classifies the given image and returns the class name."""
@property
def transform(self):
return Compose([AddChannel(), ScaleIntensity(), EnsureType()])
def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
import json
import torch
img = op_input.get().asnumpy() # (64, 64), uint8
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)
_, output_classes = outputs.max(dim=1)
result = MEDNIST_CLASSES[output_classes[0]] # get the class name
print(result)
# Get output (folder) path and create the folder if not exists
output_folder = op_output.get().path
output_folder.mkdir(parents=True, exist_ok=True)
# Write result to "output.json"
output_path = output_folder / "output.json"
with open(output_path, "w") as fp:
json.dump(result, fp)
Creating Application class¶
Our application class would look like below.
It defines App class inheriting Application class.
LoadPILOperator is connected to MedNISTClassifierOperator by using self.add_flow() in compose() method of App.
@md.resource(cpu=1, gpu=1, memory="1Gi")
@md.env(pip_packages=["pydicom >= 2.3.0", "highdicom>=0.18.2"]) # for the use of DICOM Writer operators
class App(Application):
"""Application class for the MedNIST classifier."""
def compose(self):
load_pil_op = LoadPILOperator()
classifier_op = MedNISTClassifierOperator()
self.add_flow(load_pil_op, classifier_op)
Executing app locally¶
We can execute the app in the Jupyter notebook. Before doing so, we also need to clean the output folder which was created by running the packaged containerizd app in the previous cell.
!rm -rf output
app = App()
app.run(input="input/AbdomenCT_007000.jpeg", output="output", model="classifier.zip")
Going to initiate execution of operator LoadPILOperator
Executing operator LoadPILOperator (Process ID: 409880, Operator ID: 06991530-662d-46eb-83f2-e8e1368c4bb1)
Done performing execution of operator LoadPILOperator
Going to initiate execution of operator MedNISTClassifierOperator
Executing operator MedNISTClassifierOperator (Process ID: 409880, Operator ID: 1c4a4293-869f-4843-83f0-2c857c3bde96)
/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:111: FutureWarning: <class 'monai.transforms.utility.array.AddChannel'>: 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'`.
warn_deprecated(obj, msg, warning_category)
/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.)
return torch.as_tensor(x, *args, **_kwargs).as_subclass(cls) # type: ignore
AbdomenCT
Done performing execution of operator MedNISTClassifierOperator
!cat output/output.json
"AbdomenCT"
Once the application is verified inside Jupyter notebook, we can write the whole application as a file(mednist_classifier_monaideploy.py) by concatenating code above, then add the following lines:
if __name__ == "__main__":
App(do_run=True)
The above lines are needed to execute the application code by using python interpreter.
%%writefile mednist_classifier_monaideploy.py
# 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 monai.deploy.core as md # 'md' stands for MONAI Deploy (or can use 'core' instead)
from monai.deploy.core import (
Application,
DataPath,
ExecutionContext,
Image,
InputContext,
IOType,
Operator,
OutputContext,
)
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"])
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):
import numpy as np
from PIL import Image as PILImage
input_path = op_input.get().path
if input_path.is_dir():
input_path = next(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)
@md.input("image", Image, IOType.IN_MEMORY)
@md.output("output", DataPath, IOType.DISK)
@md.env(pip_packages=["monai"])
class MedNISTClassifierOperator(Operator):
"""Classifies the given image and returns the class name."""
@property
def transform(self):
return Compose([AddChannel(), ScaleIntensity(), EnsureType()])
def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
import json
import torch
img = op_input.get().asnumpy() # (64, 64), uint8
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)
_, output_classes = outputs.max(dim=1)
result = MEDNIST_CLASSES[output_classes[0]] # get the class name
print(result)
# Get output (folder) path and create the folder if not exists
output_folder = op_output.get().path
output_folder.mkdir(parents=True, exist_ok=True)
# Write result to "output.json"
output_path = output_folder / "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"]) # for the use of DICOM Writer operators
class App(Application):
"""Application class for the MedNIST classifier."""
def compose(self):
load_pil_op = LoadPILOperator()
classifier_op = MedNISTClassifierOperator()
self.add_flow(load_pil_op, classifier_op)
if __name__ == "__main__":
App(do_run=True)
Overwriting mednist_classifier_monaideploy.py
In this time, let’s execute the app in the command line.
!python "mednist_classifier_monaideploy.py" -i "input/AbdomenCT_007000.jpeg" -o output -m "classifier.zip"
Going to initiate execution of operator LoadPILOperator
Executing operator LoadPILOperator (Process ID: 410692, Operator ID: c6ecd716-26ef-4706-8cd4-11fc7f3179bb)
Done performing execution of operator LoadPILOperator
Going to initiate execution of operator MedNISTClassifierOperator
Executing operator MedNISTClassifierOperator (Process ID: 410692, Operator ID: 7b972a34-7f9b-472e-ad4c-394526e9c20b)
/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:111: FutureWarning: <class 'monai.transforms.utility.array.AddChannel'>: 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'`.
warn_deprecated(obj, msg, warning_category)
/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.)
return torch.as_tensor(x, *args, **_kwargs).as_subclass(cls) # type: ignore
AbdomenCT
Done performing execution of operator MedNISTClassifierOperator
Above command is same with the following command line:
!monai-deploy exec "mednist_classifier_monaideploy.py" -i "input/AbdomenCT_007000.jpeg" -o output -m "classifier.zip"
Going to initiate execution of operator LoadPILOperator
Executing operator LoadPILOperator (Process ID: 410750, Operator ID: 91aa8bda-4a3b-47fd-b393-13181eb69e2c)
Done performing execution of operator LoadPILOperator
Going to initiate execution of operator MedNISTClassifierOperator
Executing operator MedNISTClassifierOperator (Process ID: 410750, Operator ID: e085c688-f8d2-4896-899a-3905105e40e8)
/home/mqin/src/monai-deploy-app-sdk/.venv05/lib/python3.8/site-packages/monai/utils/deprecate_utils.py:111: FutureWarning: <class 'monai.transforms.utility.array.AddChannel'>: 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'`.
warn_deprecated(obj, msg, warning_category)
/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.)
return torch.as_tensor(x, *args, **_kwargs).as_subclass(cls) # type: ignore
AbdomenCT
Done performing execution of operator MedNISTClassifierOperator
!cat output/output.json
"AbdomenCT"