DEEP LEARNING • LESSON 14

Understand the Python Code

In this lesson, we will go through the Transfer Learning Python code step by step and understand what each important line does and why we need it.

SIMPLE IDEA

Every part of the code has one job.

Load the images, load the pretrained model, freeze its knowledge, add our classifier, train it, and optionally fine-tune the model.

01

Import TensorFlow

import tensorflow as tf

This imports TensorFlow into our Python program.

We use TensorFlow to create, train, and use our neural network.

import tensorflow as tf

print(tf.__version__)

The second line simply checks which TensorFlow version is installed.

02

Load the Dataset

train_dataset = tf.keras.utils.image_dataset_from_directory(
    "images/",
    image_size=(224, 224),
    batch_size=32
)

This function reads images from our folders and creates a TensorFlow dataset.

images/
│
├── cats/
│   ├── cat1.jpg
│   └── cat2.jpg
│
└── dogs/
    ├── dog1.jpg
    └── dog2.jpg

The folder names are automatically treated as class labels.

cats → class 0
dogs → class 1
03

Why 224 × 224?

image_size=(224, 224)

Neural networks expect their input to have a consistent size. Images in our dataset could have different dimensions, so we resize them.

Original Image
1920 × 1080
      ↓
Resize
      ↓
224 × 224
      ↓
Neural Network

This makes the input shape consistent.

04

Why Batch Size = 32?

batch_size=32

Instead of sending the entire dataset into the model at once, we process a small group of images at a time.

1000 images

Batch 1 → 32 images
Batch 2 → 32 images
Batch 3 → 32 images
...
Batch 32 → remaining images

The exact number of batches depends on the dataset size. A batch makes training more manageable for memory and computation.

05

Check the Classes

print(train_dataset.class_names)

This shows the class names detected from our directories.

['cats', 'dogs']

Our model therefore needs to distinguish between two categories.

06

Load MobileNetV2

base_model = tf.keras.applications.MobileNetV2(
    weights="imagenet",
    include_top=False,
    pooling="avg"
)

This is one of the most important parts of the program.

We are not creating a completely new CNN. We are loading a model that has already been trained.

Our Program
      ↓
Load MobileNetV2
      ↓
Use Existing Knowledge
07

What Does weights="imagenet" Mean?

weights="imagenet"

This tells TensorFlow to load weights learned from the ImageNet dataset.

These weights contain learned visual patterns.

Image
  ↓
Edges
  ↓
Textures
  ↓
Shapes
  ↓
Complex Features

We reuse this knowledge instead of learning everything from the beginning.

08

What Does include_top=False Mean?

include_top=False

A pretrained model normally contains its original classification layer.

We do not want that original classifier because our task is different.

MobileNetV2

Feature Extraction
      ↓
Original ImageNet Classifier
      ↓
Removed

        ↓

Our Classifier
      ↓
Cat / Dog
09

What Does pooling="avg" Mean?

pooling="avg"

The convolutional layers produce feature maps. Average pooling summarizes those feature maps into a feature vector.

Feature Maps
     ↓
Average Pooling
     ↓
Feature Vector
     ↓
Classifier

This makes it convenient to connect the pretrained model to our Dense classification layer.

10

Freeze the Model

base_model.trainable = False

This tells TensorFlow not to update the pretrained model's weights during the first training stage.

MobileNetV2
     ↓
Frozen
     ↓
Existing knowledge stays unchanged

Dense Layer
     ↓
Trainable
     ↓
Learns cats vs dogs

This is called feature extraction.

11

Create the New Classifier

model = tf.keras.Sequential([
    base_model,
    tf.keras.layers.Dense(
        2,
        activation="softmax"
    )
])

We put the pretrained model and our new classifier together.

Image
  ↓
MobileNetV2
  ↓
Visual Features
  ↓
Dense(2)
  ↓
Cat / Dog

The number 2 is used because there are two classes.

12

Why Use Softmax?

activation="softmax"

Softmax converts the classifier output into probabilities across the classes.

Cat     → 0.90
Dog     → 0.10

Total   → 1.00

The largest probability becomes the predicted class.

13

Compile the Model

model.compile(
    optimizer="adam",
    loss="sparse_categorical_crossentropy",
    metrics=["accuracy"]
)

Optimizer: controls how trainable weights are updated.

Loss: measures how far the predictions are from the correct labels.

Accuracy: tells us the percentage of correct predictions.

14

Train the Model

model.fit(
    train_dataset,
    epochs=5
)

This starts the training process.

Because MobileNetV2 is frozen, the new classifier is the main part being trained.

Images
   ↓
Frozen MobileNetV2
   ↓
Features
   ↓
Trainable Dense Layer
   ↓
Prediction
15

What Is an Epoch?

epochs=5

One epoch means the model has gone through the training dataset once.

Epoch 1 → Dataset processed once
Epoch 2 → Dataset processed again
Epoch 3 → Dataset processed again
Epoch 4 → Dataset processed again
Epoch 5 → Dataset processed again

More epochs do not automatically mean a better model. Training too long can cause overfitting.

16

Start Fine-Tuning

base_model.trainable = True

Now we allow the pretrained model to become trainable.

But we usually should not immediately train every layer with a large learning rate.

17

Freeze Most Layers

for layer in base_model.layers[:-20]:
    layer.trainable = False

This keeps most of the pretrained model frozen.

MobileNetV2

Early Layers
    ↓
Frozen

Middle Layers
    ↓
Frozen

Last 20 Layers
    ↓
Trainable

The early layers usually contain general visual features, while later layers can be adapted more closely to our particular task.

18

Use a Small Learning Rate

optimizer=tf.keras.optimizers.Adam(
    learning_rate=0.00001
)

Fine-tuning uses a small learning rate because the pretrained weights are already useful.

Large Learning Rate
        ↓
Large Weight Changes
        ↓
Could destroy useful pretrained knowledge


Small Learning Rate
        ↓
Small Weight Changes
        ↓
Gradually Adapt Model
19

Why Compile Again?

model.compile(
    optimizer=tf.keras.optimizers.Adam(
        learning_rate=0.00001
    ),
    loss="sparse_categorical_crossentropy",
    metrics=["accuracy"]
)

After changing which layers are trainable, we recompile the model so the training configuration reflects those changes.

20

Fine-Tune the Model

model.fit(
    train_dataset,
    epochs=5
)

Now the trainable layers can slightly adjust their weights to better match our specific image problem.

Pretrained Knowledge
        ↓
Freeze Most Layers
        ↓
Train Classifier
        ↓
Unfreeze Selected Layers
        ↓
Small Learning Rate
        ↓
Fine-Tune
        ↓
Final Model
21

Understand the Whole Program

import tensorflow as tf
        ↓
Load Image Dataset
        ↓
Load MobileNetV2
        ↓
Use ImageNet Weights
        ↓
Remove Original Classifier
        ↓
Freeze Pretrained Layers
        ↓
Add New Dense Layer
        ↓
Compile
        ↓
Train
        ↓
Unfreeze Selected Layers
        ↓
Use Small Learning Rate
        ↓
Fine-Tune
22

Real-Life Example

Imagine you want to recognize two types of vehicles: cars and motorcycles.

Step 1

MobileNetV2
    ↓
Already understands visual patterns


Step 2

Your Vehicle Images
    ↓
Cars
Motorcycles


Step 3

New Classifier
    ↓
Car / Motorcycle


Step 4

Train


Step 5

Fine-Tune if necessary

You are not teaching the model what an edge or basic shape is again. You are adapting existing visual knowledge to your particular problem.

KEY TAKEAWAY

Understand the code as a pipeline.

The most important thing is to understand the relationship between the lines: the pretrained model provides visual knowledge, the new Dense layer provides your task-specific classifier, training teaches that classifier, and fine-tuning optionally adapts part of the pretrained model.

Quick Check

What does base_model.trainable = False do?

It freezes the pretrained model so its weights are not updated during the first training stage.

Why do we use Dense(2)?

Because our example has two classes: cats and dogs.

Why is the fine-tuning learning rate small?

Because we want to make small adjustments to useful pretrained weights rather than changing them aggressively.