Dog and Cat Classification using CNN


Introduction to CNN

Convolutional neural networks (CNN) are primarily used to classify images or identify pattern similarities between them.

So a convolutional network receives a normal color image as a rectangular box whose width and height are measured by the number of pixels along those dimensions, and whose depth is three layers deep, one for each letter in RGB.

Also, read – Understanding a Neural Network

As images move through a convolutional network, different patterns are recognised just like a normal neural network.

But here rather than focussing on one pixel at a time, a convolutional net takes in square patches of pixels and passes them through a filter.

That filter is also a square matrix smaller than the image itself, and equal in size to the patch. It is also called a kernel.

Now lets start with importing the libraries

import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
import cv2
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Flatten, Dropout, Activation, Conv2D, MaxPooling2D

We need to train a model first so we will check training data In the below code we are iterating through all images in train folder and then we will split image name with deliminiter “.”

We have names like dog.0, dog.1, cat.2 etc.. Hence after splitting we are gonna get results like “dog’, “cat” as category value of the image. To make this example more easy we will consider dog as “1” and cat as “0”.

Now every image is actually a set of pixels so how to get our computer know that. Its simple convert all those pixels into an array.

So we are going to use here a cv2 library to read our image into an array and also it will read as a gray scale image.

train_dir = # your path to train dataset
path = os.path.join(main_dir,train_dir)

for p in os.listdir(path):
    category = p.split(".")[0]
    img_array = cv2.imread(os.path.join(path,p),cv2.IMREAD_GRAYSCALE)
    new_img_array = cv2.resize(img_array, dsize=(80, 80))

Okay so the above code was more for understanding purpose. Nowe we will get to the real part of coding here.

Declare your training array X and your target array y. Here X will be the array of pixels and y will be value 0 or 1 indicating its a dog or cat Write convert function to map category “dog” or “cat” into 1 and 0

Create a function create_test_data which takes all training images into a loop. Converts into image array. Resize image into 80 X80. Append image into X array. Append category value into y array.

X = []
y = []
convert = lambda category : int(category == 'dog')
def create_test_data(path):
    for p in os.listdir(path):
        category = p.split(".")[0]
        category = convert(category)
        img_array = cv2.imread(os.path.join(path,p),cv2.IMREAD_GRAYSCALE)
        new_img_array = cv2.resize(img_array, dsize=(80, 80))

Now call the function, but also later convert X and y into numpy array We also have to reshape X with the below code

X = np.array(X).reshape(-1, 80,80,1)
y = np.array(y)

If you see the values of X you can see a variety of values between 0- 255 . Its because every pixel has different density of black and white. But with the wide range of values it becomes difficult for a training model to learn ( sometimes memorize ).

How to resolve this And you guessed it right . You can normalize the data. We can use Keras normalize here also . But well we already know all values are having range between 0-255 so we can just divide it by 255 and get all values scaled between 0 -1

That’s what we have done below. You can skip this step to see the difference between accuracy. Don’t believe everything I say. Experiment and see for yourself

#Normalize data
X = X/255.0

Now Lets train our model

model = Sequential()
# Adds a densely-connected layer with 64 units to the model:
model.add(Conv2D(64,(3,3), activation = 'relu', input_shape = X.shape[1:]))
model.add(MaxPooling2D(pool_size = (2,2)))
# Add another:
model.add(Conv2D(64,(3,3), activation = 'relu'))
model.add(MaxPooling2D(pool_size = (2,2)))

model.add(Dense(64, activation='relu'))
# Add a softmax layer with 10 output units:
model.add(Dense(1, activation='sigmoid'))


Now we will fit our model with training data.

Epochs :- How many times our model will go through data

Batch size :- How much amount of data at once you wanna pass through the model

validation_split :- How much amount of data (in this case its 20 %) you will need to check cross validation error, y, epochs=10, batch_size=32, validation_split=0.2)
Train on 20000 samples, validate on 5000 samples
Epoch 1/10
20000/20000 [==============================] - 16s 790us/step - loss: 0.6109 - acc: 0.6558 - val_loss: 0.5383 - val_acc: 0.7308
Epoch 2/10
20000/20000 [==============================] - 14s 679us/step - loss: 0.4989 - acc: 0.7557 - val_loss: 0.4989 - val_acc: 0.7564
Epoch 3/10
20000/20000 [==============================] - 14s 679us/step - loss: 0.4502 - acc: 0.7916 - val_loss: 0.4728 - val_acc: 0.7796
Epoch 4/10
20000/20000 [==============================] - 14s 680us/step - loss: 0.4059 - acc: 0.8143 - val_loss: 0.5290 - val_acc: 0.7644
Epoch 5/10
20000/20000 [==============================] - 14s 679us/step - loss: 0.3675 - acc: 0.8334 - val_loss: 0.4572 - val_acc: 0.7938
Epoch 6/10
20000/20000 [==============================] - 14s 679us/step - loss: 0.3181 - acc: 0.8610 - val_loss: 0.4744 - val_acc: 0.7958
Epoch 7/10
20000/20000 [==============================] - 14s 680us/step - loss: 0.2704 - acc: 0.8841 - val_loss: 0.4575 - val_acc: 0.7976
Epoch 8/10
20000/20000 [==============================] - 14s 681us/step - loss: 0.2155 - acc: 0.9104 - val_loss: 0.5198 - val_acc: 0.7878
Epoch 9/10
20000/20000 [==============================] - 14s 679us/step - loss: 0.1646 - acc: 0.9357 - val_loss: 0.6021 - val_acc: 0.7928
Epoch 10/10
20000/20000 [==============================] - 14s 680us/step - loss: 0.1227 - acc: 0.9532 - val_loss: 0.6653 - val_acc: 0.7874

Now the time has come to finally PREDICT, so feed your CNN model with test data to predict.

predictions = model.predict(X_test)

We are rounding the result here as we used sigmoid function and we got the probability values in our predicted data set

predicted_val = [int(round(p[0])) for p in predictions]

Now you have to make submission data frame to submit your result set.

submission_df = pd.DataFrame({'id':id_line, 'label':predicted_val})

Write your data frame to a csv file

submission_df.to_csv("submission.csv", index=False)

Also, read – 10 Machine Learning Projects to Boost your Portfolio

I hope this CNN model will help you, mention in comments on what topic you want the next article.

Aman Kharwal
Aman Kharwal

I'm a writer and data scientist on a mission to educate others about the incredible power of data📈.

Articles: 1534

Leave a Reply