Importing necessary libraries and using the GPU¶

In [1]:
import os
import tensorflow as tf
import matplotlib.pyplot as plt

import logging
tf.get_logger().setLevel(logging.ERROR)
In [2]:
# I am using my GPU
gpus = tf.config.experimental.list_physical_devices('GPU')

if gpus:
    try:
        for gpu in gpus:
            tf.config.experimental.set_memory_growth(gpu, True)
            print('Using GPU - ', gpu)
    except RuntimeError as e:
        print(e)
Using GPU -  PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')

Loading the image datasets and looking into it¶

In [7]:
TRAIN_DIR = 'horse-or-human'
VAL_DIR = 'validation-horse-or-human'

# Directory with training horse pictures
train_horse_dir = os.path.join(TRAIN_DIR, 'horses')

# Directory with training human pictures
train_human_dir = os.path.join(TRAIN_DIR, 'humans')

# Directory with validation horse pictures
validation_horse_dir = os.path.join(VAL_DIR, 'horses')

# Directory with validation human pictures
validation_human_dir = os.path.join(VAL_DIR, 'humans')
In [8]:
sample_image_horse = tf.keras.preprocessing.image.load_img(os.path.join(train_horse_dir, os.listdir(train_horse_dir)[100]))
sample_image_human = tf.keras.preprocessing.image.load_img(os.path.join(train_human_dir, os.listdir(train_human_dir)[100]))

ax = plt.subplot(1, 2, 1)
ax.imshow(sample_image_horse)
ax.set_title('Horse Image')

ax = plt.subplot(1, 2, 2)
ax.imshow(sample_image_human)
ax.set_title('Human Image')
plt.show()
No description has been provided for this image
In [9]:
sample_array = tf.keras.preprocessing.image.img_to_array(sample_image_human)
print('Each image has shape : ', sample_array.shape)
Each image has shape :  (300, 300, 3)

Creating training, validation, and test dataset¶

In [10]:
def train_val_dataset():
    
    training_dataset = tf.keras.utils.image_dataset_from_directory(
        directory = TRAIN_DIR,
        image_size=(150, 150),
        batch_size=32,
        shuffle=True,
        seed=7
    )
    
    validation_dataset = tf.keras.utils.image_dataset_from_directory(
        directory = VAL_DIR,
        image_size=(150,150),
        batch_size=32,
        seed=7
    )
    
    return training_dataset, validation_dataset
In [11]:
training_dataset, validation_dataset = train_val_dataset()
Found 1027 files belonging to 2 classes.
Found 256 files belonging to 2 classes.

Creating test set out of the validation dataset -

In [13]:
val_batches = int(validation_dataset.cardinality())
test_dataset, validation_dataset = tf.keras.utils.split_dataset(validation_dataset, val_batches//5)

print('Number of validation batches : ', validation_dataset.cardinality())
print('Number of test batches : ', test_dataset.cardinality())
Number of validation batches :  tf.Tensor(8, shape=(), dtype=int64)
Number of test batches :  tf.Tensor(1, shape=(), dtype=int64)

Loading the pretrained model¶

In [17]:
local_weights_file = 'inception_v3_model/inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5'
In [20]:
def create_pretrained_model():
    
    pre_trained_model = tf.keras.applications.inception_v3.InceptionV3(
        input_shape=(150,150,3),
        include_top=False,
        weights=None
    )
    
    pre_trained_model.load_weights(local_weights_file)
    
    for layer in pre_trained_model.layers:
        layer.trainable = False
        
    return pre_trained_model
  • count_params(): This function returns the total number of trainable and non-trainable parameters in the pre_trained_model. It includes all layers, whether they are frozen (non-trainable) or not. This is useful to understand the model size and complexity.

  • pre_trained_model.trainable_weights: This returns a list of tensors corresponding to the model's trainable parameters (i.e., weights and biases of trainable layers).

  • w.shape.num_elements():

    • w.shape gives the shape of each weight tensor.
    • num_elements() returns the total number of elements (parameters) in that tensor.
    • sum([...]): Computes the sum of all trainable parameters
In [44]:
pre_trained_model = create_pretrained_model()

num_total_params = pre_trained_model.count_params()
non_trainable_params = sum([w.shape.num_elements() for w in pre_trained_model.trainable_weights])

num_total_params, non_trainable_params
Out[44]:
(21802784, 0)

Output desired layer from pretrained model¶

In [33]:
def output_of_last_layer(pre_trained_model):
    
    last_desired_layer = pre_trained_model.get_layer('mixed7')
    last_output = last_desired_layer.output
    
    return last_output
In [34]:
last_output = output_of_last_layer(pre_trained_model)

Creating the final model¶

In [35]:
def create_final_model(pre_trained_model, last_output):
    
    x = tf.keras.layers.Flatten()(last_output)
    x = tf.keras.layers.Dense(1024, activation='relu')(x)
    x = tf.keras.layers.Dropout(0.2)(x)
    x = tf.keras.layers.Dense(1, activation='sigmoid')(x)
    
    model = tf.keras.Model(inputs = pre_trained_model.input, outputs=x)
    
    model.compile(optimizer=tf.keras.optimizers.RMSprop(learning_rate=0.00001), loss='binary_crossentropy', metrics=['accuracy'])
    
    return model
In [36]:
model = create_final_model(pre_trained_model, last_output)
In [37]:
num_total_params = model.count_params()
non_trainable_params = sum([w.shape.num_elements() for w in model.trainable_weights])

num_total_params, non_trainable_params
Out[37]:
(47512481, 38537217)

non_trainable_params are non zero since now we have some layers (dense layers) that are trainable.

Preprocess the datasets¶

In [38]:
def preprocess(image, label):
    image = tf.keras.applications.inception_v3.preprocess_input(image)
    return image, label

training_dataset = training_dataset.map(preprocess)
validation_dataset = validation_dataset.map(preprocess)
test_dataset = test_dataset.map(preprocess)

Creating Callback¶

In [39]:
class EarlyStopCallBack(tf.keras.callbacks.Callback):
    def on_epoch_end(self, epoch, logs={}):
        if logs['accuracy'] > 0.999:
            self.model.stop_training=True
            print('Model reached 99.9% accuracy')

Train the model¶

In [40]:
history = model.fit(
    training_dataset,
    validation_data=validation_dataset,
    epochs=100,
    verbose=2,
    callbacks=[EarlyStopCallBack()]
)
Epoch 1/100
33/33 - 7s - loss: 0.5560 - accuracy: 0.7176 - val_loss: 0.4259 - val_accuracy: 0.7961 - 7s/epoch - 208ms/step
Epoch 2/100
33/33 - 3s - loss: 0.3650 - accuracy: 0.8578 - val_loss: 0.3775 - val_accuracy: 0.8510 - 3s/epoch - 96ms/step
Epoch 3/100
33/33 - 4s - loss: 0.2935 - accuracy: 0.8929 - val_loss: 0.4253 - val_accuracy: 0.8471 - 4s/epoch - 132ms/step
Epoch 4/100
33/33 - 12s - loss: 0.2475 - accuracy: 0.9163 - val_loss: 0.4797 - val_accuracy: 0.7725 - 12s/epoch - 351ms/step
Epoch 5/100
33/33 - 12s - loss: 0.2099 - accuracy: 0.9279 - val_loss: 0.3302 - val_accuracy: 0.8196 - 12s/epoch - 350ms/step
Epoch 6/100
33/33 - 12s - loss: 0.1839 - accuracy: 0.9396 - val_loss: 0.2993 - val_accuracy: 0.8824 - 12s/epoch - 352ms/step
Epoch 7/100
33/33 - 12s - loss: 0.1532 - accuracy: 0.9513 - val_loss: 0.3264 - val_accuracy: 0.8157 - 12s/epoch - 352ms/step
Epoch 8/100
33/33 - 12s - loss: 0.1425 - accuracy: 0.9533 - val_loss: 0.3356 - val_accuracy: 0.8784 - 12s/epoch - 350ms/step
Epoch 9/100
33/33 - 12s - loss: 0.1354 - accuracy: 0.9562 - val_loss: 0.3686 - val_accuracy: 0.8745 - 12s/epoch - 350ms/step
Epoch 10/100
33/33 - 12s - loss: 0.1053 - accuracy: 0.9659 - val_loss: 0.2802 - val_accuracy: 0.8784 - 12s/epoch - 351ms/step
Epoch 11/100
33/33 - 12s - loss: 0.1103 - accuracy: 0.9688 - val_loss: 0.4082 - val_accuracy: 0.8667 - 12s/epoch - 351ms/step
Epoch 12/100
33/33 - 12s - loss: 0.0928 - accuracy: 0.9766 - val_loss: 0.4829 - val_accuracy: 0.8549 - 12s/epoch - 351ms/step
Epoch 13/100
33/33 - 12s - loss: 0.0968 - accuracy: 0.9727 - val_loss: 0.3604 - val_accuracy: 0.8784 - 12s/epoch - 350ms/step
Epoch 14/100
33/33 - 12s - loss: 0.0813 - accuracy: 0.9776 - val_loss: 0.2713 - val_accuracy: 0.8980 - 12s/epoch - 349ms/step
Epoch 15/100
33/33 - 12s - loss: 0.0710 - accuracy: 0.9864 - val_loss: 0.2716 - val_accuracy: 0.8941 - 12s/epoch - 349ms/step
Epoch 16/100
33/33 - 12s - loss: 0.0713 - accuracy: 0.9805 - val_loss: 0.3518 - val_accuracy: 0.8902 - 12s/epoch - 350ms/step
Epoch 17/100
33/33 - 12s - loss: 0.0517 - accuracy: 0.9912 - val_loss: 0.3803 - val_accuracy: 0.8275 - 12s/epoch - 350ms/step
Epoch 18/100
33/33 - 12s - loss: 0.0540 - accuracy: 0.9844 - val_loss: 0.3012 - val_accuracy: 0.8980 - 12s/epoch - 351ms/step
Epoch 19/100
33/33 - 12s - loss: 0.0488 - accuracy: 0.9893 - val_loss: 0.3889 - val_accuracy: 0.8745 - 12s/epoch - 351ms/step
Epoch 20/100
33/33 - 12s - loss: 0.0474 - accuracy: 0.9912 - val_loss: 0.2734 - val_accuracy: 0.9020 - 12s/epoch - 350ms/step
Epoch 21/100
33/33 - 12s - loss: 0.0431 - accuracy: 0.9922 - val_loss: 0.2982 - val_accuracy: 0.9020 - 12s/epoch - 350ms/step
Epoch 22/100
33/33 - 12s - loss: 0.0357 - accuracy: 0.9951 - val_loss: 0.3011 - val_accuracy: 0.9020 - 12s/epoch - 350ms/step
Epoch 23/100
33/33 - 12s - loss: 0.0342 - accuracy: 0.9922 - val_loss: 0.2873 - val_accuracy: 0.9059 - 12s/epoch - 351ms/step
Epoch 24/100
33/33 - 12s - loss: 0.0320 - accuracy: 0.9951 - val_loss: 0.2933 - val_accuracy: 0.9059 - 12s/epoch - 351ms/step
Epoch 25/100
33/33 - 12s - loss: 0.0308 - accuracy: 0.9961 - val_loss: 0.3210 - val_accuracy: 0.9059 - 12s/epoch - 351ms/step
Epoch 26/100
33/33 - 12s - loss: 0.0264 - accuracy: 0.9981 - val_loss: 0.3095 - val_accuracy: 0.9059 - 12s/epoch - 350ms/step
Epoch 27/100
33/33 - 11s - loss: 0.0281 - accuracy: 0.9922 - val_loss: 0.3529 - val_accuracy: 0.8471 - 11s/epoch - 343ms/step
Epoch 28/100
33/33 - 3s - loss: 0.0259 - accuracy: 0.9961 - val_loss: 0.2748 - val_accuracy: 0.8706 - 3s/epoch - 85ms/step
Epoch 29/100
33/33 - 3s - loss: 0.0224 - accuracy: 0.9971 - val_loss: 0.3306 - val_accuracy: 0.9059 - 3s/epoch - 82ms/step
Epoch 30/100
33/33 - 3s - loss: 0.0231 - accuracy: 0.9961 - val_loss: 0.3015 - val_accuracy: 0.9059 - 3s/epoch - 83ms/step
Epoch 31/100
Model reached 99.9% accuracy
33/33 - 3s - loss: 0.0160 - accuracy: 1.0000 - val_loss: 0.5061 - val_accuracy: 0.8706 - 3s/epoch - 84ms/step
In [41]:
def plot_loss_acc(history):
    '''Plots the training and validation loss and accuracy from a history object'''
    acc = history.history['accuracy']
    val_acc = history.history['val_accuracy']
    loss = history.history['loss']
    val_loss = history.history['val_loss']

    epochs = range(len(acc))

    fig, ax = plt.subplots(1,2, figsize=(12, 6))
    ax[0].plot(epochs, acc, 'bo', label='Training accuracy')
    ax[0].plot(epochs, val_acc, 'b', label='Validation accuracy')
    ax[0].set_title('Training and validation accuracy')
    ax[0].set_xlabel('epochs')
    ax[0].set_ylabel('accuracy')
    ax[0].legend()

    ax[1].plot(epochs, loss, 'bo', label='Training Loss')
    ax[1].plot(epochs, val_loss, 'b', label='Validation Loss')
    ax[1].set_title('Training and validation loss')
    ax[1].set_xlabel('epochs')
    ax[1].set_ylabel('loss')
    ax[1].legend()

    plt.show()
In [42]:
# Plot training results
plot_loss_acc(history)
No description has been provided for this image

Testing the model¶

In [45]:
test_loss, test_accuracy = model.evaluate(test_dataset, verbose=False)
test_loss, test_accuracy
Out[45]:
(2.7052661607740447e-05, 1.0)

The model achieved a test loss of approximately 2.71×10^−5 and a test accuracy of 100%. This indicates that the model performed exceptionally well on the test data, with minimal loss and perfect classification accuracy.

However, achieving 1.0 (100%) accuracy might suggest possible overfitting, especially if the dataset is small or lacks variability.

In [ ]: