Spaces:
Sleeping
Sleeping
| import numpy as np | |
| from torch.utils.data import DataLoader | |
| from torch.utils.data.sampler import Sampler | |
| from torch.utils.data.distributed import DistributedSampler | |
| from util.torch import worker_init_fn | |
| class OrderedDistributedSampler(Sampler): | |
| """ | |
| Sampler that orders samples in a specified order and assigns them to different processes. | |
| Attributes: | |
| dataset (Dataset): The dataset to sample from. | |
| num_replicas (int): The total number of processes participating in the distributed training. | |
| rank (int): The rank of the current process. | |
| num_samples (int): The number of samples per process. | |
| total_size (int): The total number of samples across all processes. | |
| Methods: | |
| __iter__(): Returns an iterator over the indices of the samples for the current process. | |
| __len__(): Returns the number of samples per process. | |
| """ | |
| def __init__(self, dataset, num_replicas=None, rank=None): | |
| """ | |
| Constructor. | |
| Args: | |
| dataset (Dataset): The dataset to sample from. | |
| num_replicas (int): Number of processes in the distributed training. Defaults to None. | |
| rank (int): The rank of the current process. Defaults to None. | |
| Raises: | |
| AssertionError: If num_replicas or rank is None. | |
| """ | |
| assert num_replicas is not None | |
| assert rank is not None | |
| self.dataset = dataset | |
| self.num_replicas = num_replicas | |
| self.rank = rank | |
| self.num_samples = int(np.ceil(len(self.dataset) * 1.0 / self.num_replicas)) | |
| self.total_size = self.num_samples * self.num_replicas | |
| def __iter__(self): | |
| """ | |
| Returns an iterator over the indices of the samples to be used in the current process. | |
| """ | |
| indices = list(range(len(self.dataset))) | |
| # add extra samples to make it evenly divisible | |
| indices += indices[: (self.total_size - len(indices))] | |
| assert len(indices) == self.total_size | |
| # subsample | |
| indices = indices[ | |
| self.rank * self.num_samples: self.rank * self.num_samples | |
| + self.num_samples | |
| ] | |
| assert len(indices) == self.num_samples | |
| return iter(indices) | |
| def __len__(self): | |
| """ | |
| Returns the number of samples per process. | |
| """ | |
| return self.num_samples | |
| def define_loaders( | |
| train_dataset, | |
| val_dataset, | |
| batch_size=32, | |
| val_bs=32, | |
| distributed=False, | |
| world_size=0, | |
| local_rank=0, | |
| num_workers=0, | |
| ): | |
| """ | |
| Define data loaders for training and validation datasets. | |
| If `distributed` is True, the data loaders will use DistributedSampler for shuffling the | |
| training dataset and OrderedDistributedSampler for sampling the validation dataset. | |
| Args: | |
| train_dataset (Dataset): The training dataset. | |
| val_dataset (Dataset): The validation dataset. | |
| batch_size (int): The batch size for training data loader. Default to 32. | |
| val_bs (int): The batch size for validation data loader. Default to 32. | |
| distributed (bool): Whether to use distributed training. Default to False. | |
| world_size (int): The total number of processes for distributed training. Default to 0. | |
| local_rank (int): The rank of the current process. Default to 0. | |
| num_workers (int): Number of workers to use for the dataloaders. Default to 0. | |
| Returns: | |
| tuple: A tuple containing the training data loader and the validation data loader. | |
| """ | |
| sampler, val_sampler = None, None | |
| if distributed: | |
| sampler = DistributedSampler( | |
| train_dataset, | |
| num_replicas=world_size, | |
| rank=local_rank, | |
| shuffle=True, | |
| seed=world_size + local_rank, | |
| ) | |
| val_sampler = OrderedDistributedSampler( | |
| val_dataset, num_replicas=world_size, rank=local_rank | |
| ) | |
| train_loader = DataLoader( | |
| train_dataset, | |
| batch_size=batch_size, | |
| sampler=sampler, | |
| shuffle=sampler is None, | |
| drop_last=True, | |
| num_workers=num_workers, | |
| pin_memory=True, | |
| worker_init_fn=worker_init_fn, | |
| collate_fn=None, | |
| persistent_workers=num_workers > 0, | |
| ) | |
| val_loader = DataLoader( | |
| val_dataset, | |
| batch_size=val_bs, | |
| sampler=val_sampler, | |
| shuffle=False, | |
| num_workers=num_workers, | |
| pin_memory=True, | |
| collate_fn=None, | |
| persistent_workers=num_workers > 0, | |
| ) | |
| return train_loader, val_loader | |