monai
medical
katielink commited on
Commit
139850b
1 Parent(s): e9c518c

complete the model package

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ models/model.ts filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ tags:
3
+ - monai
4
+ - medical
5
+ library_name: monai
6
+ license: unknown
7
+ ---
8
+ # Model Overview
9
+ A pre-trained model for volumetric (3D) segmentation of brain tumor subregions from multimodal MRIs based on BraTS 2018 data. The whole pipeline is modified from [clara_pt_brain_mri_segmentation](https://catalog.ngc.nvidia.com/orgs/nvidia/teams/med/models/clara_pt_brain_mri_segmentation).
10
+
11
+ ## Workflow
12
+
13
+ The model is trained to segment 3 nested subregions of primary brain tumors (gliomas): the "enhancing tumor" (ET), the "tumor core" (TC), the "whole tumor" (WT) based on 4 aligned input MRI scans (T1c, T1, T2, FLAIR).
14
+ - The ET is described by areas that show hyper intensity in T1c when compared to T1, but also when compared to "healthy" white matter in T1c.
15
+ - The TC describes the bulk of the tumor, which is what is typically resected. The TC entails the ET, as well as the necrotic (fluid-filled) and the non-enhancing (solid) parts of the tumor.
16
+ - The WT describes the complete extent of the disease, as it entails the TC and the peritumoral edema (ED), which is typically depicted by hyper-intense signal in FLAIR.
17
+
18
+ ## Data
19
+
20
+ The training data is from the [Multimodal Brain Tumor Segmentation Challenge (BraTS) 2018](https://www.med.upenn.edu/sbia/brats2018/data.html).
21
+
22
+ - Target: 3 tumor subregions
23
+ - Task: Segmentation
24
+ - Modality: MRI
25
+ - Size: 285 3D volumes (4 channels each)
26
+
27
+ The provided labelled data was partitioned, based on our own split, into training (200 studies), validation (42 studies) and testing (43 studies) datasets.
28
+
29
+ Please run `scripts/prepare_datalist.py` to produce the data list. The command is like:
30
+
31
+ ```
32
+ python scripts/prepare_datalist.py --path your-brats18-dataset-path
33
+ ```
34
+
35
+ ## Training configuration
36
+
37
+ This model utilized a similar approach described in 3D MRI brain tumor segmentation
38
+ using autoencoder regularization, which was a winning method in BraTS2018 [1]. The training was performed with the following:
39
+
40
+ - GPU: At least 16GB of GPU memory.
41
+ - Actual Model Input: 224 x 224 x 144
42
+ - AMP: True
43
+ - Optimizer: Adam
44
+ - Learning Rate: 1e-4
45
+ - Loss: DiceLoss
46
+
47
+ ## Input
48
+
49
+ Input: 4 channel MRI (4 aligned MRIs T1c, T1, T2, FLAIR at 1x1x1 mm)
50
+
51
+ 1. Normalizing to unit std with zero mean
52
+ 2. Randomly cropping to (224, 224, 144)
53
+ 3. Randomly spatial flipping
54
+ 4. Randomly scaling and shifting intensity of the volume
55
+
56
+ ## Output
57
+
58
+ Output: 3 channels
59
+ - Label 0: TC tumor subregion
60
+ - Label 1: WT tumor subregion
61
+ - Label 2: ET tumor subregion
62
+
63
+ ## Model Performance
64
+
65
+ The achieved Dice scores on the validation data are:
66
+ - Tumor core (TC): 0.8559
67
+ - Whole tumor (WT): 0.9026
68
+ - Enhancing tumor (ET): 0.7905
69
+ - Average: 0.8518
70
+
71
+ ## commands example
72
+
73
+ Execute training:
74
+
75
+ ```
76
+ python -m monai.bundle run training --meta_file configs/metadata.json --config_file configs/train.json --logging_file configs/logging.conf
77
+ ```
78
+
79
+ Override the `train` config to execute multi-GPU training:
80
+
81
+ ```
82
+ torchrun --standalone --nnodes=1 --nproc_per_node=8 -m monai.bundle run training --meta_file configs/metadata.json --config_file "['configs/train.json','configs/multi_gpu_train.json']" --logging_file configs/logging.conf
83
+ ```
84
+
85
+ Override the `train` config to execute evaluation with the trained model:
86
+
87
+ ```
88
+ python -m monai.bundle run evaluating --meta_file configs/metadata.json --config_file "['configs/train.json','configs/evaluate.json']" --logging_file configs/logging.conf
89
+ ```
90
+
91
+ Execute inference:
92
+
93
+ ```
94
+ python -m monai.bundle run evaluating --meta_file configs/metadata.json --config_file configs/inference.json --logging_file configs/logging.conf
95
+ ```
96
+
97
+ # Disclaimer
98
+
99
+ This is an example, not to be used for diagnostic purposes.
100
+
101
+ # References
102
+
103
+ [1] Myronenko, Andriy. "3D MRI brain tumor segmentation using autoencoder regularization." International MICCAI Brainlesion Workshop. Springer, Cham, 2018. https://arxiv.org/abs/1810.11654.
configs/evaluate.json ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "validate#postprocessing": {
3
+ "_target_": "Compose",
4
+ "transforms": [
5
+ {
6
+ "_target_": "Activationsd",
7
+ "keys": "pred",
8
+ "sigmoid": true
9
+ },
10
+ {
11
+ "_target_": "Invertd",
12
+ "keys": "pred",
13
+ "transform": "@validate#preprocessing",
14
+ "orig_keys": "image",
15
+ "meta_keys": "pred_meta_dict",
16
+ "nearest_interp": false,
17
+ "to_tensor": true,
18
+ "device": "@validate#evaluator#device"
19
+ },
20
+ {
21
+ "_target_": "AsDiscreted",
22
+ "keys": "pred",
23
+ "threshold": 0.5
24
+ },
25
+ {
26
+ "_target_": "SplitChanneld",
27
+ "keys": [
28
+ "pred",
29
+ "label"
30
+ ],
31
+ "output_postfixes": [
32
+ "tc",
33
+ "wt",
34
+ "et"
35
+ ]
36
+ },
37
+ {
38
+ "_target_": "CopyItemsd",
39
+ "keys": "pred",
40
+ "names": "pred_combined",
41
+ "times": 1
42
+ },
43
+ {
44
+ "_target_": "Lambdad",
45
+ "keys": "pred_combined",
46
+ "func": "$lambda x: torch.where(x[[2]] > 0, 4, torch.where(x[[0]] > 0, 1, torch.where(x[[1]] > 0, 2, 0)))"
47
+ },
48
+ {
49
+ "_target_": "SaveImaged",
50
+ "keys": "pred_combined",
51
+ "meta_keys": "pred_meta_dict",
52
+ "output_dir": "@output_dir",
53
+ "output_postfix": "seg",
54
+ "output_dtype": "uint8",
55
+ "resample": false,
56
+ "squeeze_end_dims": true
57
+ }
58
+ ]
59
+ },
60
+ "validate#handlers": [
61
+ {
62
+ "_target_": "CheckpointLoader",
63
+ "load_path": "$@ckpt_dir + '/model.pt'",
64
+ "load_dict": {
65
+ "model": "@network"
66
+ }
67
+ },
68
+ {
69
+ "_target_": "StatsHandler",
70
+ "iteration_log": false
71
+ },
72
+ {
73
+ "_target_": "MetricsSaver",
74
+ "save_dir": "@output_dir",
75
+ "metrics": [
76
+ "val_mean_dice",
77
+ "val_mean_dice_tc",
78
+ "val_mean_dice_wt",
79
+ "val_mean_dice_et"
80
+ ],
81
+ "metric_details": [
82
+ "val_mean_dice"
83
+ ],
84
+ "batch_transform": "$monai.handlers.from_engine(['image_meta_dict'])",
85
+ "summary_ops": "*"
86
+ }
87
+ ],
88
+ "evaluating": [
89
+ "$setattr(torch.backends.cudnn, 'benchmark', True)",
90
+ "$@validate#evaluator.run()"
91
+ ]
92
+ }
configs/inference.json ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "imports": [
3
+ "$import glob",
4
+ "$import os"
5
+ ],
6
+ "bundle_root": "/workspace/brats_mri_segmentation",
7
+ "ckpt_dir": "$@bundle_root + '/models'",
8
+ "output_dir": "$@bundle_root + '/eval'",
9
+ "data_list_file_path": "$@bundle_root + '/configs/datalist.json'",
10
+ "data_file_base_dir": "/workspace/data/medical/brats2018challenge",
11
+ "test_datalist": "$monai.data.load_decathlon_datalist(@data_list_file_path, data_list_key='testing', base_dir=@data_file_base_dir)",
12
+ "device": "$torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')",
13
+ "amp": true,
14
+ "network_def": {
15
+ "_target_": "SegResNet",
16
+ "blocks_down": [
17
+ 1,
18
+ 2,
19
+ 2,
20
+ 4
21
+ ],
22
+ "blocks_up": [
23
+ 1,
24
+ 1,
25
+ 1
26
+ ],
27
+ "init_filters": 16,
28
+ "in_channels": 4,
29
+ "out_channels": 3,
30
+ "dropout_prob": 0.2
31
+ },
32
+ "network": "$@network_def.to(@device)",
33
+ "preprocessing": {
34
+ "_target_": "Compose",
35
+ "transforms": [
36
+ {
37
+ "_target_": "LoadImaged",
38
+ "keys": "image"
39
+ },
40
+ {
41
+ "_target_": "NormalizeIntensityd",
42
+ "keys": "image",
43
+ "nonzero": true,
44
+ "channel_wise": true
45
+ },
46
+ {
47
+ "_target_": "ToTensord",
48
+ "keys": "image"
49
+ }
50
+ ]
51
+ },
52
+ "dataset": {
53
+ "_target_": "Dataset",
54
+ "data": "@test_datalist",
55
+ "transform": "@preprocessing"
56
+ },
57
+ "dataloader": {
58
+ "_target_": "DataLoader",
59
+ "dataset": "@dataset",
60
+ "batch_size": 1,
61
+ "shuffle": true,
62
+ "num_workers": 4
63
+ },
64
+ "inferer": {
65
+ "_target_": "SlidingWindowInferer",
66
+ "roi_size": [
67
+ 240,
68
+ 240,
69
+ 160
70
+ ],
71
+ "sw_batch_size": 1,
72
+ "overlap": 0.5
73
+ },
74
+ "postprocessing": {
75
+ "_target_": "Compose",
76
+ "transforms": [
77
+ {
78
+ "_target_": "Activationsd",
79
+ "keys": "pred",
80
+ "sigmoid": true
81
+ },
82
+ {
83
+ "_target_": "Invertd",
84
+ "keys": "pred",
85
+ "transform": "@preprocessing",
86
+ "orig_keys": "image",
87
+ "meta_keys": "pred_meta_dict",
88
+ "nearest_interp": false,
89
+ "to_tensor": true
90
+ },
91
+ {
92
+ "_target_": "AsDiscreted",
93
+ "keys": "pred",
94
+ "threshold": 0.5
95
+ },
96
+ {
97
+ "_target_": "SaveImaged",
98
+ "keys": "pred",
99
+ "meta_keys": "pred_meta_dict",
100
+ "output_dir": "@output_dir"
101
+ }
102
+ ]
103
+ },
104
+ "handlers": [
105
+ {
106
+ "_target_": "CheckpointLoader",
107
+ "load_path": "$@bundle_root + '/models/model.pt'",
108
+ "load_dict": {
109
+ "model": "@network"
110
+ }
111
+ },
112
+ {
113
+ "_target_": "StatsHandler",
114
+ "iteration_log": false
115
+ }
116
+ ],
117
+ "evaluator": {
118
+ "_target_": "SupervisedEvaluator",
119
+ "device": "@device",
120
+ "val_data_loader": "@dataloader",
121
+ "network": "@network",
122
+ "inferer": "@inferer",
123
+ "postprocessing": "@postprocessing",
124
+ "val_handlers": "@handlers",
125
+ "amp": true
126
+ },
127
+ "evaluating": [
128
+ "$setattr(torch.backends.cudnn, 'benchmark', True)",
129
+ "$@evaluator.run()"
130
+ ]
131
+ }
configs/logging.conf ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [loggers]
2
+ keys=root
3
+
4
+ [handlers]
5
+ keys=consoleHandler
6
+
7
+ [formatters]
8
+ keys=fullFormatter
9
+
10
+ [logger_root]
11
+ level=INFO
12
+ handlers=consoleHandler
13
+
14
+ [handler_consoleHandler]
15
+ class=StreamHandler
16
+ level=INFO
17
+ formatter=fullFormatter
18
+ args=(sys.stdout,)
19
+
20
+ [formatter_fullFormatter]
21
+ format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
configs/metadata.json ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "schema": "https://github.com/Project-MONAI/MONAI-extra-test-data/releases/download/0.8.1/meta_schema_20220324.json",
3
+ "version": "0.1.0",
4
+ "changelog": {
5
+ "0.1.0": "complete the model package"
6
+ },
7
+ "monai_version": "0.9.0",
8
+ "pytorch_version": "1.12.0",
9
+ "numpy_version": "1.21.2",
10
+ "optional_packages_version": {
11
+ "nibabel": "3.2.1",
12
+ "pytorch-ignite": "0.4.8"
13
+ },
14
+ "task": "Multimodal Brain Tumor segmentation",
15
+ "description": "A pre-trained model for volumetric (3D) segmentation of brain tumor subregions from multimodal MRIs based on BraTS 2018 data",
16
+ "authors": "MONAI team",
17
+ "copyright": "Copyright (c) MONAI Consortium",
18
+ "data_source": "https://www.med.upenn.edu/sbia/brats2018/data.html",
19
+ "data_type": "nibabel",
20
+ "image_classes": "4 channel data, T1c, T1, T2, FLAIR at 1x1x1 mm",
21
+ "label_classes": "3 channel data, channel 0 for Tumor core, channel 1 for Whole tumor, channel 2 for Enhancing tumor",
22
+ "pred_classes": "3 channels data, same as label_classes",
23
+ "eval_metrics": {
24
+ "val_mean_dice": 0.8518,
25
+ "val_mean_dice_tc": 0.8559,
26
+ "val_mean_dice_wt": 0.9026,
27
+ "val_mean_dice_et": 0.7905
28
+ },
29
+ "intended_use": "This is an example, not to be used for diagnostic purposes",
30
+ "references": [
31
+ "Myronenko, Andriy. '3D MRI brain tumor segmentation using autoencoder regularization.' International MICCAI Brainlesion Workshop. Springer, Cham, 2018. https://arxiv.org/abs/1810.11654"
32
+ ],
33
+ "network_data_format": {
34
+ "inputs": {
35
+ "image": {
36
+ "type": "image",
37
+ "format": "magnitude",
38
+ "modality": "MR",
39
+ "num_channels": 4,
40
+ "spatial_shape": [
41
+ "8*n",
42
+ "8*n",
43
+ "8*n"
44
+ ],
45
+ "dtype": "float32",
46
+ "value_range": [
47
+ 0,
48
+ 1
49
+ ],
50
+ "is_patch_data": true,
51
+ "channel_def": {
52
+ "0": "image"
53
+ }
54
+ }
55
+ },
56
+ "outputs": {
57
+ "pred": {
58
+ "type": "image",
59
+ "format": "segmentation",
60
+ "num_channels": 3,
61
+ "spatial_shape": [
62
+ "8*n",
63
+ "8*n",
64
+ "8*n"
65
+ ],
66
+ "dtype": "float32",
67
+ "value_range": [
68
+ 0,
69
+ 1
70
+ ],
71
+ "is_patch_data": true,
72
+ "channel_def": {
73
+ "0": "background",
74
+ "1": "spleen"
75
+ }
76
+ }
77
+ }
78
+ }
79
+ }
configs/multi_gpu_train.json ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "device": "$torch.device(f'cuda:{dist.get_rank()}')",
3
+ "network": {
4
+ "_target_": "torch.nn.parallel.DistributedDataParallel",
5
+ "module": "$@network_def.to(@device)",
6
+ "device_ids": [
7
+ "@device"
8
+ ]
9
+ },
10
+ "train#sampler": {
11
+ "_target_": "DistributedSampler",
12
+ "dataset": "@train#dataset",
13
+ "even_divisible": true,
14
+ "shuffle": true
15
+ },
16
+ "train#dataloader#sampler": "@train#sampler",
17
+ "train#dataloader#shuffle": false,
18
+ "train#trainer#train_handlers": "$@train#handlers[: -2 if dist.get_rank() > 0 else None]",
19
+ "validate#sampler": {
20
+ "_target_": "DistributedSampler",
21
+ "dataset": "@validate#dataset",
22
+ "even_divisible": false,
23
+ "shuffle": false
24
+ },
25
+ "validate#dataloader#sampler": "@validate#sampler",
26
+ "validate#evaluator#val_handlers": "$None if dist.get_rank() > 0 else @validate#handlers",
27
+ "training": [
28
+ "$import torch.distributed as dist",
29
+ "$dist.init_process_group(backend='nccl')",
30
+ "$torch.cuda.set_device(@device)",
31
+ "$monai.utils.set_determinism(seed=123)",
32
+ "$setattr(torch.backends.cudnn, 'benchmark', True)",
33
+ "$@train#trainer.run()",
34
+ "$dist.destroy_process_group()"
35
+ ]
36
+ }
configs/train.json ADDED
@@ -0,0 +1,335 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "imports": [
3
+ "$import glob",
4
+ "$import os"
5
+ ],
6
+ "bundle_root": "/workspace/brats_mri_segmentation",
7
+ "ckpt_dir": "$@bundle_root + '/models'",
8
+ "output_dir": "$@bundle_root + '/eval'",
9
+ "data_list_file_path": "$@bundle_root + '/configs/datalist.json'",
10
+ "data_file_base_dir": "/workspace/data/medical/brats2018challenge",
11
+ "train_datalist": "$monai.data.load_decathlon_datalist(@data_list_file_path, data_list_key='training', base_dir=@data_file_base_dir)",
12
+ "val_datalist": "$monai.data.load_decathlon_datalist(@data_list_file_path, data_list_key='validation', base_dir=@data_file_base_dir)",
13
+ "device": "$torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')",
14
+ "epochs": 300,
15
+ "num_interval_per_valid": 1,
16
+ "learning_rate": 0.0001,
17
+ "amp": true,
18
+ "network_def": {
19
+ "_target_": "SegResNet",
20
+ "blocks_down": [
21
+ 1,
22
+ 2,
23
+ 2,
24
+ 4
25
+ ],
26
+ "blocks_up": [
27
+ 1,
28
+ 1,
29
+ 1
30
+ ],
31
+ "init_filters": 16,
32
+ "in_channels": 4,
33
+ "out_channels": 3,
34
+ "dropout_prob": 0.2
35
+ },
36
+ "network": "$@network_def.to(@device)",
37
+ "loss": {
38
+ "_target_": "DiceLoss",
39
+ "smooth_nr": 0,
40
+ "smooth_dr": 1e-05,
41
+ "squared_pred": true,
42
+ "to_onehot_y": false,
43
+ "sigmoid": true
44
+ },
45
+ "optimizer": {
46
+ "_target_": "torch.optim.Adam",
47
+ "params": "$@network.parameters()",
48
+ "lr": "@learning_rate",
49
+ "weight_decay": 1e-05
50
+ },
51
+ "lr_scheduler": {
52
+ "_target_": "torch.optim.lr_scheduler.CosineAnnealingLR",
53
+ "optimizer": "@optimizer",
54
+ "T_max": "@epochs"
55
+ },
56
+ "train": {
57
+ "preprocessing_transforms": [
58
+ {
59
+ "_target_": "LoadImaged",
60
+ "keys": [
61
+ "image",
62
+ "label"
63
+ ]
64
+ },
65
+ {
66
+ "_target_": "ConvertToMultiChannelBasedOnBratsClassesd",
67
+ "keys": "label"
68
+ },
69
+ {
70
+ "_target_": "NormalizeIntensityd",
71
+ "keys": "image",
72
+ "nonzero": true,
73
+ "channel_wise": true
74
+ }
75
+ ],
76
+ "random_transforms": [
77
+ {
78
+ "_target_": "RandSpatialCropd",
79
+ "keys": [
80
+ "image",
81
+ "label"
82
+ ],
83
+ "roi_size": [
84
+ 224,
85
+ 224,
86
+ 144
87
+ ],
88
+ "random_size": false
89
+ },
90
+ {
91
+ "_target_": "RandFlipd",
92
+ "keys": [
93
+ "image",
94
+ "label"
95
+ ],
96
+ "prob": 0.5,
97
+ "spatial_axis": 0
98
+ },
99
+ {
100
+ "_target_": "RandFlipd",
101
+ "keys": [
102
+ "image",
103
+ "label"
104
+ ],
105
+ "prob": 0.5,
106
+ "spatial_axis": 1
107
+ },
108
+ {
109
+ "_target_": "RandFlipd",
110
+ "keys": [
111
+ "image",
112
+ "label"
113
+ ],
114
+ "prob": 0.5,
115
+ "spatial_axis": 2
116
+ },
117
+ {
118
+ "_target_": "RandScaleIntensityd",
119
+ "keys": "image",
120
+ "factors": 0.1,
121
+ "prob": 1.0
122
+ },
123
+ {
124
+ "_target_": "RandShiftIntensityd",
125
+ "keys": "image",
126
+ "offsets": 0.1,
127
+ "prob": 1.0
128
+ }
129
+ ],
130
+ "final_transforms": [
131
+ {
132
+ "_target_": "ToTensord",
133
+ "keys": [
134
+ "image",
135
+ "label"
136
+ ]
137
+ }
138
+ ],
139
+ "preprocessing": {
140
+ "_target_": "Compose",
141
+ "transforms": "$@train#preprocessing_transforms + @train#random_transforms + @train#final_transforms"
142
+ },
143
+ "dataset": {
144
+ "_target_": "Dataset",
145
+ "data": "@train_datalist",
146
+ "transform": "@train#preprocessing"
147
+ },
148
+ "dataloader": {
149
+ "_target_": "DataLoader",
150
+ "dataset": "@train#dataset",
151
+ "batch_size": 1,
152
+ "shuffle": true,
153
+ "num_workers": 4
154
+ },
155
+ "inferer": {
156
+ "_target_": "SimpleInferer"
157
+ },
158
+ "postprocessing": {
159
+ "_target_": "Compose",
160
+ "transforms": [
161
+ {
162
+ "_target_": "Activationsd",
163
+ "keys": "pred",
164
+ "sigmoid": true
165
+ },
166
+ {
167
+ "_target_": "AsDiscreted",
168
+ "keys": "pred",
169
+ "threshold": 0.5
170
+ }
171
+ ]
172
+ },
173
+ "handlers": [
174
+ {
175
+ "_target_": "LrScheduleHandler",
176
+ "lr_scheduler": "@lr_scheduler",
177
+ "print_lr": true
178
+ },
179
+ {
180
+ "_target_": "ValidationHandler",
181
+ "validator": "@validate#evaluator",
182
+ "epoch_level": true,
183
+ "interval": "@num_interval_per_valid"
184
+ },
185
+ {
186
+ "_target_": "StatsHandler",
187
+ "tag_name": "train_loss",
188
+ "output_transform": "$monai.handlers.from_engine(['loss'], first=True)"
189
+ },
190
+ {
191
+ "_target_": "TensorBoardStatsHandler",
192
+ "log_dir": "@output_dir",
193
+ "tag_name": "train_loss",
194
+ "output_transform": "$monai.handlers.from_engine(['loss'], first=True)"
195
+ }
196
+ ],
197
+ "key_metric": {
198
+ "train_mean_dice": {
199
+ "_target_": "MeanDice",
200
+ "include_background": true,
201
+ "output_transform": "$monai.handlers.from_engine(['pred', 'label'])"
202
+ }
203
+ },
204
+ "trainer": {
205
+ "_target_": "SupervisedTrainer",
206
+ "max_epochs": "@epochs",
207
+ "device": "@device",
208
+ "train_data_loader": "@train#dataloader",
209
+ "network": "@network",
210
+ "loss_function": "@loss",
211
+ "optimizer": "@optimizer",
212
+ "inferer": "@train#inferer",
213
+ "postprocessing": "@train#postprocessing",
214
+ "key_train_metric": "@train#key_metric",
215
+ "train_handlers": "@train#handlers",
216
+ "amp": "@amp"
217
+ }
218
+ },
219
+ "validate": {
220
+ "preprocessing": {
221
+ "_target_": "Compose",
222
+ "transforms": "$@train#preprocessing_transforms + @train#final_transforms"
223
+ },
224
+ "dataset": {
225
+ "_target_": "Dataset",
226
+ "data": "@val_datalist",
227
+ "transform": "@validate#preprocessing"
228
+ },
229
+ "dataloader": {
230
+ "_target_": "DataLoader",
231
+ "dataset": "@validate#dataset",
232
+ "batch_size": 1,
233
+ "shuffle": false,
234
+ "num_workers": 4
235
+ },
236
+ "inferer": {
237
+ "_target_": "SlidingWindowInferer",
238
+ "roi_size": [
239
+ 240,
240
+ 240,
241
+ 160
242
+ ],
243
+ "sw_batch_size": 1,
244
+ "overlap": 0.5
245
+ },
246
+ "postprocessing": {
247
+ "_target_": "Compose",
248
+ "transforms": [
249
+ {
250
+ "_target_": "Activationsd",
251
+ "keys": "pred",
252
+ "sigmoid": true
253
+ },
254
+ {
255
+ "_target_": "AsDiscreted",
256
+ "keys": "pred",
257
+ "threshold": 0.5
258
+ },
259
+ {
260
+ "_target_": "SplitChanneld",
261
+ "keys": [
262
+ "pred",
263
+ "label"
264
+ ],
265
+ "output_postfixes": [
266
+ "tc",
267
+ "wt",
268
+ "et"
269
+ ]
270
+ }
271
+ ]
272
+ },
273
+ "handlers": [
274
+ {
275
+ "_target_": "StatsHandler",
276
+ "iteration_log": false
277
+ },
278
+ {
279
+ "_target_": "TensorBoardStatsHandler",
280
+ "log_dir": "@output_dir",
281
+ "iteration_log": false
282
+ },
283
+ {
284
+ "_target_": "CheckpointSaver",
285
+ "save_dir": "@ckpt_dir",
286
+ "save_dict": {
287
+ "model": "@network"
288
+ },
289
+ "save_key_metric": true,
290
+ "key_metric_filename": "model.pt"
291
+ }
292
+ ],
293
+ "key_metric": {
294
+ "val_mean_dice": {
295
+ "_target_": "MeanDice",
296
+ "include_background": true,
297
+ "output_transform": "$monai.handlers.from_engine(['pred', 'label'])"
298
+ }
299
+ },
300
+ "additional_metrics": {
301
+ "val_mean_dice_tc": {
302
+ "_target_": "MeanDice",
303
+ "include_background": true,
304
+ "output_transform": "$monai.handlers.from_engine(['pred_tc', 'label_tc'])"
305
+ },
306
+ "val_mean_dice_wt": {
307
+ "_target_": "MeanDice",
308
+ "include_background": true,
309
+ "output_transform": "$monai.handlers.from_engine(['pred_wt', 'label_wt'])"
310
+ },
311
+ "val_mean_dice_et": {
312
+ "_target_": "MeanDice",
313
+ "include_background": true,
314
+ "output_transform": "$monai.handlers.from_engine(['pred_et', 'label_et'])"
315
+ }
316
+ },
317
+ "evaluator": {
318
+ "_target_": "SupervisedEvaluator",
319
+ "device": "@device",
320
+ "val_data_loader": "@validate#dataloader",
321
+ "network": "@network",
322
+ "inferer": "@validate#inferer",
323
+ "postprocessing": "@validate#postprocessing",
324
+ "key_val_metric": "@validate#key_metric",
325
+ "additional_metrics": "@validate#additional_metrics",
326
+ "val_handlers": "@validate#handlers",
327
+ "amp": "@amp"
328
+ }
329
+ },
330
+ "training": [
331
+ "$monai.utils.set_determinism(seed=123)",
332
+ "$setattr(torch.backends.cudnn, 'benchmark', True)",
333
+ "$@train#trainer.run()"
334
+ ]
335
+ }
docs/README.md ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Model Overview
2
+ A pre-trained model for volumetric (3D) segmentation of brain tumor subregions from multimodal MRIs based on BraTS 2018 data. The whole pipeline is modified from [clara_pt_brain_mri_segmentation](https://catalog.ngc.nvidia.com/orgs/nvidia/teams/med/models/clara_pt_brain_mri_segmentation).
3
+
4
+ ## Workflow
5
+
6
+ The model is trained to segment 3 nested subregions of primary brain tumors (gliomas): the "enhancing tumor" (ET), the "tumor core" (TC), the "whole tumor" (WT) based on 4 aligned input MRI scans (T1c, T1, T2, FLAIR).
7
+ - The ET is described by areas that show hyper intensity in T1c when compared to T1, but also when compared to "healthy" white matter in T1c.
8
+ - The TC describes the bulk of the tumor, which is what is typically resected. The TC entails the ET, as well as the necrotic (fluid-filled) and the non-enhancing (solid) parts of the tumor.
9
+ - The WT describes the complete extent of the disease, as it entails the TC and the peritumoral edema (ED), which is typically depicted by hyper-intense signal in FLAIR.
10
+
11
+ ## Data
12
+
13
+ The training data is from the [Multimodal Brain Tumor Segmentation Challenge (BraTS) 2018](https://www.med.upenn.edu/sbia/brats2018/data.html).
14
+
15
+ - Target: 3 tumor subregions
16
+ - Task: Segmentation
17
+ - Modality: MRI
18
+ - Size: 285 3D volumes (4 channels each)
19
+
20
+ The provided labelled data was partitioned, based on our own split, into training (200 studies), validation (42 studies) and testing (43 studies) datasets.
21
+
22
+ Please run `scripts/prepare_datalist.py` to produce the data list. The command is like:
23
+
24
+ ```
25
+ python scripts/prepare_datalist.py --path your-brats18-dataset-path
26
+ ```
27
+
28
+ ## Training configuration
29
+
30
+ This model utilized a similar approach described in 3D MRI brain tumor segmentation
31
+ using autoencoder regularization, which was a winning method in BraTS2018 [1]. The training was performed with the following:
32
+
33
+ - GPU: At least 16GB of GPU memory.
34
+ - Actual Model Input: 224 x 224 x 144
35
+ - AMP: True
36
+ - Optimizer: Adam
37
+ - Learning Rate: 1e-4
38
+ - Loss: DiceLoss
39
+
40
+ ## Input
41
+
42
+ Input: 4 channel MRI (4 aligned MRIs T1c, T1, T2, FLAIR at 1x1x1 mm)
43
+
44
+ 1. Normalizing to unit std with zero mean
45
+ 2. Randomly cropping to (224, 224, 144)
46
+ 3. Randomly spatial flipping
47
+ 4. Randomly scaling and shifting intensity of the volume
48
+
49
+ ## Output
50
+
51
+ Output: 3 channels
52
+ - Label 0: TC tumor subregion
53
+ - Label 1: WT tumor subregion
54
+ - Label 2: ET tumor subregion
55
+
56
+ ## Model Performance
57
+
58
+ The achieved Dice scores on the validation data are:
59
+ - Tumor core (TC): 0.8559
60
+ - Whole tumor (WT): 0.9026
61
+ - Enhancing tumor (ET): 0.7905
62
+ - Average: 0.8518
63
+
64
+ ## commands example
65
+
66
+ Execute training:
67
+
68
+ ```
69
+ python -m monai.bundle run training --meta_file configs/metadata.json --config_file configs/train.json --logging_file configs/logging.conf
70
+ ```
71
+
72
+ Override the `train` config to execute multi-GPU training:
73
+
74
+ ```
75
+ torchrun --standalone --nnodes=1 --nproc_per_node=8 -m monai.bundle run training --meta_file configs/metadata.json --config_file "['configs/train.json','configs/multi_gpu_train.json']" --logging_file configs/logging.conf
76
+ ```
77
+
78
+ Override the `train` config to execute evaluation with the trained model:
79
+
80
+ ```
81
+ python -m monai.bundle run evaluating --meta_file configs/metadata.json --config_file "['configs/train.json','configs/evaluate.json']" --logging_file configs/logging.conf
82
+ ```
83
+
84
+ Execute inference:
85
+
86
+ ```
87
+ python -m monai.bundle run evaluating --meta_file configs/metadata.json --config_file configs/inference.json --logging_file configs/logging.conf
88
+ ```
89
+
90
+ # Disclaimer
91
+
92
+ This is an example, not to be used for diagnostic purposes.
93
+
94
+ # References
95
+
96
+ [1] Myronenko, Andriy. "3D MRI brain tumor segmentation using autoencoder regularization." International MICCAI Brainlesion Workshop. Springer, Cham, 2018. https://arxiv.org/abs/1810.11654.
docs/license.txt ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Third Party Licenses
2
+ -----------------------------------------------------------------------
3
+
4
+ /*********************************************************************/
5
+ i. Multimodal Brain Tumor Segmentation Challenge 2018
6
+ https://www.med.upenn.edu/sbia/brats2018/data.html
7
+ /*********************************************************************/
8
+
9
+ Data Usage Agreement / Citations
10
+
11
+ You are free to use and/or refer to the BraTS datasets in your own
12
+ research, provided that you always cite the following two manuscripts:
13
+
14
+ [1] Menze BH, Jakab A, Bauer S, Kalpathy-Cramer J, Farahani K, Kirby
15
+ [J, Burren Y, Porz N, Slotboom J, Wiest R, Lanczi L, Gerstner E, Weber
16
+ [MA, Arbel T, Avants BB, Ayache N, Buendia P, Collins DL, Cordier N,
17
+ [Corso JJ, Criminisi A, Das T, Delingette H, Demiralp Γ, Durst CR,
18
+ [Dojat M, Doyle S, Festa J, Forbes F, Geremia E, Glocker B, Golland P,
19
+ [Guo X, Hamamci A, Iftekharuddin KM, Jena R, John NM, Konukoglu E,
20
+ [Lashkari D, Mariz JA, Meier R, Pereira S, Precup D, Price SJ, Raviv
21
+ [TR, Reza SM, Ryan M, Sarikaya D, Schwartz L, Shin HC, Shotton J,
22
+ [Silva CA, Sousa N, Subbanna NK, Szekely G, Taylor TJ, Thomas OM,
23
+ [Tustison NJ, Unal G, Vasseur F, Wintermark M, Ye DH, Zhao L, Zhao B,
24
+ [Zikic D, Prastawa M, Reyes M, Van Leemput K. "The Multimodal Brain
25
+ [Tumor Image Segmentation Benchmark (BRATS)", IEEE Transactions on
26
+ [Medical Imaging 34(10), 1993-2024 (2015) DOI:
27
+ [10.1109/TMI.2014.2377694
28
+
29
+ [2] Bakas S, Akbari H, Sotiras A, Bilello M, Rozycki M, Kirby JS,
30
+ [Freymann JB, Farahani K, Davatzikos C. "Advancing The Cancer Genome
31
+ [Atlas glioma MRI collections with expert segmentation labels and
32
+ [radiomic features", Nature Scientific Data, 4:170117 (2017) DOI:
33
+ [10.1038/sdata.2017.117
34
+
35
+ In addition, if there are no restrictions imposed from the
36
+ journal/conference you submit your paper about citing "Data
37
+ Citations", please be specific and also cite the following:
38
+
39
+ [3] Bakas S, Akbari H, Sotiras A, Bilello M, Rozycki M, Kirby J,
40
+ [Freymann J, Farahani K, Davatzikos C. "Segmentation Labels and
41
+ [Radiomic Features for the Pre-operative Scans of the TCGA-GBM
42
+ [collection", The Cancer Imaging Archive, 2017. DOI:
43
+ [10.7937/K9/TCIA.2017.KLXWJJ1Q
44
+
45
+ [4] Bakas S, Akbari H, Sotiras A, Bilello M, Rozycki M, Kirby J,
46
+ [Freymann J, Farahani K, Davatzikos C. "Segmentation Labels and
47
+ [Radiomic Features for the Pre-operative Scans of the TCGA-LGG
48
+ [collection", The Cancer Imaging Archive, 2017. DOI:
49
+ [10.7937/K9/TCIA.2017.GJQ7R0EF
models/model.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:860ccb3f1c21c99d0410ad8a1ac4ef6b8fab60cec0a503b0ba42675741a750ae
3
+ size 18840620
models/model.ts ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:729980a0bd9347bf2397701eb329e12517918dc282a2d09c40458e95b24ceed9
3
+ size 18911784
scripts/prepare_datalist.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ import glob
3
+ import json
4
+ import os
5
+
6
+ import monai
7
+ from sklearn.model_selection import train_test_split
8
+
9
+
10
+ def produce_sample_dict(line: str):
11
+ names = os.listdir(line)
12
+ seg, t1ce, t1, t2, flair = [], [], [], [], []
13
+ for name in names:
14
+ name = os.path.join(line, name)
15
+ if "_seg.nii" in name:
16
+ seg.append(name)
17
+ elif "_t1ce.nii" in name:
18
+ t1ce.append(name)
19
+ elif "_t1.nii" in name:
20
+ t1.append(name)
21
+ elif "_t2.nii" in name:
22
+ t2.append(name)
23
+ elif "_flair.nii" in name:
24
+ flair.append(name)
25
+
26
+ return {"label": seg[0], "image": t1ce + t1 + t2 + flair}
27
+
28
+
29
+ def produce_datalist(dataset_dir: str):
30
+ """
31
+ This function is used to split the dataset.
32
+ It will produce 200 samples for training, and the other samples are divided equally
33
+ into val and test sets.
34
+ """
35
+
36
+ samples = sorted(glob.glob(os.path.join(dataset_dir, "*", "*"), recursive=True))
37
+ datalist = []
38
+ for line in samples:
39
+ datalist.append(produce_sample_dict(line))
40
+ train_list, other_list = train_test_split(datalist, train_size=200)
41
+ val_list, test_list = train_test_split(other_list, train_size=0.5)
42
+
43
+ return {"training": train_list, "validation": val_list, "testing": test_list}
44
+
45
+
46
+ def main(args):
47
+ """
48
+ split the dataset and output the data list into a json file.
49
+ """
50
+ data_file_base_dir = os.path.join(args.path, "training")
51
+ output_json = args.output
52
+ # produce deterministic data splits
53
+ monai.utils.set_determinism(seed=123)
54
+ datalist = produce_datalist(dataset_dir=data_file_base_dir)
55
+ with open(output_json, "w") as f:
56
+ json.dump(datalist, f)
57
+
58
+
59
+ if __name__ == "__main__":
60
+
61
+ parser = argparse.ArgumentParser(description="")
62
+ parser.add_argument(
63
+ "--path",
64
+ type=str,
65
+ default="/workspace/data/medical/brats2018challenge",
66
+ help="root path of brats 2018 dataset.",
67
+ )
68
+ parser.add_argument(
69
+ "--output", type=str, default="configs/datalist.json", help="relative path of output datalist json file."
70
+ )
71
+ args = parser.parse_args()
72
+
73
+ main(args)