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()
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()
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()
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')
In [ ]: