Custom Dataset Class
Problem Statement
Create a custom Dataset class that generates data on-the-fly instead of storing it all in memory.
Background
For large datasets, storing everything in memory isn't practical. PyTorch's Dataset interface lets you generate or load data on demand by implementing three methods: init, len, and getitem.
Your Task
Create a class SequenceDataset that generates sequential data. For index i, it should return:
- Feature: a tensor of [i, i+1, i+2]
- Label: the sum of the feature values
The class must accept a size parameter that determines how many samples it contains.
Output Format
Each sample should be a tuple of (feature_tensor, label_tensor).
Example:
features=[[1.0, 2.0], [3.0, 4.0]], labels=[0, 1]
Dataset with 2 samples, dataset[0] returns (tensor([1., 2.]), tensor(0))
We create a Dataset class that stores features and labels and returns them as tensors
Constraints:
- Features and labels lists will have the same length
- Features can be 1D or 2D lists
- Labels are integers
- Return tensors (not lists) from getitem
1. Background Knowledge
PyTorch's Dataset class is the foundation for custom data handling in deep learning pipelines. It enables on-the-fly data generation, crucial for large-scale datasets that exceed memory limits.
Key Concepts
- torch.utils.data.Dataset: Abstract base class requiring init, len, and getitem implementations.
- len(self): Returns dataset size (total samples).
- getitem(self, idx): Returns data for index idx (feature, label pair).
- Memory Efficiency: Generates samples dynamically via getitem, avoiding full in-memory storage—ideal for infinite or massive datasets.
- Integration: Works with DataLoader for batching, shuffling, parallelism.
- Tensors: Use torch.tensor() for PyTorch compatibility (GPU acceleration, autograd).
Prerequisites: Basic PyTorch (torch), indexing, tensor operations.
2. Algorithm Approach
Procedural Generation: For index i, compute:
- Feature: xi​=[i,i+1,i+2] as 1D tensor.
- Label: yi​=3i+3=\sum\mathbf{x}i​.
No complex algorithms needed—direct mathematical mapping from index to sample. This is a synthetic dataset generator, common for prototyping, testing, or simulating sequences.
3. Step-by-Step Strategy
- Inherit Dataset:
from torch.utils.data import Dataset
import torch
class SequenceDataset(Dataset):
def __init__(self, size: int):
self.size = size # Total samples
- Implement len:
def __len__(self) -> int:
return self.size
- Implement getitem:
- Generate feature tensor: torch.tensor([idx, idx+1, idx+2], dtype=torch.float32)
- Compute label: torch.tensor(3*idx + 3, dtype=torch.float32) (or int)
- Return tuple (feature, label)
-
Handle Output Format: Test converts tensors to list/int via .tolist()/.item()—return raw tensors.
-
Test:
dataset = SequenceDataset(5)
feature, label = dataset # torch.tensor([0.,1.,2.]), torch.tensor(3.)
Complete Solution:
class SequenceDataset(Dataset):
def __init__(self, size: int):
self.size = size
def __len__(self):
return self.size
def __getitem__(self, idx):
feature = torch.tensor([idx, idx+1, idx+2], dtype=torch.float32)
label = torch.tensor(3 * idx + 3, dtype=torch.float32)
return feature, label
4. Common Pitfalls
- Returning Lists: getitem must return tensors, not lists (DataLoader expects tensors).
- Index Bounds: No explicit check needed—DataLoader handles 0 <= idx < len.
- Dtype Mismatch: Use torch.float32 for features, torch.float32/torch.long for labels. Test uses .item() (expects scalar tensor).
- Integer Overflow: Negligible for typical size (PyTorch tensors handle large ints).
- 2D Features: Constraints allow 1D/2D, but spec is 1D—keep simple.
- No Randomness: Deterministic generation; avoid random unless seeded.
5. Time & Space Complexity
| Aspect | Complexity | Explanation |
|---|---|---|
| Space | O(1) per sample | Only stores size; generates on-demand. Total: O(1) memory regardless of size. |
| Time (len) | O(1) | Simple attribute access. |
| Time (getitem) | O(1) | Constant tensor creation/sum. |
| DataLoader (batch size b) | O(b) per batch | Parallel generation scales linearly. |
Scalability: Handles arbitrary size (e.g., 109) without memory issues—perfect for streaming/large-scale training.