In machine learning and deep learning, processing an entire dataset at once is often impossible due to memory constraints. Instead, we use mini-batches, i.e. small, manageable chunks of data processed sequentially.
This guide explains how to implement a memory-efficient data pipeline in Python using generators to slice a dataset into mini-batches.
Understanding Generators and Slicing
To divide a list into chunks, we rely on two Python features:
- List Slicing:
list[start:end]extracts a specific portion of the data. Python handles out-of-bounds indices gracefully (e.g., if you ask for 5 items but only 3 remain, it simply returns the 3). - Generators (
yield): Instead of creating a list of lists containing all batches (which doubles memory usage), we useyieldto return one batch at a time.
Step 1: Implementing the Data Pipeline
We will create a function data_pipeline that accepts raw data and a batch size.
Memory Inefficient vs. Efficient Approach
def bad_pipeline(data, batch_size):
batches = []
for i in range(0, len(data), batch_size):
batches.append(data[i : i + batch_size])
return batches
from typing import Generator, List
def data_pipeline(data: List[List[int]], batch_size: int) -> Generator[List[List[int]], None, None]:
"""
Yields mini-batches from the dataset sequentially.
"""
for i in range(0, len(data), batch_size):
batch = data[i : i + batch_size]
yield batchStep 2: Testing the Mini-Batch Generator
To verify the logic, we will iterate through the generator. We expect the final batch to contain fewer items if the total count isn't perfectly divisible by the batch size.
if __name__ == "__main__":
dataset = [
[1, 2],
[1, 3],
[3, 5],
[2, 1],
[3, 3]
]
BATCH_SIZE = 2
print(f"Total items: {len(dataset)}")
print(f"Batch size: {BATCH_SIZE}")
print("-" * 20)
batch_generator = data_pipeline(dataset, BATCH_SIZE)
for i, batch in enumerate(batch_generator):
print(f"Batch {i+1}: {batch}")Output Validation:
Total items: 5
Batch size: 2
--------------------
Batch 1: [[1, 2], [1, 3]]
Batch 2: [[3, 5], [2, 1]]
Batch 3: [[3, 3]]Conclusion
Creating a mini-batch generator is a fundamental skill for data processing.
- Use
range(0, len(data), batch_size)to calculate start indices. - Use
data[i : i + batch_size]to slice the data safely. - Use
yieldto create a memory-efficient iterator.