From ba381bd2fd43873dc886e1e8dbf7e74476b0a97f Mon Sep 17 00:00:00 2001 From: Eric Kerfoot Date: Thu, 16 Feb 2023 15:47:01 +0000 Subject: [PATCH 1/9] Adding MedNIST Bundle Example Signed-off-by: Eric Kerfoot --- .../mednist_ddpm/bundle/configs/common.yaml | 60 ++++ .../mednist_ddpm/bundle/configs/infer.yaml | 14 + .../mednist_ddpm/bundle/configs/logging.conf | 21 ++ .../mednist_ddpm/bundle/configs/metadata.json | 59 ++++ .../mednist_ddpm/bundle/configs/train.yaml | 170 +++++++++++ .../bundle/configs/train_multigpu.yaml | 36 +++ .../bundle/docs/2d_ddpm_bundle_tutorial.ipynb | 278 ++++++++++++++++++ .../models/mednist_ddpm/bundle/docs/README.md | 5 + .../mednist_ddpm/bundle/scripts/__init__.py | 208 +++++++++++++ 9 files changed, 851 insertions(+) create mode 100644 model-zoo/models/mednist_ddpm/bundle/configs/common.yaml create mode 100644 model-zoo/models/mednist_ddpm/bundle/configs/infer.yaml create mode 100644 model-zoo/models/mednist_ddpm/bundle/configs/logging.conf create mode 100644 model-zoo/models/mednist_ddpm/bundle/configs/metadata.json create mode 100644 model-zoo/models/mednist_ddpm/bundle/configs/train.yaml create mode 100644 model-zoo/models/mednist_ddpm/bundle/configs/train_multigpu.yaml create mode 100644 model-zoo/models/mednist_ddpm/bundle/docs/2d_ddpm_bundle_tutorial.ipynb create mode 100644 model-zoo/models/mednist_ddpm/bundle/docs/README.md create mode 100644 model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py diff --git a/model-zoo/models/mednist_ddpm/bundle/configs/common.yaml b/model-zoo/models/mednist_ddpm/bundle/configs/common.yaml new file mode 100644 index 00000000..51d7e48b --- /dev/null +++ b/model-zoo/models/mednist_ddpm/bundle/configs/common.yaml @@ -0,0 +1,60 @@ +imports: +- $import os +- $import datetime +- $import torch +- $import scripts +- $import monai +- $import generative +- $import torch.distributed as dist + +image: $monai.utils.CommonKeys.IMAGE +label: $monai.utils.CommonKeys.LABEL +pred: $monai.utils.CommonKeys.PRED + +is_dist: '$dist.is_initialized()' +rank: '$dist.get_rank() if @is_dist else 0' +is_not_rank0: '$@rank > 0' +device: '$torch.device(f"cuda:{@rank}" if torch.cuda.is_available() else "cpu")' +softdevice: $torch.device('cpu') + +network_def: + _target_: generative.networks.nets.DiffusionModelUNet + spatial_dims: 2 + in_channels: 1 + out_channels: 1 + num_channels: [64, 128, 128] + attention_levels: [false, true, true] + num_res_blocks: 1 + num_head_channels: 128 +network: $@network_def.to(@device) + +bundle_root: . +ckpt_path: $@bundle_root + '/models/model.pt' +use_amp: true + +image_dim: 64 +image_size: [1, '@image_dim', '@image_dim'] +num_train_timesteps: 1000 + +base_transforms: +- _target_: LoadImaged + keys: '@image' + image_only: true +- _target_: EnsureChannelFirstd + keys: '@image' +- _target_: ScaleIntensityRanged + keys: '@image' + a_min: 0.0 + a_max: 255.0 + b_min: 0.0 + b_max: 1.0 + clip: true + +scheduler: + _target_: generative.networks.schedulers.DDPMScheduler + num_train_timesteps: '@num_train_timesteps' + +inferer: + _target_: generative.inferers.DiffusionInferer + scheduler: '@scheduler' + \ No newline at end of file diff --git a/model-zoo/models/mednist_ddpm/bundle/configs/infer.yaml b/model-zoo/models/mednist_ddpm/bundle/configs/infer.yaml new file mode 100644 index 00000000..dbb74e62 --- /dev/null +++ b/model-zoo/models/mednist_ddpm/bundle/configs/infer.yaml @@ -0,0 +1,14 @@ +inter_steps: '$@num_train_timesteps//10' +batch_size: 1 +num_workers: 0 +noise: $torch.rand(1,1,@image_dim,@image_dim) + +out_file: "" + +sample: '$lambda x: @inferer.sample(input_noise=x,diffusion_model=@network,scheduler=@scheduler,save_intermediates=False)' + +load_state: '$@network.load_state_dict(torch.load(@ckpt_path))' + +testing: +- '@load_state' +- '$torch.save(@sample(@noise.to(@device)), @out_file)' \ No newline at end of file diff --git a/model-zoo/models/mednist_ddpm/bundle/configs/logging.conf b/model-zoo/models/mednist_ddpm/bundle/configs/logging.conf new file mode 100644 index 00000000..db85a0b9 --- /dev/null +++ b/model-zoo/models/mednist_ddpm/bundle/configs/logging.conf @@ -0,0 +1,21 @@ +[loggers] +keys=root + +[handlers] +keys=consoleHandler + +[formatters] +keys=fullFormatter + +[logger_root] +level=INFO +handlers=consoleHandler + +[handler_consoleHandler] +class=StreamHandler +level=INFO +formatter=fullFormatter +args=(sys.stdout,) + +[formatter_fullFormatter] +format=%(asctime)s - %(name)s - %(levelname)s - %(message)s \ No newline at end of file diff --git a/model-zoo/models/mednist_ddpm/bundle/configs/metadata.json b/model-zoo/models/mednist_ddpm/bundle/configs/metadata.json new file mode 100644 index 00000000..aef66f9f --- /dev/null +++ b/model-zoo/models/mednist_ddpm/bundle/configs/metadata.json @@ -0,0 +1,59 @@ +{ + "schema": "https://github.com/Project-MONAI/MONAI-extra-test-data/releases/download/0.8.1/meta_schema_20220729.json", + "version": "0.1.0", + "changelog": { + "0.1.0": "Initial version" + }, + "monai_version": "1.0.0", + "pytorch_version": "1.10.2", + "numpy_version": "1.21.2", + "optional_packages_version": {"generative":"0.1.0"}, + "task": "MedNIST Hand Generation", + "description": "", + "authors": "Walter Hugo Lopez Pinaya, Mark Graham, and Eric Kerfoot", + "copyright": "Copyright (c) KCL", + "references": [], + "intended_use": "This is suitable for research purposes only", + "image_classes": "Single channel magnitude data", + "data_source": "MedNIST", + "network_data_format": { + "inputs": { + "image": { + "type": "image", + "format": "magnitude", + "modality": "xray", + "num_channels": 1, + "spatial_shape": [ + 1, + 64, + 64 + ], + "dtype": "float32", + "value_range": [], + "is_patch_data": false, + "channel_def": { + "0": "image" + } + } + }, + "outputs": { + "pred": { + "type": "image", + "format": "magnitude", + "modality": "xray", + "num_channels": 1, + "spatial_shape": [ + 1, + 64, + 64 + ], + "dtype": "float32", + "value_range": [], + "is_patch_data": false, + "channel_def": { + "0": "image" + } + } + } + } +} diff --git a/model-zoo/models/mednist_ddpm/bundle/configs/train.yaml b/model-zoo/models/mednist_ddpm/bundle/configs/train.yaml new file mode 100644 index 00000000..de04ec68 --- /dev/null +++ b/model-zoo/models/mednist_ddpm/bundle/configs/train.yaml @@ -0,0 +1,170 @@ +output_dir: $datetime.datetime.now().strftime('./results/output_%y%m%d_%H%M%S') +dataset_dir: ./data + +train_data: + _target_ : MedNISTDataset + root_dir: '@dataset_dir' + section: training + download: true + progress: false + seed: 0 + +val_data: + _target_ : MedNISTDataset + root_dir: '@dataset_dir' + section: validation + download: true + progress: false + seed: 0 + +train_datalist: '$[{"image": item["image"]} for item in @train_data.data if item["class_name"] == "Hand"]' +val_datalist: '$[{"image": item["image"]} for item in @val_data.data if item["class_name"] == "Hand"]' + +batch_size: 8 +num_substeps: 1 +num_workers: 4 +use_thread_workers: false + +lr: 0.000025 +rand_prob: 0.5 +num_epochs: 75 +val_interval: 5 +save_interval: 5 + +train_transforms: +- _target_: RandAffined + keys: '@image' + rotate_range: + - ['$-np.pi / 36', '$np.pi / 36'] + - ['$-np.pi / 36', '$np.pi / 36'] + translate_range: + - [-1, 1] + - [-1, 1] + scale_range: + - [-0.05, 0.05] + - [-0.05, 0.05] + spatial_size: [64, 64] + padding_mode: "zeros" + prob: '@rand_prob' + + +train_ds: + _target_: Dataset + data: $@train_datalist + transform: + _target_: Compose + transforms: '$@base_transforms + @train_transforms' + +train_loader: + _target_: ThreadDataLoader + dataset: '@train_ds' + batch_size: '@batch_size' + repeats: '@num_substeps' + num_workers: '@num_workers' + use_thread_workers: '@use_thread_workers' + persistent_workers: '$@num_workers > 0' + shuffle: true + +val_ds: + _target_: Dataset + data: $@val_datalist + transform: + _target_: Compose + transforms: '@base_transforms' + +val_loader: + _target_: DataLoader + dataset: '@val_ds' + batch_size: '@batch_size' + num_workers: '@num_workers' + persistent_workers: '$@num_workers > 0' + shuffle: false + +lossfn: + _target_: torch.nn.MSELoss + +optimizer: + _target_: torch.optim.Adam + params: $@network.parameters() + lr: '@lr' + +prepare_batch: + _target_: scripts.DiffusionPrepareBatch + num_train_timesteps: '@num_train_timesteps' + +val_handlers: +- _target_: StatsHandler + name: train_log + output_transform: '$lambda x: None' + _disabled_: '@is_not_rank0' + +evaluator: + _target_: SupervisedEvaluator + device: '@device' + val_data_loader: '@val_loader' + network: '@network' + amp: '@use_amp' + inferer: '@inferer' + prepare_batch: '@prepare_batch' + key_val_metric: + val_mean_abs_error: + _target_: MeanAbsoluteError + output_transform: $monai.handlers.from_engine([@pred, @label]) + metric_cmp_fn: '$scripts.inv_metric_cmp_fn' + val_handlers: '@val_handlers' + +# metriclogger: +# _target_: MetricLogger +# evaluator: '@evaluator' +# _disabled_: '@is_not_rank0' + +handlers: +- _target_: CheckpointLoader + _disabled_: $not os.path.exists(@ckpt_path) + load_path: '@ckpt_path' + load_dict: + model: '@network' +- _target_: ValidationHandler + validator: '@evaluator' + epoch_level: true + interval: '@val_interval' +# - '@metriclogger' +# - _target_: StatsHandler +# name: train_log +# tag_name: train_loss +# output_transform: $monai.handlers.from_engine(['loss'], first=True) +# _disabled_: '@is_not_rank0' +# - _target_: LogfileHandler +# output_dir: '@output_dir' +# _disabled_: '@is_not_rank0' +- _target_: CheckpointSaver + save_dir: '@output_dir' + save_dict: + model: '@network' + # logger: '@metriclogger' + save_interval: '@save_interval' + save_final: true + epoch_level: true + _disabled_: '@is_not_rank0' + +trainer: + _target_: SupervisedTrainer + max_epochs: '@num_epochs' + device: '@device' + train_data_loader: '@train_loader' + network: '@network' + loss_function: '@lossfn' + optimizer: '@optimizer' + inferer: '@inferer' + prepare_batch: '@prepare_batch' + key_train_metric: + train_acc: + _target_: MeanSquaredError + output_transform: $monai.handlers.from_engine([@pred, @label]) + metric_cmp_fn: '$scripts.inv_metric_cmp_fn' + train_handlers: '$list(filter(bool, @handlers))' + amp: '@use_amp' + +training: +- '$monai.utils.set_determinism(0)' +- '$@trainer.run()' diff --git a/model-zoo/models/mednist_ddpm/bundle/configs/train_multigpu.yaml b/model-zoo/models/mednist_ddpm/bundle/configs/train_multigpu.yaml new file mode 100644 index 00000000..c91d7f39 --- /dev/null +++ b/model-zoo/models/mednist_ddpm/bundle/configs/train_multigpu.yaml @@ -0,0 +1,36 @@ +# device: $torch.device(f'cuda:{dist.get_rank()}') +network: + _target_: torch.nn.parallel.DistributedDataParallel + module: $@network_def.to(@device) + device_ids: ['@device'] + find_unused_parameters: true + +tsampler: + _target_: DistributedSampler + dataset: '@train_ds' + even_divisible: true + shuffle: true +train_dataloader#sampler: '@tsampler' +train_dataloader#shuffle: false + +vsampler: + _target_: DistributedSampler + dataset: '@eval_ds' + even_divisible: false + shuffle: false +eval_dataloader#sampler: '@vsampler' + +# trainer#train_handlers: '$@handlers[: 2 if dist.get_rank() > 0 else None]' +# evaluator#val_handlers: '$None if @is_not_rank0 else @val_handlers' + +# trainer#train_handlers: '$@handlers[1 if @is_not_rank0 else 0:]' + +training: +- $import torch.distributed as dist +- $dist.init_process_group(backend='nccl') +- $print(@device) +- $torch.cuda.set_device(@device) +- $monai.utils.set_determinism(seed=123), +# - $print(@network) +- $@trainer.run() +- $dist.destroy_process_group() \ No newline at end of file diff --git a/model-zoo/models/mednist_ddpm/bundle/docs/2d_ddpm_bundle_tutorial.ipynb b/model-zoo/models/mednist_ddpm/bundle/docs/2d_ddpm_bundle_tutorial.ipynb new file mode 100644 index 00000000..af4fb64d --- /dev/null +++ b/model-zoo/models/mednist_ddpm/bundle/docs/2d_ddpm_bundle_tutorial.ipynb @@ -0,0 +1,278 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "c54f5831-58eb-4f9e-bb8a-2c2a6536a658", + "metadata": {}, + "source": [ + "# Denoising Diffusion Probabilistic Models with MedNIST Dataset Bundle \n", + "\n", + "This notebook discusses and uses the MONAI bundle it's included in for generating images from the MedNIST dataset using diffusion models. This i based off the 2d_ddpm_tutorial_ignite.ipynb notebook with a few changes.\n", + "\n", + "First thing to do is import libraries then download the MedNIST dataset:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "6d32f8a4-2bfe-4cfb-9abd-033b0c6080e6", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MONAI version: 1.1.0+45.g1a018a7b\n", + "Numpy version: 1.21.5\n", + "Pytorch version: 1.12.1\n", + "MONAI flags: HAS_EXT = False, USE_COMPILED = False, USE_META_DICT = False\n", + "MONAI rev id: 1a018a7b3034a86360d999a6bcc796bad330bba4\n", + "MONAI __file__: /home/localek10/workspace/monai/MONAI_mine/monai/__init__.py\n", + "\n", + "Optional dependencies:\n", + "Pytorch Ignite version: 0.4.8\n", + "ITK version: 5.2.1\n", + "Nibabel version: 4.0.2\n", + "scikit-image version: 0.19.2\n", + "Pillow version: 9.2.0\n", + "Tensorboard version: 2.9.0\n", + "gdown version: 4.5.1\n", + "TorchVision version: 0.13.1\n", + "tqdm version: 4.64.0\n", + "lmdb version: 1.2.1\n", + "psutil version: 5.9.0\n", + "pandas version: 1.4.3\n", + "einops version: 0.6.0\n", + "transformers version: 4.18.0\n", + "mlflow version: 1.28.0\n", + "pynrrd version: 0.4.2\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 shutil\n", + "import tempfile\n", + "from pathlib import Path\n", + "\n", + "import matplotlib.pyplot as plt\n", + "import monai\n", + "import numpy as np\n", + "import torch\n", + "from monai.bundle import ConfigParser\n", + "\n", + "# path to the bundle directory, this assumes you're running the notebook in its directory\n", + "bundle_root = str(Path(\".\").absolute().parent)\n", + "\n", + "monai.config.print_config()" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "d6fc6592-cb51-4527-97ee-add5d1cdbeb4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/tmp/tmpw33bol9_\n" + ] + } + ], + "source": [ + "directory = os.environ.get(\"MONAI_DATA_DIRECTORY\")\n", + "dataset_dir = tempfile.mkdtemp() if directory is None else directory\n", + "print(dataset_dir)" + ] + }, + { + "cell_type": "markdown", + "id": "678d2e51-dc2d-4ad9-a4c0-14a6f900398b", + "metadata": {}, + "source": [ + "A bundle can be run on the command line using the Fire library or by parsing the configuration manually then getting parsed content objects. The following is the command to train the network for the default number of epochs. It will state values in the config files which need to be set for a particular run, such as the dataset directory created above, and setting the PYTHONPATH variable. The configuration for this bundle is split into 4 yaml files, one having common definitions for training and inference, one to enable multi-GPU training, and one each for training and inference. Their combinations determine what your final configuration is, in this case the common and train files produce a training script. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d52a4ae9-0d6d-4bc4-a5b5-f84470711f2d", + "metadata": {}, + "outputs": [], + "source": [ + "configs=f\"['{bundle_root}/configs/common.yaml','{bundle_root}/configs/train.yaml']\"\n", + "\n", + "!PYTHONPATH={bundle_root} python -m monai.bundle run training \\\n", + " --meta_file {bundle_root}/configs/metadata.json \\\n", + " --config_file \"{configs}\" \\\n", + " --logging_file {bundle_root}/configs/logging.conf \\\n", + " --bundle_root {bundle_root} \\\n", + " --dataset_dir {dataset_dir}" + ] + }, + { + "cell_type": "markdown", + "id": "5030732c-deb5-448a-b575-385bda0fa308", + "metadata": {}, + "source": [ + "The test inference script can be invoked as such to produce an output saved tensor with a randomly generated image:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "40e6a3e9-3984-44b0-ba9a-5b8d58c7ea2d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2023-02-16 15:42:37,882 - INFO - --- input summary of monai.bundle.scripts.run ---\n", + "2023-02-16 15:42:37,882 - INFO - > runner_id: 'testing'\n", + "2023-02-16 15:42:37,883 - INFO - > meta_file: '/home/localek10/workspace/monai/GenerativeModels/model-zoo/models/mednist_ddpm/bundle/configs/metadata.json'\n", + "2023-02-16 15:42:37,883 - INFO - > config_file: ['/home/localek10/workspace/monai/GenerativeModels/model-zoo/models/mednist_ddpm/bundle/configs/common.yaml',\n", + " '/home/localek10/workspace/monai/GenerativeModels/model-zoo/models/mednist_ddpm/bundle/configs/infer.yaml']\n", + "2023-02-16 15:42:37,883 - INFO - > ckpt_path: './results/output_230215_174009/model_final_iteration=75000.pt'\n", + "2023-02-16 15:42:37,883 - INFO - > bundle_root: '/home/localek10/workspace/monai/GenerativeModels/model-zoo/models/mednist_ddpm/bundle'\n", + "2023-02-16 15:42:37,883 - INFO - > out_file: 'test.pt'\n", + "2023-02-16 15:42:37,883 - INFO - ---\n", + "\n", + "\n", + "100%|███████████████████████████████████████| 1000/1000 [00:10<00:00, 97.44it/s]\n", + "[[[], []], null]\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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P6877rhDTU1Nqqio0I9//ONh72dZptbWVjU1Nam6uloLFy7U/v370wz2HLW3t+umm25SXV2dpk2bpjvvvFMHDhwYtk057OemTZt07bXX5v/CfN68efrpT3+af78c9vFs7e3tqqio0KpVq/Jt5bCfra2tqqioGPZqbGzMv18O+3jGb3/7W33lK1/RxRdfrJqaGn3605/Wnj178u8n2desRO3YsSObNGlStmXLluyVV17JVq5cmdXW1mZvvvlm6qGds5/85CfZ2rVrsyeeeCKTlD311FPD3n/kkUeyurq67Iknnsj27duXffGLX8ymT5+e9fX1pRnwOfiTP/mTbOvWrdmvfvWrbO/evdntt9+eXXbZZdmxY8fy25TDfj799NPZv//7v2cHDhzIDhw4kD3wwAPZpEmTsl/96ldZlpXHPn7QL37xi+zjH/94du2112YrV67Mt5fDfj744IPZrFmzskOHDuVfPT09+ffLYR+zLMveeeedbObMmdnXvva17L//+7+zgwcPZv/xH/+R/eY3v8lvk2JfS3YS+sM//MNs+fLlw9o+9alPZd/+9rcTjSiusyeh06dPZ42NjdkjjzySbzt58mRWX1+f/eM//mOCEcbR09OTSco6OzuzLCvf/cyyLLvwwguzf/qnfyq7fezv789aWlqyjo6ObMGCBflJqFz288EHH8yuu+664Hvlso9ZlmXf+ta3sltvvdV8P9W+luSv44aGhrRnzx4tXrx4WPvixYu1a9euRKMqroMHD6q7u3vYPudyOS1YsGBM73Nvb68k6aKLLpJUnvt56tQp7dixQ8ePH9e8efPKbh/vvfde3X777frc5z43rL2c9vO1115TU1OTmpub9aUvfUmvv/66pPLax6efflpz5szRF77wBU2bNk3XX3+9tmzZkn8/1b6W5CT09ttv69SpU2poaBjW3tDQoO7u7kSjKq4z+1VO+5xlme6//37deuutmj17tqTy2s99+/ZpypQpyuVyWr58uZ566ildffXVZbWPO3bs0C9/+Uu1t7cXvFcu+zl37lw9/vjjevbZZ7VlyxZ1d3dr/vz5Onz4cNnsoyS9/vrr2rRpk1paWvTss89q+fLl+uY3v6nHH39cUrrzWXJLOXzQmaUczsiyrKCt3JTTPt933316+eWX9V//9V8F75XDfn7yk5/U3r17dfToUT3xxBO6++671dnZmX9/rO9jV1eXVq5cqZ07d2ry5MnmdmN9P5csWZL/39dcc43mzZunK664Qtu2bdPNN98saezvo/T+Wm1z5sxRW1ubJOn666/X/v37tWnTJv3FX/xFfruPel9L8k7oYx/7mCZOnFgw+/b09BTM0uXiTBqnXPb5G9/4hp5++mn9/Oc/z68PJZXXflZVVekTn/iE5syZo/b2dl133XX6/ve/Xzb7uGfPHvX09OjGG29UZWWlKisr1dnZqX/4h39QZWVlfl/G+n6erba2Vtdcc41ee+21sjmXkjR9+nRdffXVw9quuuoqvfXWW5LSfTdLchKqqqrSjTfeqI6OjmHtHR0dmj9/fqJRFVdzc7MaGxuH7fPQ0JA6OzvH1D5nWab77rtPTz75pH72s5+publ52Pvlsp8hWZZpcHCwbPbxtttu0759+7R37978a86cObrrrru0d+9eXX755WWxn2cbHBzUr3/9a02fPr1szqUk3XLLLQV/LvHqq69q5syZkhJ+N4sWeThPZyLaP/zhD7NXXnklW7VqVVZbW5u98cYbqYd2zvr7+7OXXnope+mllzJJ2fr167OXXnopHzt/5JFHsvr6+uzJJ5/M9u3bl335y18ec1HQr3/961l9fX323HPPDYu8njhxIr9NOeznmjVrsueffz47ePBg9vLLL2cPPPBANmHChGznzp1ZlpXHPoZ8MB2XZeWxn3/zN3+TPffcc9nrr7+evfDCC9nnP//5rK6uLv+zphz2Mcvej9lXVlZm3/3ud7PXXnst++d//uespqYm+9GPfpTfJsW+luwklGVZ9uijj2YzZ87MqqqqshtuuCEf8x2rfv7zn2eSCl533313lmXvRyQffPDBrLGxMcvlctlnPvOZbN++fWkH7RTaP0nZ1q1b89uUw37+5V/+Zf7avOSSS7LbbrstPwFlWXnsY8jZk1A57OeZv4WZNGlS1tTUlC1dujTbv39//v1y2Mcz/u3f/i2bPXt2lsvlsk996lPZ5s2bh72fYl9ZTwgAkExJPhMCAIwPTEIAgGSYhAAAyTAJAQCSYRICACTDJAQASIZJCACQDJMQACAZJiEAQDJMQgCAZJiEAADJ/D/fDk69KCbT4AAAAABJRU5ErkJggg==\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "configs=f\"['{bundle_root}/configs/common.yaml','{bundle_root}/configs/infer.yaml']\"\n", + "\n", + "!PYTHONPATH={bundle_root} python -m monai.bundle run testing \\\n", + " --meta_file {bundle_root}/configs/metadata.json \\\n", + " --config_file \"{configs}\" \\\n", + " --ckpt_path ./results/output_230215_174009/model_final_iteration=75000.pt \\\n", + " --bundle_root {bundle_root} \\\n", + " --out_file test.pt\n", + "\n", + "test = torch.load(\"test.pt\", map_location=\"cpu\")\n", + "\n", + "plt.imshow(test[0, 0], vmin=0, vmax=1, cmap=\"gray\")" + ] + }, + { + "cell_type": "markdown", + "id": "f581c36e-4033-4005-8969-76205470588e", + "metadata": {}, + "source": [ + "The same can be done by creating the parser object, filling in its configuration, then resolving the Python objects from the constructed bundle data:" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "cf8438b3-4c7d-48c4-bb41-ed7def73753f", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|██████████| 1000/1000 [00:09<00:00, 101.06it/s]\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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2NeyHYT+4A/+IFuyZMmItssuuyz79re/nahHcZ04CB07dixrbm7OHnrooWLb4cOHs8bGxuwf/uEfEvQwjt7e3kxS1tXVlWVZ9e5nlmXZOeeck/3jP/5j1e3jwMBA1tramnV2dmbz5s0rDkLVsp8PPPBAdvXVVwdfq5Z9zLIs+9a3vpXdfPPN5uup9rUsv44bHh7Wzp07tWDBghHtCxYs0Pbt2xP1Kl/79u1TT0/PiH0uFAqaN29eRe9zX1+fJOncc8+VVJ37efToUW3dulWHDh3SnDlzqm4f77nnHt122236/Oc/P6K9mvbzlVde0dSpU9XS0qIvfelLeu211yRV1z4+9dRTmjVrlr7whS9o8uTJuvbaa7Vp06bi66n2tSwHobfffltHjx5VU1PTiPampib19PQk6lW+ju9XNe1zlmW67777dPPNN2vmzJmSqms/d+/erbPOOkuFQkFLlizRk08+qSuuuKKq9nHr1q36xS9+oY6OjpLXqmU/Z8+erccee0zPPPOMNm3apJ6eHs2dO1fvvPNO1eyjJL322mvasGGDWltb9cwzz2jJkiX65je/qccee0xSuvNZdlM5fNSJMwdmWVYRMz6ejmra53vvvVcvvfSS/vu//7vktWrYz0svvVS7du3Se++9p8cff1x33XWXurq6iq9X+j52d3dr2bJl2rZtmyZMmGAuV+n7uXDhwuJ/X3nllZozZ44uvvhibd68WTfeeKOkyt9H6cO52mbNmqX29nZJ0rXXXqs9e/Zow4YN+ou/+Ivicp/0vpblndD555+vsWPHloy+vb29JaN0tTiexqmWff7GN76hp556Sj/72c+K80NJ1bWftbW1+sxnPqNZs2apo6NDV199tX7wgx9UzT7u3LlTvb29uv766zVu3DiNGzdOXV1d+vu//3uNGzeuuC+Vvp8nmjhxoq688kq98sorVXMuJWnKlCm64oorRrRdfvnlevPNNyWle2+W5SBUW1ur66+/Xp2dnSPaOzs7NXfu3ES9yldLS4uam5tH7PPw8LC6uroqap+zLNO9996rJ554Qj/96U/V0tIy4vVq2c+QLMs0NDRUNft46623avfu3dq1a1fxZ9asWbrzzju1a9cuffrTn66K/TzR0NCQfvWrX2nKlClVcy4l6aabbir5c4lf//rXmj59uqSE783cIg+n6XhE+5/+6Z+yl19+OVu+fHk2ceLE7PXXX0/dtVM2MDCQvfjii9mLL76YScrWrl2bvfjii8XY+UMPPZQ1NjZmTzzxRLZ79+7sy1/+csVFQb/+9a9njY2N2bPPPjsi8vr+++8Xl6mG/Vy5cmX23HPPZfv27cteeuml7P7778/GjBmTbdu2Lcuy6tjHkI+m47KsOvbzb/7mb7Jnn302e+2117Lnn38++9M//dOsoaGh+FlTDfuYZR/G7MeNG5d997vfzV555ZXsn//5n7P6+vrsRz/6UXGZFPtatoNQlmXZww8/nE2fPj2rra3NrrvuumLMt1L97Gc/yySV/Nx1111Zln0YkXzggQey5ubmrFAoZJ/97Gez3bt3p+20U2j/JGWPPPJIcZlq2M+//Mu/LF6bF1xwQXbrrbcWB6Asq459DDlxEKqG/Tz+tzDjx4/Ppk6dmi1atCjbs2dP8fVq2Mfj/v3f/z2bOXNmVigUsssuuyzbuHHjiNdT7CvzCQEAkinLZ0IAgDMDgxAAIBkGIQBAMgxCAIBkGIQAAMkwCAEAkmEQAgAkwyAEAEiGQQgAkAyDEAAgGQYhAEAy/w/fi81VGZdpEgAAAABJRU5ErkJggg==\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import sys\n", + "\n", + "sys.path.append(bundle_root)\n", + "\n", + "# configure the parser from the bundle's information\n", + "cp = ConfigParser()\n", + "cp.read_meta(f\"{bundle_root}/configs/metadata.json\")\n", + "cp.read_config([f\"{bundle_root}/configs/common.yaml\", f\"{bundle_root}/configs/infer.yaml\"])\n", + "cp[\"bundle_root\"] = bundle_root\n", + "cp[\"ckpt_path\"] = \"./results/output_230215_174009/model_final_iteration=75000.pt\"\n", + "\n", + "cp.get_parsed_content(\"load_state\") # load the saved state from the checkpoint just be resolving this value\n", + "\n", + "device = cp.get_parsed_content(\"device\") # device used by the bundle\n", + "sample = cp.get_parsed_content(\"sample\") # test sampling function\n", + "\n", + "image_dim = cp[\"image_dim\"] # get the stored dimension value, no need to resolve anything\n", + "\n", + "noise = torch.rand(1, 1, image_dim, image_dim).to(device) # or cp.get_parsed_content(\"noise\")\n", + "\n", + "test = sample(noise)\n", + "\n", + "plt.imshow(test[0, 0].cpu(), vmin=0, vmax=1, cmap=\"gray\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python [conda env:monai]", + "language": "python", + "name": "conda-env-monai-py" + }, + "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.9.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/model-zoo/models/mednist_ddpm/bundle/docs/README.md b/model-zoo/models/mednist_ddpm/bundle/docs/README.md new file mode 100644 index 00000000..c57d6df5 --- /dev/null +++ b/model-zoo/models/mednist_ddpm/bundle/docs/README.md @@ -0,0 +1,5 @@ + +# MedNIST DDPM Example Bundle + +This implements roughly equivalent code to the "Denoising Diffusion Probabilistic Models with MedNIST Dataset" example notebook. This includes scripts for training with single or multiple GPUs and a visualisation notebook. + diff --git a/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py b/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py new file mode 100644 index 00000000..47519bed --- /dev/null +++ b/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py @@ -0,0 +1,208 @@ +import torch +from functools import partial +from monai import transforms as mt +from monai.utils import first, ensure_tuple, ensure_tuple_size +from monai.engines import PrepareBatch, default_prepare_batch + +from typing import Dict, Mapping, Optional, Union + + +good_names = [ + "v19_153", "v19_223", "v20_500", "v20_195", "v20_016", "v20_635", "v19_089", "v19_227", "v19_048", "v19_078", "v19_262", "v20_529", "v20_620", "v20_453", "v19_145", "v19_215", "v19_261", + "v20_757", "v19_083", "v20_707", "v20_546", "v20_525", "v20_521", "v20_766", "v20_505", "v19_243", "v20_352", "v20_763", "v20_558", "v19_113", "v20_714", "v19_124", "v19_250", "v19_139", + "v20_648", "v19_018", "v20_646", "v19_007", "v20_613", "v20_709", "v19_209", "v19_267", "v20_719", "v20_602", "v19_090", "v19_214", "v19_131", "v20_545", "v19_277", "v19_068", "v19_022", + "v20_585", "v19_080", "v19_031", "v20_580", "v19_102", "v19_278", "v20_754", "v20_760", "v20_590", "v20_507", "v19_207", "v19_260", "v19_147", "v19_138", "v19_251", "v20_631", "v20_711", + "v20_586", "v20_017", "v19_091", "v20_825", "v20_701", "v20_544", "v19_266", "v19_023", "v19_104", "v20_700", "v19_212", "v19_026", "v20_716", "v19_247", "v20_647", "v19_205", "v20_607", + "v19_208", "v19_149", "v19_275", "v20_518", "v19_010", "v19_013", "v19_046", "v19_070", "v19_055", "v19_130", "v19_005", "v19_085", "v19_108", "v19_134", "v20_596", "v20_756", "v20_811", + "v20_513", "v19_273", "v19_107", "v19_254", "v19_143", "v20_565", "v20_604", "v20_755", "v20_640", "v19_008", "v19_058", "v20_603", "v20_802", "v19_016", "v19_054", "v20_419", "v19_060", + "v19_217", "v19_127", "v19_253", "v19_051", "v19_059", "v19_075", "v20_761", "v20_619", "v20_616", "v19_020", "v20_703", "v19_043", "v19_155", "v20_506", "v19_256", "v20_649", "v20_479", + "v19_257", "v20_816", "v19_154", "v19_272", "v19_226", "v19_004", "v19_065", "v20_769", "v19_239", "v19_230", "v20_768", "v19_067", "v20_713", "v20_295", "v19_202", "v20_572", "v19_030", + "v20_810", "v20_594", "v19_024", "v19_111", "v19_076", "v19_073", "v20_534", "v19_290", "v20_824", "v19_252", "v20_108", "v20_614", "v20_559", "v20_573", "v19_279", "v19_141", "v19_100", + "v19_119", "v20_767", "v20_569", "v20_556", "v19_265", "v19_258", "v19_033", "v19_095", "v19_050", "v19_011", "v20_584", "v19_064", "v19_072", "v19_081", "v20_715", "v20_536", "v20_216", + "v19_047", "v19_232", "v19_152", "v20_627", "v20_144", "v19_014", "v20_600", "v20_510", "v19_012", "v20_753", "v20_815", "v19_201", "v19_009", "v20_805", "v20_623", "v20_090", "v19_241", + "v19_242", "v20_532", "v19_271", +] + +good_images=[ + 'VerSe19/dataset-verse19validation/rawdata/sub-verse153/sub-verse153_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse408/sub-verse408_split-verse223_ct.nii.gz', + 'VerSe20/01_training/rawdata/sub-verse500/sub-verse500_dir-ax_ct.nii.gz', 'VerSe20/03_test/rawdata/sub-gl195/sub-gl195_dir-ax_ct.nii.gz', + 'VerSe20/01_training/rawdata/sub-gl016/sub-gl016_dir-ax_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse635/sub-verse635_ct.nii.gz', + 'VerSe19/dataset-verse19test/rawdata/sub-verse089/sub-verse089_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse410/sub-verse410_split-verse227_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse048/sub-verse048_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse078/sub-verse078_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse407/sub-verse407_split-verse262_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse529/sub-verse529_ct.nii.gz', + 'VerSe20/03_test/rawdata/sub-verse620/sub-verse620_dir-iso_ct.nii.gz', 'VerSe20/01_training/rawdata/sub-gl453/sub-gl453_dir-ax_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse145/sub-verse145_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse407/sub-verse407_split-verse215_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse406/sub-verse406_split-verse261_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse757/sub-verse757_ct.nii.gz', + 'VerSe19/dataset-verse19test/rawdata/sub-verse083/sub-verse083_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse707/sub-verse707_ct.nii.gz', + 'VerSe20/03_test/rawdata/sub-verse546/sub-verse546_dir-ax_ct.nii.gz', 'VerSe20/01_training/rawdata/sub-verse525/sub-verse525_dir-sag_ct.nii.gz', + 'VerSe20/01_training/rawdata/sub-verse521/sub-verse521_dir-ax_ct.nii.gz', 'VerSe20/03_test/rawdata/sub-verse766/sub-verse766_dir-ax_ct.nii.gz', + 'VerSe20/02_validation/rawdata/sub-verse505/sub-verse505_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse415/sub-verse415_split-verse243_ct.nii.gz', + 'VerSe20/02_validation/rawdata/sub-gl352/sub-gl352_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse763/sub-verse763_ct.nii.gz', + 'VerSe20/03_test/rawdata/sub-verse558/sub-verse558_dir-sag_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse113/sub-verse113_ct.nii.gz', + 'VerSe20/03_test/rawdata/sub-verse714/sub-verse714_dir-iso_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse124/sub-verse124_ct.nii.gz', + 'VerSe19/dataset-verse19test/rawdata/sub-verse250/sub-verse250_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse139/sub-verse139_ct.nii.gz', + 'VerSe20/03_test/rawdata/sub-verse648/sub-verse648_dir-iso_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse018/sub-verse018_ct.nii.gz', + 'VerSe20/01_training/rawdata/sub-verse646/sub-verse646_dir-iso_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse007/sub-verse007_ct.nii.gz', + 'VerSe20/03_test/rawdata/sub-verse613/sub-verse613_dir-iso_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse709/sub-verse709_ct.nii.gz', + 'VerSe19/dataset-verse19validation/rawdata/sub-verse404/sub-verse404_split-verse209_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse410/sub-verse410_split-verse267_ct.nii.gz', + 'VerSe20/02_validation/rawdata/sub-verse719/sub-verse719_ct.nii.gz', 'VerSe20/03_test/rawdata/sub-verse602/sub-verse602_dir-iso_ct.nii.gz', + 'VerSe19/dataset-verse19validation/rawdata/sub-verse400/sub-verse400_split-verse090_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse406/sub-verse406_split-verse214_ct.nii.gz', + 'VerSe19/dataset-verse19test/rawdata/sub-verse131/sub-verse131_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse545/sub-verse545_dir-ax_ct.nii.gz', + 'VerSe19/dataset-verse19test/rawdata/sub-verse417/sub-verse417_split-verse277_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse068/sub-verse068_ct.nii.gz', + 'VerSe19/dataset-verse19validation/rawdata/sub-verse022/sub-verse022_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse585/sub-verse585_ct.nii.gz', + 'VerSe19/dataset-verse19validation/rawdata/sub-verse080/sub-verse080_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse031/sub-verse031_ct.nii.gz', + 'VerSe20/02_validation/rawdata/sub-verse580/sub-verse580_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse102/sub-verse102_ct.nii.gz', + 'VerSe19/dataset-verse19test/rawdata/sub-verse417/sub-verse417_split-verse278_ct.nii.gz', 'VerSe20/03_test/rawdata/sub-verse754/sub-verse754_dir-sag_ct.nii.gz', + 'VerSe20/03_test/rawdata/sub-verse760/sub-verse760_dir-iso_ct.nii.gz', 'VerSe20/03_test/rawdata/sub-verse590/sub-verse590_dir-iso_ct.nii.gz', + 'VerSe20/01_training/rawdata/sub-verse507/sub-verse507_dir-ax_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse207/sub-verse207_ct.nii.gz', + 'VerSe19/dataset-verse19test/rawdata/sub-verse260/sub-verse260_ct.nii.gz', 'VerSe19/dataset-verse19test/rawdata/sub-verse147/sub-verse147_ct.nii.gz', + 'VerSe19/dataset-verse19test/rawdata/sub-verse138/sub-verse138_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse402/sub-verse402_split-verse251_ct.nii.gz', + 'VerSe20/01_training/rawdata/sub-verse631/sub-verse631_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse711/sub-verse711_ct.nii.gz', + 'VerSe20/01_training/rawdata/sub-verse586/sub-verse586_dir-iso_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-gl017/sub-gl017_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse091/sub-verse091_ct.nii.gz', 'VerSe20/01_training/rawdata/sub-verse825/sub-verse825_dir-ax_ct.nii.gz', + 'VerSe20/02_validation/rawdata/sub-verse701/sub-verse701_ct.nii.gz', 'VerSe20/01_training/rawdata/sub-verse544/sub-verse544_dir-ax_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse409/sub-verse409_split-verse266_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse023/sub-verse023_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse104/sub-verse104_ct.nii.gz', 'VerSe20/03_test/rawdata/sub-verse700/sub-verse700_dir-sag_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse405/sub-verse405_split-verse212_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse026/sub-verse026_ct.nii.gz', + 'VerSe20/03_test/rawdata/sub-verse716/sub-verse716_dir-iso_ct.nii.gz', 'VerSe19/dataset-verse19test/rawdata/sub-verse416/sub-verse416_split-verse247_ct.nii.gz', + 'VerSe20/03_test/rawdata/sub-verse647/sub-verse647_dir-sag_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse205/sub-verse205_ct.nii.gz', + 'VerSe20/03_test/rawdata/sub-verse607/sub-verse607_dir-sag_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse403/sub-verse403_split-verse208_ct.nii.gz', + 'VerSe19/dataset-verse19test/rawdata/sub-verse149/sub-verse149_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse415/sub-verse415_split-verse275_ct.nii.gz', + 'VerSe20/01_training/rawdata/sub-verse518/sub-verse518_dir-ax_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse010/sub-verse010_ct.nii.gz', + 'VerSe19/dataset-verse19validation/rawdata/sub-verse013/sub-verse013_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse046/sub-verse046_ct.nii.gz', + 'VerSe19/dataset-verse19test/rawdata/sub-verse070/sub-verse070_ct.nii.gz', 'VerSe19/dataset-verse19test/rawdata/sub-verse055/sub-verse055_ct.nii.gz', + 'VerSe19/dataset-verse19test/rawdata/sub-verse130/sub-verse130_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse005/sub-verse005_ct.nii.gz', + 'VerSe19/dataset-verse19test/rawdata/sub-verse085/sub-verse085_ct.nii.gz', 'VerSe19/dataset-verse19test/rawdata/sub-verse108/sub-verse108_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse134/sub-verse134_ct.nii.gz', 'VerSe20/01_training/rawdata/sub-verse596/sub-verse596_dir-ax_ct.nii.gz', + 'VerSe20/03_test/rawdata/sub-verse756/sub-verse756_dir-iso_ct.nii.gz', 'VerSe20/01_training/rawdata/sub-verse811/sub-verse811_dir-ax_ct.nii.gz', + 'VerSe20/02_validation/rawdata/sub-verse513/sub-verse513_ct.nii.gz', 'VerSe19/dataset-verse19test/rawdata/sub-verse414/sub-verse414_split-verse273_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse107/sub-verse107_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse254/sub-verse254_ct.nii.gz', + 'VerSe19/dataset-verse19test/rawdata/sub-verse143/sub-verse143_ct.nii.gz', 'VerSe20/01_training/rawdata/sub-verse565/sub-verse565_dir-ax_ct.nii.gz', + 'VerSe20/03_test/rawdata/sub-verse604/sub-verse604_dir-iso_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse755/sub-verse755_ct.nii.gz', + 'VerSe20/02_validation/rawdata/sub-verse640/sub-verse640_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse008/sub-verse008_ct.nii.gz', + 'VerSe19/dataset-verse19validation/rawdata/sub-verse058/sub-verse058_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse603/sub-verse603_ct.nii.gz', + 'VerSe20/02_validation/rawdata/sub-verse802/sub-verse802_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse016/sub-verse016_ct.nii.gz', + 'VerSe19/dataset-verse19test/rawdata/sub-verse054/sub-verse054_ct.nii.gz', 'VerSe20/03_test/rawdata/sub-gl419/sub-gl419_dir-ax_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse060/sub-verse060_ct.nii.gz', 'VerSe19/dataset-verse19test/rawdata/sub-verse217/sub-verse217_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse127/sub-verse127_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse401/sub-verse401_split-verse253_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse051/sub-verse051_ct.nii.gz', 'VerSe19/dataset-verse19test/rawdata/sub-verse059/sub-verse059_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse075/sub-verse075_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse761/sub-verse761_ct.nii.gz', + 'VerSe20/01_training/rawdata/sub-verse619/sub-verse619_dir-ax_ct.nii.gz', 'VerSe20/03_test/rawdata/sub-verse616/sub-verse616_dir-iso_ct.nii.gz', + 'VerSe19/dataset-verse19test/rawdata/sub-verse020/sub-verse020_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse703/sub-verse703_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse043/sub-verse043_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse400/sub-verse400_split-verse155_ct.nii.gz', + 'VerSe20/01_training/rawdata/sub-verse506/sub-verse506_dir-iso_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse404/sub-verse404_split-verse256_ct.nii.gz', + 'VerSe20/03_test/rawdata/sub-verse649/sub-verse649_dir-sag_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-gl479/sub-gl479_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse257/sub-verse257_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse816/sub-verse816_ct.nii.gz', + 'VerSe19/dataset-verse19test/rawdata/sub-verse154/sub-verse154_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse413/sub-verse413_split-verse272_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse409/sub-verse409_split-verse226_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse004/sub-verse004_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse065/sub-verse065_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse769/sub-verse769_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse413/sub-verse413_split-verse239_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse230/sub-verse230_ct.nii.gz', + 'VerSe20/03_test/rawdata/sub-verse768/sub-verse768_dir-ax_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse067/sub-verse067_ct.nii.gz', + 'VerSe20/02_validation/rawdata/sub-verse713/sub-verse713_ct.nii.gz', 'VerSe20/01_training/rawdata/sub-gl295/sub-gl295_dir-ax_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse402/sub-verse402_split-verse202_ct.nii.gz', 'VerSe20/03_test/rawdata/sub-verse572/sub-verse572_dir-sag_ct.nii.gz', + 'VerSe19/dataset-verse19validation/rawdata/sub-verse030/sub-verse030_ct.nii.gz', 'VerSe20/03_test/rawdata/sub-verse810/sub-verse810_dir-iso_ct.nii.gz', + 'VerSe20/01_training/rawdata/sub-verse594/sub-verse594_dir-ax_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse024/sub-verse024_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse111/sub-verse111_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse076/sub-verse076_ct.nii.gz', + 'VerSe19/dataset-verse19validation/rawdata/sub-verse073/sub-verse073_ct.nii.gz', 'VerSe20/01_training/rawdata/sub-verse534/sub-verse534_dir-iso_ct.nii.gz', + 'VerSe19/dataset-verse19validation/rawdata/sub-verse412/sub-verse412_split-verse290_ct.nii.gz', 'VerSe20/01_training/rawdata/sub-verse824/sub-verse824_dir-ax_ct.nii.gz', + 'VerSe19/dataset-verse19validation/rawdata/sub-verse252/sub-verse252_ct.nii.gz', 'VerSe20/03_test/rawdata/sub-gl108/sub-gl108_dir-ax_ct.nii.gz', + 'VerSe20/02_validation/rawdata/sub-verse614/sub-verse614_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse559/sub-verse559_ct.nii.gz', + 'VerSe20/02_validation/rawdata/sub-verse573/sub-verse573_ct.nii.gz', 'VerSe19/dataset-verse19test/rawdata/sub-verse416/sub-verse416_split-verse279_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse141/sub-verse141_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse100/sub-verse100_ct.nii.gz', + 'VerSe19/dataset-verse19test/rawdata/sub-verse119/sub-verse119_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse767/sub-verse767_ct.nii.gz', + 'VerSe20/02_validation/rawdata/sub-verse569/sub-verse569_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse556/sub-verse556_dir-ax_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse408/sub-verse408_split-verse265_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse405/sub-verse405_split-verse258_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse033/sub-verse033_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse095/sub-verse095_ct.nii.gz', + 'VerSe19/dataset-verse19test/rawdata/sub-verse050/sub-verse050_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse011/sub-verse011_ct.nii.gz', + 'VerSe20/01_training/rawdata/sub-verse584/sub-verse584_dir-ax_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse064/sub-verse064_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse072/sub-verse072_ct.nii.gz', 'VerSe19/dataset-verse19test/rawdata/sub-verse081/sub-verse081_ct.nii.gz', + 'VerSe20/02_validation/rawdata/sub-verse715/sub-verse715_ct.nii.gz', 'VerSe20/01_training/rawdata/sub-verse536/sub-verse536_dir-ax_ct.nii.gz', + 'VerSe20/03_test/rawdata/sub-gl216/sub-gl216_dir-ax_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse047/sub-verse047_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse411/sub-verse411_split-verse232_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse152/sub-verse152_ct.nii.gz', + 'VerSe20/02_validation/rawdata/sub-verse627/sub-verse627_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-gl144/sub-gl144_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse014/sub-verse014_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse600/sub-verse600_dir-ax_ct.nii.gz', + 'VerSe20/01_training/rawdata/sub-verse510/sub-verse510_dir-ax_ct.nii.gz', 'VerSe19/dataset-verse19test/rawdata/sub-verse012/sub-verse012_ct.nii.gz', + 'VerSe20/02_validation/rawdata/sub-verse753/sub-verse753_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse815/sub-verse815_ct.nii.gz', + 'VerSe19/dataset-verse19training/rawdata/sub-verse401/sub-verse401_split-verse201_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse009/sub-verse009_ct.nii.gz', + 'VerSe20/02_validation/rawdata/sub-verse805/sub-verse805_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse623/sub-verse623_ct.nii.gz', + 'VerSe20/01_training/rawdata/sub-gl090/sub-gl090_dir-ax_ct.nii.gz', 'VerSe19/dataset-verse19test/rawdata/sub-verse414/sub-verse414_split-verse241_ct.nii.gz', + 'VerSe19/dataset-verse19validation/rawdata/sub-verse242/sub-verse242_ct.nii.gz', 'VerSe20/01_training/rawdata/sub-verse532/sub-verse532_dir-ax_ct.nii.gz', + 'VerSe19/dataset-verse19test/rawdata/sub-verse271/sub-verse271_ct.nii.gz', +] + + +def respace(img, new_space=1.0,mode="trilinear"): + spatial_shape = torch.tensor(img.shape[1:]) + ssize = len(spatial_shape) + + new_space = ensure_tuple(new_space) + new_space = torch.tensor(ensure_tuple_size(new_space, ssize, first(new_space))) + + old_space = torch.tensor(img.meta["pixdim"][1:4]) + + new_shape = old_space.div(new_space).mul_(spatial_shape).long() + + return torch.nn.functional.interpolate(img[None], new_shape.tolist(),mode=mode)[0] + + +class Respaced(mt.Lambdad): + def __init__(self, keys, new_space): + super().__init__(keys, func=self._respace) + self.new_space = new_space + + def _respace(self, x): + return respace(x, self.new_space) + + +class DiffusionPrepareBatch(PrepareBatch): + """ + This class is used as a callable for the `prepare_batch` parameter of engine classes for diffusion training. + + Assuming a supervised training process, it will generate a noise field using `get_noise` for an input image, and + return the image and noise field as the image/target pair plus the noise field the kwargs under the key "noise". + This assumes the inferer being used in conjunction with this class expects a "noise" parameter to be provided. + + If the `condition_name` is provided, this must refer to a key in the input dictionary containing the condition + field to be passed to the inferer. This will appear in the keyword arguments under the key "condition". + + """ + + def __init__(self, num_train_timesteps: int, condition_name: Optional[str] = None): + self.condition_name = condition_name + self.num_train_timesteps = num_train_timesteps + + def get_noise(self, images): + """Returns the noise tensor for input tensor `images`, override this for different noise distributions.""" + return torch.randn_like(images) + + def get_timesteps(self, images): + return torch.randint(0, self.num_train_timesteps, (images.shape[0],), device=images.device).long() + + def __call__( + self, + batchdata: Dict[str, torch.Tensor], + device: Optional[Union[str, torch.device]] = None, + non_blocking: bool = False, + **kwargs, + ): + images, _ = default_prepare_batch(batchdata, device, non_blocking, **kwargs) + noise = self.get_noise(images).to(device, non_blocking=non_blocking, **kwargs) + timesteps = self.get_timesteps(images).to(device, non_blocking=non_blocking, **kwargs) + + kwargs = {"noise": noise, "timesteps": timesteps} + + if self.condition_name is not None and isinstance(batchdata, Mapping): + kwargs["conditioning"] = batchdata[self.condition_name].to(device, non_blocking=non_blocking, **kwargs) + + # return input, target, arguments, and keyword arguments where noise is the target and also a keyword value + return images, noise, (), kwargs + + +def inv_metric_cmp_fn(current_metric: float, prev_best: float) -> bool: + """ + The default function to compare metric values between current metric and previous best metric. + Args: + current_metric: metric value of current round computation. + prev_best: the best metric value of previous rounds to compare with. + """ + return current_metric < prev_best From f11d216c7bf4504a023a0f695c15720a5914c57f Mon Sep 17 00:00:00 2001 From: Eric Kerfoot Date: Thu, 16 Feb 2023 22:00:26 +0000 Subject: [PATCH 2/9] Update to bundle Signed-off-by: Eric Kerfoot --- .../mednist_ddpm/bundle/configs/common.yaml | 5 +- .../mednist_ddpm/bundle/configs/infer.yaml | 14 ++-- .../mednist_ddpm/bundle/configs/train.yaml | 21 +---- .../bundle/configs/train_multigpu.yaml | 18 ++--- .../bundle/docs/2d_ddpm_bundle_tutorial.ipynb | 81 ++++++++++++++----- .../mednist_ddpm/bundle/docs/sub_train.sh | 34 ++++++++ .../bundle/docs/sub_train_multigpu.sh | 36 +++++++++ 7 files changed, 152 insertions(+), 57 deletions(-) create mode 100755 model-zoo/models/mednist_ddpm/bundle/docs/sub_train.sh create mode 100644 model-zoo/models/mednist_ddpm/bundle/docs/sub_train_multigpu.sh diff --git a/model-zoo/models/mednist_ddpm/bundle/configs/common.yaml b/model-zoo/models/mednist_ddpm/bundle/configs/common.yaml index 51d7e48b..4f156c2b 100644 --- a/model-zoo/models/mednist_ddpm/bundle/configs/common.yaml +++ b/model-zoo/models/mednist_ddpm/bundle/configs/common.yaml @@ -1,3 +1,5 @@ +# This file defines common definitions used in training and inference, most importantly the definition definition + imports: - $import os - $import datetime @@ -15,7 +17,6 @@ is_dist: '$dist.is_initialized()' rank: '$dist.get_rank() if @is_dist else 0' is_not_rank0: '$@rank > 0' device: '$torch.device(f"cuda:{@rank}" if torch.cuda.is_available() else "cpu")' -softdevice: $torch.device('cpu') network_def: _target_: generative.networks.nets.DiffusionModelUNet @@ -26,12 +27,12 @@ network_def: attention_levels: [false, true, true] num_res_blocks: 1 num_head_channels: 128 + network: $@network_def.to(@device) bundle_root: . ckpt_path: $@bundle_root + '/models/model.pt' use_amp: true - image_dim: 64 image_size: [1, '@image_dim', '@image_dim'] num_train_timesteps: 1000 diff --git a/model-zoo/models/mednist_ddpm/bundle/configs/infer.yaml b/model-zoo/models/mednist_ddpm/bundle/configs/infer.yaml index dbb74e62..5326caf7 100644 --- a/model-zoo/models/mednist_ddpm/bundle/configs/infer.yaml +++ b/model-zoo/models/mednist_ddpm/bundle/configs/infer.yaml @@ -1,14 +1,18 @@ -inter_steps: '$@num_train_timesteps//10' +# This defines an inference script for generating a random image to a Pytorch file + batch_size: 1 num_workers: 0 -noise: $torch.rand(1,1,@image_dim,@image_dim) -out_file: "" +noise: $torch.rand(1,1,@image_dim,@image_dim) # create a random image every time this program is run + +out_file: "" # where to save the tensor to -sample: '$lambda x: @inferer.sample(input_noise=x,diffusion_model=@network,scheduler=@scheduler,save_intermediates=False)' +# using a lambda this defines a simple sampling function used below +sample: '$lambda x: @inferer.sample(input_noise=x, diffusion_model=@network, scheduler=@scheduler)' -load_state: '$@network.load_state_dict(torch.load(@ckpt_path))' +load_state: '$@network.load_state_dict(torch.load(@ckpt_path))' # command to load the saved model weights +# program to load the model weights, run `sample`, and store results to `out_file` testing: - '@load_state' - '$torch.save(@sample(@noise.to(@device)), @out_file)' \ No newline at end of file diff --git a/model-zoo/models/mednist_ddpm/bundle/configs/train.yaml b/model-zoo/models/mednist_ddpm/bundle/configs/train.yaml index de04ec68..739b3c1f 100644 --- a/model-zoo/models/mednist_ddpm/bundle/configs/train.yaml +++ b/model-zoo/models/mednist_ddpm/bundle/configs/train.yaml @@ -1,3 +1,6 @@ +# This defines the training script for the network + +# choose a new directory for every run output_dir: $datetime.datetime.now().strftime('./results/output_%y%m%d_%H%M%S') dataset_dir: ./data @@ -47,7 +50,6 @@ train_transforms: padding_mode: "zeros" prob: '@rand_prob' - train_ds: _target_: Dataset data: $@train_datalist @@ -111,12 +113,7 @@ evaluator: _target_: MeanAbsoluteError output_transform: $monai.handlers.from_engine([@pred, @label]) metric_cmp_fn: '$scripts.inv_metric_cmp_fn' - val_handlers: '@val_handlers' - -# metriclogger: -# _target_: MetricLogger -# evaluator: '@evaluator' -# _disabled_: '@is_not_rank0' + val_handlers: '$list(filter(bool, @val_handlers))' handlers: - _target_: CheckpointLoader @@ -128,20 +125,10 @@ handlers: validator: '@evaluator' epoch_level: true interval: '@val_interval' -# - '@metriclogger' -# - _target_: StatsHandler -# name: train_log -# tag_name: train_loss -# output_transform: $monai.handlers.from_engine(['loss'], first=True) -# _disabled_: '@is_not_rank0' -# - _target_: LogfileHandler -# output_dir: '@output_dir' -# _disabled_: '@is_not_rank0' - _target_: CheckpointSaver save_dir: '@output_dir' save_dict: model: '@network' - # logger: '@metriclogger' save_interval: '@save_interval' save_final: true epoch_level: true diff --git a/model-zoo/models/mednist_ddpm/bundle/configs/train_multigpu.yaml b/model-zoo/models/mednist_ddpm/bundle/configs/train_multigpu.yaml index c91d7f39..2811612f 100644 --- a/model-zoo/models/mednist_ddpm/bundle/configs/train_multigpu.yaml +++ b/model-zoo/models/mednist_ddpm/bundle/configs/train_multigpu.yaml @@ -1,4 +1,5 @@ -# device: $torch.device(f'cuda:{dist.get_rank()}') +# This can be mixed in with the training script to enable multi-GPU training + network: _target_: torch.nn.parallel.DistributedDataParallel module: $@network_def.to(@device) @@ -10,27 +11,20 @@ tsampler: dataset: '@train_ds' even_divisible: true shuffle: true -train_dataloader#sampler: '@tsampler' -train_dataloader#shuffle: false +train_loader#sampler: '@tsampler' +train_loader#shuffle: false vsampler: _target_: DistributedSampler - dataset: '@eval_ds' + dataset: '@val_ds' even_divisible: false shuffle: false -eval_dataloader#sampler: '@vsampler' - -# trainer#train_handlers: '$@handlers[: 2 if dist.get_rank() > 0 else None]' -# evaluator#val_handlers: '$None if @is_not_rank0 else @val_handlers' - -# trainer#train_handlers: '$@handlers[1 if @is_not_rank0 else 0:]' +val_loader#sampler: '@vsampler' training: - $import torch.distributed as dist - $dist.init_process_group(backend='nccl') -- $print(@device) - $torch.cuda.set_device(@device) - $monai.utils.set_determinism(seed=123), -# - $print(@network) - $@trainer.run() - $dist.destroy_process_group() \ No newline at end of file diff --git a/model-zoo/models/mednist_ddpm/bundle/docs/2d_ddpm_bundle_tutorial.ipynb b/model-zoo/models/mednist_ddpm/bundle/docs/2d_ddpm_bundle_tutorial.ipynb index af4fb64d..bb6e1e90 100644 --- a/model-zoo/models/mednist_ddpm/bundle/docs/2d_ddpm_bundle_tutorial.ipynb +++ b/model-zoo/models/mednist_ddpm/bundle/docs/2d_ddpm_bundle_tutorial.ipynb @@ -7,9 +7,11 @@ "source": [ "# Denoising Diffusion Probabilistic Models with MedNIST Dataset Bundle \n", "\n", - "This notebook discusses and uses the MONAI bundle it's included in for generating images from the MedNIST dataset using diffusion models. This i based off the 2d_ddpm_tutorial_ignite.ipynb notebook with a few changes.\n", + "This notebook discusses and uses the MONAI bundle it's included in for generating images from the MedNIST dataset using diffusion models. This is based off the 2d_ddpm_tutorial_ignite.ipynb notebook with a few changes.\n", "\n", - "First thing to do is import libraries then download the MedNIST dataset:" + "The bundle defines training and inference scripts whose use will be described here along with visualisations. The assumption with this notebook is that it's run within the bundle's `docs` directory and that the environment it runs in has `MONAI` and `GenerativeModels` installed. The command lines given are known to work in `bash` however may be problematic in Windows.\n", + "\n", + "First thing to do is import libraries and verify MONAI is present:" ] }, { @@ -96,7 +98,7 @@ "id": "678d2e51-dc2d-4ad9-a4c0-14a6f900398b", "metadata": {}, "source": [ - "A bundle can be run on the command line using the Fire library or by parsing the configuration manually then getting parsed content objects. The following is the command to train the network for the default number of epochs. It will state values in the config files which need to be set for a particular run, such as the dataset directory created above, and setting the PYTHONPATH variable. The configuration for this bundle is split into 4 yaml files, one having common definitions for training and inference, one to enable multi-GPU training, and one each for training and inference. Their combinations determine what your final configuration is, in this case the common and train files produce a training script. " + "A bundle can be run on the command line using the Fire library or by parsing the configuration manually then getting parsed content objects. The following is the command to train the network for the default number of epochs. It will define values in the config files which need to be set for a particular run, such as the dataset directory created above, and setting the PYTHONPATH variable. The configuration for this bundle is split into 4 yaml files, one having common definitions for training and inference, one to enable multi-GPU training, and one each for training and inference. Their combinations determine what your final configuration is, in this case the common and train files produce a training script. " ] }, { @@ -106,7 +108,8 @@ "metadata": {}, "outputs": [], "source": [ - "configs=f\"['{bundle_root}/configs/common.yaml','{bundle_root}/configs/train.yaml']\"\n", + "# multiple config files need to be specified this way with '' quotes, variable used in command line must be in \"\" quotes\n", + "configs=f\"'{bundle_root}/configs/common.yaml', '{bundle_root}/configs/train.yaml'\"\n", "\n", "!PYTHONPATH={bundle_root} python -m monai.bundle run training \\\n", " --meta_file {bundle_root}/configs/metadata.json \\\n", @@ -121,12 +124,12 @@ "id": "5030732c-deb5-448a-b575-385bda0fa308", "metadata": {}, "source": [ - "The test inference script can be invoked as such to produce an output saved tensor with a randomly generated image:" + "The test inference script can then be invoked as such to produce an output tensor saved to the given file with a randomly generated image. The `ckpt_path` value should point to the final checkpoint file created during the above training run, which will be in a subdirectory of `./result`. The training script's default behaviour is to create a new timestamped subdirectory in `./result` for every new run, this can be explicitly set by providing a `output_dir` value on the command line." ] }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 36, "id": "40e6a3e9-3984-44b0-ba9a-5b8d58c7ea2d", "metadata": {}, "outputs": [ @@ -134,34 +137,34 @@ "name": "stdout", "output_type": "stream", "text": [ - "2023-02-16 15:42:37,882 - INFO - --- input summary of monai.bundle.scripts.run ---\n", - "2023-02-16 15:42:37,882 - INFO - > runner_id: 'testing'\n", - "2023-02-16 15:42:37,883 - INFO - > meta_file: '/home/localek10/workspace/monai/GenerativeModels/model-zoo/models/mednist_ddpm/bundle/configs/metadata.json'\n", - "2023-02-16 15:42:37,883 - INFO - > config_file: ['/home/localek10/workspace/monai/GenerativeModels/model-zoo/models/mednist_ddpm/bundle/configs/common.yaml',\n", - " '/home/localek10/workspace/monai/GenerativeModels/model-zoo/models/mednist_ddpm/bundle/configs/infer.yaml']\n", - "2023-02-16 15:42:37,883 - INFO - > ckpt_path: './results/output_230215_174009/model_final_iteration=75000.pt'\n", - "2023-02-16 15:42:37,883 - INFO - > bundle_root: '/home/localek10/workspace/monai/GenerativeModels/model-zoo/models/mednist_ddpm/bundle'\n", - "2023-02-16 15:42:37,883 - INFO - > out_file: 'test.pt'\n", - "2023-02-16 15:42:37,883 - INFO - ---\n", + "2023-02-16 21:00:18,139 - INFO - --- input summary of monai.bundle.scripts.run ---\n", + "2023-02-16 21:00:18,139 - INFO - > runner_id: 'testing'\n", + "2023-02-16 21:00:18,139 - INFO - > meta_file: '/home/localek10/workspace/monai/GenerativeModels/model-zoo/models/mednist_ddpm/bundle/configs/metadata.json'\n", + "2023-02-16 21:00:18,139 - INFO - > config_file: ('/home/localek10/workspace/monai/GenerativeModels/model-zoo/models/mednist_ddpm/bundle/configs/common.yaml',\n", + " '/home/localek10/workspace/monai/GenerativeModels/model-zoo/models/mednist_ddpm/bundle/configs/infer.yaml')\n", + "2023-02-16 21:00:18,139 - INFO - > ckpt_path: './results/output_230215_174009/model_final_iteration=75000.pt'\n", + "2023-02-16 21:00:18,140 - INFO - > bundle_root: '/home/localek10/workspace/monai/GenerativeModels/model-zoo/models/mednist_ddpm/bundle'\n", + "2023-02-16 21:00:18,140 - INFO - > out_file: 'test.pt'\n", + "2023-02-16 21:00:18,140 - INFO - ---\n", "\n", "\n", - "100%|███████████████████████████████████████| 1000/1000 [00:10<00:00, 97.44it/s]\n", + "100%|███████████████████████████████████████| 1000/1000 [00:10<00:00, 97.10it/s]\n", "[[[], []], null]\n" ] }, { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 25, + "execution_count": 36, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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P6877rhDTU1Nqqio0I9//ONh72dZptbWVjU1Nam6uloLFy7U/v370wz2HLW3t+umm25SXV2dpk2bpjvvvFMHDhwYtk057OemTZt07bXX5v/CfN68efrpT3+af78c9vFs7e3tqqio0KpVq/Jt5bCfra2tqqioGPZqbGzMv18O+3jGb3/7W33lK1/RxRdfrJqaGn3605/Wnj178u8n2desRO3YsSObNGlStmXLluyVV17JVq5cmdXW1mZvvvlm6qGds5/85CfZ2rVrsyeeeCKTlD311FPD3n/kkUeyurq67Iknnsj27duXffGLX8ymT5+e9fX1pRnwOfiTP/mTbOvWrdmvfvWrbO/evdntt9+eXXbZZdmxY8fy25TDfj799NPZv//7v2cHDhzIDhw4kD3wwAPZpEmTsl/96ldZlpXHPn7QL37xi+zjH/94du2112YrV67Mt5fDfj744IPZrFmzskOHDuVfPT09+ffLYR+zLMveeeedbObMmdnXvva17L//+7+zgwcPZv/xH/+R/eY3v8lvk2JfS3YS+sM//MNs+fLlw9o+9alPZd/+9rcTjSiusyeh06dPZ42NjdkjjzySbzt58mRWX1+f/eM//mOCEcbR09OTSco6OzuzLCvf/cyyLLvwwguzf/qnfyq7fezv789aWlqyjo6ObMGCBflJqFz288EHH8yuu+664Hvlso9ZlmXf+ta3sltvvdV8P9W+luSv44aGhrRnzx4tXrx4WPvixYu1a9euRKMqroMHD6q7u3vYPudyOS1YsGBM73Nvb68k6aKLLpJUnvt56tQp7dixQ8ePH9e8efPKbh/vvfde3X777frc5z43rL2c9vO1115TU1OTmpub9aUvfUmvv/66pPLax6efflpz5szRF77wBU2bNk3XX3+9tmzZkn8/1b6W5CT09ttv69SpU2poaBjW3tDQoO7u7kSjKq4z+1VO+5xlme6//37deuutmj17tqTy2s99+/ZpypQpyuVyWr58uZ566ildffXVZbWPO3bs0C9/+Uu1t7cXvFcu+zl37lw9/vjjevbZZ7VlyxZ1d3dr/vz5Onz4cNnsoyS9/vrr2rRpk1paWvTss89q+fLl+uY3v6nHH39cUrrzWXJLOXzQmaUczsiyrKCt3JTTPt933316+eWX9V//9V8F75XDfn7yk5/U3r17dfToUT3xxBO6++671dnZmX9/rO9jV1eXVq5cqZ07d2ry5MnmdmN9P5csWZL/39dcc43mzZunK664Qtu2bdPNN98saezvo/T+Wm1z5sxRW1ubJOn666/X/v37tWnTJv3FX/xFfruPel9L8k7oYx/7mCZOnFgw+/b09BTM0uXiTBqnXPb5G9/4hp5++mn9/Oc/z68PJZXXflZVVekTn/iE5syZo/b2dl133XX6/ve/Xzb7uGfPHvX09OjGG29UZWWlKisr1dnZqX/4h39QZWVlfl/G+n6erba2Vtdcc41ee+21sjmXkjR9+nRdffXVw9quuuoqvfXWW5LSfTdLchKqqqrSjTfeqI6OjmHtHR0dmj9/fqJRFVdzc7MaGxuH7fPQ0JA6OzvH1D5nWab77rtPTz75pH72s5+publ52Pvlsp8hWZZpcHCwbPbxtttu0759+7R37978a86cObrrrru0d+9eXX755WWxn2cbHBzUr3/9a02fPr1szqUk3XLLLQV/LvHqq69q5syZkhJ+N4sWeThPZyLaP/zhD7NXXnklW7VqVVZbW5u98cYbqYd2zvr7+7OXXnope+mllzJJ2fr167OXXnopHzt/5JFHsvr6+uzJJ5/M9u3bl335y18ec1HQr3/961l9fX323HPPDYu8njhxIr9NOeznmjVrsueffz47ePBg9vLLL2cPPPBANmHChGznzp1ZlpXHPoZ8MB2XZeWxn3/zN3+TPffcc9nrr7+evfDCC9nnP//5rK6uLv+zphz2Mcvej9lXVlZm3/3ud7PXXnst++d//uespqYm+9GPfpTfJsW+luwklGVZ9uijj2YzZ87MqqqqshtuuCEf8x2rfv7zn2eSCl533313lmXvRyQffPDBrLGxMcvlctlnPvOZbN++fWkH7RTaP0nZ1q1b89uUw37+5V/+Zf7avOSSS7LbbrstPwFlWXnsY8jZk1A57OeZv4WZNGlS1tTUlC1dujTbv39//v1y2Mcz/u3f/i2bPXt2lsvlsk996lPZ5s2bh72fYl9ZTwgAkExJPhMCAIwPTEIAgGSYhAAAyTAJAQCSYRICACTDJAQASIZJCACQDJMQACAZJiEAQDJMQgCAZJiEAADJ/D/fDk69KCbT4AAAAABJRU5ErkJggg==\n", + "image/png": "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fvGL2dSpU7O+vr40HT4Lf/zHf5w9/PDD2a9+9ats79692a233ppdeuml2dGjR4ttKmGcTz75ZPbv//7v2YEDB7IDBw5k9913X1ZTU5P96le/yrKsMsb4h37xi19kH/vYx7Krr746W7FiRXF7JYzz/vvvz2bOnJkdOnSo+NPT01P8fSWMMcuy7Pe//302Y8aM7Gtf+1r2P//zP9nBgwez//iP/8heffXVYpsUYy3bSeiP/uiPsmXLlg3b9qlPfSr77ne/m6hHcZ05CZ06dSprbm7OHnzwweK2EydOZI2Njdnf//3fJ+hhHD09PZmkrLOzM8uyyh1nlmXZhRdemP3DP/xDxY2xv78/a21tzTo6OrL58+cXJ6FKGef999+fXXPNNcHfVcoYsyzLvvOd72Q333yz+ftUYy3Lj+OGhoa0Z88eLVq0aNj2RYsWadeuXYl6la+DBw+qu7t72JgLhYLmz58/rsd8ekmOiy66SFJljvPkyZPasWOHjh07prlz51bcGO+++27deuut+vznPz9seyWN85VXXtG0adPU0tKiL33pS3rttdckVdYYn3zySc2ePVtf+MIXNGXKFF177bXaunVr8fepxlqWk9Dbb7+tkydPqqmpadj2pqYmdXd3J+pVvk6Pq5LGnGWZ7r33Xt18882aNWuWpMoa5759+3TeeeepUCho2bJleuKJJ3TllVdW1Bh37NihX/7yl2pvby/5XaWMc86cOXr00Uf1zDPPaOvWreru7ta8efP0zjvvVMwYJem1117T5s2b1draqmeeeUbLli3Tt7/9bT366KOS0j2fZbeUwx86vZTDaVmWlWyrNJU05nvuuUcvvfSS/vu//7vkd5Uwzk9+8pPau3evjhw5oscee0x33nmnOjs7i78f72Ps6urSihUrtHPnTk2aNMlsN97HuXjx4uJ/X3XVVZo7d64+8YlPaNu2bbrxxhsljf8xSu+v1TZ79my1tbVJkq699lrt379fmzdv1l/8xV8U233YYy3LK6GPfOQjmjhxYsns29PTUzJLV4rTaZxKGfO3vvUtPfnkk/r5z39eXB9Kqqxx1tbW6rLLLtPs2bPV3t6ua665Rj/60Y8qZox79uxRT0+Prr/+elVXV6u6ulqdnZ36u7/7O1VXVxfHMt7Heab6+npdddVVeuWVVyrmuZSkqVOn6sorrxy27YorrtAbb7whKd1rsywnodraWl1//fXq6OgYtr2jo0Pz5s1L1Kt8tbS0qLm5ediYh4aG1NnZOa7GnGWZ7rnnHj3++OP62c9+ppaWlmG/r5RxhmRZpsHBwYoZ4y233KJ9+/Zp7969xZ/Zs2frjjvu0N69e/Xxj3+8IsZ5psHBQf3617/W1KlTK+a5lKSbbrqp5OsSv/nNbzRjxgxJCV+buUUexuh0RPsf//Efs5dffjlbuXJlVl9fn/32t79N3bWz1t/fn7344ovZiy++mEnKNmzYkL344ovF2PmDDz6YNTY2Zo8//ni2b9++7Mtf/vK4i4J+85vfzBobG7Nnn312WOT1+PHjxTaVMM7Vq1dnzz33XHbw4MHspZdeyu67775swoQJ2c6dO7Msq4wxhvxhOi7LKmOcf/3Xf509++yz2WuvvZY9//zz2Z/+6Z9mDQ0NxfeaShhjlr0fs6+urs6+//3vZ6+88kr2T//0T1ldXV32k5/8pNgmxVjLdhLKsix76KGHshkzZmS1tbXZddddV4z5jlc///nPM0klP3feeWeWZe9HJO+///6subk5KxQK2Wc+85ls3759aTvtFBqfpOzhhx8utqmEcf7lX/5l8dz86Ec/mt1yyy3FCSjLKmOMIWdOQpUwztPfhampqcmmTZuWLVmyJNu/f3/x95UwxtP+7d/+LZs1a1ZWKBSyT33qU9mWLVuG/T7FWFlPCACQTFneEwIAnBuYhAAAyTAJAQCSYRICACTDJAQASIZJCACQDJMQACAZJiEAQDJMQgCAZJiEAADJMAkBAJL5/wB3dS17EkusPwAAAABJRU5ErkJggg==\n", "text/plain": [ "
" ] @@ -171,7 +174,7 @@ } ], "source": [ - "configs=f\"['{bundle_root}/configs/common.yaml','{bundle_root}/configs/infer.yaml']\"\n", + "configs=f\"'{bundle_root}/configs/common.yaml', '{bundle_root}/configs/infer.yaml'\"\n", "\n", "!PYTHONPATH={bundle_root} python -m monai.bundle run testing \\\n", " --meta_file {bundle_root}/configs/metadata.json \\\n", @@ -230,7 +233,7 @@ "source": [ "import sys\n", "\n", - "sys.path.append(bundle_root)\n", + "sys.path.append(bundle_root) # make sure we load the script files we need\n", "\n", "# configure the parser from the bundle's information\n", "cp = ConfigParser()\n", @@ -252,6 +255,42 @@ "\n", "plt.imshow(test[0, 0].cpu(), vmin=0, vmax=1, cmap=\"gray\")" ] + }, + { + "cell_type": "markdown", + "id": "2feab4e5-2745-4d35-9eec-a2bb8340cf51", + "metadata": {}, + "source": [ + "Multi-GPU can be enabled by including the `train_multigpu.yaml` configuration file:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "173cda1c-ac90-410f-b34d-b6cbb0044c7a", + "metadata": {}, + "outputs": [], + "source": [ + "configs=f\"'{bundle_root}/configs/common.yaml', '{bundle_root}/configs/train.yaml', '{bundle_root}/configs/train_multigpu.yaml'\"\n", + "\n", + "!PYTHONPATH={bundle_root} torchrun --standalone --nnodes=1 --nproc_per_node=2 -m monai.bundle run training \\\n", + " --meta_file {bundle_root}/configs/metadata.json \\\n", + " --config_file \"{configs}\" \\\n", + " --logging_file {bundle_root}/configs/logging.conf \\\n", + " --bundle_root {bundle_root} \\\n", + " --dataset_dir {dataset_dir}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cb719023-8250-43c4-ab10-911829332498", + "metadata": {}, + "outputs": [], + "source": [ + "if directory is None:\n", + " shutil.rmtree(root_dir)" + ] } ], "metadata": { diff --git a/model-zoo/models/mednist_ddpm/bundle/docs/sub_train.sh b/model-zoo/models/mednist_ddpm/bundle/docs/sub_train.sh new file mode 100755 index 00000000..237b16f5 --- /dev/null +++ b/model-zoo/models/mednist_ddpm/bundle/docs/sub_train.sh @@ -0,0 +1,34 @@ +#! /bin/bash +#SBATCH --nodes=1 +#SBATCH -J mednist_train +#SBATCH -c 4 +#SBATCH --gres=gpu:1 +#SBATCH --time=2:00:00 +#SBATCH -p small + +set -v + +# change this if run submitted from a different directory +export BUNDLE="$(pwd)/.." + +# have to set PYTHONPATH to find MONAI and GenerativeModels as well as the bundle's script directory +export PYTHONPATH="$HOME/MONAI:$HOME/GenerativeModels:$BUNDLE" + +# change this to load a checkpoint instead of started from scratch +CKPT=none + +CONFIG="'$BUNDLE/configs/common.yaml', '$BUNDLE/configs/train.yaml'" + +# change this to point to where MedNIST is located +DATASET="$(pwd)" + +# it's useful to include the configuration in the log file +cat "$BUNDLE/configs/common.yaml" +cat "$BUNDLE/configs/train.yaml" + +python -m monai.bundle run training \ + --meta_file "$BUNDLE/configs/metadata.json" \ + --config_file "$CONFIG" \ + --logging_file "$BUNDLE/configs/logging.conf" \ + --bundle_root "$BUNDLE" \ + --dataset_dir "$DATASET" diff --git a/model-zoo/models/mednist_ddpm/bundle/docs/sub_train_multigpu.sh b/model-zoo/models/mednist_ddpm/bundle/docs/sub_train_multigpu.sh new file mode 100644 index 00000000..7c424af0 --- /dev/null +++ b/model-zoo/models/mednist_ddpm/bundle/docs/sub_train_multigpu.sh @@ -0,0 +1,36 @@ +#! /bin/bash +#SBATCH --nodes=1 +#SBATCH -J mednist_train +#SBATCH -c 4 +#SBATCH --gres=gpu:2 +#SBATCH --time=2:00:00 +#SBATCH -p big + +set -v + +# change this if run submitted from a different directory +export BUNDLE="$(pwd)/.." + +# have to set PYTHONPATH to find MONAI and GenerativeModels as well as the bundle's script directory +export PYTHONPATH="$HOME/MONAI:$HOME/GenerativeModels:$BUNDLE" + +# change this to load a checkpoint instead of started from scratch +CKPT=none + +CONFIG="'$BUNDLE/configs/common.yaml', '$BUNDLE/configs/train.yaml', '$BUNDLE/configs/train_multigpu.yaml'" + +# change this to point to where MedNIST is located +DATASET="$(pwd)" + +# it's useful to include the configuration in the log file +cat "$BUNDLE/configs/common.yaml" +cat "$BUNDLE/configs/train.yaml" +cat "$BUNDLE/configs/train_multigpu.yaml" + +# remember to change arguments to match how many nodes and GPUs you have +torchrun --standalone --nnodes=1 --nproc_per_node=2 -m monai.bundle run training \ + --meta_file "$BUNDLE/configs/metadata.json" \ + --config_file "$CONFIG" \ + --logging_file "$BUNDLE/configs/logging.conf" \ + --bundle_root "$BUNDLE" \ + --dataset_dir "$DATASET" \ No newline at end of file From cca437735adfb46eaf1daf41fad772a74539b3ba Mon Sep 17 00:00:00 2001 From: Eric Kerfoot Date: Thu, 16 Feb 2023 22:04:01 +0000 Subject: [PATCH 3/9] Update to bundle Signed-off-by: Eric Kerfoot --- .../mednist_ddpm/bundle/docs/2d_ddpm_bundle_tutorial.ipynb | 4 +--- model-zoo/models/mednist_ddpm/bundle/docs/README.md | 4 ++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/model-zoo/models/mednist_ddpm/bundle/docs/2d_ddpm_bundle_tutorial.ipynb b/model-zoo/models/mednist_ddpm/bundle/docs/2d_ddpm_bundle_tutorial.ipynb index bb6e1e90..8cc1e693 100644 --- a/model-zoo/models/mednist_ddpm/bundle/docs/2d_ddpm_bundle_tutorial.ipynb +++ b/model-zoo/models/mednist_ddpm/bundle/docs/2d_ddpm_bundle_tutorial.ipynb @@ -63,8 +63,6 @@ "\n", "import matplotlib.pyplot as plt\n", "import monai\n", - "import numpy as np\n", - "import torch\n", "from monai.bundle import ConfigParser\n", "\n", "# path to the bundle directory, this assumes you're running the notebook in its directory\n", @@ -289,7 +287,7 @@ "outputs": [], "source": [ "if directory is None:\n", - " shutil.rmtree(root_dir)" + " shutil.rmtree(dataset_dir)" ] } ], diff --git a/model-zoo/models/mednist_ddpm/bundle/docs/README.md b/model-zoo/models/mednist_ddpm/bundle/docs/README.md index c57d6df5..6483aff5 100644 --- a/model-zoo/models/mednist_ddpm/bundle/docs/README.md +++ b/model-zoo/models/mednist_ddpm/bundle/docs/README.md @@ -3,3 +3,7 @@ This implements roughly equivalent code to the "Denoising Diffusion Probabilistic Models with MedNIST Dataset" example notebook. This includes scripts for training with single or multiple GPUs and a visualisation notebook. +The files included here demonstrate how to use the bundle: + * [2d_ddpm_bundle_tutorial.ipynb](./2d_ddpm_bundle_tutorial.ipynb) - demonstrates command line and in-code invocation of the bundle's training and inference scripts + * [sub_train.sh](sub_train.sh) - SLURM submission script example for training + * [sub_train_multigpu.sh](sub_train_multigpu.sh) - SLURM submission script example for training with multiple GPUs From 1a83fd902ee739cabafd0f49279e8f7d5d4d9cef Mon Sep 17 00:00:00 2001 From: Eric Kerfoot Date: Thu, 16 Feb 2023 22:16:58 +0000 Subject: [PATCH 4/9] Update script file to remove leftover junk Signed-off-by: Eric Kerfoot --- .../mednist_ddpm/bundle/scripts/__init__.py | 156 +----------------- 1 file changed, 3 insertions(+), 153 deletions(-) diff --git a/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py b/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py index 47519bed..1e5451a9 100644 --- a/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py +++ b/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py @@ -1,157 +1,7 @@ -import torch -from functools import partial -from monai import transforms as mt -from monai.utils import first, ensure_tuple, ensure_tuple_size -from monai.engines import PrepareBatch, default_prepare_batch from typing import Dict, Mapping, Optional, Union - - -good_names = [ - "v19_153", "v19_223", "v20_500", "v20_195", "v20_016", "v20_635", "v19_089", "v19_227", "v19_048", "v19_078", "v19_262", "v20_529", "v20_620", "v20_453", "v19_145", "v19_215", "v19_261", - "v20_757", "v19_083", "v20_707", "v20_546", "v20_525", "v20_521", "v20_766", "v20_505", "v19_243", "v20_352", "v20_763", "v20_558", "v19_113", "v20_714", "v19_124", "v19_250", "v19_139", - "v20_648", "v19_018", "v20_646", "v19_007", "v20_613", "v20_709", "v19_209", "v19_267", "v20_719", "v20_602", "v19_090", "v19_214", "v19_131", "v20_545", "v19_277", "v19_068", "v19_022", - "v20_585", "v19_080", "v19_031", "v20_580", "v19_102", "v19_278", "v20_754", "v20_760", "v20_590", "v20_507", "v19_207", "v19_260", "v19_147", "v19_138", "v19_251", "v20_631", "v20_711", - "v20_586", "v20_017", "v19_091", "v20_825", "v20_701", "v20_544", "v19_266", "v19_023", "v19_104", "v20_700", "v19_212", "v19_026", "v20_716", "v19_247", "v20_647", "v19_205", "v20_607", - "v19_208", "v19_149", "v19_275", "v20_518", "v19_010", "v19_013", "v19_046", "v19_070", "v19_055", "v19_130", "v19_005", "v19_085", "v19_108", "v19_134", "v20_596", "v20_756", "v20_811", - "v20_513", "v19_273", "v19_107", "v19_254", "v19_143", "v20_565", "v20_604", "v20_755", "v20_640", "v19_008", "v19_058", "v20_603", "v20_802", "v19_016", "v19_054", "v20_419", "v19_060", - "v19_217", "v19_127", "v19_253", "v19_051", "v19_059", "v19_075", "v20_761", "v20_619", "v20_616", "v19_020", "v20_703", "v19_043", "v19_155", "v20_506", "v19_256", "v20_649", "v20_479", - "v19_257", "v20_816", "v19_154", "v19_272", "v19_226", "v19_004", "v19_065", "v20_769", "v19_239", "v19_230", "v20_768", "v19_067", "v20_713", "v20_295", "v19_202", "v20_572", "v19_030", - "v20_810", "v20_594", "v19_024", "v19_111", "v19_076", "v19_073", "v20_534", "v19_290", "v20_824", "v19_252", "v20_108", "v20_614", "v20_559", "v20_573", "v19_279", "v19_141", "v19_100", - "v19_119", "v20_767", "v20_569", "v20_556", "v19_265", "v19_258", "v19_033", "v19_095", "v19_050", "v19_011", "v20_584", "v19_064", "v19_072", "v19_081", "v20_715", "v20_536", "v20_216", - "v19_047", "v19_232", "v19_152", "v20_627", "v20_144", "v19_014", "v20_600", "v20_510", "v19_012", "v20_753", "v20_815", "v19_201", "v19_009", "v20_805", "v20_623", "v20_090", "v19_241", - "v19_242", "v20_532", "v19_271", -] - -good_images=[ - 'VerSe19/dataset-verse19validation/rawdata/sub-verse153/sub-verse153_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse408/sub-verse408_split-verse223_ct.nii.gz', - 'VerSe20/01_training/rawdata/sub-verse500/sub-verse500_dir-ax_ct.nii.gz', 'VerSe20/03_test/rawdata/sub-gl195/sub-gl195_dir-ax_ct.nii.gz', - 'VerSe20/01_training/rawdata/sub-gl016/sub-gl016_dir-ax_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse635/sub-verse635_ct.nii.gz', - 'VerSe19/dataset-verse19test/rawdata/sub-verse089/sub-verse089_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse410/sub-verse410_split-verse227_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse048/sub-verse048_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse078/sub-verse078_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse407/sub-verse407_split-verse262_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse529/sub-verse529_ct.nii.gz', - 'VerSe20/03_test/rawdata/sub-verse620/sub-verse620_dir-iso_ct.nii.gz', 'VerSe20/01_training/rawdata/sub-gl453/sub-gl453_dir-ax_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse145/sub-verse145_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse407/sub-verse407_split-verse215_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse406/sub-verse406_split-verse261_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse757/sub-verse757_ct.nii.gz', - 'VerSe19/dataset-verse19test/rawdata/sub-verse083/sub-verse083_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse707/sub-verse707_ct.nii.gz', - 'VerSe20/03_test/rawdata/sub-verse546/sub-verse546_dir-ax_ct.nii.gz', 'VerSe20/01_training/rawdata/sub-verse525/sub-verse525_dir-sag_ct.nii.gz', - 'VerSe20/01_training/rawdata/sub-verse521/sub-verse521_dir-ax_ct.nii.gz', 'VerSe20/03_test/rawdata/sub-verse766/sub-verse766_dir-ax_ct.nii.gz', - 'VerSe20/02_validation/rawdata/sub-verse505/sub-verse505_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse415/sub-verse415_split-verse243_ct.nii.gz', - 'VerSe20/02_validation/rawdata/sub-gl352/sub-gl352_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse763/sub-verse763_ct.nii.gz', - 'VerSe20/03_test/rawdata/sub-verse558/sub-verse558_dir-sag_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse113/sub-verse113_ct.nii.gz', - 'VerSe20/03_test/rawdata/sub-verse714/sub-verse714_dir-iso_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse124/sub-verse124_ct.nii.gz', - 'VerSe19/dataset-verse19test/rawdata/sub-verse250/sub-verse250_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse139/sub-verse139_ct.nii.gz', - 'VerSe20/03_test/rawdata/sub-verse648/sub-verse648_dir-iso_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse018/sub-verse018_ct.nii.gz', - 'VerSe20/01_training/rawdata/sub-verse646/sub-verse646_dir-iso_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse007/sub-verse007_ct.nii.gz', - 'VerSe20/03_test/rawdata/sub-verse613/sub-verse613_dir-iso_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse709/sub-verse709_ct.nii.gz', - 'VerSe19/dataset-verse19validation/rawdata/sub-verse404/sub-verse404_split-verse209_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse410/sub-verse410_split-verse267_ct.nii.gz', - 'VerSe20/02_validation/rawdata/sub-verse719/sub-verse719_ct.nii.gz', 'VerSe20/03_test/rawdata/sub-verse602/sub-verse602_dir-iso_ct.nii.gz', - 'VerSe19/dataset-verse19validation/rawdata/sub-verse400/sub-verse400_split-verse090_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse406/sub-verse406_split-verse214_ct.nii.gz', - 'VerSe19/dataset-verse19test/rawdata/sub-verse131/sub-verse131_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse545/sub-verse545_dir-ax_ct.nii.gz', - 'VerSe19/dataset-verse19test/rawdata/sub-verse417/sub-verse417_split-verse277_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse068/sub-verse068_ct.nii.gz', - 'VerSe19/dataset-verse19validation/rawdata/sub-verse022/sub-verse022_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse585/sub-verse585_ct.nii.gz', - 'VerSe19/dataset-verse19validation/rawdata/sub-verse080/sub-verse080_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse031/sub-verse031_ct.nii.gz', - 'VerSe20/02_validation/rawdata/sub-verse580/sub-verse580_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse102/sub-verse102_ct.nii.gz', - 'VerSe19/dataset-verse19test/rawdata/sub-verse417/sub-verse417_split-verse278_ct.nii.gz', 'VerSe20/03_test/rawdata/sub-verse754/sub-verse754_dir-sag_ct.nii.gz', - 'VerSe20/03_test/rawdata/sub-verse760/sub-verse760_dir-iso_ct.nii.gz', 'VerSe20/03_test/rawdata/sub-verse590/sub-verse590_dir-iso_ct.nii.gz', - 'VerSe20/01_training/rawdata/sub-verse507/sub-verse507_dir-ax_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse207/sub-verse207_ct.nii.gz', - 'VerSe19/dataset-verse19test/rawdata/sub-verse260/sub-verse260_ct.nii.gz', 'VerSe19/dataset-verse19test/rawdata/sub-verse147/sub-verse147_ct.nii.gz', - 'VerSe19/dataset-verse19test/rawdata/sub-verse138/sub-verse138_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse402/sub-verse402_split-verse251_ct.nii.gz', - 'VerSe20/01_training/rawdata/sub-verse631/sub-verse631_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse711/sub-verse711_ct.nii.gz', - 'VerSe20/01_training/rawdata/sub-verse586/sub-verse586_dir-iso_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-gl017/sub-gl017_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse091/sub-verse091_ct.nii.gz', 'VerSe20/01_training/rawdata/sub-verse825/sub-verse825_dir-ax_ct.nii.gz', - 'VerSe20/02_validation/rawdata/sub-verse701/sub-verse701_ct.nii.gz', 'VerSe20/01_training/rawdata/sub-verse544/sub-verse544_dir-ax_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse409/sub-verse409_split-verse266_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse023/sub-verse023_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse104/sub-verse104_ct.nii.gz', 'VerSe20/03_test/rawdata/sub-verse700/sub-verse700_dir-sag_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse405/sub-verse405_split-verse212_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse026/sub-verse026_ct.nii.gz', - 'VerSe20/03_test/rawdata/sub-verse716/sub-verse716_dir-iso_ct.nii.gz', 'VerSe19/dataset-verse19test/rawdata/sub-verse416/sub-verse416_split-verse247_ct.nii.gz', - 'VerSe20/03_test/rawdata/sub-verse647/sub-verse647_dir-sag_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse205/sub-verse205_ct.nii.gz', - 'VerSe20/03_test/rawdata/sub-verse607/sub-verse607_dir-sag_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse403/sub-verse403_split-verse208_ct.nii.gz', - 'VerSe19/dataset-verse19test/rawdata/sub-verse149/sub-verse149_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse415/sub-verse415_split-verse275_ct.nii.gz', - 'VerSe20/01_training/rawdata/sub-verse518/sub-verse518_dir-ax_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse010/sub-verse010_ct.nii.gz', - 'VerSe19/dataset-verse19validation/rawdata/sub-verse013/sub-verse013_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse046/sub-verse046_ct.nii.gz', - 'VerSe19/dataset-verse19test/rawdata/sub-verse070/sub-verse070_ct.nii.gz', 'VerSe19/dataset-verse19test/rawdata/sub-verse055/sub-verse055_ct.nii.gz', - 'VerSe19/dataset-verse19test/rawdata/sub-verse130/sub-verse130_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse005/sub-verse005_ct.nii.gz', - 'VerSe19/dataset-verse19test/rawdata/sub-verse085/sub-verse085_ct.nii.gz', 'VerSe19/dataset-verse19test/rawdata/sub-verse108/sub-verse108_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse134/sub-verse134_ct.nii.gz', 'VerSe20/01_training/rawdata/sub-verse596/sub-verse596_dir-ax_ct.nii.gz', - 'VerSe20/03_test/rawdata/sub-verse756/sub-verse756_dir-iso_ct.nii.gz', 'VerSe20/01_training/rawdata/sub-verse811/sub-verse811_dir-ax_ct.nii.gz', - 'VerSe20/02_validation/rawdata/sub-verse513/sub-verse513_ct.nii.gz', 'VerSe19/dataset-verse19test/rawdata/sub-verse414/sub-verse414_split-verse273_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse107/sub-verse107_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse254/sub-verse254_ct.nii.gz', - 'VerSe19/dataset-verse19test/rawdata/sub-verse143/sub-verse143_ct.nii.gz', 'VerSe20/01_training/rawdata/sub-verse565/sub-verse565_dir-ax_ct.nii.gz', - 'VerSe20/03_test/rawdata/sub-verse604/sub-verse604_dir-iso_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse755/sub-verse755_ct.nii.gz', - 'VerSe20/02_validation/rawdata/sub-verse640/sub-verse640_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse008/sub-verse008_ct.nii.gz', - 'VerSe19/dataset-verse19validation/rawdata/sub-verse058/sub-verse058_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse603/sub-verse603_ct.nii.gz', - 'VerSe20/02_validation/rawdata/sub-verse802/sub-verse802_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse016/sub-verse016_ct.nii.gz', - 'VerSe19/dataset-verse19test/rawdata/sub-verse054/sub-verse054_ct.nii.gz', 'VerSe20/03_test/rawdata/sub-gl419/sub-gl419_dir-ax_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse060/sub-verse060_ct.nii.gz', 'VerSe19/dataset-verse19test/rawdata/sub-verse217/sub-verse217_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse127/sub-verse127_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse401/sub-verse401_split-verse253_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse051/sub-verse051_ct.nii.gz', 'VerSe19/dataset-verse19test/rawdata/sub-verse059/sub-verse059_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse075/sub-verse075_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse761/sub-verse761_ct.nii.gz', - 'VerSe20/01_training/rawdata/sub-verse619/sub-verse619_dir-ax_ct.nii.gz', 'VerSe20/03_test/rawdata/sub-verse616/sub-verse616_dir-iso_ct.nii.gz', - 'VerSe19/dataset-verse19test/rawdata/sub-verse020/sub-verse020_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse703/sub-verse703_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse043/sub-verse043_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse400/sub-verse400_split-verse155_ct.nii.gz', - 'VerSe20/01_training/rawdata/sub-verse506/sub-verse506_dir-iso_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse404/sub-verse404_split-verse256_ct.nii.gz', - 'VerSe20/03_test/rawdata/sub-verse649/sub-verse649_dir-sag_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-gl479/sub-gl479_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse257/sub-verse257_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse816/sub-verse816_ct.nii.gz', - 'VerSe19/dataset-verse19test/rawdata/sub-verse154/sub-verse154_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse413/sub-verse413_split-verse272_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse409/sub-verse409_split-verse226_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse004/sub-verse004_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse065/sub-verse065_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse769/sub-verse769_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse413/sub-verse413_split-verse239_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse230/sub-verse230_ct.nii.gz', - 'VerSe20/03_test/rawdata/sub-verse768/sub-verse768_dir-ax_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse067/sub-verse067_ct.nii.gz', - 'VerSe20/02_validation/rawdata/sub-verse713/sub-verse713_ct.nii.gz', 'VerSe20/01_training/rawdata/sub-gl295/sub-gl295_dir-ax_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse402/sub-verse402_split-verse202_ct.nii.gz', 'VerSe20/03_test/rawdata/sub-verse572/sub-verse572_dir-sag_ct.nii.gz', - 'VerSe19/dataset-verse19validation/rawdata/sub-verse030/sub-verse030_ct.nii.gz', 'VerSe20/03_test/rawdata/sub-verse810/sub-verse810_dir-iso_ct.nii.gz', - 'VerSe20/01_training/rawdata/sub-verse594/sub-verse594_dir-ax_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse024/sub-verse024_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse111/sub-verse111_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse076/sub-verse076_ct.nii.gz', - 'VerSe19/dataset-verse19validation/rawdata/sub-verse073/sub-verse073_ct.nii.gz', 'VerSe20/01_training/rawdata/sub-verse534/sub-verse534_dir-iso_ct.nii.gz', - 'VerSe19/dataset-verse19validation/rawdata/sub-verse412/sub-verse412_split-verse290_ct.nii.gz', 'VerSe20/01_training/rawdata/sub-verse824/sub-verse824_dir-ax_ct.nii.gz', - 'VerSe19/dataset-verse19validation/rawdata/sub-verse252/sub-verse252_ct.nii.gz', 'VerSe20/03_test/rawdata/sub-gl108/sub-gl108_dir-ax_ct.nii.gz', - 'VerSe20/02_validation/rawdata/sub-verse614/sub-verse614_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse559/sub-verse559_ct.nii.gz', - 'VerSe20/02_validation/rawdata/sub-verse573/sub-verse573_ct.nii.gz', 'VerSe19/dataset-verse19test/rawdata/sub-verse416/sub-verse416_split-verse279_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse141/sub-verse141_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse100/sub-verse100_ct.nii.gz', - 'VerSe19/dataset-verse19test/rawdata/sub-verse119/sub-verse119_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse767/sub-verse767_ct.nii.gz', - 'VerSe20/02_validation/rawdata/sub-verse569/sub-verse569_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse556/sub-verse556_dir-ax_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse408/sub-verse408_split-verse265_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse405/sub-verse405_split-verse258_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse033/sub-verse033_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse095/sub-verse095_ct.nii.gz', - 'VerSe19/dataset-verse19test/rawdata/sub-verse050/sub-verse050_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse011/sub-verse011_ct.nii.gz', - 'VerSe20/01_training/rawdata/sub-verse584/sub-verse584_dir-ax_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse064/sub-verse064_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse072/sub-verse072_ct.nii.gz', 'VerSe19/dataset-verse19test/rawdata/sub-verse081/sub-verse081_ct.nii.gz', - 'VerSe20/02_validation/rawdata/sub-verse715/sub-verse715_ct.nii.gz', 'VerSe20/01_training/rawdata/sub-verse536/sub-verse536_dir-ax_ct.nii.gz', - 'VerSe20/03_test/rawdata/sub-gl216/sub-gl216_dir-ax_ct.nii.gz', 'VerSe19/dataset-verse19validation/rawdata/sub-verse047/sub-verse047_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse411/sub-verse411_split-verse232_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse152/sub-verse152_ct.nii.gz', - 'VerSe20/02_validation/rawdata/sub-verse627/sub-verse627_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-gl144/sub-gl144_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse014/sub-verse014_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse600/sub-verse600_dir-ax_ct.nii.gz', - 'VerSe20/01_training/rawdata/sub-verse510/sub-verse510_dir-ax_ct.nii.gz', 'VerSe19/dataset-verse19test/rawdata/sub-verse012/sub-verse012_ct.nii.gz', - 'VerSe20/02_validation/rawdata/sub-verse753/sub-verse753_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse815/sub-verse815_ct.nii.gz', - 'VerSe19/dataset-verse19training/rawdata/sub-verse401/sub-verse401_split-verse201_ct.nii.gz', 'VerSe19/dataset-verse19training/rawdata/sub-verse009/sub-verse009_ct.nii.gz', - 'VerSe20/02_validation/rawdata/sub-verse805/sub-verse805_ct.nii.gz', 'VerSe20/02_validation/rawdata/sub-verse623/sub-verse623_ct.nii.gz', - 'VerSe20/01_training/rawdata/sub-gl090/sub-gl090_dir-ax_ct.nii.gz', 'VerSe19/dataset-verse19test/rawdata/sub-verse414/sub-verse414_split-verse241_ct.nii.gz', - 'VerSe19/dataset-verse19validation/rawdata/sub-verse242/sub-verse242_ct.nii.gz', 'VerSe20/01_training/rawdata/sub-verse532/sub-verse532_dir-ax_ct.nii.gz', - 'VerSe19/dataset-verse19test/rawdata/sub-verse271/sub-verse271_ct.nii.gz', -] - - -def respace(img, new_space=1.0,mode="trilinear"): - spatial_shape = torch.tensor(img.shape[1:]) - ssize = len(spatial_shape) - - new_space = ensure_tuple(new_space) - new_space = torch.tensor(ensure_tuple_size(new_space, ssize, first(new_space))) - - old_space = torch.tensor(img.meta["pixdim"][1:4]) - - new_shape = old_space.div(new_space).mul_(spatial_shape).long() - - return torch.nn.functional.interpolate(img[None], new_shape.tolist(),mode=mode)[0] - - -class Respaced(mt.Lambdad): - def __init__(self, keys, new_space): - super().__init__(keys, func=self._respace) - self.new_space = new_space - - def _respace(self, x): - return respace(x, self.new_space) +import torch +from monai.engines import PrepareBatch, default_prepare_batch class DiffusionPrepareBatch(PrepareBatch): @@ -200,7 +50,7 @@ def __call__( def inv_metric_cmp_fn(current_metric: float, prev_best: float) -> bool: """ - The default function to compare metric values between current metric and previous best metric. + This inverts comparison for those metrics which reduce like loss values, such that the lower one is better. Args: current_metric: metric value of current round computation. prev_best: the best metric value of previous rounds to compare with. From 81575259b22577a3e0c240331fa7d1c466e74396 Mon Sep 17 00:00:00 2001 From: Eric Kerfoot <17726042+ericspod@users.noreply.github.com> Date: Sat, 18 Feb 2023 01:57:48 +0000 Subject: [PATCH 5/9] Update model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py Co-authored-by: Walter Hugo Lopez Pinaya --- model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py b/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py index 1e5451a9..ef91dcad 100644 --- a/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py +++ b/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py @@ -21,7 +21,7 @@ def __init__(self, num_train_timesteps: int, condition_name: Optional[str] = Non self.condition_name = condition_name self.num_train_timesteps = num_train_timesteps - def get_noise(self, images): + def get_noise(self, images: torch.Tensor) -> torch.Tensor: """Returns the noise tensor for input tensor `images`, override this for different noise distributions.""" return torch.randn_like(images) From 3fc5fa557becfcd16f052e7a27acc81cdb76eea9 Mon Sep 17 00:00:00 2001 From: Eric Kerfoot <17726042+ericspod@users.noreply.github.com> Date: Sat, 18 Feb 2023 01:58:49 +0000 Subject: [PATCH 6/9] Update model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py Co-authored-by: Walter Hugo Lopez Pinaya --- model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py b/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py index ef91dcad..17a5e50c 100644 --- a/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py +++ b/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py @@ -25,7 +25,7 @@ def get_noise(self, images: torch.Tensor) -> torch.Tensor: """Returns the noise tensor for input tensor `images`, override this for different noise distributions.""" return torch.randn_like(images) - def get_timesteps(self, images): + def get_timesteps(self, images: torch.Tensor) -> torch.Tensor: return torch.randint(0, self.num_train_timesteps, (images.shape[0],), device=images.device).long() def __call__( From 4357bc8fa2ef036e981a5ad2fd8ade3aa246f7dc Mon Sep 17 00:00:00 2001 From: Eric Kerfoot <17726042+ericspod@users.noreply.github.com> Date: Sat, 18 Feb 2023 01:59:05 +0000 Subject: [PATCH 7/9] Update model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py Co-authored-by: Walter Hugo Lopez Pinaya --- model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py b/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py index 17a5e50c..d5e35e39 100644 --- a/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py +++ b/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py @@ -51,6 +51,7 @@ def __call__( def inv_metric_cmp_fn(current_metric: float, prev_best: float) -> bool: """ This inverts comparison for those metrics which reduce like loss values, such that the lower one is better. + Args: current_metric: metric value of current round computation. prev_best: the best metric value of previous rounds to compare with. From 271a9041b61a1106e8c7528af084c876dc4ac4bf Mon Sep 17 00:00:00 2001 From: Eric Kerfoot Date: Sun, 19 Feb 2023 00:53:26 +0000 Subject: [PATCH 8/9] Update from runtests.sh Signed-off-by: Eric Kerfoot --- model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py | 2 ++ tests/utils.py | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py b/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py index d5e35e39..224a0062 100644 --- a/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py +++ b/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py @@ -1,5 +1,7 @@ +from __future__ import annotations from typing import Dict, Mapping, Optional, Union + import torch from monai.engines import PrepareBatch, default_prepare_batch diff --git a/tests/utils.py b/tests/utils.py index cb1cabdc..601bd9e9 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,6 +1,8 @@ # COPIED FROM https://github.com/Project-MONAI/MONAI/blob/fdd07f36ecb91cfcd491533f4792e1a67a9f89fc/tests/utils.py # --------------------------------------------------------------- +from __future__ import annotations + # 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. @@ -11,7 +13,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - from __future__ import annotations import copy From d277bfa9529e035b005f17cdbf1bf4e4fe4d7a7b Mon Sep 17 00:00:00 2001 From: Eric Kerfoot Date: Sun, 19 Feb 2023 01:47:26 +0000 Subject: [PATCH 9/9] Fixes --- .../mednist_ddpm/bundle/configs/common.yaml | 2 +- .../mednist_ddpm/bundle/configs/infer.yaml | 22 ++++++++++++++++++- .../bundle/docs/2d_ddpm_bundle_tutorial.ipynb | 2 ++ .../mednist_ddpm/bundle/scripts/__init__.py | 4 ++-- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/model-zoo/models/mednist_ddpm/bundle/configs/common.yaml b/model-zoo/models/mednist_ddpm/bundle/configs/common.yaml index 4f156c2b..e48b917b 100644 --- a/model-zoo/models/mednist_ddpm/bundle/configs/common.yaml +++ b/model-zoo/models/mednist_ddpm/bundle/configs/common.yaml @@ -1,4 +1,4 @@ -# This file defines common definitions used in training and inference, most importantly the definition definition +# This file defines common definitions used in training and inference, most importantly the network definition imports: - $import os diff --git a/model-zoo/models/mednist_ddpm/bundle/configs/infer.yaml b/model-zoo/models/mednist_ddpm/bundle/configs/infer.yaml index 5326caf7..f140c3b6 100644 --- a/model-zoo/models/mednist_ddpm/bundle/configs/infer.yaml +++ b/model-zoo/models/mednist_ddpm/bundle/configs/infer.yaml @@ -12,7 +12,27 @@ sample: '$lambda x: @inferer.sample(input_noise=x, diffusion_model=@network, sch load_state: '$@network.load_state_dict(torch.load(@ckpt_path))' # command to load the saved model weights +save_trans: + _target_: Compose + transforms: + - _target_: ScaleIntensity + minv: 0.0 + maxv: 255.0 + - _target_: ToTensor + track_meta: false + - _target_: SaveImage + output_ext: "jpg" + resample: false + output_dtype: '$torch.uint8' + separate_folder: false + output_postfix: '@out_file' + # program to load the model weights, run `sample`, and store results to `out_file` testing: - '@load_state' -- '$torch.save(@sample(@noise.to(@device)), @out_file)' \ No newline at end of file +- '$torch.save(@sample(@noise.to(@device)), @out_file)' + +#alternative version which saves to a jpg file +testing_jpg: +- '@load_state' +- '$@save_trans(@sample(@noise.to(@device))[0])' \ No newline at end of file diff --git a/model-zoo/models/mednist_ddpm/bundle/docs/2d_ddpm_bundle_tutorial.ipynb b/model-zoo/models/mednist_ddpm/bundle/docs/2d_ddpm_bundle_tutorial.ipynb index 8cc1e693..4cd3f5d4 100644 --- a/model-zoo/models/mednist_ddpm/bundle/docs/2d_ddpm_bundle_tutorial.ipynb +++ b/model-zoo/models/mednist_ddpm/bundle/docs/2d_ddpm_bundle_tutorial.ipynb @@ -61,6 +61,8 @@ "import tempfile\n", "from pathlib import Path\n", "\n", + "import torch\n", + "\n", "import matplotlib.pyplot as plt\n", "import monai\n", "from monai.bundle import ConfigParser\n", diff --git a/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py b/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py index 224a0062..344830d2 100644 --- a/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py +++ b/model-zoo/models/mednist_ddpm/bundle/scripts/__init__.py @@ -19,7 +19,7 @@ class DiffusionPrepareBatch(PrepareBatch): """ - def __init__(self, num_train_timesteps: int, condition_name: Optional[str] = None): + def __init__(self, num_train_timesteps: int, condition_name: str | None = None) -> None: self.condition_name = condition_name self.num_train_timesteps = num_train_timesteps @@ -33,7 +33,7 @@ def get_timesteps(self, images: torch.Tensor) -> torch.Tensor: def __call__( self, batchdata: Dict[str, torch.Tensor], - device: Optional[Union[str, torch.device]] = None, + device: Union[str, torch.device] | None = None, non_blocking: bool = False, **kwargs, ):