CadetX
CX Learn | Complete Neural Networks Guide
TensorFlow · Keras
CadetX logo CadetX CX Learn
NN-101 · Module 11 Intermediate about 40 minutes 7 Lessons Prereq: Modules 1 to 10

Transfer Learning & Pretrained Models

Training a big network from scratch can take millions of examples and weeks of computing. Transfer learning lets you skip most of that by starting from a model that has already learned from a huge dataset, and adapting it to your own problem. It's how most real-world deep learning projects are built today.

  • Level: Intermediate
  • Time: about 40 minutes
  • Needs: Modules 1 to 10

By the end of this module you will be able to

  • Explain what transfer learning is and why it works
  • Explain the difference between feature extraction and fine-tuning
  • Choose a strategy based on how much data you have and how similar it is
  • Find pretrained models for images and text
  • Build an image classifier on top of a pretrained model in Keras
  • Recognise when transfer learning won't help

11.1What is transfer learning?

Transfer learning means taking a model trained on one task and reusing what it learned for a different, related task.

You already do this

If you can drive a car, learning to drive a van takes hours, not months. You don't relearn steering, braking or road signs; you just adjust to the bigger size. Your "driving knowledge" transfers. In the same way, a network that has learned to recognise a thousand kinds of objects already knows about edges, textures, shapes and parts. It just needs a little extra training to recognise your objects.

This works because of what you learned in Module 8: the early layers of a CNN learn general features (edges, colours, textures) that are useful for almost any image task. Only the last layers are specific to the original task.

Training from scratchTransfer learning
Data neededOften tens of thousands of labelled examples or moreOften just hundreds, sometimes fewer
Training timeHours to weeks, often on expensive GPUsMinutes to hours
Typical accuracy with little dataPoor: overfits easilyUsually much better

11.2Feature extraction and fine-tuning

There are two main ways to reuse a pretrained model. Both start the same way: remove the model's original output layer (its "head") and add a new one for your classes.

Three ways to train. Training from scratch trains every layer from random weights. Feature extraction keeps the pretrained layers frozen and trains only a new output head. Fine-tuning also unfreezes the top pretrained layers and trains them slowly.From scratchEarly layers: edgesMiddle: shapesDeeper: partsTop: objectsNew head: your classesEverything learns from randomFeature extractionEarly layers: edges🔒Middle: shapes🔒Deeper: parts🔒Top: objects🔒New head: your classesOnly the new head learnsFine-tuningEarly layers: edges🔒Middle: shapes🔒Deeper: partsTop: objectsNew head: your classesTop layers adjust gentlyTrainedTrained slowly (tiny learning rate)Frozen
Figure 1. Which layers learn in each strategy. Frozen layers keep the weights they learned on the big dataset. A frozen layer is set with trainable = False in Keras.
StrategyWhat you doWhen to use it
Feature extractionFreeze the whole pretrained model and train only the new head. The pretrained model acts as a fixed "feature finder"Small datasets; fast and hard to overfit
Fine-tuningAfter training the head, unfreeze some of the top pretrained layers and train them with a very small learning rateMore data, or your images differ a bit from the original ones

Two golden rules of fine-tuning

1. Train the new head first. A new head starts with random weights, so its first big, messy gradients could wreck the carefully learned pretrained weights. 2. Use a tiny learning rate (for example 0.00001) when fine-tuning, so the pretrained knowledge is adjusted gently, not overwritten.

11.3Choosing a strategy

The right approach depends on two questions: how much labelled data do you have? And how similar is it to what the model was originally trained on?

Try it: transfer learning advisor

11.4Where to find pretrained models

SourceWhat you'll find
Keras ApplicationsPopular image models, pretrained on ImageNet, in one line: MobileNetV2, EfficientNet, ResNet50, VGG16 and more
Hugging FaceHundreds of thousands of pretrained models for text, images and audio, including BERT-style and GPT-style Transformers (Module 10)
TensorFlow Hub / Kaggle ModelsReady-to-use models for many tasks
PyTorch Hub, torchvisionPretrained models for PyTorch users
ModelSizeGood for
MobileNetV2Small (about 3.5 million weights)Fast; phones and laptops; a great first choice
EfficientNetSmall to large familyStrong accuracy for its size
ResNet50About 25 million weightsA reliable, well-understood workhorse

