File size: 1,858 Bytes
3b2d368 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | import math
import torch
from torch.utils.data import DistributedSampler
# WARNING: Do NOT change your GPU count when using this sampler- it will not resume properly
class ResumableSampler(DistributedSampler):
def __init__(self, dataset, num_replicas=None, rank=None, shuffle=True, seed=0, drop_last=False):
super().__init__(dataset, num_replicas, rank, shuffle, seed, drop_last)
self.start_index = 0
self.batch_size = 0
# Follows the default DistributedSampler exactly, but with the addition of the start_index term
def __iter__(self):
if self.shuffle:
g = torch.Generator()
g.manual_seed(self.seed + self.epoch)
indices = torch.randperm(len(self.dataset), generator=g).tolist()
else:
indices = list(range(len(self.dataset)))
if not self.drop_last:
padding_size = self.total_size - len(indices)
if padding_size <= len(indices):
indices += indices[:padding_size]
else:
indices += (indices * math.ceil(padding_size / len(indices)))[:padding_size]
else:
indices = indices[:self.total_size]
assert len(indices) == self.total_size
indices = indices[self.rank:self.total_size:self.num_replicas]
assert len(indices) == self.num_samples
skip = self.start_index * self.batch_size
self.start_index = 0 # Reset for future epochs
if skip >= len(indices):
return iter([])
indices = indices[skip:]
return iter(indices)
# Make sure this is per-rank-step (do NOT multiply by worldsize, but DO include gradient acumulations when necessary)
def set_start_index(self, start_index, batch_size):
self.start_index = start_index
self.batch_size = batch_size
|