What DataLoader does
DataLoader wraps a Dataset and adds: batching (group N examples into a tensor of shape [N, ...]), shuffling (sampling order), parallel loading (multiple worker processes), and pin memory (for faster CPU→GPU transfer). One line at the top of your training loop, and the rest of the code can just iterate over batches.
The two arguments that matter most are batch_size (tune for VRAM and throughput) and num_workers (tune for CPU/IO bandwidth). Default num_workers=0 is single-process, which is fine for tiny datasets and a debugging nightmare for everything else.
num_workers to roughly the number of physical CPU cores you have available. On a 16-core box, num_workers=8 is a sensible starting point. Test with htop open — workers should be busy, GPU should be busy, neither should be idle waiting on the other.Common pitfalls
Forgetting shuffle=True on training — if your data is class-sorted, the model overfits the first class and never recovers. Always shuffle the training loader.
Shuffling the validation loader — wastes time and breaks reproducibility of per-batch metrics. Validation loaders use shuffle=False.
Using num_workers>0 on CUDA without pin_memory=True — leaves CPU→GPU bandwidth on the table. Always pair them.
Mutating shared state in __getitem__ — workers are subprocesses, so any global state is per-worker. Logging counters, RNG state, etc. behave subtly differently than you expect.
Custom collate
The default collate_fn stacks tensors with the same shape. For variable-length sequences (text, audio, sets), you need a custom collate that pads or packs. Hugging Face's DataCollatorWithPadding handles the common case for you.
shuffle=True, num_workers>0, pin_memory=True on CUDA. Three things to set on every validation DataLoader: shuffle=False, num_workers>0, pin_memory=True.