Transfer learning isn't just for images. In language, almost every project today starts from a pretrained Transformer and fine-tunes it, for example to sort support emails or analyse reviews. That's how LLMs like ChatGPT and Claude are built too: a huge pretrained model, then further training for specific behaviour.

11.5Transfer learning in Keras

Here's a complete, real-world template: an image classifier built on MobileNetV2. Put your images in one folder per class (for example photos/cracked and photos/ok), and it trains in two stages: first the new head, then fine-tuning.

transfer_mobilenet.py
# Run this in Google Colab or on your own computer (it downloads the pretrained weights)
import keras
from keras import layers

# 1. Load MobileNetV2, pretrained on over a million ImageNet photos, minus its top layer
base = keras.applications.MobileNetV2(
    input_shape=(160, 160, 3), include_top=False, weights="imagenet")
base.trainable = False                          # freeze its 2.2 million weights

# 2. Load YOUR images: one folder per class, e.g. photos/cracked, photos/ok
train_ds = keras.utils.image_dataset_from_directory(
    "photos", validation_split=0.2, subset="training", seed=1,
    image_size=(160, 160), batch_size=32)
val_ds = keras.utils.image_dataset_from_directory(
    "photos", validation_split=0.2, subset="validation", seed=1,
    image_size=(160, 160), batch_size=32)

# 3. Add a small new head for your classes
inputs = keras.Input(shape=(160, 160, 3))
x = keras.applications.mobilenet_v2.preprocess_input(inputs)   # same scaling as ImageNet
x = base(x, training=False)
x = layers.GlobalAveragePooling2D()(x)
x = layers.Dropout(0.2)(x)
outputs = layers.Dense(len(train_ds.class_names), activation="softmax")(x)
model = keras.Model(inputs, outputs)

# 4. Stage 1: train only the new head
model.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"])
model.fit(train_ds, validation_data=val_ds, epochs=10)

# 5. Stage 2: fine-tune the top layers of the base with a tiny learning rate
base.trainable = True
for layer in base.layers[:-30]:                 # keep the early layers frozen
    layer.trainable = False
model.compile(optimizer=keras.optimizers.Adam(1e-5),
              loss="sparse_categorical_crossentropy", metrics=["accuracy"])
model.fit(train_ds, validation_data=val_ds, epochs=10)

Run this in Google Colab

This code downloads the pretrained weights and needs your own folder of images, so we haven't shown output here. In Colab, upload a zip of your folders, unzip it, and run the code. A GPU (Runtime → Change runtime type) makes it much faster. With a few hundred images per class of everyday objects, this approach often reaches high accuracy within a few epochs.

Reading the code

  • include_top=False removes MobileNetV2's original 1,000-class output layer.
  • base.trainable = False freezes it for stage 1 (feature extraction).
  • preprocess_input scales your images exactly the way the original training images were scaled. Forgetting this is a very common mistake.
  • Stage 2 unfreezes only the top 30 layers, and uses a learning rate of 0.00001.

11.6When transfer learning doesn't help

Transfer learning works best when the pretrained model learned from a large, varied dataset. It helps much less if the original training data was small or narrow. Here's a real experiment: we trained a small CNN on handwritten digits 0 to 4, then reused it to learn digits 5 to 9 from just 25 images.

transfer_digits.py
import os
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
import numpy as np
from sklearn.datasets import load_digits
import keras
from keras import layers

X, y = load_digits(return_X_y=True)
X = (X / 16.0).reshape(-1, 8, 8, 1)

# The "big" task: digits 0-4, with plenty of data (about 900 images)
big = y < 5
X_big, y_big = X[big], y[big]

# The NEW task: digits 5-9, with only 5 labelled images of each
rng = np.random.default_rng(0)
new_idx = np.where(y >= 5)[0]
train_idx = np.concatenate([rng.choice(new_idx[y[new_idx] == d], 5, replace=False)
                            for d in range(5, 10)])
test_idx = np.setdiff1d(new_idx, train_idx)
X_small, y_small = X[train_idx], y[train_idx] - 5
X_test, y_test = X[test_idx], y[test_idx] - 5

def feature_extractor():
    return keras.Sequential([
        keras.Input(shape=(8, 8, 1)),
        layers.Conv2D(32, 3, padding="same", activation="relu"),
        layers.MaxPooling2D(2),
        layers.Conv2D(64, 3, padding="same", activation="relu"),
        layers.Flatten(),
    ], name="features")

