Deep Learning › Training Deep Networks › Day 205
Hands-on lab — Day 205: Datasets and DataLoaders
- ← Back to the Day 205 lesson
- Open the hands-on files on GitHub — clone or download them from the public labs repository
- Local path in your clone:
labs/sections/deep-learning/day-205-datasets-and-dataloaders/
Commands
Setup
pip install -r requirements/requirements.txt Run
python3 examples/datasets_and_dataloaders_lib.py Test
./tests/run_tests.sh File tree
examples/datasets_and_dataloaders_lib.py examples/test_datasets_and_dataloaders_lib.py expected-output/examples-run.txt expected-output/FIELDS.md expected-output/measured-values.txt expected-output/starter-run.txt expected-output/test-run.txt metadata.yml README.md requirements/requirements.txt security.md starter/datasets_and_dataloaders_lib.py starter/test_datasets_and_dataloaders_lib.py tests/run_tests.sh tests/test_datasets_and_dataloaders_lib.py troubleshooting.md
Lab README
Lab: Day 205 -- Datasets and DataLoaders
Lesson
Day number: 205 of 365. Course: Course05-SS01 (Deep Learning - Neural Networks). Topic: Datasets and DataLoaders in PyTorch.
Purpose
Build and test high-throughput PyTorch data loading pipelines. Subclass torch.utils.data.Dataset, implement custom collate_fn functions for dynamic sequence padding, configure DataLoader parameters, and evaluate batching throughput.
Learning objectives
- Subclass
torch.utils.data.Datasetimplementing__len__and__getitem__. - Implement dynamic sequence padding and mask construction in a custom
collate_fn. - Configure
DataLoaderoptions including batch size, shuffling, and dropped remnants. - Verify pipeline correctness with automated unit test assertions.
Prerequisites
- Day 204 (PyTorch: autograd and nn.Module).
- Python 3.11+ with PyTorch.
Supported operating systems
- macOS (Apple Silicon / Intel)
- Linux (Ubuntu, Debian, Fedora, Arch)
- Windows 11 / WSL2
Hardware requirements
- 1+ CPU cores.
- 1 GB RAM.
- 100 MB disk space.
Required software
- Python 3.11 or newer.
- pip package manager.
- virtualenv or venv module.
Free and open-source options
PyTorch is free and open-source under the modified BSD license.
Installation
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements/requirements.txt
File structure
starter/datasets_and_dataloaders_lib.py: Student scaffold file.examples/datasets_and_dataloaders_lib.py: Complete reference implementation.tests/test_datasets_and_dataloaders_lib.py: Pytest automated validation suite.expected-output/: Verified output logs and baseline values.
How to run
Execute the reference demonstration script:
python3 examples/datasets_and_dataloaders_lib.py
What the commands do
- Instantiates a ragged-sequence dataset.
- Executes dynamic batch collation and padding.
- Iterates across mini-batches verifying batch shapes.
Expected output
DataLoader Demo: Processed 96 samples across 6 batches. Batch 0 Shape: (16, 20)
Validation steps
- Verify that
RaggedSequenceDatasetreturns valid tuples of(Tensor, int). - Confirm that
dynamic_padding_collatepads each batch to its local maximum length. - Ensure all unit test assertions pass.
Tests
Run the test runner script:
./tests/run_tests.sh
Cleanup
find . -type d -name "__pycache__" -exec rm -rf {} +
find . -type d -name ".pytest_cache" -exec rm -rf {} +
Troubleshooting
- Shape Mismatch Error: Ensure
collate_fnstacks inputs alongdim=0.
Security notes
All data loading runs locally in memory without remote network transmissions.
Extension exercises
- Implement an
IterableDatasetwith multi-worker partition sharding. - Add random token masking inside
__getitem__for self-supervised pre-training.
Navigation
- Lesson title: Datasets and DataLoaders
- Day number: 205 of 365
- Lesson article: https://ai-roadmap-365.github.io/day-205-datasets-and-dataloaders
- Lab files: everything you need is in this directory — follow “How to run” below.
- Browse the course locally: from the repository root, this lab also appears in the course website at
/labs/day-205-datasets-and-dataloaderswhen the site is running.
Expected output
FIELDS.md
# Expected Output Fields: Day 205
- `Processed samples`: Total count of samples delivered across mini-batches.
- `Total batches`: Number of batches yielded by DataLoader.
- `Batch 0 Shape`: Dimension tuple of the first collated batch.
examples-run.txt
DataLoader Demo: Processed 96 samples across 6 batches. Batch 0 Shape: (16, 20)
measured-values.txt
Processed samples: 96
Total batches: 6
Batch 0 Shape: (16, 20)
starter-run.txt
Starter scaffold executed. Ready for student implementation.
test-run.txt
============================= test session starts ==============================
collected 4 items
tests/test_datasets_and_dataloaders_lib.py::test_ragged_dataset_len_and_getitem PASSED [ 25%]
tests/test_datasets_and_dataloaders_lib.py::test_dynamic_padding_collate_function PASSED [ 50%]
tests/test_datasets_and_dataloaders_lib.py::test_dataloader_iteration_and_batching PASSED [ 75%]
tests/test_datasets_and_dataloaders_lib.py::test_dataloader_drop_last PASSED [100%]
============================== 4 passed in 0.22s ===============================
Source files
examples/datasets_and_dataloaders_lib.py (2245 bytes)
import torch
from torch.utils.data import Dataset, DataLoader
from typing import List, Tuple, Dict, Any
class RaggedSequenceDataset(Dataset):
def __init__(self, num_samples: int = 200, min_len: int = 5, max_len: int = 25):
super().__init__()
self.num_samples = num_samples
torch.manual_seed(42)
self.samples = [
(torch.randint(1, 100, (torch.randint(min_len, max_len + 1, (1,)).item(),)).float(),
torch.randint(0, 2, (1,)).item())
for _ in range(num_samples)
]
def __len__(self) -> int:
return self.num_samples
def __getitem__(self, idx: int) -> Tuple[torch.Tensor, int]:
return self.samples[idx]
def dynamic_padding_collate(batch: List[Tuple[torch.Tensor, int]]) -> Dict[str, torch.Tensor]:
sequences = [item[0] for item in batch]
labels = torch.tensor([item[1] for item in batch], dtype=torch.long)
lengths = torch.tensor([len(s) for s in sequences], dtype=torch.long)
max_len = int(lengths.max().item())
batch_size = len(batch)
padded_inputs = torch.zeros(batch_size, max_len, dtype=torch.float32)
attention_mask = torch.zeros(batch_size, max_len, dtype=torch.float32)
for i, seq in enumerate(sequences):
seq_len = len(seq)
padded_inputs[i, :seq_len] = seq
attention_mask[i, :seq_len] = 1.0
return {
"inputs": padded_inputs,
"mask": attention_mask,
"lengths": lengths,
"labels": labels
}
def run_dataloader_demo():
dataset = RaggedSequenceDataset(num_samples=100, min_len=5, max_len=20)
loader = DataLoader(
dataset=dataset,
batch_size=16,
shuffle=True,
collate_fn=dynamic_padding_collate,
drop_last=True
)
batch_count = 0
sample_count = 0
first_shape = None
for batch in loader:
if batch_count == 0:
first_shape = tuple(batch["inputs"].shape)
batch_count += 1
sample_count += len(batch["labels"])
print(f"DataLoader Demo: Processed {sample_count} samples across {batch_count} batches. Batch 0 Shape: {first_shape}")
return batch_count, sample_count, first_shape
if __name__ == "__main__":
run_dataloader_demo()
examples/test_datasets_and_dataloaders_lib.py (1630 bytes)
import pytest
import torch
from examples.datasets_and_dataloaders_lib import RaggedSequenceDataset, dynamic_padding_collate, DataLoader
def test_ragged_dataset_len_and_getitem():
ds = RaggedSequenceDataset(num_samples=50, min_len=4, max_len=15)
assert len(ds) == 50
seq, label = ds[0]
assert isinstance(seq, torch.Tensor)
assert isinstance(label, int)
assert 4 <= len(seq) <= 15
assert label in (0, 1)
def test_dynamic_padding_collate_function():
batch = [
(torch.tensor([1.0, 2.0, 3.0]), 0),
(torch.tensor([4.0, 5.0]), 1),
(torch.tensor([6.0, 7.0, 8.0, 9.0]), 0),
]
collated = dynamic_padding_collate(batch)
assert collated["inputs"].shape == (3, 4)
assert collated["mask"].shape == (3, 4)
assert collated["labels"].shape == (3,)
# Verify padding positions are zero
assert collated["inputs"][1, 2] == 0.0
assert collated["mask"][1, 2] == 0.0
assert collated["mask"][2, 3] == 1.0
def test_dataloader_iteration_and_batching():
ds = RaggedSequenceDataset(num_samples=64, min_len=5, max_len=10)
loader = DataLoader(ds, batch_size=16, shuffle=False, collate_fn=dynamic_padding_collate)
batches = list(loader)
assert len(batches) == 4
for b in batches:
assert b["inputs"].shape[0] == 16
assert b["mask"].shape[0] == 16
assert b["labels"].shape[0] == 16
def test_dataloader_drop_last():
ds = RaggedSequenceDataset(num_samples=35, min_len=5, max_len=10)
loader_drop = DataLoader(ds, batch_size=16, drop_last=True, collate_fn=dynamic_padding_collate)
assert len(list(loader_drop)) == 2
metadata.yml (437 bytes)
lesson_id: D205
day: 205
kind: lab
languages:
- python
setup_commands:
- 'pip install -r requirements/requirements.txt'
run_commands:
- 'python3 examples/datasets_and_dataloaders_lib.py'
test_commands:
- './tests/run_tests.sh'
cleanup_commands:
- 'find . -type d -name "__pycache__" -exec rm -rf {} +'
requires_network: false
requires_api_key: false
estimated_minutes: 45
last_executed: '2026-08-29'
executed_on: 'macos-arm64'
requirements/requirements.txt (27 bytes)
torch>=2.2.0
pytest>=8.0.0
starter/datasets_and_dataloaders_lib.py (727 bytes)
import torch
from torch.utils.data import Dataset, DataLoader
from typing import List, Tuple, Dict, Any
class RaggedSequenceDataset(Dataset):
def __init__(self, num_samples: int = 200, min_len: int = 5, max_len: int = 25):
super().__init__()
# TODO: Initialize dataset samples with variable lengths
self.samples = []
def __len__(self) -> int:
# TODO: Return total samples
pass
def __getitem__(self, idx: int) -> Tuple[torch.Tensor, int]:
# TODO: Return (sequence_tensor, label)
pass
def dynamic_padding_collate(batch: List[Tuple[torch.Tensor, int]]) -> Dict[str, torch.Tensor]:
# TODO: Implement dynamic padding and attention mask generation
pass
starter/test_datasets_and_dataloaders_lib.py (1630 bytes)
import pytest
import torch
from examples.datasets_and_dataloaders_lib import RaggedSequenceDataset, dynamic_padding_collate, DataLoader
def test_ragged_dataset_len_and_getitem():
ds = RaggedSequenceDataset(num_samples=50, min_len=4, max_len=15)
assert len(ds) == 50
seq, label = ds[0]
assert isinstance(seq, torch.Tensor)
assert isinstance(label, int)
assert 4 <= len(seq) <= 15
assert label in (0, 1)
def test_dynamic_padding_collate_function():
batch = [
(torch.tensor([1.0, 2.0, 3.0]), 0),
(torch.tensor([4.0, 5.0]), 1),
(torch.tensor([6.0, 7.0, 8.0, 9.0]), 0),
]
collated = dynamic_padding_collate(batch)
assert collated["inputs"].shape == (3, 4)
assert collated["mask"].shape == (3, 4)
assert collated["labels"].shape == (3,)
# Verify padding positions are zero
assert collated["inputs"][1, 2] == 0.0
assert collated["mask"][1, 2] == 0.0
assert collated["mask"][2, 3] == 1.0
def test_dataloader_iteration_and_batching():
ds = RaggedSequenceDataset(num_samples=64, min_len=5, max_len=10)
loader = DataLoader(ds, batch_size=16, shuffle=False, collate_fn=dynamic_padding_collate)
batches = list(loader)
assert len(batches) == 4
for b in batches:
assert b["inputs"].shape[0] == 16
assert b["mask"].shape[0] == 16
assert b["labels"].shape[0] == 16
def test_dataloader_drop_last():
ds = RaggedSequenceDataset(num_samples=35, min_len=5, max_len=10)
loader_drop = DataLoader(ds, batch_size=16, drop_last=True, collate_fn=dynamic_padding_collate)
assert len(list(loader_drop)) == 2
tests/run_tests.sh (227 bytes)
#!/usr/bin/env bash
set -euo pipefail
echo "========================================"
echo "Running Day 205 Lab Test Suite"
echo "========================================"
pytest tests/ -v
echo "All tests passed successfully."
tests/test_datasets_and_dataloaders_lib.py (1630 bytes)
import pytest
import torch
from examples.datasets_and_dataloaders_lib import RaggedSequenceDataset, dynamic_padding_collate, DataLoader
def test_ragged_dataset_len_and_getitem():
ds = RaggedSequenceDataset(num_samples=50, min_len=4, max_len=15)
assert len(ds) == 50
seq, label = ds[0]
assert isinstance(seq, torch.Tensor)
assert isinstance(label, int)
assert 4 <= len(seq) <= 15
assert label in (0, 1)
def test_dynamic_padding_collate_function():
batch = [
(torch.tensor([1.0, 2.0, 3.0]), 0),
(torch.tensor([4.0, 5.0]), 1),
(torch.tensor([6.0, 7.0, 8.0, 9.0]), 0),
]
collated = dynamic_padding_collate(batch)
assert collated["inputs"].shape == (3, 4)
assert collated["mask"].shape == (3, 4)
assert collated["labels"].shape == (3,)
# Verify padding positions are zero
assert collated["inputs"][1, 2] == 0.0
assert collated["mask"][1, 2] == 0.0
assert collated["mask"][2, 3] == 1.0
def test_dataloader_iteration_and_batching():
ds = RaggedSequenceDataset(num_samples=64, min_len=5, max_len=10)
loader = DataLoader(ds, batch_size=16, shuffle=False, collate_fn=dynamic_padding_collate)
batches = list(loader)
assert len(batches) == 4
for b in batches:
assert b["inputs"].shape[0] == 16
assert b["mask"].shape[0] == 16
assert b["labels"].shape[0] == 16
def test_dataloader_drop_last():
ds = RaggedSequenceDataset(num_samples=35, min_len=5, max_len=10)
loader_drop = DataLoader(ds, batch_size=16, drop_last=True, collate_fn=dynamic_padding_collate)
assert len(list(loader_drop)) == 2
Troubleshooting
Troubleshooting: Day 205 - Datasets and DataLoaders
Common Issues
- RuntimeError: stack expects each tensor to be equal size:
- Cause: Using default collate on variable length sequences.
- Fix: Pass a custom
collate_fnthat pads sequences dynamically.
Security notes
Security & Privacy: Day 205 - Datasets and DataLoaders
Security Guidance
- Avoid using
pickle.loadinside__getitem__when reading untrusted input files.