Sampler that restricts data loading to a subset of input sampler indices. It is especially useful in conjunction with :class:`torch.nn.parallel.DistributedDataParallel`. In such case, each process can pass a DistributedSampler instance as a DataLoader sampler, and load a subset of t
| 6 | |
| 7 | |
| 8 | class DistributedProxySampler(DistributedSampler): |
| 9 | """Sampler that restricts data loading to a subset of input sampler indices. |
| 10 | |
| 11 | It is especially useful in conjunction with |
| 12 | :class:`torch.nn.parallel.DistributedDataParallel`. In such case, each |
| 13 | process can pass a DistributedSampler instance as a DataLoader sampler, |
| 14 | and load a subset of the original dataset that is exclusive to it. |
| 15 | |
| 16 | .. note:: |
| 17 | Input sampler is assumed to be of constant size. |
| 18 | |
| 19 | Arguments: |
| 20 | sampler: Input data sampler. |
| 21 | num_replicas (optional): Number of processes participating in |
| 22 | distributed training. |
| 23 | rank (optional): Rank of the current process within num_replicas. |
| 24 | """ |
| 25 | |
| 26 | def __init__(self, sampler, num_replicas=None, rank=None): |
| 27 | super(DistributedProxySampler, self).__init__(sampler, num_replicas=num_replicas, rank=rank, shuffle=False) |
| 28 | self.sampler = sampler |
| 29 | |
| 30 | def __iter__(self): |
| 31 | # deterministically shuffle based on epoch |
| 32 | torch.manual_seed(self.epoch) |
| 33 | indices = list(self.sampler) |
| 34 | |
| 35 | # add extra samples to make it evenly divisible |
| 36 | indices += indices[:(self.total_size - len(indices))] |
| 37 | if len(indices) != self.total_size: |
| 38 | raise RuntimeError("{} vs {}".format(len(indices), self.total_size)) |
| 39 | |
| 40 | # subsample |
| 41 | indices = indices[self.rank:self.total_size:self.num_replicas] |
| 42 | if len(indices) != self.num_samples: |
| 43 | raise RuntimeError("{} vs {}".format(len(indices), self.num_samples)) |
| 44 | |
| 45 | return iter(indices) |