diff --git a/generative/networks/nets/diffusion_model_unet.py b/generative/networks/nets/diffusion_model_unet.py index fe8bf95c..aafde6b4 100644 --- a/generative/networks/nets/diffusion_model_unet.py +++ b/generative/networks/nets/diffusion_model_unet.py @@ -1890,3 +1890,176 @@ def forward( h = self.out(h) return h + + +class DiffusionModelEncoder(nn.Module): + """ + Classification Network based on the Encoder of the Diffusion Model, followed by fully connected layers. This network is based on + Wolleb et al. "Diffusion Models for Medical Anomaly Detection" (https://arxiv.org/abs/2203.04306). + + Args: + spatial_dims: number of spatial dimensions. + in_channels: number of input channels. + out_channels: number of output channels. + num_res_blocks: number of residual blocks (see ResnetBlock) per level. + num_channels: tuple of block output channels. + attention_levels: list of levels to add attention. + norm_num_groups: number of groups for the normalization. + norm_eps: epsilon for the normalization. + resblock_updown: if True use residual blocks for downsampling. + num_head_channels: number of channels in each attention head. + with_conditioning: if True add spatial transformers to perform conditioning. + transformer_num_layers: number of layers of Transformer blocks to use. + cross_attention_dim: number of context dimensions to use. + num_class_embeds: if specified (as an int), then this model will be class-conditional with `num_class_embeds` classes. + upcast_attention: if True, upcast attention operations to full precision. + """ + + def __init__( + self, + spatial_dims: int, + in_channels: int, + out_channels: int, + num_res_blocks: Sequence[int] | int = (2, 2, 2, 2), + num_channels: Sequence[int] = (32, 64, 64, 64), + attention_levels: Sequence[bool] = (False, False, True, True), + norm_num_groups: int = 32, + norm_eps: float = 1e-6, + resblock_updown: bool = False, + num_head_channels: int | Sequence[int] = 8, + with_conditioning: bool = False, + transformer_num_layers: int = 1, + cross_attention_dim: int | None = None, + num_class_embeds: int | None = None, + upcast_attention: bool = False, + ) -> None: + super().__init__() + if with_conditioning is True and cross_attention_dim is None: + raise ValueError( + "DiffusionModelEncoder expects dimension of the cross-attention conditioning (cross_attention_dim) " + "when using with_conditioning." + ) + if cross_attention_dim is not None and with_conditioning is False: + raise ValueError( + "DiffusionModelEncoder expects with_conditioning=True when specifying the cross_attention_dim." + ) + + # All number of channels should be multiple of num_groups + if any((out_channel % norm_num_groups) != 0 for out_channel in num_channels): + raise ValueError("DiffusionModelEncoder expects all num_channels being multiple of norm_num_groups") + if len(num_channels) != len(attention_levels): + raise ValueError("DiffusionModelEncoder expects num_channels being same size of attention_levels") + + if isinstance(num_head_channels, int): + num_head_channels = ensure_tuple_rep(num_head_channels, len(attention_levels)) + + if len(num_head_channels) != len(attention_levels): + raise ValueError( + "num_head_channels should have the same length as attention_levels. For the i levels without attention," + " i.e. `attention_level[i]=False`, the num_head_channels[i] will be ignored." + ) + + self.in_channels = in_channels + self.block_out_channels = num_channels + self.out_channels = out_channels + self.num_res_blocks = num_res_blocks + self.attention_levels = attention_levels + self.num_head_channels = num_head_channels + self.with_conditioning = with_conditioning + + # input + self.conv_in = Convolution( + spatial_dims=spatial_dims, + in_channels=in_channels, + out_channels=num_channels[0], + strides=1, + kernel_size=3, + padding=1, + conv_only=True, + ) + + # time + time_embed_dim = num_channels[0] * 4 + self.time_embed = nn.Sequential( + nn.Linear(num_channels[0], time_embed_dim), nn.SiLU(), nn.Linear(time_embed_dim, time_embed_dim) + ) + + # class embedding + self.num_class_embeds = num_class_embeds + if num_class_embeds is not None: + self.class_embedding = nn.Embedding(num_class_embeds, time_embed_dim) + + # down + self.down_blocks = nn.ModuleList([]) + output_channel = num_channels[0] + for i in range(len(num_channels)): + input_channel = output_channel + output_channel = num_channels[i] + is_final_block = i == len(num_channels) # - 1 + + down_block = get_down_block( + spatial_dims=spatial_dims, + in_channels=input_channel, + out_channels=output_channel, + temb_channels=time_embed_dim, + num_res_blocks=num_res_blocks[i], + norm_num_groups=norm_num_groups, + norm_eps=norm_eps, + add_downsample=not is_final_block, + resblock_updown=resblock_updown, + with_attn=(attention_levels[i] and not with_conditioning), + with_cross_attn=(attention_levels[i] and with_conditioning), + num_head_channels=num_head_channels[i], + transformer_num_layers=transformer_num_layers, + cross_attention_dim=cross_attention_dim, + upcast_attention=upcast_attention, + ) + + self.down_blocks.append(down_block) + + self.out = nn.Sequential(nn.Linear(4096, 512), nn.ReLU(), nn.Dropout(0.1), nn.Linear(512, self.out_channels)) + + def forward( + self, + x: torch.Tensor, + timesteps: torch.Tensor, + context: torch.Tensor | None = None, + class_labels: torch.Tensor | None = None, + ) -> torch.Tensor: + """ + Args: + x: input tensor (N, C, SpatialDims). + timesteps: timestep tensor (N,). + context: context tensor (N, 1, ContextDim). + class_labels: context tensor (N, ). + """ + # 1. time + t_emb = get_timestep_embedding(timesteps, self.block_out_channels[0]) + + # timesteps does not contain any weights and will always return f32 tensors + # but time_embedding might actually be running in fp16. so we need to cast here. + # there might be better ways to encapsulate this. + t_emb = t_emb.to(dtype=x.dtype) + emb = self.time_embed(t_emb) + + # 2. class + if self.num_class_embeds is not None: + if class_labels is None: + raise ValueError("class_labels should be provided when num_class_embeds > 0") + class_emb = self.class_embedding(class_labels) + class_emb = class_emb.to(dtype=x.dtype) + emb = emb + class_emb + + # 3. initial convolution + h = self.conv_in(x) + + # 4. down + if context is not None and self.with_conditioning is False: + raise ValueError("model should have with_conditioning = True if context is provided") + for downsample_block in self.down_blocks: + h, _ = downsample_block(hidden_states=h, temb=emb, context=context) + + h = h.reshape(h.shape[0], -1) + output = self.out(h) + + return output diff --git a/tutorials/generative/anomaly_detection/anomalydetection_tutorial_classifier_guidance.ipynb b/tutorials/generative/anomaly_detection/anomalydetection_tutorial_classifier_guidance.ipynb new file mode 100644 index 00000000..71e58a54 --- /dev/null +++ b/tutorials/generative/anomaly_detection/anomalydetection_tutorial_classifier_guidance.ipynb @@ -0,0 +1,1458 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "2470cf02", + "metadata": {}, + "outputs": [], + "source": [ + "# Copyright (c) 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", + "# http://www.apache.org/licenses/LICENSE-2.0\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "id": "63d95da6", + "metadata": {}, + "source": [ + "# Diffusion Models for Medical Anomaly Detection with Classifier Guidance\n", + "\n", + "This tutorial illustrates how to use MONAI for training a 2D gradient-guided anomaly detection using DDIMs [1].\n", + "\n", + "We train a diffusion model on 2D slices of brain MR images. A classification model is trained to predict whether the given slice shows a tumor or not.\\\n", + "We then translate an input slice to its healthy reconstruction using DDIMs.\\\n", + "Anomaly detection is performed by taking the difference between input and output, as proposed in [1].\n", + "\n", + "[1] - Wolleb et al. \"Diffusion Models for Medical Anomaly Detection\" https://arxiv.org/abs/2203.04306\n", + "\n", + "## Setup environment" + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "id": "75f2d5f3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "running install\n", + "/home/juliawolleb/anaconda3/envs/experiment/lib/python3.10/site-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.\n", + " warnings.warn(\n", + "/home/juliawolleb/anaconda3/envs/experiment/lib/python3.10/site-packages/setuptools/command/easy_install.py:144: EasyInstallDeprecationWarning: easy_install command is deprecated. Use build and pip and other standards-based tools.\n", + " warnings.warn(\n", + "running bdist_egg\n", + "running egg_info\n", + "writing generative.egg-info/PKG-INFO\n", + "writing dependency_links to generative.egg-info/dependency_links.txt\n", + "writing requirements to generative.egg-info/requires.txt\n", + "writing top-level names to generative.egg-info/top_level.txt\n", + "reading manifest file 'generative.egg-info/SOURCES.txt'\n", + "writing manifest file 'generative.egg-info/SOURCES.txt'\n", + "installing library code to build/bdist.linux-x86_64/egg\n", + "running install_lib\n", + "warning: install_lib: 'build/lib' does not exist -- no Python modules to install\n", + "\n", + "creating build/bdist.linux-x86_64/egg\n", + "creating build/bdist.linux-x86_64/egg/EGG-INFO\n", + "copying generative.egg-info/PKG-INFO -> build/bdist.linux-x86_64/egg/EGG-INFO\n", + "copying generative.egg-info/SOURCES.txt -> build/bdist.linux-x86_64/egg/EGG-INFO\n", + "copying generative.egg-info/dependency_links.txt -> build/bdist.linux-x86_64/egg/EGG-INFO\n", + "copying generative.egg-info/requires.txt -> build/bdist.linux-x86_64/egg/EGG-INFO\n", + "copying generative.egg-info/top_level.txt -> build/bdist.linux-x86_64/egg/EGG-INFO\n", + "zip_safe flag not set; analyzing archive contents...\n", + "creating 'dist/generative-0.1.0-py3.10.egg' and adding 'build/bdist.linux-x86_64/egg' to it\n", + "removing 'build/bdist.linux-x86_64/egg' (and everything under it)\n", + "Processing generative-0.1.0-py3.10.egg\n", + "Removing /home/juliawolleb/anaconda3/envs/experiment/lib/python3.10/site-packages/generative-0.1.0-py3.10.egg\n", + "Copying generative-0.1.0-py3.10.egg to /home/juliawolleb/anaconda3/envs/experiment/lib/python3.10/site-packages\n", + "generative 0.1.0 is already the active version in easy-install.pth\n", + "\n", + "Installed /home/juliawolleb/anaconda3/envs/experiment/lib/python3.10/site-packages/generative-0.1.0-py3.10.egg\n", + "Processing dependencies for generative==0.1.0\n", + "Searching for monai-weekly==1.2.dev2304\n", + "Best match: monai-weekly 1.2.dev2304\n", + "Adding monai-weekly 1.2.dev2304 to easy-install.pth file\n", + "\n", + "Using /home/juliawolleb/anaconda3/envs/experiment/lib/python3.10/site-packages\n", + "Searching for numpy==1.23.2\n", + "Best match: numpy 1.23.2\n", + "Adding numpy 1.23.2 to easy-install.pth file\n", + "Installing f2py script to /home/juliawolleb/anaconda3/envs/experiment/bin\n", + "Installing f2py3 script to /home/juliawolleb/anaconda3/envs/experiment/bin\n", + "Installing f2py3.10 script to /home/juliawolleb/anaconda3/envs/experiment/bin\n", + "\n", + "Using /home/juliawolleb/anaconda3/envs/experiment/lib/python3.10/site-packages\n", + "Searching for torch==1.12.1\n", + "Best match: torch 1.12.1\n", + "Adding torch 1.12.1 to easy-install.pth file\n", + "Installing convert-caffe2-to-onnx script to /home/juliawolleb/anaconda3/envs/experiment/bin\n", + "Installing convert-onnx-to-caffe2 script to /home/juliawolleb/anaconda3/envs/experiment/bin\n", + "Installing torchrun script to /home/juliawolleb/anaconda3/envs/experiment/bin\n", + "\n", + "Using /home/juliawolleb/anaconda3/envs/experiment/lib/python3.10/site-packages\n", + "Searching for typing-extensions==4.3.0\n", + "Best match: typing-extensions 4.3.0\n", + "Adding typing-extensions 4.3.0 to easy-install.pth file\n", + "\n", + "Using /home/juliawolleb/anaconda3/envs/experiment/lib/python3.10/site-packages\n", + "Finished processing dependencies for generative==0.1.0\n" + ] + } + ], + "source": [ + "!python -c \"import monai\" || pip install -q \"monai-weekly[pillow, tqdm]\"\n", + "!python -c \"import matplotlib\" || pip install -q matplotlib\n", + "!python -c \"import seaborn\" || pip install -q seaborn" + ] + }, + { + "cell_type": "markdown", + "id": "6b766027", + "metadata": {}, + "source": [ + "## Setup imports" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "id": "972ed3f3", + "metadata": { + "jupyter": { + "outputs_hidden": false + }, + "lines_to_next_cell": 2 + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "path ['/home/juliawolleb/PycharmProjects/MONAI/GenerativeModels/tutorials/generative/anomaly_detection/classifier_guidance_anomalydetection', '/home/juliawolleb/anaconda3/envs/experiment/lib/python310.zip', '/home/juliawolleb/anaconda3/envs/experiment/lib/python3.10', '/home/juliawolleb/anaconda3/envs/experiment/lib/python3.10/lib-dynload', '', '/home/juliawolleb/anaconda3/envs/experiment/lib/python3.10/site-packages', '/home/juliawolleb/anaconda3/envs/experiment/lib/python3.10/site-packages/PyYAML-6.0-py3.10-linux-x86_64.egg', '/home/juliawolleb/PycharmProjects/Python_Tutorials/Calgary_Infants/calgary/HD-BET', '/home/juliawolleb/anaconda3/envs/experiment/lib/python3.10/site-packages/lpips-0.1.4-py3.10.egg', '/home/juliawolleb/anaconda3/envs/experiment/lib/python3.10/site-packages/tqdm-4.64.1-py3.10.egg', '/home/juliawolleb/anaconda3/envs/experiment/lib/python3.10/site-packages/generative-0.1.0-py3.10.egg', '/home/juliawolleb/PycharmProjects/MONAI/GenerativeModels/', '/home/juliawolleb/PycharmProjects/MONAI/GenerativeModels/', '/home/juliawolleb/PycharmProjects/MONAI/GenerativeModels/']\n", + "MONAI version: 1.2.dev2304\n", + "Numpy version: 1.23.2\n", + "Pytorch version: 1.12.1\n", + "MONAI flags: HAS_EXT = False, USE_COMPILED = False, USE_META_DICT = False\n", + "MONAI rev id: 9a57be5aab9f2c2a134768c0c146399150e247a0\n", + "MONAI __file__: /home/juliawolleb/anaconda3/envs/experiment/lib/python3.10/site-packages/monai/__init__.py\n", + "\n", + "Optional dependencies:\n", + "Pytorch Ignite version: 0.4.10\n", + "ITK version: 5.3.0\n", + "Nibabel version: 4.0.1\n", + "scikit-image version: 0.19.3\n", + "Pillow version: 9.2.0\n", + "Tensorboard version: 2.12.0\n", + "gdown version: 4.6.4\n", + "TorchVision version: 0.13.1\n", + "tqdm version: 4.64.1\n", + "lmdb version: 1.4.0\n", + "psutil version: 5.9.4\n", + "pandas version: 1.5.3\n", + "einops version: 0.6.0\n", + "transformers version: 4.21.3\n", + "mlflow version: 2.1.1\n", + "pynrrd version: 1.0.0\n", + "\n", + "For details about installing the optional dependencies, please visit:\n", + " https://docs.monai.io/en/latest/installation.html#installing-the-recommended-dependencies\n", + "\n" + ] + } + ], + "source": [ + "import os\n", + "import time\n", + "import tempfile\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import torch\n", + "import torch.nn.functional as F\n", + "from monai import transforms\n", + "from monai.apps import DecathlonDataset\n", + "from monai.config import print_config\n", + "from monai.data import DataLoader\n", + "from monai.utils import set_determinism\n", + "from torch.cuda.amp import GradScaler, autocast\n", + "from tqdm import tqdm\n", + "\n", + "from generative.inferers import DiffusionInferer\n", + "from generative.networks.nets.diffusion_model_unet import DiffusionModelEncoder, DiffusionModelUNet\n", + "from generative.networks.schedulers.ddim import DDIMScheduler\n", + "\n", + "torch.multiprocessing.set_sharing_strategy(\"file_system\")\n", + "\n", + "print_config()" + ] + }, + { + "cell_type": "markdown", + "id": "7d4ff515", + "metadata": {}, + "source": [ + "## Setup data directory" + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "id": "8b4323e7", + "metadata": { + "jupyter": { + "outputs_hidden": false + } + }, + "outputs": [], + "source": [ + "directory = os.environ.get(\"MONAI_DATA_DIRECTORY\")\n", + "root_dir = tempfile.mkdtemp() if directory is None else directory" + ] + }, + { + "cell_type": "markdown", + "id": "99175d50", + "metadata": {}, + "source": [ + "## Set deterministic training for reproducibility" + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "id": "34ea510f", + "metadata": { + "jupyter": { + "outputs_hidden": false + } + }, + "outputs": [], + "source": [ + "set_determinism(42)" + ] + }, + { + "cell_type": "markdown", + "id": "c3f70dd1-236a-47ff-a244-575729ad92ba", + "metadata": { + "tags": [] + }, + "source": [ + "## Preprocessing of the BRATS Dataset in 2D slices for training\n", + "We download the BRATS training dataset from the Decathlon dataset. \\\n", + "We slice the volumes in axial 2D slices, and assign slice-wise labels (0 for healthy, 1 for diseased) to all slices.\n", + "Here we use transforms to augment the training dataset:\n", + "\n", + "1. `LoadImaged` loads the brain MR images from files.\n", + "1. `EnsureChannelFirstd` ensures the original data to construct \"channel first\" shape.\n", + "1. `ScaleIntensityRangePercentilesd` takes the lower and upper intensity percentiles and scales them to [0, 1].\n" + ] + }, + { + "cell_type": "code", + "execution_count": 94, + "id": "c68d2d91-9a0b-4ac1-ae49-f4a64edbd82a", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + ": Class `AddChannel` has been deprecated since version 0.8. please use MetaTensor data type and monai.transforms.EnsureChannelFirst instead.\n" + ] + } + ], + "source": [ + "channel = 0 # 0 = Flair\n", + "assert channel in [0, 1, 2, 3], \"Choose a valid channel\"\n", + "\n", + "train_transforms = transforms.Compose(\n", + " [\n", + " transforms.LoadImaged(keys=[\"image\", \"label\"]),\n", + " transforms.EnsureChannelFirstd(keys=[\"image\", \"label\"]),\n", + " transforms.Lambdad(keys=[\"image\"], func=lambda x: x[channel, :, :, :]),\n", + " transforms.AddChanneld(keys=[\"image\"]),\n", + " transforms.EnsureTyped(keys=[\"image\", \"label\"]),\n", + " transforms.Orientationd(keys=[\"image\", \"label\"], axcodes=\"RAS\"),\n", + " transforms.Spacingd(keys=[\"image\", \"label\"], pixdim=(3.0, 3.0, 2.0), mode=(\"bilinear\", \"nearest\")),\n", + " transforms.CenterSpatialCropd(keys=[\"image\", \"label\"], roi_size=(64, 64, 44)),\n", + " transforms.ScaleIntensityRangePercentilesd(keys=\"image\", lower=0, upper=99.5, b_min=0, b_max=1),\n", + " transforms.RandSpatialCropd(keys=[\"image\", \"label\"], roi_size=(64, 64, 1), random_size=False),\n", + " transforms.Lambdad(keys=[\"image\", \"label\"], func=lambda x: x.squeeze(-1)),\n", + " transforms.CopyItemsd(keys=[\"label\"], times=1, names=[\"slice_label\"]),\n", + " transforms.Lambdad(keys=[\"slice_label\"], func=lambda x: 0.0 if x.sum() > 0 else 1.0),\n", + " ]\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 107, + "id": "da1927b0", + "metadata": { + "jupyter": { + "outputs_hidden": false + } + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Loading dataset: 100%|████████████████████████| 388/388 [03:02<00:00, 2.13it/s]" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Length of training data: 388\n", + "Train image shape torch.Size([1, 64, 64])\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\n" + ] + } + ], + "source": [ + "batch_size = 64\n", + "\n", + "train_ds = DecathlonDataset(\n", + " root_dir=root_dir,\n", + " task=\"Task01_BrainTumour\",\n", + " section=\"training\", # validation\n", + " cache_rate=1.0, # you may need a few Gb of RAM... Set to 0 otherwise\n", + " num_workers=4,\n", + " download=False, # Set download to True if the dataset hasnt been downloaded yet\n", + " seed=0,\n", + " transform=train_transforms,\n", + ")\n", + "\n", + "print(f\"Length of training data: {len(train_ds)}\") # this gives the number of patients in the training set\n", + "print(f'Train image shape {train_ds[0][\"image\"].shape}')\n", + "\n", + "train_loader = DataLoader(\n", + " train_ds, batch_size=batch_size, shuffle=True, num_workers=4, drop_last=True, persistent_workers=True\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "fac55e9d", + "metadata": { + "tags": [] + }, + "source": [ + "## Preprocessing of the BRATS Dataset in 2D slices for validation\n", + "We download the BRATS validation dataset from the Decathlon dataset, and define the dataloader to load 2D slices for validation.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "id": "73d72110-a8b3-4e03-91cc-1dab4d5a7b87", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Loading dataset: 100%|██████████████████████████| 96/96 [00:48<00:00, 2.00it/s]" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Length of training data: 96\n", + "Validation Image shape torch.Size([1, 64, 64])\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\n" + ] + } + ], + "source": [ + "val_ds = DecathlonDataset(\n", + " root_dir=root_dir,\n", + " task=\"Task01_BrainTumour\",\n", + " section=\"validation\",\n", + " cache_rate=1.0, # you may need a few Gb of RAM... Set to 0 otherwise\n", + " num_workers=4,\n", + " download=False, # Set download to True if the dataset hasnt been downloaded yet\n", + " seed=0,\n", + " transform=train_transforms,\n", + ")\n", + "print(f\"Length of training data: {len(val_ds)}\")\n", + "print(f'Validation Image shape {val_ds[0][\"image\"].shape}')\n", + "\n", + "val_loader = DataLoader(\n", + " val_ds, batch_size=batch_size, shuffle=False, num_workers=4, drop_last=True, persistent_workers=True\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "08428bc6", + "metadata": {}, + "source": [ + "## Define network, scheduler, optimizer, and inferer\n", + "At this step, we instantiate the MONAI components to create a DDIM, the UNET, the noise scheduler, and the inferer used for training and sampling. We are using\n", + "the deterministic DDIM scheduler containing 1000 timesteps, and a 2D UNET with attention mechanisms\n", + "in the 3rd level (`num_head_channels=64`).\n" + ] + }, + { + "cell_type": "code", + "execution_count": 108, + "id": "bee5913e", + "metadata": { + "jupyter": { + "outputs_hidden": false + }, + "lines_to_next_cell": 2 + }, + "outputs": [], + "source": [ + "device = torch.device(\"cuda\")\n", + "\n", + "model = DiffusionModelUNet(\n", + " spatial_dims=2,\n", + " in_channels=1,\n", + " out_channels=1,\n", + " num_channels=(64, 64, 64),\n", + " attention_levels=(False, False, True),\n", + " num_res_blocks=1,\n", + " num_head_channels=64,\n", + " with_conditioning=False,\n", + ")\n", + "model.to(device)\n", + "\n", + "scheduler = DDIMScheduler(num_train_timesteps=1000)\n", + "\n", + "optimizer = torch.optim.Adam(params=model.parameters(), lr=2.5e-5)\n", + "\n", + "inferer = DiffusionInferer(scheduler)" + ] + }, + { + "cell_type": "markdown", + "id": "2a4d3ab2", + "metadata": { + "tags": [] + }, + "source": [ + "## Model training of the diffusion model\n", + "We train our diffusion model for 2000 epochs." + ] + }, + { + "cell_type": "code", + "execution_count": 109, + "id": "6c0ed909", + "metadata": { + "jupyter": { + "outputs_hidden": false + }, + "lines_to_next_cell": 2 + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 0 Validation loss 0.9828271865844727\n", + "Epoch 20 Validation loss 0.45277565717697144\n", + "Epoch 40 Validation loss 0.16044068336486816\n", + "Epoch 60 Validation loss 0.06908729672431946\n", + "Epoch 80 Validation loss 0.037922561168670654\n", + "Epoch 100 Validation loss 0.024700244888663292\n", + "Epoch 120 Validation loss 0.02825773134827614\n", + "Epoch 140 Validation loss 0.01575350947678089\n", + "Epoch 160 Validation loss 0.02807718887925148\n", + "Epoch 180 Validation loss 0.03635002672672272\n", + "Epoch 200 Validation loss 0.018522320315241814\n", + "Epoch 220 Validation loss 0.020984284579753876\n", + "Epoch 240 Validation loss 0.02985953912138939\n", + "Epoch 260 Validation loss 0.018604595214128494\n", + "Epoch 280 Validation loss 0.02505004033446312\n", + "Epoch 300 Validation loss 0.018166495487093925\n", + "Epoch 320 Validation loss 0.012706207111477852\n", + "Epoch 340 Validation loss 0.03222103416919708\n", + "Epoch 360 Validation loss 0.010545151308178902\n", + "Epoch 380 Validation loss 0.017768580466508865\n", + "Epoch 400 Validation loss 0.023036960512399673\n", + "Epoch 420 Validation loss 0.023991823196411133\n", + "Epoch 440 Validation loss 0.014143284410238266\n", + "Epoch 460 Validation loss 0.010133783333003521\n", + "Epoch 480 Validation loss 0.019768211990594864\n", + "Epoch 500 Validation loss 0.016018100082874298\n", + "Epoch 520 Validation loss 0.016411196440458298\n", + "Epoch 540 Validation loss 0.012067019008100033\n", + "Epoch 560 Validation loss 0.017793692648410797\n", + "Epoch 580 Validation loss 0.015390219166874886\n", + "Epoch 600 Validation loss 0.015438873320817947\n", + "Epoch 620 Validation loss 0.019228052347898483\n", + "Epoch 640 Validation loss 0.022589124739170074\n", + "Epoch 660 Validation loss 0.022526469081640244\n", + "Epoch 680 Validation loss 0.0310574471950531\n", + "Epoch 700 Validation loss 0.016018839552998543\n", + "Epoch 720 Validation loss 0.018153013661503792\n", + "Epoch 740 Validation loss 0.01506253331899643\n", + "Epoch 760 Validation loss 0.00914084818214178\n", + "Epoch 780 Validation loss 0.017407484352588654\n", + "Epoch 800 Validation loss 0.013946758583188057\n", + "Epoch 820 Validation loss 0.013289306312799454\n", + "Epoch 840 Validation loss 0.007855996489524841\n", + "Epoch 860 Validation loss 0.01187637448310852\n", + "Epoch 880 Validation loss 0.018494905903935432\n", + "Epoch 900 Validation loss 0.009516816586256027\n", + "Epoch 920 Validation loss 0.030950400978326797\n", + "Epoch 940 Validation loss 0.017931077629327774\n", + "Epoch 960 Validation loss 0.017525378614664078\n", + "Epoch 980 Validation loss 0.016576599329710007\n", + "Epoch 1000 Validation loss 0.007525463588535786\n", + "Epoch 1020 Validation loss 0.008745957165956497\n", + "Epoch 1040 Validation loss 0.023068588227033615\n", + "Epoch 1060 Validation loss 0.023049402981996536\n", + "Epoch 1080 Validation loss 0.020367465913295746\n", + "Epoch 1100 Validation loss 0.026941468939185143\n", + "Epoch 1120 Validation loss 0.019598377868533134\n", + "Epoch 1140 Validation loss 0.023052945733070374\n", + "Epoch 1160 Validation loss 0.020239276811480522\n", + "Epoch 1180 Validation loss 0.009076420217752457\n", + "Epoch 1200 Validation loss 0.011559909209609032\n", + "Epoch 1220 Validation loss 0.023455770686268806\n", + "Epoch 1240 Validation loss 0.015224231407046318\n", + "Epoch 1260 Validation loss 0.020417172461748123\n", + "Epoch 1280 Validation loss 0.025817634537816048\n", + "Epoch 1300 Validation loss 0.012675277888774872\n", + "Epoch 1320 Validation loss 0.014165625907480717\n", + "Epoch 1340 Validation loss 0.021743204444646835\n", + "Epoch 1360 Validation loss 0.00959782674908638\n", + "Epoch 1380 Validation loss 0.014942880719900131\n", + "Epoch 1400 Validation loss 0.033313099294900894\n", + "Epoch 1420 Validation loss 0.025836177170276642\n", + "Epoch 1440 Validation loss 0.015067282132804394\n", + "Epoch 1460 Validation loss 0.01235564611852169\n", + "Epoch 1480 Validation loss 0.012111244723200798\n", + "Epoch 1500 Validation loss 0.00833088904619217\n", + "Epoch 1520 Validation loss 0.01528056338429451\n", + "Epoch 1540 Validation loss 0.017444560304284096\n", + "Epoch 1560 Validation loss 0.014621825888752937\n", + "Epoch 1580 Validation loss 0.019431518390774727\n", + "Epoch 1600 Validation loss 0.016186822205781937\n", + "Epoch 1620 Validation loss 0.02027059532701969\n", + "Epoch 1640 Validation loss 0.01720491796731949\n", + "Epoch 1660 Validation loss 0.011756360530853271\n", + "Epoch 1680 Validation loss 0.02627478912472725\n", + "Epoch 1700 Validation loss 0.023451916873455048\n", + "Epoch 1720 Validation loss 0.011613328941166401\n", + "Epoch 1740 Validation loss 0.026256393641233444\n", + "Epoch 1760 Validation loss 0.008156227879226208\n", + "Epoch 1780 Validation loss 0.01597723178565502\n", + "Epoch 1800 Validation loss 0.013070507906377316\n", + "Epoch 1820 Validation loss 0.01726200059056282\n", + "Epoch 1840 Validation loss 0.009824991226196289\n", + "Epoch 1860 Validation loss 0.014878236688673496\n", + "Epoch 1880 Validation loss 0.017673484981060028\n", + "Epoch 1900 Validation loss 0.016455603763461113\n", + "Epoch 1920 Validation loss 0.02442217618227005\n", + "Epoch 1940 Validation loss 0.026278261095285416\n", + "Epoch 1960 Validation loss 0.02376818098127842\n", + "Epoch 1980 Validation loss 0.016214493662118912\n", + "train diffusion completed, total time: 6097.77689909935.\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkQAAAHZCAYAAABn8CRaAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/NK7nSAAAACXBIWXMAAA9hAAAPYQGoP6dpAACIC0lEQVR4nO3dd3xT5dsG8OukI92FsktL2VKgDEGW7A2CbNkbQQTFySuCAoKCAwQR/IEyKhsEFNnIFgQZsstehbJL90zyvH8ccpo0SWfSpOX68umH9Mzn5CTNnftZkhBCgIiIiOgFprJ3AYiIiIjsjQERERERvfAYEBEREdELjwERERERvfAYEBEREdELjwERERERvfAYEBEREdELjwERERERvfAYEBEREdELjwERFQhDhgyBJEkoW7asvYtClCtly5aFJEkYMmSIxW0SExMxdepU1KxZE56enpAkCZIk4b333jPa7s6dOxg1ahQqVKgANzc3Zbvff//dpteQVVOmTFHKRI4jL+5L8+bNIUkSmjdvbrNzZBcDIgezf/9+5YU4ZcoUexeHHER4eDi+/fZbtG3bFuXKlYOXlxfc3d1RunRptGvXDtOnT8fNmzftXcwXyq1bt5T3quGPk5MTChUqhKCgIDRo0ABjxozB8uXLERcXZ5XzpqamonXr1pgyZQrOnj2LhIQEs9vduXMHderUwaJFi3Djxg0kJydb5fxknuHfbkmS4O3tbfHeGEpMTISvr6/Rvvv377d9gcmEs70LQESWJScn49NPP8X8+fPNfqBFREQgIiICu3btwueff45evXrhu+++Q2BgoB1KSwCg0+kQHR2N6Oho3LlzB8eOHcOCBQvg7e2NESNGYNq0afD09Mzx8devX48jR44AkDOjgwcPRtGiRQFA+R8Apk+fjidPnsDZ2RlffvklmjZtCi8vLwBAUFBQLq6QsiIuLg6///47+vXrl+F2f/zxB2JiYvKoVJQRBkRUICxbtgzLli2zdzGs6unTp3j99deVDz9vb2/07dsXrVq1QkBAAFxcXPDgwQMcPnwYGzduxNWrV7Fu3To0bNjQpOqEbKtLly6YPn268ntCQgKioqJw8eJFHDhwAFu2bEFsbCy+//57bN26FVu2bEGlSpXMHuvWrVsZnuuvv/4CAJQsWRK//PILnJycMtyua9euGD9+fA6uyvamTJlSIDPh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ctuOdevWoVOnTjh27Bj+/PNPVKhQAf3790fLli0REBAAFxcXPHjwAEePHsWGDRuUD/f0ateujQYNGuDo0aP4+eefkZKSgsGDB8PX1xdXr17F//73P+zfvx8NGzbMdFyqnBgwYAAWLlyIxMREZQLXYsWKZTq799KlS1G3bl3cv38fX3zxBXbu3Ilhw4YhJCQEbm5uePr0Kc6ePYsdO3Zg79696Nq1q9Fgc3PmzEH//v3x2muvoWXLlggODoavry+ePXuGEydOYN68eUovyYymfMiKqKgoo2/ViYmJiIqKwsWLF7F//35s2bJFycC+9NJL2LJli9E0I/YyYMAATJkyBTExMRg+fDiuXbuGdu3aQZIknDhxArNnz8a9e/dQu3Zto8bgejExMejSpQvKli2L7t27o379+ggKCoKzszPu37+PP//8UxlQMCAgwGSqoIy4uLhg0aJFylQTjRs3xscff4xWrVopU3fMnDlTqU777rvvLA4SWBB8/vnn2LhxI27cuIFp06bh/PnzJlN36AfabdiwodnAZtasWdi9ezdiY2PRr18/HDhwAD179oSPj48ydceVK1dQt25di1X/Tk5OWLt2LRo1aoS4uDiMGDEC69evR79+/fDSSy/BxcUFjx49wn///YctW7bgyJEj+PDDD7N17+3GHsNjk2WGw79n9Uc/TLwQQmg0GjF+/Hjh5OSU6X6enp4iISHB6Px37twRZcqUsbhPmTJlxIULFzIc8j+zKSBysq3hNAmG16uXncldM5LZcPK3b98WFSpUsPj8tG3bVmzfvl35/ejRoxmeLzOJiYli3LhxwtXVNdP7KUmSGDBggLh3757JccLCwkTx4sUt7vvBBx9ka3LX7NDpdEbTfiCDqU/Su3XrlnjllVey9D4YOnSo0b76e5nRT2YTg2YkKxOuGv74+PiIDz74QMTHx2d43LycukMIIdatW2fx74Wbm5tYt26dxfdXVp+D0qVLi1OnTpmcOyuTiC5btsxqk7tmJLdTSZibuiM7sjK5682bN0WVKlUyfK5fffXVDCd33bdvn/D29ra4/+TJk7N0X86cOSMqVaqUpfs/depUk/05dQfZnJOTE77++mtcvHgRH374IWrXro3ChQvDyckJ3t7eqFatGvr374/Q0FDcv38f7u7uRvsHBgbi1KlT+Pjjj1G5cmWo1Wr4+vqiZs2amDx5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HYWLi4t4/PixsiyvrzG73dJz+3p0xOvTD5WwYMGCbB3bnvcvK58J+eU9yIDITtq0aSMKFy4sFi1aJPbu3SvefPNNAUCsWLHC3kWz6LvvvhMARPv27c0OJCaEPLZEo0aNxA8//CC2bdsmtm/fLj755BPh5uYmqlWrJuLi4oyOqR+E69NPPxX79+8X3377rVCr1XYZuLBv377i//7v/5TB7RYtWiReeukl4ezsLHbv3q1sFxYWJry8vETTpk3Ftm3bxMaNG0X16tUzHGTMEa7P0Jo1awQAsWjRIpN1+ekebtu2Taxfv14sWbJEABC9evUS69evF+vXrxfx8fFCCNvcr6SkJFGtWjURGBgoVq5cKXbv3i26detm9YEZs3KNCQkJ4pVXXhGSJIm5c+eavC+vXbumHOubb74RQ4YMEcuXLxf79u0Ta9euFW3bthUAxJQpU+xyjZldn61ej45yfYbat28v3N3dRVRUlNljOdr9y8pnghD55z3IgMhOYmNjxbvvvitKliwpXF1dRY0aNcTq1avtXawMNWvWTACw+COE/E21W7duomzZssLd3V24urqKSpUqifHjx1t8k8+dO1dUrlxZuLq6ijJlyojJkyeLlJSUvLw0IYT8LaRWrVrC19dXODk5iWLFiolu3bqJf//912TbEydOiFatWgkPDw/h4+MjunbtavTBY8hRrs9QmzZthKenp9E3Nr38dA+DgoIsvh5v3rypbGeL+/XgwQMxaNAg4efnJ9zc3ESDBg2MAue8usabN29m+L4cPHiwcqzNmzeLxo0bi2LFiglnZ2dl9GBLf3vy4hozuz5bvh4d4fr07ty5I1QqlRg0aJDFYzna/cvKZ4JefngPSkI8r3wkIiIiekGxUTURERG98BgQERER0QuPARERERG98BgQERER0QuPARERERG98BgQERER0QuPARERERG98BgQERHlkiRJdp3hnohyjwEREeWpsmXLKgFERj/Lli2zd1GJ6AXibO8CENGLqVKlSihevLjF9SVKlMjD0hDRi44BERHZxaeffoohQ4bYuxhERABYZUZERETEgIiIHJ9ho+VVq1ahXr168PLygp+fH7p27Yrz589b3Dc+Ph7Tp09HjRo14OnpCR8fH9SvXx/z58+HRqOxuF9kZCQmT56M2rVrw8fHB15eXggODsZbb72F//77z+J+27dvR9Om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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "n_epochs = 2000\n", + "val_interval = 20\n", + "epoch_loss_list = []\n", + "val_epoch_loss_list = []\n", + "\n", + "scaler = GradScaler()\n", + "total_start = time.time()\n", + "\n", + "for epoch in range(n_epochs):\n", + " model.train()\n", + " epoch_loss = 0\n", + "\n", + " for step, data in enumerate(train_loader):\n", + " images = data[\"image\"].to(device)\n", + " classes = data[\"slice_label\"].to(device)\n", + " optimizer.zero_grad(set_to_none=True)\n", + " timesteps = torch.randint(0, 1000, (len(images),)).to(device) # pick a random time step t\n", + "\n", + " with autocast(enabled=True):\n", + " # Generate random noise\n", + " noise = torch.randn_like(images).to(device)\n", + "\n", + " # Get model prediction\n", + " noise_pred = inferer(inputs=images, diffusion_model=model, noise=noise, timesteps=timesteps)\n", + " loss = F.mse_loss(noise_pred.float(), noise.float())\n", + "\n", + " scaler.scale(loss).backward()\n", + " scaler.step(optimizer)\n", + " scaler.update()\n", + " epoch_loss += loss.item()\n", + " epoch_loss_list.append(epoch_loss / (step + 1))\n", + "\n", + " if (epoch) % val_interval == 0:\n", + " model.eval()\n", + " val_epoch_loss = 0\n", + "\n", + " for step, data in enumerate(val_loader):\n", + " images = data[\"image\"].to(device)\n", + " classes = data[\"slice_label\"].to(device)\n", + " timesteps = torch.randint(0, 1000, (len(images),)).to(device)\n", + " with torch.no_grad():\n", + " with autocast(enabled=True):\n", + " noise = torch.randn_like(images).to(device)\n", + " noise_pred = inferer(inputs=images, diffusion_model=model, noise=noise, timesteps=timesteps)\n", + " val_loss = F.mse_loss(noise_pred.float(), noise.float())\n", + "\n", + " val_epoch_loss += val_loss.item()\n", + " val_epoch_loss_list.append(val_epoch_loss / (step + 1))\n", + " print(\"Epoch\", epoch, \"Validation loss\", val_epoch_loss / (step + 1))\n", + "\n", + "total_time = time.time() - total_start\n", + "print(f\"train diffusion completed, total time: {total_time}.\")\n", + "\n", + "plt.style.use(\"seaborn-bright\")\n", + "plt.title(\"Learning Curves Diffusion Model\", fontsize=20)\n", + "plt.plot(np.linspace(1, n_epochs, n_epochs), epoch_loss_list, color=\"C0\", linewidth=2.0, label=\"Train\")\n", + "plt.plot(\n", + " np.linspace(val_interval, n_epochs, int(n_epochs / val_interval)),\n", + " val_epoch_loss_list,\n", + " color=\"C1\",\n", + " linewidth=2.0,\n", + " label=\"Validation\",\n", + ")\n", + "plt.yticks(fontsize=12)\n", + "plt.xticks(fontsize=12)\n", + "plt.xlabel(\"Epochs\", fontsize=16)\n", + "plt.ylabel(\"Loss\", fontsize=16)\n", + "plt.legend(prop={\"size\": 14})\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "326101ed-333b-44a9-933f-55760b5d93a4", + "metadata": {}, + "source": [ + "## Check the performance of the diffusion model\n", + "\n", + "We generate a random image from noise to check whether our diffusion model works properly for an image generation task.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 161, + "id": "8f7a9e99-a8a4-4c8f-a42f-17ef91b18585", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|███████████████████████████████████████| 1000/1000 [00:23<00:00, 42.86it/s]\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "model.eval()\n", + "noise = torch.randn((1, 1, 64, 64))\n", + "noise = noise.to(device)\n", + "scheduler.set_timesteps(num_inference_steps=1000)\n", + "with autocast(enabled=True):\n", + " image, intermediates = inferer.sample(\n", + " input_noise=noise, diffusion_model=model, scheduler=scheduler, save_intermediates=True, intermediate_steps=100\n", + " )\n", + "\n", + "chain = torch.cat(intermediates, dim=-1)\n", + "\n", + "plt.style.use(\"default\")\n", + "plt.imshow(chain[0, 0].cpu(), vmin=0, vmax=1, cmap=\"gray\")\n", + "plt.tight_layout()\n", + "plt.axis(\"off\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "546f9983-c2e2-4c24-b03a-ebe34627638a", + "metadata": {}, + "source": [ + "## Define the classification model\n", + "First, we define the classification model. It follows the encoder architecture of the diffusion model, combined with linear layers for binary classification between healthy and diseased slices.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 174, + "id": "44cc6928-2525-4e61-8805-15b409097bbb", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [ + { + "data": { + "text/plain": [ + "DiffusionModelEncoder(\n", + " (conv_in): Convolution(\n", + " (conv): Conv2d(1, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", + " )\n", + " (time_embed): Sequential(\n", + " (0): Linear(in_features=32, out_features=128, bias=True)\n", + " (1): SiLU()\n", + " (2): Linear(in_features=128, out_features=128, bias=True)\n", + " )\n", + " (down_blocks): ModuleList(\n", + " (0): DownBlock(\n", + " (resnets): ModuleList(\n", + " (0): ResnetBlock(\n", + " (norm1): GroupNorm(32, 32, eps=1e-06, affine=True)\n", + " (nonlinearity): SiLU()\n", + " (conv1): Convolution(\n", + " (conv): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", + " )\n", + " (time_emb_proj): Linear(in_features=128, out_features=32, bias=True)\n", + " (norm2): GroupNorm(32, 32, eps=1e-06, affine=True)\n", + " (conv2): Convolution(\n", + " (conv): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", + " )\n", + " (skip_connection): Identity()\n", + " )\n", + " )\n", + " (downsampler): Downsample(\n", + " (op): Convolution(\n", + " (conv): Conv2d(32, 32, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))\n", + " )\n", + " )\n", + " )\n", + " (1): AttnDownBlock(\n", + " (attentions): ModuleList(\n", + " (0): AttentionBlock(\n", + " (norm): GroupNorm(32, 64, eps=1e-06, affine=True)\n", + " (to_q): Linear(in_features=64, out_features=64, bias=True)\n", + " (to_k): Linear(in_features=64, out_features=64, bias=True)\n", + " (to_v): Linear(in_features=64, out_features=64, bias=True)\n", + " (proj_attn): Linear(in_features=64, out_features=64, bias=True)\n", + " )\n", + " )\n", + " (resnets): ModuleList(\n", + " (0): ResnetBlock(\n", + " (norm1): GroupNorm(32, 32, eps=1e-06, affine=True)\n", + " (nonlinearity): SiLU()\n", + " (conv1): Convolution(\n", + " (conv): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", + " )\n", + " (time_emb_proj): Linear(in_features=128, out_features=64, bias=True)\n", + " (norm2): GroupNorm(32, 64, eps=1e-06, affine=True)\n", + " (conv2): Convolution(\n", + " (conv): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", + " )\n", + " (skip_connection): Convolution(\n", + " (conv): Conv2d(32, 64, kernel_size=(1, 1), stride=(1, 1))\n", + " )\n", + " )\n", + " )\n", + " (downsampler): Downsample(\n", + " (op): Convolution(\n", + " (conv): Conv2d(64, 64, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))\n", + " )\n", + " )\n", + " )\n", + " (2): AttnDownBlock(\n", + " (attentions): ModuleList(\n", + " (0): AttentionBlock(\n", + " (norm): GroupNorm(32, 64, eps=1e-06, affine=True)\n", + " (to_q): Linear(in_features=64, out_features=64, bias=True)\n", + " (to_k): Linear(in_features=64, out_features=64, bias=True)\n", + " (to_v): Linear(in_features=64, out_features=64, bias=True)\n", + " (proj_attn): Linear(in_features=64, out_features=64, bias=True)\n", + " )\n", + " )\n", + " (resnets): ModuleList(\n", + " (0): ResnetBlock(\n", + " (norm1): GroupNorm(32, 64, eps=1e-06, affine=True)\n", + " (nonlinearity): SiLU()\n", + " (conv1): Convolution(\n", + " (conv): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", + " )\n", + " (time_emb_proj): Linear(in_features=128, out_features=64, bias=True)\n", + " (norm2): GroupNorm(32, 64, eps=1e-06, affine=True)\n", + " (conv2): Convolution(\n", + " (conv): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", + " )\n", + " (skip_connection): Identity()\n", + " )\n", + " )\n", + " (downsampler): Downsample(\n", + " (op): Convolution(\n", + " (conv): Conv2d(64, 64, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))\n", + " )\n", + " )\n", + " )\n", + " )\n", + " (out): Sequential(\n", + " (0): Linear(in_features=4096, out_features=512, bias=True)\n", + " (1): ReLU()\n", + " (2): Dropout(p=0.1, inplace=False)\n", + " (3): Linear(in_features=512, out_features=2, bias=True)\n", + " )\n", + ")" + ] + }, + "execution_count": 174, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "device = torch.device(\"cuda\")\n", + "classifier = DiffusionModelEncoder(\n", + " spatial_dims=2,\n", + " in_channels=1,\n", + " out_channels=2,\n", + " num_channels=(32, 64, 64),\n", + " attention_levels=(False, True, True),\n", + " num_res_blocks=(1, 1, 1),\n", + " num_head_channels=64,\n", + " with_conditioning=False,\n", + ")\n", + "\n", + "classifier.to(device)" + ] + }, + { + "cell_type": "markdown", + "id": "45fab83a-b4c8-42cb-96c9-4e9f1e191111", + "metadata": {}, + "source": [ + "## Model training of the classification model\n", + "We train our classification model for 1000 epochs.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "de18d5cb-68e7-407c-afe9-8efd7a5a904a", + "metadata": { + "lines_to_next_cell": 0 + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 9 Validation loss 0.2536351333061854\n", + "Epoch 19 Validation loss 0.3019549027085304\n", + "Epoch 29 Validation loss 0.34552596261103946\n", + "Epoch 39 Validation loss 0.2783070926864942\n", + "Epoch 49 Validation loss 0.28460513055324554\n", + "Epoch 59 Validation loss 0.25296298414468765\n", + "Epoch 69 Validation loss 0.3343521902958552\n", + "Epoch 79 Validation loss 0.2634535978237788\n", + "Epoch 89 Validation loss 0.2862999041875203\n", + "Epoch 99 Validation loss 0.22700381030639014\n", + "Epoch 109 Validation loss 0.27035540093978244\n", + "Epoch 119 Validation loss 0.2451721504330635\n", + "Epoch 129 Validation loss 0.2890484283367793\n", + "Epoch 139 Validation loss 0.27566688507795334\n", + "Epoch 149 Validation loss 0.28788923223813373\n", + "Epoch 159 Validation loss 0.2524748469392459\n", + "Epoch 169 Validation loss 0.3107323000828425\n", + "Epoch 179 Validation loss 0.21660694728295007\n", + "Epoch 189 Validation loss 0.2702282816171646\n", + "Epoch 199 Validation loss 0.2677164326111476\n", + "Epoch 209 Validation loss 0.33349836121002835\n", + "Epoch 219 Validation loss 0.2969249188899994\n", + "Epoch 229 Validation loss 0.268981905033191\n", + "Epoch 239 Validation loss 0.29199230174223584\n", + "Epoch 249 Validation loss 0.2806356226404508\n", + "Epoch 259 Validation loss 0.301661084095637\n", + "Epoch 269 Validation loss 0.25811708470185596\n", + "Epoch 279 Validation loss 0.2599738910794258\n", + "Epoch 289 Validation loss 0.23392533014218012\n", + "Epoch 299 Validation loss 0.2580989971756935\n", + "Epoch 309 Validation loss 0.22807281464338303\n", + "Epoch 319 Validation loss 0.2510971352458\n", + "Epoch 329 Validation loss 0.25221700221300125\n", + "Epoch 339 Validation loss 0.25722870975732803\n", + "Epoch 349 Validation loss 0.2516109471519788\n", + "Epoch 359 Validation loss 0.22627043972412744\n", + "Epoch 369 Validation loss 0.28725822021563846\n", + "Epoch 379 Validation loss 0.2712069054444631\n", + "Epoch 389 Validation loss 0.29460274676481885\n", + "Epoch 399 Validation loss 0.2599460730950038\n", + "Epoch 409 Validation loss 0.22882529348134995\n", + "Epoch 419 Validation loss 0.24265126883983612\n", + "Epoch 429 Validation loss 0.23436561226844788\n", + "Epoch 439 Validation loss 0.25520699471235275\n", + "Epoch 449 Validation loss 0.22466829667488733\n", + "Epoch 459 Validation loss 0.26379595696926117\n", + "Epoch 469 Validation loss 0.23318989326556525\n", + "Epoch 479 Validation loss 0.264743114511172\n", + "Epoch 489 Validation loss 0.25179669509331387\n", + "Epoch 499 Validation loss 0.20064709583918253\n", + "Epoch 509 Validation loss 0.2527008851369222\n", + "Epoch 519 Validation loss 0.24675505111614862\n", + "Epoch 529 Validation loss 0.2267578070362409\n", + "Epoch 539 Validation loss 0.2342942381898562\n", + "Epoch 549 Validation loss 0.2587633654475212\n", + "Epoch 559 Validation loss 0.21963710337877274\n", + "Epoch 569 Validation loss 0.2676527574658394\n", + "Epoch 579 Validation loss 0.25124627848466236\n", + "Epoch 589 Validation loss 0.22307553887367249\n", + "Epoch 599 Validation loss 0.28288981815179187\n", + "Epoch 609 Validation loss 0.2745586136976878\n", + "Epoch 619 Validation loss 0.2356488679846128\n", + "Epoch 629 Validation loss 0.191768117249012\n", + "Epoch 639 Validation loss 0.23102722316980362\n", + "Epoch 649 Validation loss 0.2544248104095459\n", + "Epoch 659 Validation loss 0.23119398951530457\n", + "Epoch 669 Validation loss 0.20733060439427695\n", + "Epoch 679 Validation loss 0.22538802524407706\n", + "Epoch 689 Validation loss 0.216872605184714\n", + "Epoch 699 Validation loss 0.22977381944656372\n", + "Epoch 709 Validation loss 0.21891566862662634\n", + "Epoch 719 Validation loss 0.223398727675279\n", + "Epoch 729 Validation loss 0.24623310069243112\n", + "Epoch 739 Validation loss 0.23960118989149728\n", + "Epoch 749 Validation loss 0.21641289939483008\n", + "Epoch 759 Validation loss 0.21971949686606726\n", + "Epoch 769 Validation loss 0.22835112363100052\n", + "Epoch 779 Validation loss 0.2273434673746427\n", + "Epoch 789 Validation loss 0.18299358462293944\n", + "Epoch 799 Validation loss 0.1827801006535689\n", + "Epoch 809 Validation loss 0.21519174302617708\n", + "Epoch 819 Validation loss 0.1936649220685164\n", + "Epoch 829 Validation loss 0.23625890165567398\n", + "Epoch 839 Validation loss 0.2425163264075915\n", + "Epoch 849 Validation loss 0.16746311262249947\n", + "Epoch 859 Validation loss 0.20408761004606882\n", + "Epoch 869 Validation loss 0.2144848903020223\n", + "Epoch 879 Validation loss 0.23374033719301224\n", + "Epoch 889 Validation loss 0.23659739891688028\n", + "Epoch 899 Validation loss 0.24609535684188208\n", + "Epoch 909 Validation loss 0.2324757898847262\n", + "Epoch 919 Validation loss 0.24446949362754822\n", + "Epoch 929 Validation loss 0.19177630295356116\n", + "Epoch 939 Validation loss 0.2438896174232165\n", + "Epoch 949 Validation loss 0.2519366617004077\n", + "Epoch 959 Validation loss 0.20046784232060114\n", + "Epoch 969 Validation loss 0.21268909921248755\n", + "Epoch 979 Validation loss 0.2184151684244474\n", + "Epoch 989 Validation loss 0.21281357357899347\n", + "Epoch 999 Validation loss 0.21612912913163504\n", + "train completed, total time: 1351.5848128795624.\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkQAAAHZCAYAAABn8CRaAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/NK7nSAAAACXBIWXMAAA9hAAAPYQGoP6dpAADJeUlEQVR4nOydd3jU9B/H37m7LrqgZZaNgGwQUUFQFBmCKIIKAiJL4YeKe6MMQUUUBXHhYCiylOFiKwiiLBEQ2btQdulurzfy+yNN7ptcksut3h39vJ6nT+8yv5fLJe98JsfzPA+CIAiCIIgyjCnUAyAIgiAIggg1JIgIgiAIgijzkCAiCIIgCKLMQ4KIIAiCIIgyDwkigiAIgiDKPCSICIIgCIIo85AgIgiCIAiizEOCiCAIgiCIMg8JIoIgCIIgyjwkiAiCCDlDhgwBx3GoU6dOqIdCEEQZhQQRQQSQDRs2gOM4cByH8ePHh3o4RJiQnp6Od999F127dkXdunWRkJCAuLg4VK9eHd26dcOkSZNw/PjxUA+TIMo0llAPgCAI4mrFarXi1Vdfxccffwyr1eo2PyMjAxkZGVizZg3Gjh2LBx54AO+99x5q1qwZgtESRNmGBBFBECFnzpw5mDNnTqiHEVAuX76Me+65B3/++ScAIDExEf3798cdd9yBGjVqICoqCufOncPmzZuxdOlSHD58GIsXL0a7du3w9NNPh3bwBFEGIUFEEAQRYJxOJx588EFJDPXo0QOzZ89G5cqV3Za9++678dZbb2HevHl44YUXSnuoBEGUQIKIIAgiwMyYMQPr1q0DAHTu3Bk//PADLBbty63JZMLDDz+MTp064dChQ6U1TIIgGCiomiDCkG3btuHRRx9Fw4YNkZCQgPj4eDRq1AiPP/44Dh8+rLvusWPHMHXqVNx9992oU6cO4uLiEBcXh9q1a6Nfv35YtWqV7vpz5syRAsNPnDgBq9WKadOmoW3btqhYsaIsYFy5rNPpxOeff46bb74ZFSpUQHx8PFq0aIE333wTBQUFmvv0lGWmDFTfvn07+vfvjxo1aiAmJgbVq1fHoEGDsH//ft3PBgD5+fl444030Lx5c8THxyM1NRUdOnTArFmzwPO8LDB+w4YNHrenxGaz4d133wUAxMbGYvbs2bpiiKVGjRro1KmTbJrRDDzld6GkTp064DgOQ4YMAQD8/fffGDJkCOrWrYuYmBhwHAcAuOaaa8BxHDp06OBxvOfOnYPFYgHHcXjuuedUl7Hb7fjqq6/Qo0cPpKWlISYmBhUrVsStt96KadOmoaioSHcff//9N4YPH46GDRsiPj4esbGxqFmzJq6//no8/vjj+PHHH8HzvMexEoRHeIIgAsb69et5ADwAfty4cV6vb7PZ+FGjRknbUPuLioriP//8c9X1jx07pruu+PfQQw/xNptNdRuzZ8+Wltu+fTvfqlUrt/XFz8Yuu3fvXr5Tp06a+7zxxhv5vLw81X0OHjyYB8DXrl1bdT673xkzZvAWi0V1H+XKleN///13zeN76tQpvn79+ppj7NmzJ79mzRrp/fr16zW3pcVPP/0kO87+4unYiLDfxfHjx93m165dmwfADx48mP/0009VjyHP8/xrr73GA+A5jlPdDssHH3wgrfv333+7zT9y5AjfpEkT3XOxQYMG/KFDh1S3//777/Mmk8nj+Zybm6s7ToIwArnMCCKMGD58OL7++msAQPfu3TFw4EA0bNgQHMdh165dmDZtGv777z+MGDECVatWxd133y1b3+FwIDo6Gt26dUOXLl3QpEkTpKSkIDMzE4cOHcLHH3+M//77D/PmzUO9evUwYcIEj+P5999/8fDDD6Nfv36oWrUqTp06hZiYGLdlR4wYgS1btmDw4MHo27evtOyUKVPw119/Ydu2bZg0aRLefvttn4/P6tWrsXXrVrRo0QJPPfUUmjdvjsLCQixbtgzTp09HQUEBBg0ahMOHDyM6Olq2bnFxMXr06IEjR45Ix3fEiBGoWbMmTp8+jc8//xw///wzLl686PP4AOD333+XXvfs2dOvbQWD7du3Y968eahZsyaef/55XH/99XA4HNi0aRMAYODAgZg0aRJ4nsf8+fPx6quvam7r22+/BQA0atQIrVu3ls07e/Ys2rdvj/PnzyMxMREjRoxA586dUaVKFWRnZ2PNmjWYPn06Dh8+jDvvvBM7d+5EcnKytP6ePXvw/PPPw+l0om7dunjiiSfQqlUrpKSkIC8vD4cPH8b69euxbNmyIBwlokwSakVGEFcT/liIvv/+e2ndL774QnWZwsJCyQpTp04dNytPXl4en5GRobkPp9PJDxkyhAfAx8fH81lZWW7LsJYGAPxXX32luT3lst98843bMkVFRXyzZs14AHxqaqqq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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "\n", + "n_epochs = 1000\n", + "val_interval = 10\n", + "epoch_loss_list = []\n", + "val_epoch_loss_list = []\n", + "optimizer_cls = torch.optim.Adam(params=classifier.parameters(), lr=2.5e-5)\n", + "\n", + "\n", + "scaler = GradScaler()\n", + "total_start = time.time()\n", + "for epoch in range(n_epochs):\n", + " classifier.train()\n", + " epoch_loss = 0\n", + "\n", + " for step, data in enumerate(train_loader):\n", + " images = data[\"image\"].to(device)\n", + " classes = data[\"slice_label\"].to(device)\n", + " # classes[classes==2]=0\n", + "\n", + " optimizer_cls.zero_grad(set_to_none=True)\n", + " timesteps = torch.randint(0, 1000, (len(images),)).to(device)\n", + "\n", + " with autocast(enabled=False):\n", + " # Generate random noise\n", + " noise = torch.randn_like(images).to(device)\n", + "\n", + " # Get model prediction\n", + " noisy_img = scheduler.add_noise(images, noise, timesteps) # add t steps of noise to the input image\n", + " pred = classifier(noisy_img, timesteps)\n", + "\n", + " loss = F.cross_entropy(pred, classes.long())\n", + "\n", + " loss.backward()\n", + " optimizer_cls.step()\n", + "\n", + " epoch_loss += loss.item()\n", + " epoch_loss_list.append(epoch_loss / (step + 1))\n", + "\n", + " if (epoch + 1) % val_interval == 0:\n", + " classifier.eval()\n", + " val_epoch_loss = 0\n", + "\n", + " for step, data_val in enumerate(val_loader):\n", + " images = data_val[\"image\"].to(device)\n", + " classes = data_val[\"slice_label\"].to(device)\n", + " timesteps = torch.randint(0, 1, (len(images),)).to(\n", + " device\n", + " ) # check validation accuracy on the original images, i.e., do not add noise\n", + "\n", + " with torch.no_grad():\n", + " with autocast(enabled=False):\n", + " noise = torch.randn_like(images).to(device)\n", + " pred = classifier(images, timesteps)\n", + " val_loss = F.cross_entropy(pred, classes.long(), reduction=\"mean\")\n", + "\n", + " val_epoch_loss += val_loss.item()\n", + " _, predicted = torch.max(pred, 1)\n", + " val_epoch_loss_list.append(val_epoch_loss / (step + 1))\n", + " print(\"Epoch\", epoch, \"Validation loss\", val_epoch_loss / (step + 1))\n", + "\n", + "total_time = time.time() - total_start\n", + "print(f\"train completed, total time: {total_time}.\")\n", + "\n", + "## Learning curves for the Classifier\n", + "\n", + "plt.style.use(\"seaborn-bright\")\n", + "plt.title(\"Learning Curves\", fontsize=20)\n", + "plt.plot(np.linspace(1, n_epochs, n_epochs), epoch_loss_list, color=\"C0\", linewidth=2.0, label=\"Train\")\n", + "plt.plot(\n", + " np.linspace(val_interval, n_epochs, int(n_epochs / val_interval)),\n", + " val_epoch_loss_list,\n", + " color=\"C1\",\n", + " linewidth=2.0,\n", + " label=\"Validation\",\n", + ")\n", + "plt.yticks(fontsize=12)\n", + "plt.xticks(fontsize=12)\n", + "plt.xlabel(\"Epochs\", fontsize=16)\n", + "plt.ylabel(\"Loss\", fontsize=16)\n", + "plt.legend(prop={\"size\": 14})\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "a676b3fe", + "metadata": {}, + "source": [ + "# Image-to-image translation to a healthy subject\n", + "We pick a diseased subject of the validation set as input image. We want to translate it to its healthy reconstruction." + ] + }, + { + "cell_type": "code", + "execution_count": 162, + "id": "fe0d9eac-1477-4d6d-a885-d3c4acb4a781", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "minmax tensor(0.) tensor(1.3396)\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "DiffusionModelEncoder(\n", + " (conv_in): Convolution(\n", + " (conv): Conv2d(1, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", + " )\n", + " (time_embed): Sequential(\n", + " (0): Linear(in_features=32, out_features=128, bias=True)\n", + " (1): SiLU()\n", + " (2): Linear(in_features=128, out_features=128, bias=True)\n", + " )\n", + " (down_blocks): ModuleList(\n", + " (0): DownBlock(\n", + " (resnets): ModuleList(\n", + " (0): ResnetBlock(\n", + " (norm1): GroupNorm(32, 32, eps=1e-06, affine=True)\n", + " (nonlinearity): SiLU()\n", + " (conv1): Convolution(\n", + " (conv): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", + " )\n", + " (time_emb_proj): Linear(in_features=128, out_features=32, bias=True)\n", + " (norm2): GroupNorm(32, 32, eps=1e-06, affine=True)\n", + " (conv2): Convolution(\n", + " (conv): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", + " )\n", + " (skip_connection): Identity()\n", + " )\n", + " )\n", + " (downsampler): Downsample(\n", + " (op): Convolution(\n", + " (conv): Conv2d(32, 32, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))\n", + " )\n", + " )\n", + " )\n", + " (1): AttnDownBlock(\n", + " (attentions): ModuleList(\n", + " (0): AttentionBlock(\n", + " (norm): GroupNorm(32, 64, eps=1e-06, affine=True)\n", + " (to_q): Linear(in_features=64, out_features=64, bias=True)\n", + " (to_k): Linear(in_features=64, out_features=64, bias=True)\n", + " (to_v): Linear(in_features=64, out_features=64, bias=True)\n", + " (proj_attn): Linear(in_features=64, out_features=64, bias=True)\n", + " )\n", + " )\n", + " (resnets): ModuleList(\n", + " (0): ResnetBlock(\n", + " (norm1): GroupNorm(32, 32, eps=1e-06, affine=True)\n", + " (nonlinearity): SiLU()\n", + " (conv1): Convolution(\n", + " (conv): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", + " )\n", + " (time_emb_proj): Linear(in_features=128, out_features=64, bias=True)\n", + " (norm2): GroupNorm(32, 64, eps=1e-06, affine=True)\n", + " (conv2): Convolution(\n", + " (conv): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", + " )\n", + " (skip_connection): Convolution(\n", + " (conv): Conv2d(32, 64, kernel_size=(1, 1), stride=(1, 1))\n", + " )\n", + " )\n", + " )\n", + " (downsampler): Downsample(\n", + " (op): Convolution(\n", + " (conv): Conv2d(64, 64, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))\n", + " )\n", + " )\n", + " )\n", + " (2): AttnDownBlock(\n", + " (attentions): ModuleList(\n", + " (0): AttentionBlock(\n", + " (norm): GroupNorm(32, 64, eps=1e-06, affine=True)\n", + " (to_q): Linear(in_features=64, out_features=64, bias=True)\n", + " (to_k): Linear(in_features=64, out_features=64, bias=True)\n", + " (to_v): Linear(in_features=64, out_features=64, bias=True)\n", + " (proj_attn): Linear(in_features=64, out_features=64, bias=True)\n", + " )\n", + " )\n", + " (resnets): ModuleList(\n", + " (0): ResnetBlock(\n", + " (norm1): GroupNorm(32, 64, eps=1e-06, affine=True)\n", + " (nonlinearity): SiLU()\n", + " (conv1): Convolution(\n", + " (conv): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", + " )\n", + " (time_emb_proj): Linear(in_features=128, out_features=64, bias=True)\n", + " (norm2): GroupNorm(32, 64, eps=1e-06, affine=True)\n", + " (conv2): Convolution(\n", + " (conv): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", + " )\n", + " (skip_connection): Identity()\n", + " )\n", + " )\n", + " (downsampler): Downsample(\n", + " (op): Convolution(\n", + " (conv): Conv2d(64, 64, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))\n", + " )\n", + " )\n", + " )\n", + " )\n", + " (out): Sequential(\n", + " (0): Linear(in_features=4096, out_features=512, bias=True)\n", + " (1): ReLU()\n", + " (2): Dropout(p=0.1, inplace=False)\n", + " (3): Linear(in_features=512, out_features=2, bias=True)\n", + " )\n", + ")" + ] + }, + "execution_count": 162, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "idx_unhealthy = np.argwhere(data_val[\"slice_label\"].numpy() == 0).squeeze()\n", + "idx = idx_unhealthy[4] # Pick a random slice of the validation set to be transformed\n", + "inputimg = data_val[\"image\"][idx] # Pick an input slice of the validation set to be transformed\n", + "inputlabel = data_val[\"slice_label\"][idx] # Check whether it is healthy or diseased\n", + "print(\"minmax\", inputimg.min(), inputimg.max())\n", + "\n", + "plt.figure(\"input\" + str(inputlabel))\n", + "plt.imshow(inputimg[0, ...], vmin=0, vmax=1, cmap=\"gray\")\n", + "plt.axis(\"off\")\n", + "plt.tight_layout()\n", + "plt.show()\n", + "\n", + "model.eval()\n", + "classifier.eval()" + ] + }, + { + "cell_type": "markdown", + "id": "0cd48c2d", + "metadata": {}, + "source": [ + "### Encoding the input image in noise with the reversed DDIM sampling scheme\n", + "In order to sample using gradient guidance, we first need to encode the input image in noise by using the reversed DDIM sampling scheme.\\\n", + "We define the number of steps in the noising and denoising process by L.\\\n", + "The encoding process is presented in Equation 6 of the paper \"Diffusion Models for Medical Anomaly Detection\" (https://arxiv.org/pdf/2203.04306.pdf).\n" + ] + }, + { + "cell_type": "code", + "execution_count": 176, + "id": "f71e4924", + "metadata": { + "jupyter": { + "outputs_hidden": false + }, + "lines_to_next_cell": 2 + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|█████████████████████████████████████████| 200/200 [00:05<00:00, 33.36it/s]\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "L = 200\n", + "current_img = inputimg[None, ...].to(device)\n", + "scheduler.set_timesteps(num_inference_steps=1000)\n", + "\n", + "progress_bar = tqdm(range(L)) # go back and forth L timesteps\n", + "for t in progress_bar: # go through the noising process\n", + " with autocast(enabled=False):\n", + " with torch.no_grad():\n", + " model_output = model(current_img, timesteps=torch.Tensor((t,)).to(current_img.device))\n", + " current_img, _ = scheduler.reversed_step(model_output, t, current_img)\n", + "\n", + "plt.style.use(\"default\")\n", + "plt.imshow(current_img[0, 0].cpu(), vmin=0, vmax=1, cmap=\"gray\")\n", + "plt.tight_layout()\n", + "plt.axis(\"off\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "a7c8346a-6296-4800-b978-c10fcdf09779", + "metadata": {}, + "source": [ + "### Denoising process using gradient guidance\n", + "From the noisy image, we apply DDIM sampling scheme for denoising for L steps.\\\n", + "Additionally, we apply gradient guidance using the classifier network towards the desired class label y=0 (healthy). This is presented in Algorithm 2 of https://arxiv.org/pdf/2105.05233.pdf, and in Algorithm 1 of https://arxiv.org/pdf/2203.04306.pdf. \\\n", + "The scale s is used to amplify the gradient." + ] + }, + { + "cell_type": "code", + "execution_count": 173, + "id": "7ab274bd-ea60-4674-b59b-d41de98fee5b", + "metadata": { + "lines_to_next_cell": 2 + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|█████████████████████████████████████████| 200/200 [00:15<00:00, 12.79it/s]\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "y = torch.tensor(0) # define the desired class label\n", + "scale = 6 # define the desired gradient scale s\n", + "progress_bar = tqdm(range(L)) # go back and forth L timesteps\n", + "\n", + "for i in progress_bar: # go through the denoising process\n", + " t = L - i\n", + " with autocast(enabled=True):\n", + " with torch.no_grad():\n", + " model_output = model(\n", + " current_img, timesteps=torch.Tensor((t,)).to(current_img.device)\n", + " ).detach() # this is supposed to be epsilon\n", + "\n", + " with torch.enable_grad():\n", + " x_in = current_img.detach().requires_grad_(True)\n", + " logits = classifier(x_in, timesteps=torch.Tensor((t,)).to(current_img.device))\n", + " log_probs = F.log_softmax(logits, dim=-1)\n", + " selected = log_probs[range(len(logits)), y.view(-1)]\n", + " a = torch.autograd.grad(selected.sum(), x_in)[0]\n", + " alpha_prod_t = scheduler.alphas_cumprod[t]\n", + " updated_noise = (\n", + " model_output - (1 - alpha_prod_t).sqrt() * scale * a\n", + " ) # update the predicted noise epsilon with the gradient of the classifier\n", + "\n", + " current_img, _ = scheduler.step(updated_noise, t, current_img)\n", + " torch.cuda.empty_cache()\n", + "\n", + "plt.style.use(\"default\")\n", + "plt.imshow(current_img[0, 0].cpu().detach().numpy(), vmin=0, vmax=1, cmap=\"gray\")\n", + "plt.tight_layout()\n", + "plt.axis(\"off\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "d2e343f8-c6f3-4071-a5e6-771e2343c3bc", + "metadata": { + "lines_to_next_cell": 2 + }, + "source": [ + "# Anomaly Detection\n", + "To get the anomaly map, we compute the difference between the input image the output of our image-to-image translation model towards the healthy reconstruction." + ] + }, + { + "cell_type": "code", + "execution_count": 175, + "id": "ecffaaf3-a7df-453e-81a9-757113d85084", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAbsAAAG7CAYAAABaaTseAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/NK7nSAAAACXBIWXMAAA9hAAAPYQGoP6dpAAASLElEQVR4nO3dQaht11kH8HUlD9pAK7SSDJLSN4iYQNNCJ9WUYilRFBQcFAXn4qRKB8UMOujrIFAHltJJESdOdNBBKbSgg4hPpNB0UGodtJI3eAEzyIMWNBCFBI5DQc/3f7nrnXvvy//+fsO93tpnnb3PfX82fOvbZ4fD4bAAoNgvXPUCAOCiCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6j3yTv/h2dmLYfStEywFACY3xpHD4Yv3ne3JDoB6wg6AesIOgHrCDoB6wg6AesIOgHrveOuB7QUAXJ0HyyBPdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1HvkqhcAXKQbYeytS1sFXDVPdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANSz9YB3gcsqn0+fk/5U0rzJzrp3rsN/bXwO9PFkB0A9YQdAPWEHQD1hB0A9YQdAPdWY18pO1eCO927M2a0anL5TWsP0s/9AmPPzMPb2cHz3O02VldPnrLXW+zbmpD9/VZx08WQHQD1hB0A9YQdAPWEHQD1hB0A9YQdAPVsPrpVT3u60jWGnbD01Rk7bCE75Welcvx3GvnfOz7mfaRtBkrZGTNL63j8c/8+Nz4Gr58kOgHrCDoB6wg6AesIOgHrCDoB6qjEvxW4D5qlabqqUWytX8u1U7D2xMeeNMDZVPKZ1p2bG0/nST3tq+Jzm/DiMTVIVaWo6fW84vlM9meak6zpVXe7+lqdru1NNm9awWwFLO092ANQTdgDUE3YA1BN2ANQTdgDUE3YA1LP14FKkcuhURj2N7W4veHxjzlQankrGd8vTz7uGtdZ6amPOVHKf1p3K9Kfrt7NtY635O6X1vTIcT7+VnRL+dF13xybT1o10L+A4T3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUs/XgyqXO+Dud59MbEXZMZd47byJYa687fzK9IeCxMGfagvFamJO2Ebw+HN99k8NO2f/NMDZJv5VpDbtl/9NveTq+1rylw5sNOD9PdgDUE3YA1BN2ANQTdgDUE3YA1FONeSlS9WS6BTuVi6kCcKrm2zlf+pxkp7H0TvVduubTZ+1cu7X2Gj6n831gY84kVfvuNChPFZypofiOne8Lx3myA6CesAOgnrADoJ6wA6CesAOgnrADoJ6tByc1lWvvlHivNZdy75b9T581lbqvNZd/p3Wn9U3zUon8ZTWW/ngYu3NJa1hrrR8Ox9M1mppbp3WnP/+PDsfTvXgzjO1sOTnl73Wt3HSadp7sAKgn7ACoJ+wAqCfsAKgn7ACoJ+wAqGfrwbmlkvup1DyVSqdbMM2byszXyqXXbwzHU9f+afvDznaAteby77Rd4dEwNpW7p/uU1jfZKXdPWw923qLwWpgz3aenwpyfhLFXwtiO6beXTH8br4c5aXsG15knOwDqCTsA6gk7AOoJOwDqCTsA6qnGPKmdSrCpim6tuQIwVfKlsel8qcpv+k7pp5O+007V4GNhbKryS+ubqlnTtUuVlTv3PVWETud7MsyZ1peaHz8TxqYG0ulepPv+9MacNDZ5O4xN1zXdd1p4sgOgnrADoJ6wA6CesAOgnrADoJ6wA6CerQfnlkrQp8uZSqhTw+I0Nkll8FPj3zRnKstOzaN3zpfmpHLyqYF0KidPjYQn6XzT2lPZ/05D8XS+U37OWvNWgSQ1y57uYbrv03aUnYbYa+Xvu2O6tqf+HE7Bkx0A9YQdAPWEHQD1hB0A9YQdAPVUY57UTkPZqZpwrbmqK1UTpua+U3VbqtibfiKpQjJdh5snXENaRzrfs8Pxfwpz0n3aaVj8sFfsTQ2207p3mlvvNNFOc1JF6NQAfKpSvt/5pmu0WwHLRfJkB0A9YQdAPWEHQD1hB0A9YQdAPWEHQD1bD85tp6w4lUpP5ctpLDVh3imD32ncPJVxpznJTqPlNC/9tF/aWMObYWz6TaRS/NTUebqHabvHVCK/cy/Wmn/Lu2X1O//VTGtP1zV93zsnXMNae9tyuCqe7ACoJ+wAqCfsAKgn7ACoJ+wAqCfsAKhn68G57XQtT6XIO7cgzdkpNX9043xpi0Na31S6nt4qsPOd0pshdsvxJ9O1eC3MSVsPpq0l9zbPd0rp2u28IWDnrQfpu6atEZO0hp23caRr5K0HV8WTHQD1hB0A9YQdAPWEHQD1hB0A9VRjXop0mVMF21TVlaryUlXjVFn272HOVKmWKuJSo95UJTlJTZgnqSJuGkuVd+l8U9XlTiXfWvn+Tqb17TYl3vmv4W4Ym37nqRLy1eH4Y2HOTrXjqZtl8zDyZAdAPWEHQD1hB0A9YQdAPWEHQD1hB0A9Ww8uxU7Z+lqnb5q8W4Z+TGoEnUrup3LtH4c5j4ex6fumLQ7T+tKfQ7p2U1n91Pz4fuebvlO6DtPad+/TtPadrTJrzb/znd9/Wncam67FTjPqtfa2LEzrs43honmyA6CesAOgnrADoJ6wA6CesAOgnrADoJ6tB5dit/v9Tif7nVua3mAwrSGVa6dy8qnEOl2jdL5JKtOfvm8qJb8Zxqb17ZaTT9c2XfOprD5tFfiDMPaN4fju1pYnNs432b2u028svaUj/W1M0n3afcMCD8qTHQD1hB0A9YQdAPWEHQD1hB0A9VRjntRUhbXTGDnNSxVdqUn0dLtTNdpU5ffrYc5LYWyqktz9TlPD4vTTTt93ks43jaV1pyrJTwzHXw5zJs+EsW+Fsamy8tPzlM9P615rfe3FYSBdh1M3t57Ot1Nxeb/POu8cjaAvmic7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6tl6cFJTWfFjYU5qcjzdnlSmP5XirzWvL5VyTw18fxDm7DTWTWXc6TtN1zZd12mLyPRd18rX6OZwPN2nJ8PYVI5/L8x5/ujRL62PjTO+vP4inO+p4fjtecrvhK0HT37x+PEv/FVYw3QPd0r+15q3U6Sy//Rbnu7vznYiLponOwDqCTsA6gk7AOoJOwDqCTsA6qnGPKmp0jA1u52q3tZa66fD8amacK254myttV4fjqcKsaki7ukwZ1p3kqre0vW7Mxz/ZJhzezierkO65pN0b385jH3z6NGPHD41znhu/ePR47fX341zbvzsuXHsVz74b0eP3/mP3xjnfOUX/3gc+/xf/+W0inHOfP3SvUhVuDvVk6lJ9E5TZw2fr4onOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOqdHQ6Hwzv6h2e3Lngp7xY7jVzfF8ZSg+GpxDptL0i7SaZ5vxXmvDQcT02OnwljU2n4bkn2dI1S8+hp28TOvVhrrQ8Ox1MD8Pl39LHDm0eP/+iFXxvnPPfn/3D0+JfXl8Y5X19/Oo69sL5y9PinXvveOGd9+z3z2Oe+Ogz8/jxnLPv/+zAn/Y6m3+zuVh7bCB4Wh8Ot+/4bT3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDU89aDS5HKl9NWhulNADfDnJfvu5r/74dhbNpGcDfM+UkYe3w4nrrLp7cHTG89uBnmTNsf0taDdL7pbRLpOz0/jvzLh45vZTj7vbBL6E+OH/7Nz35mnHLjI/P6vvtLnz0+8IWzeQ1356F5+00q+//X4Xh6C0a65lxnnuwAqCfsAKgn7ACoJ+wAqCfsAKinEfS5perJncawU3XiWnPj2tRY+smNNaSi3KlSM1XETdWOa6316eH47TAnVexN1+jZMGeq4JwrJHPj6+kaTdW0a+XvNM1LDbunKsn0552qT6eqxqlCcq18jabPSvdpajqdrt3NMHZ3OJ6ahicaQT8sNIIGgCXsALgGhB0A9YQdAPWEHQD1hB0A9TSCPrdUbjxtS0iXOY1Nn5VKpX8WxqaS9qmRcZqTthekkvtXhuMf3zzf1Pj6p2HO5G4YS+ebtoKk893cGJu2TKw1X6O0TSV5dDiett6ksWnrwUthzrTF4IkwJ22NSFsWaOfJDoB6wg6AesIOgHrCDoB6wg6AesIOgHq2HpzUThf01Cn+7Y3zpfLqqTQ8vcFg+k67bz2YxtJ1+GgYm+btvCnh1TBnRyrFn94qsFYux59Mf8rhPv3qH81j3//6MLB7n6Z1pP+Cpu0KaRtIOt+0dm8vuA482QFQT9gBUE/YAVBP2AFQT9gBUE815pWbKs52pYq4qZFwqrCbqgbTnGSqUEzNnm9vfM7O+tKcVN053cOdyti11vrwcDxVuU7n++Q85fu3wvmmZstp3amh+PRfTbrv94bjqXpSZSXHebIDoJ6wA6CesAOgnrADoJ6wA6CesAOgnq0HJzWVZe+WQ++c72/C2NSMN21XuDscT2X6j4exae27WxkmqUR+krYK7MzbaUa91lZT57Fp+A/CnJ31TVsS0hrWmr/TG2HOJG1XSH8bp/6N8W7iyQ6AesIOgHrCDoB6wg6AesIOgHqqMU/q1E1oT32+qfLt5TBnqthLlYE7DYvTTzFVd06NqlNl4CRd71S5OK09VYSmysDpPqU50/2Yrs9ae9WYUzPxNGetvz386OjxPzz7TDjfVPmZGk7v3HeuA092ANQTdgDUE3YA1BN2ANQTdgDUE3YA1LP14FqZSutPvcUhNep9fjj+nTBnZ0tAKqufxlJJezrfVO6eth7sNJ1Oc6a176x7rXX3z44f/1z4Tt/96jg0bzFIW1juDcfT9oJT/5Zp4ckOgHrCDoB6wg6AesIOgHrCDoB6wg6AerYecB9TJ/vUgT9tPUhvWJiEcvf3vHD8+H+/uPE5ad0/D2PPDsfT1oO0zWG6tukNBtNnzffpO4d/Hsd+92wa+XBYQzKt49UwxzYCTseTHQD1hB0A9YQdAPWEHQD1hB0A9c4Oh8PhHf3Ds1sXvBQu3lSxt1P1lioN0/mmisdUabgjVVZOn5W+UzIVNZ+6YXH6TpPUCDpVmD49HL8T5qTvO1FxyYM7HG7d9994sgOgnrADoJ6wA6CesAOgnrADoJ6wA6CeRtDXylTmvbONIJWMp/NNDYF3tzJMTr2VIa1h57ruSM23T23aYnCZazjlVhmuO092ANQTdgDUE3YA1BN2ANQTdgDUE3YA1LP1gPXwl3KfelvCZZzrQc53WSX3O9spTu3U2zPgOE92ANQTdgDUE3YA1BN2ANQTdgDUU43JBXjYqzsfdg9zhempPezro4UnOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqCTsA6gk7AOoJOwDqPXLVCwCA/3VjOP7WA53Vkx0A9YQdAPWEHQD1hB0A9YQdAPXOUY353o3Tv70xBwD+r/c/0GxPdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQ7OxwOh6teBABcJE92ANQTdgDUE3YA1BN2ANQTdgDUE3YA1BN2ANQTdgDUE3YA1PsfHnc8lSExf2kAAAAASUVORK5CYII=\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "\n", + "diff = abs(inputimg.cpu() - current_img[0, 0].cpu()).detach().numpy()\n", + "plt.style.use(\"default\")\n", + "plt.imshow(diff[0, ...], cmap=\"jet\")\n", + "plt.tight_layout()\n", + "plt.axis(\"off\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c459ab23-459d-4063-824e-39dac93abb43", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "jupytext": { + "formats": "py:percent,ipynb" + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tutorials/generative/anomaly_detection/anomalydetection_tutorial_classifier_guidance.py b/tutorials/generative/anomaly_detection/anomalydetection_tutorial_classifier_guidance.py new file mode 100644 index 00000000..54fdb6f6 --- /dev/null +++ b/tutorials/generative/anomaly_detection/anomalydetection_tutorial_classifier_guidance.py @@ -0,0 +1,505 @@ +# --- +# jupyter: +# jupytext: +# formats: py:percent,ipynb +# text_representation: +# extension: .py +# format_name: percent +# format_version: '1.3' +# jupytext_version: 1.14.4 +# kernelspec: +# display_name: Python 3 (ipykernel) +# language: python +# name: python3 +# --- + +# %% +# Copyright (c) MONAI Consortium +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# %% [markdown] +# # Diffusion Models for Medical Anomaly Detection with Classifier Guidance +# +# This tutorial illustrates how to use MONAI for training a 2D gradient-guided anomaly detection using DDIMs [1]. +# +# We train a diffusion model on 2D slices of brain MR images. A classification model is trained to predict whether the given slice shows a tumor or not.\ +# We then translate an input slice to its healthy reconstruction using DDIMs.\ +# Anomaly detection is performed by taking the difference between input and output, as proposed in [1]. +# +# [1] - Wolleb et al. "Diffusion Models for Medical Anomaly Detection" https://arxiv.org/abs/2203.04306 +# +# ## Setup environment + +# %% +# !python -c "import monai" || pip install -q "monai-weekly[pillow, tqdm]" +# !python -c "import matplotlib" || pip install -q matplotlib +# !python -c "import seaborn" || pip install -q seaborn + +# %% [markdown] +# ## Setup imports + +# %% jupyter={"outputs_hidden": false} +import os +import time +import tempfile +import matplotlib.pyplot as plt +import numpy as np +import torch +import torch.nn.functional as F +from monai import transforms +from monai.apps import DecathlonDataset +from monai.config import print_config +from monai.data import DataLoader +from monai.utils import set_determinism +from torch.cuda.amp import GradScaler, autocast +from tqdm import tqdm + +from generative.inferers import DiffusionInferer +from generative.networks.nets.diffusion_model_unet import DiffusionModelEncoder, DiffusionModelUNet +from generative.networks.schedulers.ddim import DDIMScheduler + +torch.multiprocessing.set_sharing_strategy("file_system") + +print_config() + + +# %% [markdown] +# ## Setup data directory + +# %% jupyter={"outputs_hidden": false} +directory = os.environ.get("MONAI_DATA_DIRECTORY") +root_dir = tempfile.mkdtemp() if directory is None else directory + +# %% [markdown] +# ## Set deterministic training for reproducibility + +# %% jupyter={"outputs_hidden": false} +set_determinism(42) + +# %% [markdown] tags=[] +# ## Preprocessing of the BRATS Dataset in 2D slices for training +# We download the BRATS training dataset from the Decathlon dataset. \ +# We slice the volumes in axial 2D slices, and assign slice-wise labels (0 for healthy, 1 for diseased) to all slices. +# Here we use transforms to augment the training dataset: +# +# 1. `LoadImaged` loads the brain MR images from files. +# 1. `EnsureChannelFirstd` ensures the original data to construct "channel first" shape. +# 1. `ScaleIntensityRangePercentilesd` takes the lower and upper intensity percentiles and scales them to [0, 1]. +# + +# %% +channel = 0 # 0 = Flair +assert channel in [0, 1, 2, 3], "Choose a valid channel" + +train_transforms = transforms.Compose( + [ + transforms.LoadImaged(keys=["image", "label"]), + transforms.EnsureChannelFirstd(keys=["image", "label"]), + transforms.Lambdad(keys=["image"], func=lambda x: x[channel, :, :, :]), + transforms.AddChanneld(keys=["image"]), + transforms.EnsureTyped(keys=["image", "label"]), + transforms.Orientationd(keys=["image", "label"], axcodes="RAS"), + transforms.Spacingd(keys=["image", "label"], pixdim=(3.0, 3.0, 2.0), mode=("bilinear", "nearest")), + transforms.CenterSpatialCropd(keys=["image", "label"], roi_size=(64, 64, 44)), + transforms.ScaleIntensityRangePercentilesd(keys="image", lower=0, upper=99.5, b_min=0, b_max=1), + transforms.RandSpatialCropd(keys=["image", "label"], roi_size=(64, 64, 1), random_size=False), + transforms.Lambdad(keys=["image", "label"], func=lambda x: x.squeeze(-1)), + transforms.CopyItemsd(keys=["label"], times=1, names=["slice_label"]), + transforms.Lambdad(keys=["slice_label"], func=lambda x: 0.0 if x.sum() > 0 else 1.0), + ] +) + +# %% jupyter={"outputs_hidden": false} +batch_size = 64 + +train_ds = DecathlonDataset( + root_dir=root_dir, + task="Task01_BrainTumour", + section="training", # validation + cache_rate=1.0, # you may need a few Gb of RAM... Set to 0 otherwise + num_workers=4, + download=False, # Set download to True if the dataset hasnt been downloaded yet + seed=0, + transform=train_transforms, +) + +print(f"Length of training data: {len(train_ds)}") # this gives the number of patients in the training set +print(f'Train image shape {train_ds[0]["image"].shape}') + +train_loader = DataLoader( + train_ds, batch_size=batch_size, shuffle=True, num_workers=4, drop_last=True, persistent_workers=True +) + +# %% [markdown] tags=[] +# ## Preprocessing of the BRATS Dataset in 2D slices for validation +# We download the BRATS validation dataset from the Decathlon dataset, and define the dataloader to load 2D slices for validation. +# +# + +# %% +val_ds = DecathlonDataset( + root_dir=root_dir, + task="Task01_BrainTumour", + section="validation", + cache_rate=1.0, # you may need a few Gb of RAM... Set to 0 otherwise + num_workers=4, + download=False, # Set download to True if the dataset hasnt been downloaded yet + seed=0, + transform=train_transforms, +) +print(f"Length of training data: {len(val_ds)}") +print(f'Validation Image shape {val_ds[0]["image"].shape}') + +val_loader = DataLoader( + val_ds, batch_size=batch_size, shuffle=False, num_workers=4, drop_last=True, persistent_workers=True +) + + +# %% [markdown] +# ## Define network, scheduler, optimizer, and inferer +# At this step, we instantiate the MONAI components to create a DDIM, the UNET, the noise scheduler, and the inferer used for training and sampling. We are using +# the deterministic DDIM scheduler containing 1000 timesteps, and a 2D UNET with attention mechanisms +# in the 3rd level (`num_head_channels=64`). +# + +# %% jupyter={"outputs_hidden": false} +device = torch.device("cuda") + +model = DiffusionModelUNet( + spatial_dims=2, + in_channels=1, + out_channels=1, + num_channels=(64, 64, 64), + attention_levels=(False, False, True), + num_res_blocks=1, + num_head_channels=64, + with_conditioning=False, +) +model.to(device) + +scheduler = DDIMScheduler(num_train_timesteps=1000) + +optimizer = torch.optim.Adam(params=model.parameters(), lr=2.5e-5) + +inferer = DiffusionInferer(scheduler) + + +# %% [markdown] tags=[] +# ## Model training of the diffusion model +# We train our diffusion model for 2000 epochs. + +# %% jupyter={"outputs_hidden": false} +n_epochs = 2000 +val_interval = 20 +epoch_loss_list = [] +val_epoch_loss_list = [] + +scaler = GradScaler() +total_start = time.time() + +for epoch in range(n_epochs): + model.train() + epoch_loss = 0 + + for step, data in enumerate(train_loader): + images = data["image"].to(device) + classes = data["slice_label"].to(device) + optimizer.zero_grad(set_to_none=True) + timesteps = torch.randint(0, 1000, (len(images),)).to(device) # pick a random time step t + + with autocast(enabled=True): + # Generate random noise + noise = torch.randn_like(images).to(device) + + # Get model prediction + noise_pred = inferer(inputs=images, diffusion_model=model, noise=noise, timesteps=timesteps) + loss = F.mse_loss(noise_pred.float(), noise.float()) + + scaler.scale(loss).backward() + scaler.step(optimizer) + scaler.update() + epoch_loss += loss.item() + epoch_loss_list.append(epoch_loss / (step + 1)) + + if (epoch) % val_interval == 0: + model.eval() + val_epoch_loss = 0 + + for step, data in enumerate(val_loader): + images = data["image"].to(device) + classes = data["slice_label"].to(device) + timesteps = torch.randint(0, 1000, (len(images),)).to(device) + with torch.no_grad(): + with autocast(enabled=True): + noise = torch.randn_like(images).to(device) + noise_pred = inferer(inputs=images, diffusion_model=model, noise=noise, timesteps=timesteps) + val_loss = F.mse_loss(noise_pred.float(), noise.float()) + + val_epoch_loss += val_loss.item() + val_epoch_loss_list.append(val_epoch_loss / (step + 1)) + print("Epoch", epoch, "Validation loss", val_epoch_loss / (step + 1)) + +total_time = time.time() - total_start +print(f"train diffusion completed, total time: {total_time}.") + +plt.style.use("seaborn-bright") +plt.title("Learning Curves Diffusion Model", fontsize=20) +plt.plot(np.linspace(1, n_epochs, n_epochs), epoch_loss_list, color="C0", linewidth=2.0, label="Train") +plt.plot( + np.linspace(val_interval, n_epochs, int(n_epochs / val_interval)), + val_epoch_loss_list, + color="C1", + linewidth=2.0, + label="Validation", +) +plt.yticks(fontsize=12) +plt.xticks(fontsize=12) +plt.xlabel("Epochs", fontsize=16) +plt.ylabel("Loss", fontsize=16) +plt.legend(prop={"size": 14}) +plt.show() + + +# %% [markdown] +# ## Check the performance of the diffusion model +# +# We generate a random image from noise to check whether our diffusion model works properly for an image generation task. +# +# + +# %% +model.eval() +noise = torch.randn((1, 1, 64, 64)) +noise = noise.to(device) +scheduler.set_timesteps(num_inference_steps=1000) +with autocast(enabled=True): + image, intermediates = inferer.sample( + input_noise=noise, diffusion_model=model, scheduler=scheduler, save_intermediates=True, intermediate_steps=100 + ) + +chain = torch.cat(intermediates, dim=-1) + +plt.style.use("default") +plt.imshow(chain[0, 0].cpu(), vmin=0, vmax=1, cmap="gray") +plt.tight_layout() +plt.axis("off") +plt.show() + + +# %% [markdown] +# ## Define the classification model +# First, we define the classification model. It follows the encoder architecture of the diffusion model, combined with linear layers for binary classification between healthy and diseased slices. +# + +# %% +device = torch.device("cuda") +classifier = DiffusionModelEncoder( + spatial_dims=2, + in_channels=1, + out_channels=2, + num_channels=(32, 64, 64), + attention_levels=(False, True, True), + num_res_blocks=(1, 1, 1), + num_head_channels=64, + with_conditioning=False, +) + +classifier.to(device) + + +# %% [markdown] +# ## Model training of the classification model +# We train our classification model for 1000 epochs. +# + +# %% + +n_epochs = 1000 +val_interval = 10 +epoch_loss_list = [] +val_epoch_loss_list = [] +optimizer_cls = torch.optim.Adam(params=classifier.parameters(), lr=2.5e-5) + + +scaler = GradScaler() +total_start = time.time() +for epoch in range(n_epochs): + classifier.train() + epoch_loss = 0 + + for step, data in enumerate(train_loader): + images = data["image"].to(device) + classes = data["slice_label"].to(device) + # classes[classes==2]=0 + + optimizer_cls.zero_grad(set_to_none=True) + timesteps = torch.randint(0, 1000, (len(images),)).to(device) + + with autocast(enabled=False): + # Generate random noise + noise = torch.randn_like(images).to(device) + + # Get model prediction + noisy_img = scheduler.add_noise(images, noise, timesteps) # add t steps of noise to the input image + pred = classifier(noisy_img, timesteps) + + loss = F.cross_entropy(pred, classes.long()) + + loss.backward() + optimizer_cls.step() + + epoch_loss += loss.item() + epoch_loss_list.append(epoch_loss / (step + 1)) + + if (epoch + 1) % val_interval == 0: + classifier.eval() + val_epoch_loss = 0 + + for step, data_val in enumerate(val_loader): + images = data_val["image"].to(device) + classes = data_val["slice_label"].to(device) + timesteps = torch.randint(0, 1, (len(images),)).to( + device + ) # check validation accuracy on the original images, i.e., do not add noise + + with torch.no_grad(): + with autocast(enabled=False): + noise = torch.randn_like(images).to(device) + pred = classifier(images, timesteps) + val_loss = F.cross_entropy(pred, classes.long(), reduction="mean") + + val_epoch_loss += val_loss.item() + _, predicted = torch.max(pred, 1) + val_epoch_loss_list.append(val_epoch_loss / (step + 1)) + print("Epoch", epoch, "Validation loss", val_epoch_loss / (step + 1)) + +total_time = time.time() - total_start +print(f"train completed, total time: {total_time}.") + +## Learning curves for the Classifier + +plt.style.use("seaborn-bright") +plt.title("Learning Curves", fontsize=20) +plt.plot(np.linspace(1, n_epochs, n_epochs), epoch_loss_list, color="C0", linewidth=2.0, label="Train") +plt.plot( + np.linspace(val_interval, n_epochs, int(n_epochs / val_interval)), + val_epoch_loss_list, + color="C1", + linewidth=2.0, + label="Validation", +) +plt.yticks(fontsize=12) +plt.xticks(fontsize=12) +plt.xlabel("Epochs", fontsize=16) +plt.ylabel("Loss", fontsize=16) +plt.legend(prop={"size": 14}) +plt.show() +# %% [markdown] +# # Image-to-image translation to a healthy subject +# We pick a diseased subject of the validation set as input image. We want to translate it to its healthy reconstruction. + +# %% +idx_unhealthy = np.argwhere(data_val["slice_label"].numpy() == 0).squeeze() +idx = idx_unhealthy[4] # Pick a random slice of the validation set to be transformed +inputimg = data_val["image"][idx] # Pick an input slice of the validation set to be transformed +inputlabel = data_val["slice_label"][idx] # Check whether it is healthy or diseased +print("minmax", inputimg.min(), inputimg.max()) + +plt.figure("input" + str(inputlabel)) +plt.imshow(inputimg[0, ...], vmin=0, vmax=1, cmap="gray") +plt.axis("off") +plt.tight_layout() +plt.show() + +model.eval() +classifier.eval() + +# %% [markdown] +# ### Encoding the input image in noise with the reversed DDIM sampling scheme +# In order to sample using gradient guidance, we first need to encode the input image in noise by using the reversed DDIM sampling scheme.\ +# We define the number of steps in the noising and denoising process by L.\ +# The encoding process is presented in Equation 6 of the paper "Diffusion Models for Medical Anomaly Detection" (https://arxiv.org/pdf/2203.04306.pdf). +# + +# %% jupyter={"outputs_hidden": false} +L = 200 +current_img = inputimg[None, ...].to(device) +scheduler.set_timesteps(num_inference_steps=1000) + +progress_bar = tqdm(range(L)) # go back and forth L timesteps +for t in progress_bar: # go through the noising process + with autocast(enabled=False): + with torch.no_grad(): + model_output = model(current_img, timesteps=torch.Tensor((t,)).to(current_img.device)) + current_img, _ = scheduler.reversed_step(model_output, t, current_img) + +plt.style.use("default") +plt.imshow(current_img[0, 0].cpu(), vmin=0, vmax=1, cmap="gray") +plt.tight_layout() +plt.axis("off") +plt.show() + + +# %% [markdown] +# ### Denoising process using gradient guidance +# From the noisy image, we apply DDIM sampling scheme for denoising for L steps.\ +# Additionally, we apply gradient guidance using the classifier network towards the desired class label y=0 (healthy). This is presented in Algorithm 2 of https://arxiv.org/pdf/2105.05233.pdf, and in Algorithm 1 of https://arxiv.org/pdf/2203.04306.pdf. \ +# The scale s is used to amplify the gradient. + +# %% +y = torch.tensor(0) # define the desired class label +scale = 6 # define the desired gradient scale s +progress_bar = tqdm(range(L)) # go back and forth L timesteps + +for i in progress_bar: # go through the denoising process + t = L - i + with autocast(enabled=True): + with torch.no_grad(): + model_output = model( + current_img, timesteps=torch.Tensor((t,)).to(current_img.device) + ).detach() # this is supposed to be epsilon + + with torch.enable_grad(): + x_in = current_img.detach().requires_grad_(True) + logits = classifier(x_in, timesteps=torch.Tensor((t,)).to(current_img.device)) + log_probs = F.log_softmax(logits, dim=-1) + selected = log_probs[range(len(logits)), y.view(-1)] + a = torch.autograd.grad(selected.sum(), x_in)[0] + alpha_prod_t = scheduler.alphas_cumprod[t] + updated_noise = ( + model_output - (1 - alpha_prod_t).sqrt() * scale * a + ) # update the predicted noise epsilon with the gradient of the classifier + + current_img, _ = scheduler.step(updated_noise, t, current_img) + torch.cuda.empty_cache() + +plt.style.use("default") +plt.imshow(current_img[0, 0].cpu().detach().numpy(), vmin=0, vmax=1, cmap="gray") +plt.tight_layout() +plt.axis("off") +plt.show() + + +# %% [markdown] +# # Anomaly Detection +# To get the anomaly map, we compute the difference between the input image the output of our image-to-image translation model towards the healthy reconstruction. + + +# %% + +diff = abs(inputimg.cpu() - current_img[0, 0].cpu()).detach().numpy() +plt.style.use("default") +plt.imshow(diff[0, ...], cmap="jet") +plt.tight_layout() +plt.axis("off") +plt.show() + +# %%