Skip to main content

Transfer Learning and Fine-Tuning with ResNet-18 on CIFAR-10


1. Learning Objectives

By completing this notebook, you will understand:
  • How to load the CIFAR-10 dataset using torchvision
  • How to preprocess images for a pretrained model
  • How to load a pretrained ResNet-18
  • How to replace the final classification layer
  • How to freeze pretrained layers
  • How to train only the new classifier
  • How to unfreeze a pretrained block
  • How to fine-tune a pretrained model
  • How to evaluate classification accuracy
  • How to inspect model predictions

Key concepts


2. Project Workflow

The complete workflow is:

3. Import Libraries

We first import PyTorch, neural-network components, optimizers, datasets, transformations, pretrained models, and data loaders.

Explanation

  • torch provides the main PyTorch functionality.
  • torch.nn provides neural-network layers and loss functions.
  • torch.optim provides optimizers such as Adam.
  • datasets provides datasets such as CIFAR-10.
  • transforms provides image preprocessing operations.
  • models provides pretrained models such as ResNet-18.
  • DataLoader loads data in batches during training.

4. Select the Device

PyTorch can train the model using either a GPU or CPU.

Explanation

checks whether a CUDA-enabled NVIDIA GPU is available. If CUDA is available:
is selected. Otherwise:
is selected.

Why this matters

GPU training is usually much faster for deep-learning models.

5. Define Image Transformations

The pretrained ResNet-18 expects images with a format similar to the images it was originally trained on.

Explanation

Resize

CIFAR-10 images are only:
We resize them to:
because ResNet-18 was designed around ImageNet-sized inputs.

ToTensor

converts the image into a PyTorch tensor. It also converts pixel values into approximately:

Normalize

normalizes the RGB channels using the mean and standard deviation commonly used for ImageNet-pretrained models.

Simple idea


6. Load CIFAR-10

Now we download and load the training and testing datasets.

Explanation

CIFAR10 contains:
  • 50,000 training images
  • 10,000 test images
  • 10 classes
  • RGB color images
The 10 classes are:

Important parameters

loads the training dataset.
loads the test dataset.
downloads the dataset automatically if it is not already available.
applies our preprocessing pipeline. You do not need to manually download CIFAR-10. The dataset will be stored in:

7. Create DataLoaders

The dataset is now converted into batches using DataLoader.

Explanation

batch_size=64

Instead of processing all images at once, the model processes:
at a time.

shuffle=True

The training images are shuffled between epochs. This helps prevent the model from learning based on the original ordering of the dataset.

Test loader

We normally don’t need to shuffle test data because we are only evaluating the model.

Check dataset size

Expected output:

8. Load Pretrained ResNet-18

This is the main transfer learning step.

What is ResNet-18?

ResNet-18 is a convolutional neural network containing residual blocks. The pretrained model has already learned useful visual features such as:
Instead of training all these features from scratch, we reuse them.

What does weights="DEFAULT" mean?

It loads pretrained weights rather than randomly initializing the network. Conceptually:
This is called transfer learning.

9. Understand the Original ResNet Output

The original ResNet-18 was trained on ImageNet. ImageNet classification contains:
Therefore, the original final layer produces:
But CIFAR-10 contains only:
Therefore, we need to replace the final classification layer.

10. Replace the Final Layer

Explanation

The original layer is conceptually:
We replace it with:

model.fc.in_features

This gives us the number of input features expected by the original fully connected layer. We reuse that value instead of manually specifying it.

10

This represents the number of CIFAR-10 classes.

New architecture


11. Move the Model to the Device

Explanation

This moves the model to either:
or:
depending on the device selected earlier. The input tensors must also be moved to the same device during training.

12. Freeze the Pretrained Layers

Initially, we don’t want to modify the pretrained ResNet layers.

Explanation

requires_grad=False means:
Do not calculate/update gradients for this parameter.
So the pretrained ResNet acts as a fixed feature extractor. Conceptually:

13. Unfreeze the Final Classifier

We need the new final layer to learn the CIFAR-10 classification task.
Now:

Why?

The pretrained backbone already contains useful visual knowledge. The new classifier has never seen CIFAR-10, so it needs to learn.

14. Define the Loss Function

For a multi-class classification problem, we use cross-entropy loss.

