Data Management#
Use this page to quickly reference how to work with PyTorch datasets, create batches with data loaders, split data reproducibly, and apply preprocessing without leaking information across partitions.
Datasets#
Dataset#
A PyTorch Dataset provides access to individual examples.
__len__returns the number of examples.__getitem__returns one example at the given index.
from torch.utils.data import Dataset
class ExampleDataset(Dataset):
def __len__(self):
return ...
def __getitem__(self, index):
inputs = ...
target = ...
return inputs, target
The dataset does not group examples into batches. That is the responsibility of the DataLoader.
TensorDataset#
Use TensorDataset when the complete dataset is already stored in tensors.
from torch.utils.data import TensorDataset
dataset = TensorDataset(features, targets)
All tensors passed to TensorDataset must contain the same number of examples along dimension 0.
Inspecting a Dataset#
Inspect examples before training to verify shapes, dtypes, and labels.
print("Number of examples:", len(dataset))
inputs, target = dataset[0]
print("Input shape:", inputs.shape)
print("Input dtype:", inputs.dtype)
print("Target:", target)
For image data, visual inspection is also useful for detecting corrupted inputs or incorrect labels.
Data Loaders#
Batching Terminology#
Term |
Meaning |
|---|---|
Sample |
One example from a dataset |
Batch |
A collection of examples processed together |
Iteration / training step |
One parameter update using one batch |
Epoch |
One complete pass through the training dataset |
DataLoader#
A DataLoader retrieves examples from a dataset and groups them into batches.
from torch.utils.data import DataLoader
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
valid_loader = DataLoader(valid_dataset, batch_size=256, shuffle=False)
Training examples are normally shuffled. Validation and test examples do not need shuffling.
Argument |
Meaning |
|---|---|
|
Dataset providing individual examples |
|
Number of examples grouped into one batch |
|
Randomly reorder examples before batching |
|
Discard the final incomplete batch when |
Inspecting a Batch#
Retrieve one batch directly from the loader.
inputs, targets = next(iter(train_loader))
print(inputs.shape)
print(targets.shape)
Typical shapes are:
tabular inputs → (B, D)
image inputs → (B, C, H, W)
targets → (B,)
where B is the current batch size.
Inspecting one batch is one of the fastest ways to detect mismatches between the data pipeline, model input, and loss function.
Batch Size#
Batch size controls how many examples are processed together in one iteration.
loader = DataLoader(dataset, batch_size=128)
Inspect the number of batches directly with:
len(loader)
With drop_last=False, a dataset containing \(N\) examples and batch size \(B\) produces \(\left\lceil \frac{N}{B} \right\rceil\) batches.
Incomplete Final Batches#
If the dataset size is not divisible by the batch size, the final batch is smaller.
1000 examples
batch size 64
→ 15 full batches of 64
→ 1 final batch of 40
This matters when aggregating losses and metrics across an epoch.
Warning
Do not assume that every batch has the same number of examples unless drop_last=True.
Dataset Splits#
random_split#
For a simple random partition, use random_split with a seeded generator.
from torch.utils.data import random_split
total = len(dataset)
n_train = int(total * 0.8)
lengths = [n_train, total - n_train]
generator = torch.Generator().manual_seed(42)
train_dataset, valid_dataset = random_split(dataset, lengths, generator=generator)
The seed fixes the random partition so that repeated runs assign the same examples to each subset.
Warning
Subsets created with random_split refer to the same underlying dataset. If that dataset owns a transform, all subsets use that transform.
Subset#
When more control is needed, create the split indices explicitly and use Subset.
from torch.utils.data import Subset
total = len(dataset)
n_train = int(total * 0.8)
generator = torch.Generator().manual_seed(42)
indices = torch.randperm(total, generator=generator)
train_indices = indices[:n_train]
valid_indices = indices[n_train:]
train_dataset = Subset(dataset, train_indices)
valid_dataset = Subset(dataset, valid_indices)
Explicit indices are useful when the same partition must be reused across several dataset instances or preprocessing configurations. For example, training and validation images may require different transforms. Create two dataset instances that refer to the same examples, then apply the same split indices to each one.
train_data = ImageFolder(root="data", transform=train_transform)
valid_data = ImageFolder(root="data", transform=eval_transform)
train_dataset = Subset(train_data, train_indices)
valid_dataset = Subset(valid_data, valid_indices)
Structured Splits#
Random example-level splitting is inappropriate when the observations are not independent. Split according to the unit that must remain separate across partitions.
Data structure |
Split by |
|---|---|
Independent examples |
Example |
Repeated observations from one subject |
Subject or group |
Several samples derived from one source |
Original source |
Time-ordered observations |
Time |
The split must respect the structure that defines independent examples. Repeated observations from the same subject, derived samples from the same source, or time-ordered observations should not be randomly distributed across training and evaluation partitions.
Preprocessing#
Per-Example Transformations#
Per-example transformations operate independently on each example and do not estimate parameters from the dataset. For example, an image can be converted to a tensor and its values scaled to the range [0, 1].
import torchvision.transforms.v2 as v2
transform = v2.Compose([
v2.ToImage(),
v2.ToDtype(torch.float32, scale=True)
])
Such transformations can be attached directly to many torchvision datasets.
Fitted Preprocessing#
Fitted preprocessing estimates parameters or rules from data. It must be fitted using the training set only and then applied unchanged to validation and test data. Typical examples include:
means and standard deviations;
imputation values;
feature-selection rules;
dimensionality-reduction parameters.
Create the data partitions before fitting any data-dependent preprocessing.
Warning
Validation and test data must not influence fitted preprocessing parameters.
Image Data#
ImageFolder#
Use ImageFolder to load images that are organized in one directory per class.
data/
│
├── cat/
│ ├── cat001.jpg
│ ├── cat002.jpg
│ └── ...
│
├── dog/
│ ├── dog001.jpg
│ ├── dog002.jpg
│ └── ...
│
└── bird/
├── bird001.jpg
├── bird002.jpg
└── ...
from torchvision.datasets import ImageFolder
dataset = ImageFolder(root="data", transform=transform)
Useful attributes include .classes and .class_to_idx.
Attribute |
Meaning |
|---|---|
|
List of class names in alphabetical order |
|
Dictionary mapping class names to integer indices |
ImageFolder assigns integer class indices from the directory names.
Training and Evaluation Transforms#
Training and evaluation data may use different transformations.
train_transform = v2.Compose([
v2.ToImage(),
v2.RandomHorizontalFlip(),
v2.ToDtype(torch.float32, scale=True)
])
eval_transform = v2.Compose([
v2.ToImage(),
v2.ToDtype(torch.float32, scale=True)
])
Training may use stochastic transformations such as augmentation. Validation and test transformations should normally be deterministic.
Pretrained Model Transforms#
Pretrained torchvision weights provide the preprocessing expected by the model.
weights = ...
transform = weights.transforms()
Use the transformation associated with the selected pretrained weights unless the application requires a deliberate alternative. See Transfer Learning for freezing, replacing heads, and fine-tuning pretrained models.