Deep Learning
Deep Learning for Cats vs Dogs Classification!
A step-by-step guide to distinguish between cats and dogs!
Stuck behind the paywall? Click here to read the full story with my friend link!
According to BarkPost.com, there are like 14 breeds of Dogs and Cats which look the same. So, I thought It would be an interesting project to come up with a model that successfully classifies between them.

Overview
The main aim of the project is to distinguish which image contains a dog in it and which one has a cat in it.
It is actually a relatively simple task as compared to:
But, let’s see how the model performs.
Environment and tools
The Code?
The actual code is available on my Github.
Data
The dataset I used is taken from Kaggle.
Kaggle is the world’s largest data science community with powerful tools and resources to help you achieve your data science goals.
The dataset was a part of the Dogs vs Cats Competition held on the platform. It contains about 25,000 images of different Dogs and Cats.
The training archive contains 25,000 images of dogs and cats. Train your algorithm on these files and predict the labels for test1.zip (1 = dog, 0 = cat).
Importing Libraries
import os
import json
import random
import pandas as pd
from keras.regularizers import l2
from keras.models import Sequential
from matplotlib import pyplot as plt
from keras.preprocessing.image import load_img
from sklearn.model_selection import train_test_split
from keras.preprocessing.image import ImageDataGenerator
from keras.layers import Conv2D, MaxPooling2D, Dropout, Flatten, Dense, Activation, BatchNormalization
Data Handling
I had to download the data from Kaggle directly to Colab.
import json
!mkdir .kaggletoken = {"username":"USER_NAME", "key":"YOUR_KEY"}with open('/content/.kaggle/kaggle.json', 'w') as file:
json.dump(token,file)!mkdir ~/.kaggle!cp /content/.kaggle/kaggle.json ~/.kaggle/kaggle.json!kaggle config set -n path -v{/content}
!kaggle competitions download -c dogs-vs-cats -p/content!unzip -q test1.zip -d .
!unzip -q train.zip -d .
Data Preprocessing
To preprocess, what I did is that I just took the file names and split them using train_test_split, more on this later. And then I used another Generator to get the images right before training. Because playing around with 20k+ images and using for loops is a hassle.
filenames = os.listdir('/content/train/')
categories = []for filename in filenames:
category = filename.split('.')[0]if category == 'dog':
categories.append(1)
else:
categories.append(0)df = pd.DataFrame({
'filename': filenames,
'category': categories
})df.category = df.category.map({
0: '0',
1: '1'
})
Now, I have the filenames and the categories in my hand. We are using the train_test_split dependency from sklearn.model_selection.
train_test_split
is a function in Sklearn model selection for splitting data arrays into two subsets: for training data and for testing data. With this function, you don't need to divide the dataset manually.By default, Sklearn train_test_split will make random partitions for the two subsets. However, you can also specify a random state for the operation.
train_df, test_df = train_test_split(df, test_size=0.20, random_state=42)
train_df = train_df.reset_index(drop=True)
test_df = test_df.reset_index(drop=True)
I used a splitting value of 20% meaning that our training set would be 80% of the whole set and the test_set would be just 20%.
Next, I used the ImageGenerator function to alter the images a bit.
# For train settrain_datagen = ImageDataGenerator(
rotation_range=15,
rescale=1./255,
shear_range=0.1,
zoom_range=0.2,
horizontal_flip=True,
width_shift_range=0.1,
height_shift_range=0.1
)train_generator = train_datagen.flow_from_dataframe(
train_df,
"/content/train/",
x_col='filename',
y_col='category',
target_size=(224, 224),
class_mode='categorical',
batch_size=32)# For test settest_datagen = ImageDataGenerator(
rescale=1./255
)test_generator = validation_datagen.flow_from_dataframe(
test_df,
"/content/train/",
x_col='filename',
y_col='category',
target_size=(224, 224),
class_mode='categorical',
batch_size=32)
Viewing the Initial Data
# Helper Functiondef check(t):
if t[0] == 1:
return "Cat"
return "Dog"
plt.figure(figsize=(12, 12))for i in range(0, 15):
plt.subplot(5, 3, i+1)for X_batch, Y_batch in validation_generator:
image = X_batch[0]
plt.xlabel(check(Y_batch[0]))
plt.imshow(image)
breakplt.tight_layout()
plt.show()

Model Architecture
Finally, we’re now at the fun part! The architecture I’ve designed here consists of 4 Convolutional Layers!
Now, I used Convolutional Layers with:
- kernel size: 5, 3
- kernel initializer: he_uniform
- Activation: elu
- Max Pool: (2, 2)
- Batch Normalization
- Dropout of 30%
model = Sequential()model.add(Conv2D(64, kernel_size=5, kernel_initializer='he_uniform', padding='same', input_shape=(224, 224, 3)))
model.add(Activation('elu'))
model.add(BatchNormalization())
model.add(Dropout(0.3))model.add(Conv2D(128, kernel_size=3, strides=2, kernel_initializer='he_uniform'))
model.add(Activation('elu'))
model.add(MaxPooling2D(2, 2))
model.add(BatchNormalization())
model.add(Dropout(0.3))model.add(Conv2D(64, kernel_size=3, kernel_initializer='he_uniform', padding='same'))
model.add(Activation('elu'))
model.add(MaxPooling2D(2, 2))
model.add(BatchNormalization())
model.add(Dropout(0.3))model.add(Conv2D(128, kernel_size=5, strides=2, kernel_initializer='he_uniform', padding='same'))
model.add(Activation('elu'))
model.add(MaxPooling2D(2, 2))
model.add(BatchNormalization())
model.add(Dropout(0.3))
And then the three Dense layers with:
- Activation: relu, Sigmoid
- Batch Normalization
- Dropout of 30%, 40%
model.add(Dense(756, kernel_initializer='he_uniform'))
model.add(Activation('relu'))
model.add(BatchNormalization())
model.add(Dropout(0.4))model.add(Dense(256, kernel_initializer='he_uniform'))
model.add(Activation('relu'))
model.add(BatchNormalization())
model.add(Dropout(0.5))model.add(Dense(2, kernel_initializer='he_uniform'))
model.add(Activation('sigmoid'))
Then, I compiled the model using:
model.compile(
loss = 'binary_crossentropy',
optimizer='adam',
metrics=['accuracy'])
Model Training
I did two sets of training.
history = model.fit(
YOUR_DATA,
epochs=YOUR_EPOCHS,
validation_data=YOUR_DATA)
First set
I did for 15 epochs:



Graphs
Here is the code for the graphs if you’re wondering.
score = model.evaluate(validation_generator, verbose=0)
print("%s: %.2f%%" % (model.metrics_names[1], score[1]*100))# summarize history for accuracyplt.subplot(211)plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.title('model accuracy')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')# summarize history for lossplt.subplot(212)
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')plt.subplots_adjust(right=3, top=3)plt.show()
Results & Conclusion
Hence, after two sets of training runs, I could get up to 95.42%.
I actually am happy with how things turned out. Let me show you an example of how the model performs on the test set.

As we can see, the model was wrong just once. This one

But yeah, this can be ignored. 😅
Alright y’all, I hope this article helps you. Let’s connect on Linkedin!
References/Further Reading
Contacts
If you want to keep updated with my latest articles and projects follow me on Medium. These are some of my contacts details:
Happy Learning. :)