What does it do?

It compares:
and produces a loss value. For example:
If the model predicts the correct class with high confidence:

15. Define the Optimizer

Initially, only the final classifier is trainable.

Explanation

Adam updates the trainable weights to reduce the loss. The optimizer receives:
because only the final layer is currently trainable. The learning rate is:

Simple idea


16. Train the Final Classifier

We initially train for three epochs.

16.1 Set Training Mode

This tells PyTorch that the model is being used for training. This is important for layers whose behavior changes between training and evaluation.

16.2 Reset Accuracy Counters

These variables track how many predictions are correct.

16.3 Loop Through Batches

Each iteration provides:
For example:
because our batch size is 64.

16.4 Move Data to the Device

The data must be on the same device as the model.

16.5 Clear Previous Gradients

PyTorch accumulates gradients by default. We clear the previous gradients before calculating new ones.

16.6 Forward Pass

The images pass through ResNet. Conceptually:
The output shape is approximately:
because:

16.7 Calculate Loss

The loss measures how different the predictions are from the correct labels.

16.8 Backpropagation

PyTorch calculates gradients for the trainable parameters. Because the ResNet backbone is frozen:

16.9 Update Parameters

Adam uses the calculated gradients to update the trainable weights.

16.10 Get Predictions

The model produces 10 scores for every image. For example:
argmax(1) selects the class with the highest score:

16.11 Calculate Accuracy

For example:
Accuracy:

16.12 Print Training Results

Example:
The exact values will vary.

17. Fine-Tuning

Now we move from transfer learning to fine-tuning. Initially:
Now we want some pretrained features to adapt to CIFAR-10.

18. Unfreeze layer4

Explanation

ResNet-18 contains several major layers:
We keep the earlier layers frozen and only unfreeze:

Why layer4?

Earlier layers generally learn more generic features:
Later layers learn more task-specific visual features:
Therefore, adapting the final ResNet block is a simple and efficient fine-tuning strategy.

19. Create a Smaller Learning Rate

Explanation

The learning rate is reduced from:
to:
This is important because the pretrained layers already contain useful knowledge. We don’t want to make large updates that could destroy the learned features.

Trainable parameters

At this point:
The filter() expression selects only parameters where:

20. Fine-Tune the Model

We train for two additional epochs.

What changed?

Previously:
Now:
So the pretrained ResNet features can adapt to CIFAR-10.

21. Transfer Learning vs Fine-Tuning

The project contains both concepts.

Transfer learning

We reuse knowledge from ImageNet.

Fine-tuning

We allow some pretrained features to adapt to the new task.

Easy interview explanation

Transfer learning means reusing a pretrained model for a new task, while fine-tuning means updating some of those pretrained layers so their features adapt to the new dataset.

22. Evaluate the Model

After training, we evaluate the model on the test dataset.

23. Switch to Evaluation Mode

This tells PyTorch that we are evaluating rather than training. It changes the behavior of certain layers such as:
  • Dropout
  • Batch Normalization

24. Disable Gradient Calculation

During testing, we don’t need gradients. This:
  • reduces memory usage
  • reduces computation
  • makes inference faster
We only need predictions.

25. Calculate Test Predictions

The model produces scores for each of the 10 classes. argmax(1) selects the class with the highest score.

26. Calculate Test Accuracy

Finally:
Example output:
The exact accuracy can vary depending on hardware, training time, PyTorch/torchvision versions, and training configuration.

27. Display Some Predictions

We can inspect actual and predicted classes.
These class names correspond to the CIFAR-10 labels.

28. Get a Batch of Test Images

Explanation

creates an iterator over the test batches.
gets the first batch. So we obtain:

29. Generate Predictions

The model predicts the class for each image.

30. Print Actual vs Predicted

Example:
This lets us quickly see how the model is performing on individual examples.

31. Complete Code

The following is the complete beginner-friendly version that can be placed into a single notebook.

32. What Happens During Prediction?

The complete prediction process is:
For example:

33. Important Parameters to Remember


34. Final Mental Model

Remember the project using this simple sequence:

One-Sentence Summary

Use a pretrained ResNet-18 as a feature extractor, train a new CIFAR-10 classifier, then fine-tune the final ResNet block with a smaller learning rate.