Deep Learning

Deep Learning for Cats vs Dogs Classification!

Danyal Jamil
Sep 21, 2020 · 5 min read

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.

Cats and Dogs — https://barkpost.com/discover/breeds-that-look-like-cats/
Cats and Dogs — https://barkpost.com/discover/breeds-that-look-like-cats/
Picture from noerihito

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 .kaggle
token = {"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)
break
plt.tight_layout()
plt.show()
Image for post
Image for post
Picture by Author

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:

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:

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:

Image for post
Image for post
Picture by Author
Image for post
Image for post
Picture by Author

Second set

I trained for another 15 epochs this time.

Image for post
Image for post
Picture by Author
Image for post
Image for post
Picture by Author

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.

Image for post
Image for post
Picture by Author

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

Image for post
Image for post
Picture by Author

But yeah, this can be ignored. 😅

Alright y’all, I hope this article helps you. Let’s connect on Linkedin!

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. :)

Quick Code

Find the best tutorials and courses for the web, mobile…

Sign up for Developer Updates

By Quick Code

Receive weekly updates about new posts on programming, development, data science, web development and more Take a look.

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more information about our privacy practices.

Check your inbox
Medium sent you an email at to complete your subscription.

Danyal Jamil

Written by

Machine Learning Enthusiast | Quick Learner | Student

Quick Code

Find the best tutorials and courses for the web, mobile, chatbot, AR/VR development, database management, data science, web design and cryptocurrency. Practice in JavaScript, Java, Python, R, Android, Swift, Objective-C, React, Node Js, Ember, C++, SQL & more.

Danyal Jamil

Written by

Machine Learning Enthusiast | Quick Learner | Student

Quick Code

Find the best tutorials and courses for the web, mobile, chatbot, AR/VR development, database management, data science, web design and cryptocurrency. Practice in JavaScript, Java, Python, R, Android, Swift, Objective-C, React, Node Js, Ember, C++, SQL & more.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store