Image Classification of Cats and Dogs. Dataset is available at Kaggle. I have taken only 2000 pictures of dogs and 2000 pictures of cats out of 25000 pictures.

In [1]:
import numpy as np
import os
import random
import tensorflow as tf
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
In [3]:
BASE_DIR = 'cats_and_dogs_filtered'

train_dir = os.path.join(BASE_DIR, 'train')
validation_dir = os.path.join(BASE_DIR, 'validation')

# Directory with training cat/dog pictures
train_cats_dir = os.path.join(train_dir, 'cats')
train_dogs_dir = os.path.join(train_dir, 'dogs')

# Directory with validation cat/dog pictures
validation_cats_dir = os.path.join(validation_dir, 'cats')
validation_dogs_dir = os.path.join(validation_dir, 'dogs')


print(f"Contents of base directory: {os.listdir(BASE_DIR)}")

print(f"\nContents of train directory: {os.listdir(train_dir)}")

print(f"\nContents of validation directory: {validation_dir}")
Contents of base directory: ['train', 'validation']

Contents of train directory: ['cats', 'dogs']

Contents of validation directory: cats_and_dogs_filtered\validation
In [4]:
train_cat_fnames = os.listdir(train_cats_dir)
train_dog_fnames = os.listdir(train_dogs_dir)

print(f"5 files in cats subdir: {train_cat_fnames[:5]}")
print(f"5 files in dogs subdir: {train_dog_fnames[:5]}")
5 files in cats subdir: ['cat.2252.jpg', 'cat.2253.jpg', 'cat.2254.jpg', 'cat.2255.jpg', 'cat.2256.jpg']
5 files in dogs subdir: ['dog.8171.jpg', 'dog.8172.jpg', 'dog.8173.jpg', 'dog.8174.jpg', 'dog.8175.jpg']
In [5]:
print(f'total training cat images: {len(os.listdir(train_cats_dir))}')
print(f'total training dog images: {len(os.listdir(train_dogs_dir))}')

print(f'total validation cat images: {len(os.listdir(validation_cats_dir))}')
print(f'total validation dog images: {len(os.listdir(validation_dogs_dir))}')
total training cat images: 1500
total training dog images: 1500
total validation cat images: 500
total validation dog images: 500
In [6]:
# Parameters for your graph; you will output images in a 4x4 configuration
nrows = 4
ncols = 4

# Set up matplotlib fig, and size it to fit 4x4 pics
fig = plt.gcf()
fig.set_size_inches(ncols * 4, nrows * 4)

next_cat_pix = [os.path.join(train_cats_dir, fname)
                for fname in random.sample(train_cat_fnames, k=8)]

next_dog_pix = [os.path.join(train_dogs_dir, fname)
                for fname in random.sample(train_dog_fnames, k=8)]

for i, img_path in enumerate(next_cat_pix+next_dog_pix):
    # Set up subplot; subplot indices start at 1
    sp = plt.subplot(nrows, ncols, i + 1)
    sp.axis('Off') # Don't show axes (or gridlines)

    img = mpimg.imread(img_path)
    plt.imshow(img)

plt.show()
No description has been provided for this image
In [9]:
# Instantiate the Dataset object for the training set
train_dataset = tf.keras.utils.image_dataset_from_directory(
    train_dir,
    image_size=(150, 150),
    batch_size=20,
    label_mode='binary'
    )

# Instantiate the Dataset object for the validation set
validation_dataset = tf.keras.utils.image_dataset_from_directory(
    validation_dir,
    image_size=(150, 150),
    batch_size=20,
    label_mode='binary'
    )
Found 3000 files belonging to 2 classes.
Found 1000 files belonging to 2 classes.
In [10]:
SHUFFLE_BUFFER_SIZE = 1000
PREFETCH_BUFFER_SIZE = tf.data.AUTOTUNE

