Transfer Learning Using Feature Extraction In Deep Learning

Nutan
7 min readJan 21, 2023

--

In this blog, we will see the example of transfer learning using feature extraction. We will take the convolutional base of a previously-trained network for new data set, then we will training a new classified on top of the ouput. In this blog we will use VGG16 pre-trained model as convolution base.

What is Transfer Learning?

Normally, very few people train an entire Convolutional Network from scratch, because we don’t have sufficient dataset size.

Transfer learning is a method for feature representation from a pre-trained model that we don’t need to train a new model from scratch. A pre-trained network is simply a saved network previously trained on a huge dataset, typically on a large-scale image classification task. We can use pre-trained model, which is trained on ImageNet(ImageNet, which contains 1.2 million images with 1000 categories). ImageNet contains many animal classes, including different species of cats and dogs. The weights obtained from the models can be reused in other computer vision tasks.

There ate two main Transfer Learning methods are:

Feature extraction

In feature extraction, we take a ConvNet pretrained on ImageNet, remove the last fully-connected layer (this layer’s outputs are the 1000 class scores for a different task like ImageNet), then treat the rest of the ConvNet as a fixed feature extractor for the new dataset. These features are then run through a new classifier, which is trained from scratch.

It is called feature extraction because we use the pre-trained CNN as a fixed feature-extractor, and only change the output layer.

Created by Nutan

Fine-tuning

The fine-tuning strategy is to not only replace and retrain the classifier on top of the ConvNet on the new dataset, but to also fine-tune the weights of the pretrained network by continuing the backpropagation.

In this blog we will use VGG16 pre-trained model as convolution base. So first learn more about VGG16.

What is VGG16?

VGG16 Architecture

Source

We are using VGG16 as convolution base network, which is trained on ImageNet, then we will add new classifier on top of these features.

Instantiate the VGG16 model:

The VGG16 model, among others, comes pre-packaged with Keras. We can import it from the keras.applications module.

Note: each Keras Application expects a specific kind of input preprocessing. For VGG16, call tf.keras.applications.vgg16.preprocess_input on your inputs before passing them to the model.

`vgg16.preprocess_input` will convert the input images from RGB to BGR,
then will zero-center each color channel with respect to the ImageNet dataset, without scaling.

VGG16(include_top=True, weights=’imagenet’, input_tensor=None, input_shape=None, pooling=None, classes=1000, classifier_activation=’softmax’)

Args:
include_top: whether to include the 3 fully-connected layers at the top of the network.

weights: one of `None` (random initialization), ‘imagenet’ (pre-training on ImageNet), or the path to the weights file to be loaded.

input_tensor: optional Keras tensor (i.e. output of `layers.Input()`) to use as image input for the model.

input_shape: optional shape tuple, only to be specified
if `include_top` is False (otherwise the input shape has to be `(224, 224, 3)` (with `channels_last` data format) or `(3, 224, 224)` (with `channels_first` data format). It should have exactly 3 input channels, and width and height should be no smaller than 32. E.g. `(200, 200, 3)` would be one valid value.

pooling: Optional pooling mode for feature extraction
when `include_top` is `False`.
— `None` means that the output of the model will be
the 4D tensor output of the
last convolutional block.
— `avg` means that global average pooling
will be applied to the output of the
last convolutional block, and thus
the output of the model will be a 2D tensor.
— `max` means that global max pooling will
be applied.

classes: optional number of classes to classify images
into, only to be specified if `include_top` is True, and
if no `weights` argument is specified.

classifier_activation: A `str` or callable. The activation function to use
on the “top” layer. Ignored unless `include_top=True`. Set
`classifier_activation=None` to return the logits of the “top” layer.
When loading pretrained weights, `classifier_activation` can only
be `None` or `”softmax”`.

Returns:
A `keras.Model` instance.

Import tensorflow and check version of tensorflow

We will use tensorflow module in this blog, so let us import the tensorflow and check the version of tensorflow.

import tensorflow as tf
from tensorflow import keras

Check the tensorflow version

tf.__version__

Output:’2.11.0'

Let us Visualize the our data set

Declare the image path

img_path = '/INPUT-FOLDER/cats_and_dogs_small/test/cats/cat.1700.jpg'
img_path

Preprocess the image into a 4D tensor

import numpy as np
from tensorflow.keras.utils import load_img, img_to_array
img = load_img(img_path, target_size=(150, 150))
print(img)

Output: <PIL.Image.Image image mode=RGB size=150x150 at 0x7F1CAD481110>

img_to_tensor = img_to_array(img)
img_to_tensor = np.expand_dims(img_to_tensor, axis=0)
img_to_tensor /= 255.
print(img_to_tensor.shape)

Output: (1, 150, 150, 3)

import matplotlib.pyplot as plt

plt.imshow(img_to_tensor[0])
plt.show()

Output:

Instantiate the VGG16 model:

from tensorflow.keras.applications import VGG16

We are passing three arguments to the VGG16() model:

weights: to specify which weight checkpoint to initialize the model

include_top: include-top refers to including or not the densely-connected classifier on top of the network. By default, this densely-connected classifier would correspond to the 1000 classes from ImageNet. We will use our own classifier, so no need to include it.

input_shape: the shape of the image tensors that we will feed to the network. Input shape is optional, if we don’t pass it, then the network will be able to process inputs of any size.

conv_base = VGG16(weights='imagenet',
include_top=False,
input_shape=(150, 150, 3))

VGG16 model summary

conv_base.summary()

Output:

The final feature map has shape (4, 4, 512). That’s the feature on top of which we will stick a densely-connected classifier.

Declare training, validation and test directory

import os
from tensorflow.keras.preprocessing.image import ImageDataGenerator
base_dir = '/INPUT-FOLDER/cats_and_dogs_small'

train_dir = os.path.join(base_dir, 'train')
validation_dir = os.path.join(base_dir, 'validation')
test_dir = os.path.join(base_dir, 'test')
print(train_dir)
print(validation_dir)
print(test_dir)

Output:

/INPUT-FOLDER/train
/INPUT-FOLDER/validation
/INPUT-FOLDER/test

Create a model with which will extend the convolution base model

from tensorflow.keras.models import load_model
from tensorflow.keras import models, layers, optimizers

We are creating a sequential model and adding layer the convolution network which is VGG16 to the Sequential model.

model = models.Sequential()
model.add(conv_base)
model.add(layers.Flatten())
model.add(layers.Dense(256, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))

Model summary

model.summary()

Output:

We can see, the convolutional base of VGG16 has 14,714,688 parameters, which is very large. The classifier we are adding on top has 2 million parameters.

Freeze the convolution base

Before we compile and train our model, we have to freeze the convolution base. We have to use pre-trained model and their weights, so stop getting updated during training.

In Keras, freezing a network is done by setting its trainable attribute to False:

print('This is the number of trainable weights '
'before freezing the convolution base:', len(model.trainable_weights))

Output: This is the number of trainable weights before freezing the convolution base: 30

conv_base.trainable = False
print('This is the number of trainable weights '
'before freezing the convolution base:', len(model.trainable_weights))

Output: This is the number of trainable weights before freezing the convolution base: 4

Now only the weights from the two Dense layers that we added will be trained. That's a total of four weight tensors: two per layer (the main weight matrix and the bias vector).

If you ever modify weight trainability after compilation, you should then re-compile the model, or these changes would be ignored.

Now we can start training our model, with the same data augmentation configuration.

Data augmentation

train_datagen = ImageDataGenerator(
rescale=1./255,
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest')

# Note that the validation data should not be augmented!
test_datagen = ImageDataGenerator(rescale=1./255)

train_generator = train_datagen.flow_from_directory(
# This is the target directory
train_dir,
# All images will be resized to 150x150
target_size=(150, 150),
batch_size=20,
# Since we use binary_crossentropy loss, we need binary labels
class_mode='binary')

validation_generator = test_datagen.flow_from_directory(
validation_dir,
target_size=(150, 150),
batch_size=20,
class_mode='binary')

Output:

Found 2500 images belonging to 2 classes.
Found 1000 images belonging to 2 classes.

Compile the model

model.compile(loss='binary_crossentropy',
optimizer=optimizers.RMSprop(),
metrics=['acc'])

Train the model

history = model.fit(
train_generator,
steps_per_epoch=50,
epochs=10,
validation_data=validation_generator,
validation_steps=50,
verbose=1)

Output:

As we can see, we reach a validation accuracy of about 90%. This is much better than our small convnet trained from scratch.

Save the model

model.save('output/cats_and_dogs_small.h5')

Visualize the accuracy and loss

acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(len(acc))

Plot Training and validation accuracy

plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()
plt.show()

Output:

Plot Training and validation loss

plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')

plt.legend()
plt.show()

Output:

That’s it in this blog. If you have any query related to my blog, you can email me at nutanbhogendrasharma@gmail.com.

Thanks for reading 😊😊😊.

--

--

Nutan

knowledge of Machine Learning, React Native, React, Python, Java, SpringBoot, Django, Flask, Wordpress. Never stop learning because life never stops teaching.