Image classification is a central task in computer vision and artificial intelligence. From identifying everyday objects in photos to detecting diseases in medical images, custom image classifiers can drive valuable AI solutions across domains. This tutorial walks through building, training, and evaluating a custom image classification model using PyTorch, one of the most popular frameworks in deep learning.
Why Choose PyTorch for Image Classification?
PyTorch is widely regarded for its flexible architecture and dynamic computation graphs, making it well suited for rapid prototyping and research in neural networks. Its intuitive API and strong community support make it an excellent choice for vision tasks, whether you are working on a simple classifier or experimenting with cutting-edge architectures.
- Dynamic computation graphs: Modify models on the fly, which helps with debugging and experimentation.
- Rich vision library:
torchvisionprovides datasets, model architectures, and image transformations. - Industry adoption: PyTorch is widely used by researchers and organizations for real-world computer vision applications.
Getting Ready: Prerequisites and Setup
Before you begin, ensure the following:
- Basic knowledge of Python and neural networks
- PyTorch and torchvision installed (
pip install torch torchvision) - A labeled image dataset organized by class folders (such as cats vs dogs, or any custom categories)
Step 1: Data Preparation and Loading
Proper data handling is crucial for any machine learning project. Organization matters: PyTorch’s ImageFolder expects images grouped in directories named after their class labels. A common directory structure looks like this:
data/train/dogsdata/train/catsdata/val/dogsdata/val/cats
PyTorch’s torchvision.transforms module helps with preprocessing and augmentation:
import torch
from torchvision import datasets, transforms
train_transforms = transforms.Compose([transforms.Resize((128, 128)),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),])
val_transforms = transforms.Compose([transforms.Resize((128, 128)),
transforms.ToTensor(),])
train_dataset = datasets.ImageFolder('data/train', transform=train_transforms)
val_dataset = datasets.ImageFolder('data/val', transform=val_transforms)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=32, shuffle=True)
val_loader = torch.utils.data.DataLoader(val_dataset, batch_size=32)
Augmentation, such as random flips, helps prevent overfitting, especially for smaller datasets.
Step 2: Building a Convolutional Neural Network
Convolutional neural networks (CNNs) excel at processing images by learning local spatial patterns. Below is a straightforward implementation using PyTorch’s nn.Module:
import torch.nn as nn
class SimpleCNN(nn.Module):
def __init__(self, num_classes):
super(SimpleCNN, self).__init__()
self.features = nn.Sequential(nn.Conv2d(3, 16, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(16, 32, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2),)
self.classifier = nn.Sequential(nn.Flatten(),
nn.Linear(32 * 32 * 32, 128),
nn.ReLU(),
nn.Linear(128, num_classes),)
def forward(self, x):
x = self.features(x)
x = self.classifier(x)
return x
Set num_classes to match your dataset. For cats vs dogs, use num_classes = 2.
Step 3: Training the Model
With your data and model ready, it's time to configure the training process. Use CrossEntropyLoss for multi-class classification and Adam optimizer for adaptive learning rates. Move your model to GPU if available for faster training.
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = SimpleCNN(num_classes=2).to(device)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
The training loop iterates over batches, computes loss, performs backpropagation, and updates model weights:
for epoch in range(10):
model.train()
running_loss = 0.0
for images, labels in train_loader:
images, labels = images.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model(images)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
print(f'Epoch {epoch + 1}, Loss: {running_loss / len(train_loader):.4f}')
Monitor training loss to ensure your model is learning. If loss plateaus or increases, revisit learning rate or model complexity.
Step 4: Evaluating Model Performance
Evaluation on a separate validation set provides an unbiased measure of model performance. Compute classification accuracy as a starting point:
model.eval()
total = 0
correct = 0
with torch.no_grad():
for images, labels in val_loader:
images, labels = images.to(device), labels.to(device)
outputs = model(images)
_, predicted = torch.max(outputs, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f'Validation Accuracy: {100 * correct / total:.2f}%')
For deeper insights, consider confusion matrices and per-class accuracy to identify strengths and weaknesses of your classifier.
Step 5: Making Predictions on New Images
After training, you can use your model to classify new images. Ensure images receive the same preprocessing as training data:
from PIL import Image
image = Image.open('test.jpg')
image = val_transforms(image).unsqueeze(0).to(device)
model.eval()
with torch.no_grad():
output = model(image)
_, predicted = torch.max(output, 1)
print(f'Predicted class: {train_dataset.classes[predicted.item()]}')
This workflow applies to single images, but can be adapted for batch predictions or deployment pipelines.
Step 6: Enhancing Accuracy with Transfer Learning
If your dataset is small or your base model underperforms, transfer learning can help. Leveraging pretrained models such as ResNet or VGG allows you to reuse visual features learned from massive datasets like ImageNet, often boosting accuracy and reducing training time.
from torchvision import models
import torch.nn as nn
model = models.resnet18(pretrained=True)
for param in model.parameters():
param.requires_grad = False
model.fc = nn.Linear(model.fc.in_features, num_classes)
model = model.to(device)
With transfer learning, only the classifier's final layer is trained, which adapts the model to your specific classes. You can also choose to fine-tune deeper layers for further improvements.
Best Practices for Custom Image Classification Projects
- Use data augmentation (random flips, rotations, color jitter) to expand your dataset and reduce overfitting.
- Track both training and validation metrics to catch overfitting early.
- Experiment with different architectures, optimizers, and learning rates.
- Save trained models with
torch.save(model.state_dict(), 'model.pth')for later use or deployment. - Deploy models with frameworks like TorchServe or convert them to ONNX for integration with production systems.
Summary and Next Steps
Building a custom image classifier with PyTorch involves preparing and augmenting your data, designing a suitable CNN or adapting a pretrained model, and systematically training and evaluating results. This workflow forms the backbone for tackling a wide range of computer vision challenges using AI. As you gain experience, explore advanced techniques like data balancing, fine-tuning, or automated hyperparameter optimization to further improve your models.