The two-method contract
For any data shape you can reduce to "indexable list of samples", a custom Dataset just needs:
__len__(self)— total samples__getitem__(self, idx)— return the sample at index idx
That's the entire contract. The DataLoader does the rest.
The patterns you'll write five hundred times
- ImageFolder-style — a directory tree where subfolder names are class labels. torchvision ships
ImageFolderfor the canonical case; you'll write variants for "your data is similar but slightly different". - CSV / pandas — load a manifest file with paths and labels, fetch from disk on demand.
- HDF5 / Parquet / WebDataset — for large datasets, read from a disk-backed format.
- In-memory tensors — for small data that fits, just hold the tensors as attributes.
Lazy vs eager loading
Big datasets must load lazily — read from disk inside __getitem__, not in __init__. Small datasets can load eagerly and pre-process in __init__. The boundary is roughly "fits in RAM with headroom" vs "doesn't" — usually 10-100 GB depending on your machine.