def with_new_head(base):
    model = keras.Sequential([base, layers.Dense(5, activation="softmax")])
    model.compile(optimizer=keras.optimizers.Adam(1e-3),
                  loss="sparse_categorical_crossentropy", metrics=["accuracy"])
    return model

# 1. Pretrain on the big task
keras.utils.set_random_seed(0)
base = feature_extractor()
pre = keras.Sequential([base, layers.Dense(5, activation="softmax")])
pre.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"])
pre.fit(X_big, y_big, epochs=30, verbose=0)
pretrained_weights = base.get_weights()

# 2. Three ways to learn the new task from just 25 images
results = {}
keras.utils.set_random_seed(1)
scratch = with_new_head(feature_extractor())                  # a) start from nothing
scratch.fit(X_small, y_small, epochs=100, verbose=0)
results["From scratch"] = scratch.evaluate(X_test, y_test, verbose=0)[1]

keras.utils.set_random_seed(1)
frozen_base = feature_extractor(); frozen_base.set_weights(pretrained_weights)
frozen_base.trainable = False                                 # b) freeze the base
frozen = with_new_head(frozen_base)
frozen.fit(X_small, y_small, epochs=100, verbose=0)
results["Feature extraction (frozen)"] = frozen.evaluate(X_test, y_test, verbose=0)[1]

frozen_base.trainable = True                                  # c) then fine-tune it all
fine = keras.Sequential([frozen_base, frozen.layers[-1]])
fine.compile(optimizer=keras.optimizers.Adam(1e-4),           # much smaller learning rate
             loss="sparse_categorical_crossentropy", metrics=["accuracy"])
fine.fit(X_small, y_small, epochs=30, verbose=0)
results["Fine-tuned"] = fine.evaluate(X_test, y_test, verbose=0)[1]

print(f"Training images for the new task: {len(X_small)}  |  Test images: {len(X_test)}")
for name, acc in results.items():
    print(f"{name:28} test accuracy = {acc:.3f}")
Output
Training images for the new task: 25  |  Test images: 871
From scratch                 test accuracy = 0.931
Feature extraction (frozen)  test accuracy = 0.892
Fine-tuned                   test accuracy = 0.894

What the output tells us

  • Training from scratch won (93.1%), and both transfer approaches did a little worse (89%).
  • Why? The "pretrained" model only ever saw about 900 tiny 8 × 8 images of five digits. Its features were too narrow to beat learning afresh, and digits are simple enough to learn from 25 examples anyway.
  • Compare that with MobileNetV2, which learned from over a million varied photos. Its features are general enough to help with almost any photo task.
Transfer learning helps most when…It may not help when…
The pretrained model learned from a huge, varied datasetThe source dataset was small or narrow
Your data is similar in kind (e.g. photos to photos)Your data is completely different (e.g. photos to audio)
You have little labelled dataYou already have huge amounts of labelled data

The lesson: always compare against a baseline, just as you did in the Machine Learning track. Don't assume a technique helps; test it.

SummaryKey takeaways

  • Transfer learning reuses a model trained on a big dataset for a new, related task.
  • It works because early layers learn general features (edges, textures, shapes).
  • Feature extraction: freeze the pretrained model, train a new head. Best for small datasets.
  • Fine-tuning: then unfreeze top layers and train them with a tiny learning rate. Train the head first.
  • Choose based on how much data you have and how similar it is to the original data.
  • Find models in Keras Applications and Hugging Face. Use the model's own preprocess_input.
  • Transfer helps most when the source is large and varied; always compare with a baseline.

Check your understanding

Your neural networks roadmap

  1. 01
    Introduction to Neural NetworksWhat neural networks are and how they work
  2. 02
    The Perceptron and the Artificial NeuronBuild a single neuron from scratch
  3. 03
    Activation FunctionsSigmoid, tanh, ReLU and softmax
  4. 04
    Loss Functions and Gradient DescentHow networks measure and reduce error
  5. 05
    BackpropagationHow every weight learns its share of the blame
  6. 06
    Building Networks with KerasYour first deep learning library
  7. 07
    Training Better NetworksOverfitting, dropout, batch normalisation, early stopping
  8. 08
    Convolutional Neural NetworksTeaching computers to see
  9. 09
  10. 10
    Transformers and AttentionThe architecture behind ChatGPT and Claude
  11. 11
    Transfer Learning and Pretrained ModelsYou are here
  12. 12
    Capstone ProjectBuild and present a deep learning project