-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add an example demonstrating how to intake a MONAI model (#2)
- Loading branch information
1 parent
49b8acf
commit 621c020
Showing
8 changed files
with
348 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
################################################ | ||
# REQUIRED SECTION: | ||
# The section below must be kept for all models. | ||
################################################ | ||
|
||
FROM ubuntu:jammy-20221101 | ||
|
||
# Sets arguments | ||
ARG USER_ID | ||
|
||
# Sets working directory | ||
WORKDIR app | ||
|
||
# Installs utilities | ||
RUN apt update -y \ | ||
&& apt install -y curl vim wget | ||
|
||
# Installs GPU | ||
# see for template: https://gitlab.com/nvidia/container-images/cuda/-/blob/master/dist/11.7.0/ubuntu2204/base/Dockerfile | ||
ENV PATH /usr/local/nvidia/bin:/usr/local/cuda/bin:${PATH} | ||
ENV LD_LIBRARY_PATH /usr/local/nvidia/lib:/usr/local/nvidia/lib64 | ||
|
||
ENV NVARCH x86_64 | ||
|
||
ENV CUDA_VERSION 11.7.0 | ||
ENV NV_CUDA_CUDART_VERSION 11.7.60-1 | ||
ENV NV_CUDA_COMPAT_PACKAGE cuda-compat-11-7 | ||
ENV NV_CUDA_LIB_VERSION 11.7.0-1 | ||
|
||
# see for environment variables: https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/user-guide.html#environment-variables-oci-spec | ||
ENV NVIDIA_VISIBLE_DEVICES all | ||
ENV NVIDIA_DRIVER_CAPABILITIES compute,utility | ||
ENV NVIDIA_REQUIRE_CUDA "cuda>=11.7 brand=tesla,driver>=450,driver<451 brand=tesla,driver>=470,driver<471 brand=unknown,driver>=470,driver<471 brand=nvidia,driver>=470,driver<471 brand=nvidiartx,driver>=470,driver<471 brand=quadrortx,driver>=470,driver<471 brand=unknown,driver>=510,driver<511 brand=nvidia,driver>=510,driver<511 brand=nvidiartx,driver>=510,driver<511 brand=quadrortx,driver>=510,driver<511" | ||
|
||
RUN apt install -y --no-install-recommends \ | ||
gnupg2 \ | ||
ca-certificates | ||
# see: https://github.com/NVIDIA/nvidia-docker/issues/1632#issuecomment-1125739652 | ||
RUN curl -fsSL https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/${NVARCH}/3bf863cc.pub | apt-key add - | ||
RUN echo "deb https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/${NVARCH} /" > /etc/apt/sources.list.d/cuda.list | ||
RUN rm -rf /var/lib/apt/lists/* | ||
# see for package versions: https://ubuntu.pkgs.org/22.04/cuda-amd64/ | ||
RUN apt-get update && apt-get install -y --no-install-recommends \ | ||
cuda-cudart-11-7=${NV_CUDA_CUDART_VERSION} \ | ||
cuda-libraries-11-7=${NV_CUDA_LIB_VERSION} \ | ||
${NV_CUDA_COMPAT_PACKAGE} \ | ||
&& ln -s cuda-11.7 /usr/local/cuda \ | ||
&& rm -rf /var/lib/apt/lists/* | ||
RUN echo "/usr/local/nvidia/lib" >> /etc/ld.so.conf.d/nvidia.conf \ | ||
&& echo "/usr/local/nvidia/lib64" >> /etc/ld.so.conf.d/nvidia.conf | ||
|
||
# Installs Python 3.9 | ||
RUN apt update -y \ | ||
&& apt install -y software-properties-common | ||
RUN DEBIAN_FRONTEND="noninteractive" add-apt-repository ppa:deadsnakes/ppa | ||
RUN DEBIAN_FRONTEND="noninteractive" apt install -y python3.9-dev | ||
|
||
# python3.9 also installs python3.10, and on ubuntu:jammy python3.10 is the | ||
# default version. To override this, manually delete and recreate the python3 | ||
# symbolic link. | ||
RUN rm /usr/bin/python3 | ||
RUN ln -s python3.9 /usr/bin/python3 | ||
|
||
RUN DEBIAN_FRONTEND="noninteractive" apt install -y \ | ||
python-is-python3 \ | ||
python3-gdcm \ | ||
python3-opencv \ | ||
python3-pip \ | ||
python3.9-distutils | ||
|
||
############################################################### | ||
# CUSTOM SECTION: | ||
# The section below is specific to the MonaiFlexibleUNet model. | ||
# Please customize it with the commands needed for your model. | ||
############################################################### | ||
|
||
# If needed, copy custom pretrained weights for your model into the Docker image. | ||
# The example MonaiFlexibleUNet model downloads its pretrained weights at start-up time, for ease | ||
# of definition, but your model's weights will likely need to be copied into the Docker image as | ||
# shown below: | ||
# COPY path/to/local/model_weights.pth model_weights.pth | ||
|
||
# Install PyPI requirements for this example | ||
COPY bunkerhill/examples/monai/requirements.txt requirements.txt | ||
RUN pip install -r requirements.txt | ||
|
||
# Prepares /app/model_release | ||
COPY bunkerhill bunkerhill | ||
COPY README.md README.md | ||
COPY setup.py setup.py | ||
RUN pip install --editable . | ||
|
||
ENV PYTHONUNBUFFERED=1 | ||
|
||
# Add a new user "host_user" | ||
RUN useradd -u ${USER_ID} host_user | ||
|
||
# Make host_user the owner of the /app folder and update folder permissions | ||
RUN chown -R host_user:host_user /app | ||
RUN chmod 755 /app | ||
|
||
# Change to non-root privilege | ||
USER host_user |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
"""The class definition and model server entrypoint for the MonaiFlexibleUNet model.""" | ||
|
||
from typing import Dict | ||
|
||
import numpy as np | ||
import torch | ||
|
||
from monai.networks.nets import FlexibleUNet | ||
|
||
from bunkerhill.base_model import BaseModel | ||
from bunkerhill.bunkerhill_types import Outputs, SeriesInstanceUID | ||
from bunkerhill.model_runner import ModelRunner | ||
|
||
|
||
class MonaiFlexibleUNet(BaseModel): | ||
"""A wrapper around the trained nnUNet model for the MSD Hippocampus model. | ||
Attributes: | ||
_model: The pretrained PyTorch model to call at inference time. | ||
""" | ||
_SEGMENTATION_OUTPUT_ATTRIBUTE_NAME: str = 'unet_seg_pred' | ||
|
||
def __init__(self): | ||
# Set model directory where pretrained model weights will be downloaded and unpacked. | ||
torch.hub.set_dir('/app') | ||
|
||
# Try loading a standard Torch model from a pth.tar file downloaded from HuggingFace Hub | ||
# Try compiling that model with torch.compile() for speed | ||
self.device = 'cuda' if torch.cuda.is_available() else 'cpu' | ||
self.model = FlexibleUNet( | ||
in_channels=1, out_channels=1, backbone='efficientnet-b0', pretrained=True | ||
) | ||
|
||
# Move model to GPU if available | ||
self.model.to(self.device) | ||
|
||
# Set model to eval mode | ||
self.model.eval() | ||
|
||
def inference(self, pixel_array: Dict[SeriesInstanceUID, np.ndarray]) -> Outputs: | ||
"""Runs inference on the pixel array for a DICOM series. | ||
Args: | ||
pixel_array: A dict mapping the DICOM series UID to its pixel array. | ||
Returns: | ||
A dictionary containing the output segmentation and softmax ndarrays. | ||
""" | ||
# Ensure pixel_array dict only contains a single series. | ||
if len(pixel_array) > 1: | ||
raise ValueError(f'Model only accepts a single series. {len(pixel_array)} were passed.') | ||
|
||
# Convert series pixel array from np.ndarray array to torch.Tensor. | ||
series_instance_uid = list(pixel_array.keys())[0] | ||
series_pixel_array = torch.from_numpy(pixel_array[series_instance_uid]) | ||
|
||
# Move series_pixel_array to GPU if available and cast dtype to float32 | ||
series_pixel_array = series_pixel_array.to(self.device, dtype=torch.float32) | ||
|
||
# Add batch dimension to series_pixel_array | ||
series_pixel_array = series_pixel_array.unsqueeze(0) | ||
|
||
# Run inference | ||
with torch.no_grad(): | ||
segmentation = self.model(series_pixel_array) | ||
|
||
# Resize segmentation, move it to CPU, convert dtype to int16, and convert to ndarray. | ||
segmentation = segmentation.squeeze().to('cpu', dtype=torch.int16).numpy() | ||
|
||
# Convert nnUNet segmentation and softmax tensors into output attributes. | ||
return {self._SEGMENTATION_OUTPUT_ATTRIBUTE_NAME: {series_instance_uid: segmentation}} | ||
|
||
|
||
if __name__ == '__main__': | ||
model = MonaiFlexibleUNet() | ||
model_runner = ModelRunner(model) | ||
model_runner.start_run_loop() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
monai==1.1.0 | ||
torch==2.0.0 |
Oops, something went wrong.