Btw I wrapped dataloader into a class just to measure time. I don’t really know if this is ok considering multiprocessing and dataloader’s complexity but it may help:
import torch
from torch.utils.data import Dataset, DataLoader

import time


def timeit(method):
    def timed(*args, **kw):
        ts = time.time()
        result = method(*args, **kw)
        te = time.time()
        if 'log_time' in kw:
            name = kw.get('log_name', method.__name__.upper())
            kw['log_time'][name] = int((te - ts) * 1000)
        else:
            print('%r  %2.2f ms' % \
                  (method.__name__, (te - ts) * 1000))
        return result

    return timed


# class DLtimer(object):
#     def __new__(cls, obj):
#         obj.__next__ = timeit(obj.__next__)
#         return obj
class DLtimer(object):
    def __init__(self, obj):
        self.dataloader = iter(obj)
    def __iter__(self):
        return self
    @timeit
    def __next__(self):
        return next(self.dataloader)


class DS(Dataset):
    def __init__(self):
        self.data = torch.rand(1000, 10)

    def __len__(self):
        return self.data.size(0)

    def __getitem__(self, item):
        return self.data[item]


ds = DS()
train_loader = DataLoader(ds, batch_size=10, shuffle=True,
                          num_workers=0, pin_memory=True, drop_last=True)
train_loader = DLtimer(train_loader)
for i, data in enumerate(train_loader):
    print(i)

The spoiler is using multiprocessing to just read data from ram may be undesirable.