Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
42a45e0
Merge pull request #19 from Project-MONAI/master
Nic-Ma Feb 1, 2021
cd16a13
Merge pull request #32 from Project-MONAI/master
Nic-Ma Feb 24, 2021
6f87afd
Merge pull request #180 from Project-MONAI/dev
Nic-Ma Jul 22, 2021
f398298
Merge pull request #214 from Project-MONAI/dev
Nic-Ma Sep 8, 2021
ec463d6
Merge pull request #397 from Project-MONAI/dev
Nic-Ma Apr 4, 2022
ca62306
Merge pull request #429 from Project-MONAI/dev
Nic-Ma Jul 8, 2022
8de4af1
5090 releasing 1.0.0 (#5170)
wyli Sep 16, 2022
0a4b085
Remove batch dim in `SobelGradients` and `SobelGradientsd` (#5182)
KumoLiu Sep 20, 2022
1c1815c
Add channel dim in `ComputeHoVerMaps` and `ComputeHoVerMapsd` (#5183)
KumoLiu Sep 21, 2022
ed5fd2d
update federated learning figure (#5194)
holgerroth Sep 22, 2022
6a4dd92
Fix typo in `RandScaleIntensityd` (#5210)
KumoLiu Sep 26, 2022
b9f5dd8
5193 5204 import error msg/warnings (#5205)
wyli Sep 26, 2022
c71df93
5211 5214 infer device from first item RandElastic, simplify `first_k…
wyli Sep 27, 2022
e672b70
3844 flexible min/max_pixdim options for Spacing (#5212)
wyli Sep 27, 2022
bacc6bb
4264 Add antialiasing option for `Resized` (#5223)
yiheng-wang-nv Sep 29, 2022
a7e62d7
Visualisation classes to allow kwargs. combine GradCAM and ++ test fi…
rijobro Sep 29, 2022
3d493ea
protobuf should use PYEXE not pip (#5231)
rijobro Sep 29, 2022
4026c5e
5232 Enhance bundle page with more information (#5234)
Nic-Ma Sep 30, 2022
0cf3088
5163 metatensor support for `OneOf` (#5217)
wyli Sep 30, 2022
b862c75
5233 Add file check for the logging config (#5235)
Nic-Ma Sep 30, 2022
df84c3d
Fix 1D data error in `VarAutoEncoder` (#5236)
KumoLiu Sep 30, 2022
06aee55
Solve LoadImage issue when track_meta is False (#5239)
macdavid Sep 30, 2022
21e0ad5
Add multi-gpu support to MonaiAlgo (#5228)
holgerroth Sep 30, 2022
e8879a0
HoVerNet Mode and Branch to independent StrEnum (#5219)
bhashemian Sep 30, 2022
68d1b34
Occlusion sensitivity to use slidiing_window_inference (#5230)
rijobro Sep 30, 2022
2687b72
UpSample optional kernel_size for deconv mode (#5221)
myron Oct 1, 2022
6e63284
5251 replace None type metadict content with 'none' (#5252)
wyli Oct 3, 2022
1ee8ba0
fix bug in retina detector (#5255)
Can-Zhao Oct 3, 2022
94673a9
[pre-commit.ci] pre-commit suggestions/consolidate autofixes (#5256)
pre-commit-ci[bot] Oct 4, 2022
d76adc7
5253 fixes output offset - spacing (#5254)
wyli Oct 4, 2022
c9d1a71
4320 update docstrings for gradient based saliency (#5268)
wyli Oct 5, 2022
eb0795e
CVE-2007-4559 Patch (#5274)
TrellixVulnTeam Oct 6, 2022
5a517fb
Upsample mode deconvgroup (#5282)
myron Oct 8, 2022
9b09863
5187 update the docstring of the is_pad parameter (#5296)
binliunls Oct 8, 2022
b61b21e
4206 adds ext tests and deps (#4207)
wyli Oct 9, 2022
f6f6529
fixes cherrypicking issues of spacing
wyli Oct 10, 2022
9fa35cc
5304 Add authenticated option for bundle api (#5306)
yiheng-wang-nv Oct 10, 2022
f040ec0
5269 5291 Update PyTorch base docker to 22.09 (#5293)
Nic-Ma Oct 11, 2022
d1fafc4
[ReadyForReview] Auto3DSeg DataAnalyzer OOM and other minor issue (#5…
mingxin-zheng Oct 11, 2022
c77521e
updates to Gaussian map for sliding window inference (#5302)
myron Oct 12, 2022
a215ea6
fixes DiceCELoss for multichannel targets (#5292)
myron Oct 12, 2022
ef6fe38
auto updates (#5321)
monai-bot Oct 13, 2022
1e74bd6
auto updates (#5322)
monai-bot Oct 13, 2022
dd49e37
tutorial 982 984 fixes occ sens, 987 ce loss (#5323)
wyli Oct 13, 2022
2b455e3
Fix installation verification command (#5328)
dzenanz Oct 13, 2022
258f3ca
Segresnet improvements (#5281)
myron Oct 13, 2022
9d43d19
SlidingWindowInferer: option to adaptively stitch in cpu memory for l…
myron Oct 13, 2022
fe5a3bf
Command format fix with backslashes on Windows System (#5280)
Maxime-Perret Oct 14, 2022
7c3e838
adding a multigpu test of TestFLMonaiAlgo (#5327)
wyli Oct 14, 2022
50749ec
Dicece check for float target (#5326)
myron Oct 15, 2022
59fb2c3
MonaiAlgo FedStats (#5240)
holgerroth Oct 15, 2022
ee04909
5284 Fixes release integration tests (#5342)
wyli Oct 17, 2022
c0e3fa8
skip cache for releasing branch; update test info
wyli Oct 17, 2022
e1d7a2e
skip test if no downloading
wyli Oct 18, 2022
ba5fea2
5345 update output devices slidingwindow (#5346)
wyli Oct 17, 2022
9e444d4
Enhancement for WarmupCosineSchedule to specify the beginning fractio…
myron Oct 18, 2022
652511f
MonaiAlgo: fix logging in multi-gpu training (#5355)
holgerroth Oct 19, 2022
10ab34a
str2list utility for commandline parsing of comma separated lists (#5…
myron Oct 19, 2022
158211b
Merge pull request #449 from Project-MONAI/dev
Nic-Ma Oct 20, 2022
30dc873
[DLMED] change to multi-process
Nic-Ma Oct 20, 2022
8c014d1
[DLMED] update dataloader
Nic-Ma Oct 20, 2022
9c423b6
update fl docs (#5364)
holgerroth Oct 20, 2022
4609206
Remove meta_dict and fix affine to spacing conversion (#5367)
mingxin-zheng Oct 20, 2022
e5d651a
Merge branch 'dev' into 5308-shared-cache
Nic-Ma Oct 21, 2022
3f4ff8f
[DLMED] disable multi-processing if GPU cache
Nic-Ma Oct 21, 2022
f6325e2
adding premerge tests for py3.10 (#5370)
wyli Oct 21, 2022
8a7747d
releasing test py310
wyli Oct 21, 2022
1d86895
[DLMED] add runtime cache
Nic-Ma Oct 21, 2022
52a7fde
skip test.pypi.org
wyli Oct 21, 2022
8b2e240
[DLMED] add GPU test
Nic-Ma Oct 21, 2022
9176f60
Merge branch 'dev' into 5308-shared-cache
Nic-Ma Oct 21, 2022
494f3b0
Merge branch 'dev' into 5308-shared-cache
Nic-Ma Oct 21, 2022
ce7fc18
5284 adds a changelog v1.0.1 (#5319)
wyli Oct 21, 2022
df541ee
[MONAI] code formatting
monai-bot Oct 21, 2022
a3be198
[DLMED] update subclasses
Nic-Ma Oct 21, 2022
bc09a4c
enable test.pypi.org
wyli Oct 21, 2022
72e09cf
[DLMED] fix pickle
Nic-Ma Oct 22, 2022
49321b6
[DLMED] remove test code
Nic-Ma Oct 22, 2022
87ca8e4
[DLMED] update according to comments
Nic-Ma Oct 23, 2022
8271a19
5381 and deprecate `compute_meandice` `compute_meaniou` (#5382)
wyli Oct 24, 2022
4fa0194
Merge branch 'dev' into 5308-shared-cache
Nic-Ma Oct 24, 2022
f24c9b0
[DLMED] fix with test
Nic-Ma Oct 24, 2022
d2b93c8
[DLMED] update according to comments
Nic-Ma Oct 24, 2022
660802c
Merge branch 'releasing/1.0.1' into dev
wyli Oct 24, 2022
fa6a14b
Merge branch 'dev' into 5308-shared-cache
Nic-Ma Oct 24, 2022
4be39e1
[DLMED] enhance doc-string
Nic-Ma Oct 24, 2022
58a3341
[DLMED] update according to comments
Nic-Ma Oct 24, 2022
7e5cdd7
Merge branch 'dev' into 5308-shared-cache
wyli Oct 25, 2022
51d70e7
Merge branch 'dev' into 5308-shared-cache
Nic-Ma Nov 3, 2022
19f62fc
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 3, 2022
d46d8f5
[DLMED] add dist broadcast objects
Nic-Ma Nov 3, 2022
a47138c
Merge branch 'dev' into 5308-shared-cache
Nic-Ma Nov 8, 2022
3bee98a
[DLMED] update according to comments
Nic-Ma Nov 8, 2022
ab38c13
[DLMED] simplify the list conversion
Nic-Ma Nov 8, 2022
bb019db
[DLMED] add dist test
Nic-Ma Nov 8, 2022
bf22f82
[DLMED] fix dist test
Nic-Ma Nov 8, 2022
dd416e7
Merge branch 'dev' into 5308-shared-cache
Nic-Ma Nov 8, 2022
d9fc959
[MONAI] code formatting
monai-bot Nov 8, 2022
c233a3e
Merge branch 'dev' into 5308-shared-cache
Nic-Ma Nov 8, 2022
f9235a3
Merge branch 'dev' into 5308-shared-cache
Nic-Ma Nov 9, 2022
cb4997d
[DLMED] add more doc-string
Nic-Ma Nov 9, 2022
18a651a
[DLMED] fix CI test error
Nic-Ma Nov 9, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions monai/apps/datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class MedNISTDataset(Randomizable, CacheDataset):
will take the minimum of (cache_num, data_length x cache_rate, data_length).
cache_rate: percentage of cached data in total, default is 1.0 (cache all).
will take the minimum of (cache_num, data_length x cache_rate, data_length).
num_workers: the number of worker threads to use.
num_workers: the number of worker threads if computing cache in the initialization.
If num_workers is None then the number returned by os.cpu_count() is used.
If a value less than 1 is specified, 1 will be used instead.
progress: whether to display a progress bar when downloading dataset and computing the transform cache content.
Expand All @@ -70,6 +70,8 @@ class MedNISTDataset(Randomizable, CacheDataset):
may set `copy=False` for better performance.
as_contiguous: whether to convert the cached NumPy array or PyTorch tensor to be contiguous.
it may help improve the performance of following logic.
runtime_cache: whether to compute cache at the runtime, default to `False` to prepare
the cache content at initializaiton.

Raises:
ValueError: When ``root_dir`` is not a directory.
Expand Down Expand Up @@ -97,6 +99,7 @@ def __init__(
progress: bool = True,
copy_cache: bool = True,
as_contiguous: bool = True,
runtime_cache: bool = False,
) -> None:
root_dir = Path(root_dir)
if not root_dir.is_dir():
Expand Down Expand Up @@ -135,6 +138,7 @@ def __init__(
progress=progress,
copy_cache=copy_cache,
as_contiguous=as_contiguous,
runtime_cache=runtime_cache,
)

def randomize(self, data: np.ndarray) -> None:
Expand Down Expand Up @@ -212,7 +216,7 @@ class DecathlonDataset(Randomizable, CacheDataset):
will take the minimum of (cache_num, data_length x cache_rate, data_length).
cache_rate: percentage of cached data in total, default is 1.0 (cache all).
will take the minimum of (cache_num, data_length x cache_rate, data_length).
num_workers: the number of worker threads to use.
num_workers: the number of worker threads if computing cache in the initialization.
If num_workers is None then the number returned by os.cpu_count() is used.
If a value less than 1 is specified, 1 will be used instead.
progress: whether to display a progress bar when downloading dataset and computing the transform cache content.
Expand All @@ -223,6 +227,8 @@ class DecathlonDataset(Randomizable, CacheDataset):
may set `copy=False` for better performance.
as_contiguous: whether to convert the cached NumPy array or PyTorch tensor to be contiguous.
it may help improve the performance of following logic.
runtime_cache: whether to compute cache at the runtime, default to `False` to prepare
the cache content at initializaiton.
Comment thread
Nic-Ma marked this conversation as resolved.

Raises:
ValueError: When ``root_dir`` is not a directory.
Expand Down Expand Up @@ -290,6 +296,7 @@ def __init__(
progress: bool = True,
copy_cache: bool = True,
as_contiguous: bool = True,
runtime_cache: bool = False,
) -> None:
root_dir = Path(root_dir)
if not root_dir.is_dir():
Expand Down Expand Up @@ -342,6 +349,7 @@ def __init__(
progress=progress,
copy_cache=copy_cache,
as_contiguous=as_contiguous,
runtime_cache=runtime_cache,
)

def get_indices(self) -> np.ndarray:
Expand Down Expand Up @@ -438,7 +446,7 @@ class TciaDataset(Randomizable, CacheDataset):
will take the minimum of (cache_num, data_length x cache_rate, data_length).
cache_rate: percentage of cached data in total, default is 0.0 (no cache).
will take the minimum of (cache_num, data_length x cache_rate, data_length).
num_workers: the number of worker threads to use.
num_workers: the number of worker threads if computing cache in the initialization.
If num_workers is None then the number returned by os.cpu_count() is used.
If a value less than 1 is specified, 1 will be used instead.
progress: whether to display a progress bar when downloading dataset and computing the transform cache content.
Expand All @@ -449,6 +457,8 @@ class TciaDataset(Randomizable, CacheDataset):
may set `copy=False` for better performance.
as_contiguous: whether to convert the cached NumPy array or PyTorch tensor to be contiguous.
it may help improve the performance of following logic.
runtime_cache: whether to compute cache at the runtime, default to `False` to prepare
the cache content at initializaiton.

Example::

Expand Down Expand Up @@ -504,6 +514,7 @@ def __init__(
progress: bool = True,
copy_cache: bool = True,
as_contiguous: bool = True,
runtime_cache: bool = False,
) -> None:
root_dir = Path(root_dir)
if not root_dir.is_dir():
Expand Down Expand Up @@ -550,6 +561,7 @@ def __init__(
progress=progress,
copy_cache=copy_cache,
as_contiguous=as_contiguous,
runtime_cache=runtime_cache,
)

def get_indices(self) -> np.ndarray:
Expand Down
6 changes: 6 additions & 0 deletions monai/data/dataloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ def __init__(self, dataset: Dataset, num_workers: int = 0, **kwargs) -> None:
init_seed = _g.initial_seed()
_seed = torch.empty((), dtype=torch.int64).random_(generator=_g).item()
set_rnd(dataset, int(_seed))
# disable unnecessary multiprocessing caching
from monai.data.dataset import CacheDataset # avoid circular import

if isinstance(dataset, CacheDataset) and dataset.runtime_cache:
dataset.disable_share_memory_cache()

_g.manual_seed(init_seed)
if "collate_fn" not in kwargs:
kwargs["collate_fn"] = list_data_collate
Expand Down
46 changes: 43 additions & 3 deletions monai/data/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@
import time
import warnings
from copy import copy, deepcopy
from multiprocessing.managers import ListProxy
from multiprocessing.pool import ThreadPool
from pathlib import Path
from typing import IO, TYPE_CHECKING, Any, Callable, Dict, List, Optional, Sequence, Union

import numpy as np
import torch
import torch.distributed as dist
from torch.multiprocessing import Manager
from torch.serialization import DEFAULT_PROTOCOL
from torch.utils.data import Dataset as _TorchDataset
from torch.utils.data import Subset
Expand Down Expand Up @@ -748,6 +751,7 @@ def __init__(
as_contiguous: bool = True,
hash_as_key: bool = False,
hash_func: Callable[..., bytes] = pickle_hashing,
runtime_cache: bool = False,
) -> None:
"""
Args:
Expand All @@ -757,7 +761,7 @@ def __init__(
will take the minimum of (cache_num, data_length x cache_rate, data_length).
cache_rate: percentage of cached data in total, default is 1.0 (cache all).
will take the minimum of (cache_num, data_length x cache_rate, data_length).
num_workers: the number of worker threads to use.
num_workers: the number of worker threads if computing cache in the initialization.
If num_workers is None then the number returned by os.cpu_count() is used.
If a value less than 1 is speficied, 1 will be used instead.
progress: whether to display a progress bar.
Expand All @@ -773,6 +777,14 @@ def __init__(
the dataset has duplicated items or augmented dataset.
hash_func: if `hash_as_key`, a callable to compute hash from data items to be cached.
defaults to `monai.data.utils.pickle_hashing`.
runtime_cache: whether to compute cache at the runtime, default to `False` to prepare
the cache content at initializaiton, if `True`, it will cache during the first epoch
of model training, so it can start the first mini-batch earlier. please note that:
1. when using this option in multi-gpu distributed training,
`torch.cuda.set_device()` must be called before initializing this class.
2. to execute `runtime cache` on GPU memory, must co-work with
`monai.data.DataLoader`, and can't work with `monai.data.DistributedSampler`
as GPU Tensor usually can't be shared in the multiprocessing context.

"""
if not isinstance(transform, Compose):
Expand All @@ -788,9 +800,11 @@ def __init__(
self.num_workers = num_workers
if self.num_workers is not None:
self.num_workers = max(int(self.num_workers), 1)
self.runtime_cache = runtime_cache
self.cache_num = 0
self._cache: List = []
self._cache: Union[List, ListProxy] = []
self._hash_keys: List = []
self._is_dist = dist.is_available() and dist.is_initialized()
self.set_data(data)

def set_data(self, data: Sequence):
Expand All @@ -807,6 +821,18 @@ def set_data(self, data: Sequence):
def _compute_cache_num(data_len: int):
self.cache_num = min(int(self.set_num), int(data_len * self.set_rate), data_len)

def _compute_cache(indices=None):
if self.runtime_cache:
cache = Manager().list([None for _ in range(self.cache_num)])
if self._is_dist:
obj_list = [cache]
# broadcast the ProxyList to all the ranks, then share the same cache content at runtime
dist.broadcast_object_list(obj_list, src=0)
cache = obj_list[0]
else:
cache = self._fill_cache(indices)
return cache

if self.hash_as_key:
# only compute cache for the unique items of dataset, and record the last index for duplicated items
mapping = {self.hash_func(v): i for i, v in enumerate(data)}
Expand All @@ -816,7 +842,16 @@ def _compute_cache_num(data_len: int):
else:
_compute_cache_num(len(self.data))
indices = list(range(self.cache_num))
self._cache = self._fill_cache(indices)

self._cache = _compute_cache(indices)

def disable_share_memory_cache(self):
"""
If the cache content is multiprocessing share memory list, convert it to a regular ptython list.
Because multiprocessing ProxyList is not supported for the GPU caching, may need to explicitly diasble it.

"""
self._cache = list(self._cache)

def _fill_cache(self, indices=None) -> List:
"""
Expand Down Expand Up @@ -871,6 +906,10 @@ def _transform(self, index: int):
if self._cache is None:
raise RuntimeError("cache buffer is not initialized, please call `set_data()` first.")
data = self._cache[cache_index]
# runtime cache computation
if data is None:
data = self._cache[cache_index] = self._load_cache_item(cache_index)

# load data from cache and execute from the first random transform
start_run = False
if not isinstance(self.transform, Compose):
Expand Down Expand Up @@ -973,6 +1012,7 @@ def __init__(
seed: int = 0,
copy_cache: bool = True,
as_contiguous: bool = True,
runtime_cache: bool = False,
) -> None:
if shuffle:
self.set_random_state(seed=seed)
Expand Down
7 changes: 6 additions & 1 deletion tests/test_decathlondataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,12 @@ def _test_dataset(dataset):

_test_dataset(data)
data = DecathlonDataset(
root_dir=testing_dir, task="Task04_Hippocampus", transform=transform, section="validation", download=False
root_dir=testing_dir,
task="Task04_Hippocampus",
transform=transform,
section="validation",
download=False,
runtime_cache=True,
)
_test_dataset(data)
self.assertTrue(data[0]["image"].meta["filename_or_obj"].endswith("hippocampus_163.nii.gz"))
Expand Down
2 changes: 1 addition & 1 deletion tests/test_integration_fast_train.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ def test_train_timing(self):

# set CacheDataset, ThreadDataLoader and DiceCE loss for MONAI fast training
train_ds = CacheDataset(data=train_files, transform=train_transforms, cache_rate=1.0, num_workers=8)
val_ds = CacheDataset(data=val_files, transform=val_transforms, cache_rate=1.0, num_workers=5)
val_ds = CacheDataset(data=val_files, transform=val_transforms, cache_rate=1.0, runtime_cache=True)
# disable multi-workers because `ThreadDataLoader` works with multi-threads
train_loader = ThreadDataLoader(train_ds, num_workers=0, batch_size=4, shuffle=True)
val_loader = ThreadDataLoader(val_ds, num_workers=0, batch_size=1)
Expand Down
10 changes: 5 additions & 5 deletions tests/test_integration_segmentation_3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ def run_training_test(root_dir, device="cuda:0", cachedataset=0, readers=(None,

# create a training data loader
if cachedataset == 2:
train_ds = monai.data.CacheDataset(data=train_files, transform=train_transforms, cache_rate=0.8)
train_ds = monai.data.CacheDataset(
data=train_files, transform=train_transforms, cache_rate=0.8, runtime_cache=True
)
elif cachedataset == 3:
train_ds = monai.data.LMDBDataset(data=train_files, transform=train_transforms, cache_dir=root_dir)
else:
Expand Down Expand Up @@ -170,7 +172,7 @@ def run_training_test(root_dir, device="cuda:0", cachedataset=0, readers=(None,
plot_2d_or_3d_image(val_outputs, epoch + 1, writer, index=0, tag="output")
print(f"train completed, best_metric: {best_metric:0.4f} at epoch: {best_metric_epoch}")
writer.close()
return epoch_loss_values, best_metric, best_metric_epoch
return epoch_loss_values, best_metric


def run_inference_test(root_dir, device="cuda:0"):
Expand Down Expand Up @@ -256,9 +258,7 @@ def train_and_infer(self, idx=0):
_readers = ("itkreader", "itkreader")
elif idx == 2:
_readers = ("itkreader", "nibabelreader")
losses, best_metric, best_metric_epoch = run_training_test(
self.data_dir, device=self.device, cachedataset=idx, readers=_readers
)
losses, best_metric = run_training_test(self.data_dir, device=self.device, cachedataset=idx, readers=_readers)
infer_metric = run_inference_test(self.data_dir, device=self.device)

# check training properties
Expand Down
4 changes: 3 additions & 1 deletion tests/test_mednistdataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ def _test_dataset(dataset):
_test_dataset(data)

# testing from
data = MedNISTDataset(root_dir=Path(testing_dir), transform=transform, section="test", download=False)
data = MedNISTDataset(
root_dir=Path(testing_dir), transform=transform, section="test", download=False, runtime_cache=True
)
self.assertEqual(data.get_num_classes(), 6)
_test_dataset(data)
data = MedNISTDataset(root_dir=testing_dir, section="test", download=False)
Expand Down
25 changes: 24 additions & 1 deletion tests/test_sampler_dist.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
import unittest

import numpy as np
import torch
import torch.distributed as dist

from monai.data import DistributedSampler
from monai.data import CacheDataset, DataLoader, DistributedSampler
from monai.transforms import ToTensor
from tests.utils import DistCall, DistTestCase


Expand Down Expand Up @@ -43,6 +45,27 @@ def test_uneven(self):
if dist.get_rank() == 1:
np.testing.assert_allclose(samples, np.array([2, 4]))

@DistCall(nnodes=1, nproc_per_node=2)
def test_cachedataset(self):
data = [1, 2, 3, 4, 5]
dataset = CacheDataset(data=data, transform=ToTensor(track_meta=False), cache_rate=1.0, runtime_cache=True)
sampler = DistributedSampler(dataset=dataset, shuffle=False, even_divisible=False)
dataloader = DataLoader(dataset=dataset, sampler=sampler, batch_size=1, num_workers=2)
for i in range(3):
dist.barrier()
if i > 0:
# verify the runtime cache content is completed after first epoch
for j, c in enumerate(dataset._cache):
self.assertTrue(isinstance(c, torch.Tensor))
torch.testing.assert_allclose(c, j + 1)
for k, d in enumerate(dataloader):
self.assertTrue(isinstance(d, torch.Tensor))
if dist.get_rank() == 0:
torch.testing.assert_allclose(d[0], k * 2 + 1)

if dist.get_rank() == 1:
torch.testing.assert_allclose(d[0], (k + 1) * 2)


if __name__ == "__main__":
unittest.main()
1 change: 1 addition & 0 deletions tests/test_tciadataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def _test_dataset(dataset):
section="validation",
download=False,
val_frac=val_frac,
runtime_cache=True,
)
_test_dataset(data)
self.assertTrue(
Expand Down