train_dataset_final = train_dataset.cache().shuffle(SHUFFLE_BUFFER_SIZE).prefetch(PREFETCH_BUFFER_SIZE)
validation_dataset_final = validation_dataset.cache().prefetch(PREFETCH_BUFFER_SIZE)
In [7]:
model = tf.keras.models.Sequential([
    # Rescale the image. Note the input shape is the desired size of the image: 150x150 with 3 bytes for color
    tf.keras.Input(shape=(150, 150, 3)),
    tf.keras.layers.Rescaling(1./255),
    # Convolution and Pooling layers
    tf.keras.layers.Conv2D(16, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    tf.keras.layers.Conv2D(32, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    # Flatten the results to feed into a DNN
    tf.keras.layers.Flatten(),
    # 512 neuron hidden layer
    tf.keras.layers.Dense(512, activation='relu'),
    # Only 1 output neuron. It will contain a value from 0-1 where 0 for one class ('cats') and 1 for the other ('dogs')
    tf.keras.layers.Dense(1, activation='sigmoid')
])
In [8]:
model.compile(
    optimizer=tf.keras.optimizers.RMSprop(learning_rate=0.001),
    loss='binary_crossentropy',
    metrics = ['accuracy']
    )
In [11]:
history = model.fit(
    train_dataset_final,
    epochs=15,
    validation_data=validation_dataset_final,
    verbose=2
    )
Epoch 1/15
150/150 - 20s - 130ms/step - accuracy: 0.5203 - loss: 0.7441 - val_accuracy: 0.5480 - val_loss: 0.6833
Epoch 2/15
150/150 - 12s - 78ms/step - accuracy: 0.6217 - loss: 0.6648 - val_accuracy: 0.5530 - val_loss: 0.7504
Epoch 3/15
150/150 - 11s - 72ms/step - accuracy: 0.6773 - loss: 0.5962 - val_accuracy: 0.7200 - val_loss: 0.5805
Epoch 4/15
150/150 - 11s - 76ms/step - accuracy: 0.7297 - loss: 0.5349 - val_accuracy: 0.7210 - val_loss: 0.5489
Epoch 5/15
150/150 - 11s - 71ms/step - accuracy: 0.7787 - loss: 0.4683 - val_accuracy: 0.7480 - val_loss: 0.5439
Epoch 6/15
150/150 - 11s - 73ms/step - accuracy: 0.8223 - loss: 0.3857 - val_accuracy: 0.7300 - val_loss: 0.6118
Epoch 7/15
150/150 - 12s - 79ms/step - accuracy: 0.8620 - loss: 0.3095 - val_accuracy: 0.7390 - val_loss: 0.6194
Epoch 8/15
150/150 - 11s - 75ms/step - accuracy: 0.9187 - loss: 0.2125 - val_accuracy: 0.7470 - val_loss: 0.6840
Epoch 9/15
150/150 - 11s - 71ms/step - accuracy: 0.9520 - loss: 0.1215 - val_accuracy: 0.7420 - val_loss: 0.9397
Epoch 10/15
150/150 - 11s - 70ms/step - accuracy: 0.9750 - loss: 0.0765 - val_accuracy: 0.7400 - val_loss: 1.0651
Epoch 11/15
150/150 - 11s - 71ms/step - accuracy: 0.9857 - loss: 0.0449 - val_accuracy: 0.7310 - val_loss: 1.2519
Epoch 12/15
150/150 - 11s - 72ms/step - accuracy: 0.9893 - loss: 0.0399 - val_accuracy: 0.7430 - val_loss: 1.5859
Epoch 13/15
150/150 - 11s - 72ms/step - accuracy: 0.9867 - loss: 0.1154 - val_accuracy: 0.7290 - val_loss: 1.4268
Epoch 14/15
150/150 - 11s - 70ms/step - accuracy: 0.9957 - loss: 0.0153 - val_accuracy: 0.7490 - val_loss: 1.6677
Epoch 15/15
150/150 - 11s - 75ms/step - accuracy: 0.9903 - loss: 0.0274 - val_accuracy: 0.7520 - val_loss: 1.5733
In [12]:
# Plotting the training accuracy

acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(len(acc))

plt.plot(epochs, acc, 'r', label = 'Training accuracy')
plt.plot(epochs, val_acc, 'b', label = 'Validation accuracy')
plt.title('Training and Validation Accuracy')
plt.legend(loc=0)
plt.show()
No description has been provided for this image
In [13]:
plt.plot(epochs, loss, 'r', label = 'Training Loss')
plt.plot(epochs, val_loss, 'b', label = 'Validation Loss')
plt.title('Training and Validation Loss')
plt.legend(loc=0)
plt.show()
No description has been provided for this image
In [30]:
from collections import Counter
# Let's predict on the complete dataset

prediction = model.predict(validation_dataset_final, verbose=False)
labels = np.concatenate([label_batch.numpy() for _, label_batch in validation_dataset_final])
labels = [int(lab) for label in labels for lab in label]
prediction = [1 if x[0] > 0.5 else 0 for x in prediction]
In [32]:
match = sum(a == b for a, b in zip(prediction, labels))
non_match = len(labels) - match_count
In [33]:
match, non_match
Out[33]:
(752, 248)
In [34]:
# Define a new Model that will take an image as input, and will output
# intermediate representations for all layers in the previous model
successive_outputs = [layer.output for layer in model.layers]
visualization_model = tf.keras.models.Model(inputs = model.inputs, outputs = successive_outputs)

# Prepare a random input image from the training set.
cat_img_files = [os.path.join(train_cats_dir, f) for f in train_cat_fnames]
dog_img_files = [os.path.join(train_dogs_dir, f) for f in train_dog_fnames]
img_path = random.choice(cat_img_files + dog_img_files)
img = tf.keras.utils.load_img(img_path, target_size=(150, 150))  # this is a PIL image
x = tf.keras.utils.img_to_array(img) # Numpy array with shape (150, 150, 3)
x = x.reshape((1,) + x.shape) # Numpy array with shape (1, 150, 150, 3)

# Run the image through the network, thus obtaining all
# intermediate representations for this image.
successive_feature_maps = visualization_model.predict(x)

# These are the names of the layers, so you can have them as part of our plot
layer_names = [layer.name for layer in model.layers]

# Display the representations
for layer_name, feature_map in zip(layer_names, successive_feature_maps):

    if len(feature_map.shape) == 4:

        #-------------------------------------------
        # Just do this for the conv / maxpool layers, not the fully-connected layers
        #-------------------------------------------
        n_features = feature_map.shape[-1]  # number of features in the feature map
        size = feature_map.shape[1]  # feature map shape (1, size, size, n_features)

        # Tile the images in this matrix
        display_grid = np.zeros((size, size * n_features))

        #-------------------------------------------------
        # Postprocess the feature to be visually palatable
        #-------------------------------------------------
        for i in range(n_features):
            x = feature_map[0, :, :, i]
            x -= x.mean()
            x /= x.std ()
            x *=  64
            x += 128
            x = np.clip(x, 0, 255).astype('uint8')
            display_grid[:, i * size : (i + 1) * size] = x # Tile each filter into a horizontal grid

        #-----------------
        # Display the grid
        #-----------------
        scale = 20. / n_features
        plt.figure(figsize=(scale * n_features, scale))
        plt.title(layer_name)
        plt.grid(False)
        plt.imshow(display_grid, aspect='auto', cmap='viridis')
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 160ms/step
C:\Users\nishi\AppData\Local\Temp\ipykernel_19156\634036457.py:41: RuntimeWarning: invalid value encountered in divide
  x /= x.std ()
C:\Users\nishi\AppData\Local\Temp\ipykernel_19156\634036457.py:44: RuntimeWarning: invalid value encountered in cast
  x = np.clip(x, 0, 255).astype('uint8')
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
In [ ]: