Hello! Welcome to your next lesson in our Computer Vision module.
In our last session, we successfully built and trained our first Convolutional Neural Network from scratch using PyTorch. We used the standard CIFAR-10 dataset provided by torchvision, which was a great way to understand the end-to-end training workflow.
Today, we'll address a critical aspect of real-world machine learning: data preparation. It's rare that your project's data will be as neatly packaged as CIFAR-10. Your goal for this lesson is to prepare image datasets using DataLoader and apply data augmentation.
We will cover two main topics:
- Creating Custom Datasets: You'll learn how to load images from a folder structure and labels from a file (like a CSV), which is a common scenario in many projects.
- Data Augmentation: You'll learn how to artificially increase the size and diversity of your training data by applying random transformations to your images. This is one of the most effective techniques for improving model performance and preventing overfitting.
Let's begin by learning how to move beyond the built-in datasets.
1. Handling Custom Datasets with PyTorch
In the last lesson, loading CIFAR-10 was a single line of code. But what if your images are in a folder, and their labels are listed in a separate CSV file? PyTorch provides a flexible solution for this: the torch.utils.data.Dataset class.
To handle a custom dataset, you create a new class that inherits from Dataset and override three essential methods:
__init__(self, ...): The constructor. This is where you'll do one-time setup, like loading the CSV file with annotations, defining the root directory of your images, and preparing the transformations to be applied.__len__(self): This method must return the total number of samples in your dataset. PyTorch uses this to know the dataset's size.__getitem__(self, idx): This is the core method. Given an indexidx, it is responsible for loading theidx-th sample from your disk (e.g., an image), retrieving its corresponding label, applying any necessary transformations, and returning the sample (usually as a(image, label)tuple).
This approach is memory-efficient because images are loaded from the disk one by one as they are needed, rather than all at once.
Let's watch a video that demonstrates how to implement this from scratch.
How to build custom Datasets for Images in Pytorch
Aladdin Persson provides a clear, concise walkthrough of creating a custom Dataset class to load images of cats and dogs. Pay close attention to how the CSV file is used within the class to link image files to their labels.
Watch the segment from 01:15 to 04:40. Focus on the implementation of the __init__, __len__, and __getitem__ methods within the CatsAndDogsDataset class.
To reinforce this fundamental concept, let's review the official PyTorch documentation, which provides another excellent example.
Writing Custom Datasets, DataLoaders and Transforms
This official PyTorch tutorial, 'Writing Custom Datasets, DataLoaders and Transforms', walks through creating a dataset for facial landmarks. It's a great textual resource that solidifies the structure of a custom Dataset class.
Read the section titled 'Dataset class'. It explains the abstract Dataset class and shows a complete implementation for a facial landmarks dataset. Notice the similarity in structure to the video you just watched.
2. From Custom Dataset to DataLoader
Once you have your custom Dataset class, using it with DataLoader is exactly the same as with a built-in dataset. The DataLoader wraps your Dataset and provides an iterator that serves data in batches, shuffles it every epoch, and can even use multiple CPU cores to load data in parallel, preventing data loading from becoming a bottleneck during training.
Let's see this in action by continuing the video from before.
How to build custom Datasets for Images in Pytorch
Now, let's see how the custom CatsAndDogsDataset is instantiated and passed to a DataLoader to prepare for training.
Watch from 04:40 to 07:14. Observe how a Dataset object is created and then used to initialize train_loader and test_loader with specific batch sizes and shuffle settings.
The key parameters for DataLoader that you'll frequently use are:
dataset: TheDatasetobject you created.batch_size: The number of samples to load per batch.shuffle: Set toTruefor the training loader to shuffle the data at the start of every epoch. This is crucial for effective training. It's typicallyFalsefor the validation/test loader.num_workers: The number of subprocesses to use for data loading. Setting this to a value greater than 0 can significantly speed up training, as data is loaded in parallel on the CPU while the GPU is busy with computations. A good starting point isnum_workers=2ornum_workers=4.
For a more detailed breakdown of these parameters, you can refer to the guide "A Guide to the DataLoader Class and Abstractions in PyTorch" (LINK), particularly the section on Data Loading in PyTorch.
3. Data Augmentation: Getting More from Your Data
One of the biggest challenges in deep learning is getting enough labeled data. Data augmentation is a powerful and widely used technique that helps solve this problem by creating modified copies of your existing data.
For an image classification task, a rotated cat is still a cat. So is a slightly darker cat, or a horizontally flipped cat. By applying these random transformations during training, we teach the model to be robust to such variations, which improves its ability to generalize to new, unseen images.

PyTorch's torchvision.transforms module provides a rich library of functions for this purpose. We can chain multiple transformations together using transforms.Compose.
Common augmentation transforms include:
RandomResizedCrop: Crops a random part of the image and resizes it to a fixed size. This helps the model focus on different parts of the object.RandomHorizontalFlip: Flips the image horizontally with a given probability (usually 50%).RandomRotation: Rotates the image by a random angle.ColorJitter: Randomly changes the brightness, contrast, saturation, and hue of an image.
Let's watch a practical demonstration of how to apply these augmentations.
Pytorch Data Augmentation using Torchvision
In this video, Aladdin Persson visually demonstrates the effect of various data augmentation techniques. This will give you an intuitive understanding of what each transform does.
Watch this video from the beginning until 09:12. Pay attention to: The motivation for data augmentation (00:00 - 00:35). How transforms.Compose is used to chain transformations (01:26 - 02:22). The visualization of different transforms like RandomHorizontalFlip, ColorJitter, RandomCrop, and RandomRotation (02:22 - 06:00). The concept of normalization (transforms.Normalize) and why it's an important final step after converting the image to a tensor (06:00 - 07:48).
4. Putting It All Together: A Practical Workflow
Now let's combine everything into a coherent workflow. When preparing data, you will typically create two separate transformation pipelines:
- Training Transforms: This pipeline includes random augmentations (
RandomResizedCrop,RandomHorizontalFlip, etc.) to create variety and make the model robust. - Validation/Test Transforms: This pipeline includes only the necessary preprocessing steps (
Resize,CenterCrop,ToTensor,Normalize). We do not use random augmentations here because we want a consistent, deterministic evaluation of our model's performance on the validation and test sets.
Here is what a complete setup might look like in code:
import torch
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms
from PIL import Image
import pandas as pd
import os
# 1. Define transformation pipelines
# For training: include data augmentation
train_transforms = transforms.Compose([
transforms.Resize((256, 256)),
transforms.RandomCrop(224),
transforms.RandomHorizontalFlip(p=0.5),
transforms.ColorJitter(brightness=0.2, contrast=0.2),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
# For validation/testing: no random augmentation
val_transforms = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
# 2. Define your custom Dataset class
class CustomImageDataset(Dataset):
def __init__(self, annotations_file, img_dir, transform=None):
self.img_labels = pd.read_csv(annotations_file)
self.img_dir = img_dir
self.transform = transform
def __len__(self):
return len(self.img_labels)
def __getitem__(self, idx):
img_path = os.path.join(self.img_dir, self.img_labels.iloc[idx, 0])
image = Image.open(img_path).convert("RGB") # Ensure image is RGB
label = self.img_labels.iloc[idx, 1]
if self.transform:
image = self.transform(image)
return image, label
# 3. Create Dataset instances with the appropriate transforms
# Assuming you have 'train_labels.csv' and 'val_labels.csv'
train_dataset = CustomImageDataset(
annotations_file='path/to/train_labels.csv',
img_dir='path/to/images',
transform=train_transforms
)
val_dataset = CustomImageDataset(
annotations_file='path/to/val_labels.csv',
img_dir='path/to/images',
transform=val_transforms
)
# 4. Create DataLoaders
train_loader = DataLoader(dataset=train_dataset, batch_size=32, shuffle=True, num_workers=2)
val_loader = DataLoader(dataset=val_dataset, batch_size=32, shuffle=False, num_workers=2)
This structured approach ensures that your model learns from a diverse set of augmented images while being evaluated on a consistent set of validation images.
Conclusion
Great work! You have now mastered the essential skills for preparing image data for any computer vision task in PyTorch. This is a huge step toward building professional, real-world AI applications.
Key Takeaways:
- You can handle any custom image dataset by creating a class that inherits from
torch.utils.data.Datasetand implementing__len__and__getitem__. - The
DataLoaderworks seamlessly with customDatasetobjects to provide efficient batching, shuffling, and parallel data loading. - Data augmentation is a critical technique for improving model generalization and reducing overfitting. It is applied during training but not during validation or testing.
torchvision.transforms.Composeis used to create powerful data processing pipelines for both augmentation and standard preprocessing.
Preview of the Next Lesson:
So far, we've trained our own CNNs from scratch. While this is great for learning, state-of-the-art results are often achieved by standing on the shoulders of giants. In the next lesson, "Use transfer learning with pre-trained models (ResNet, VGG)," you will learn how to take powerful models that have been pre-trained on massive datasets (like ImageNet) and adapt them for your own tasks. This is a highly effective and widely used shortcut to building high-performance models.