Understanding Convolution Neural Networks by@sub_zero_ai_freak

July 16th 2020 462 reads

I am an AI developer and my areas of expertise are Deep Learning , High Performance Computing .

This article is a simple guide that will help you build and understand the concepts behind building a simple CNN. By the end of this article you will be able to build a simple CNN based on the PyTorch API and will classify clothing using the FashionMNIST dateset. This is assuming you have prior knowledge to Artificial Neural Networks.

**CNN**

The concept of CNN or Convolution Neural Networks was popularized by Yann André LeCun who is also known as the father of the convolution nets.

A CNN works very similar to how our human eye works. The core operations that are behind the CNN’s are matrix additions and multiplications.So, there is no need to get worried about them.

But to know about the working of the CNN’s we need to know how the image gets stored in the computer.

The above example shows us how the image is stored which is in the form of arrays.

But these are only grey scale images. So an RGB or a color image is 3 such matrices stacked on one other.

The above multi-dimension matrix represents a colored image. But in this article we would discuss the classification of grey scale images.

The core function behind a CNN is the convolution operation. It is multiplication of the image matrix with a filter matrix to extract some important features from the image matrix.

The above diagram shows the convolution operation on an image matrix. The convolution matrix is filled by moving the filter matrix through the image matrix.

Another important component of a CNN is called the Max-pool layer. This helps us in reducing the number of features i.e. it sharpens them so that our CNN performs better.

To all of the convolutional layers we apply the RELU activation function.

While mapping the convolutional layers to the output we need to use a linear layer. So we use layers called the fully connected layers abbreviated as fc.

The final fc’s activation mostly is a sigmoid activation function.

We can clearly see the output maps between 0 and 1 for all input values.

So now you are aware of the layers we are going to use. This knowledge is enough for building a simple CNN but one optional layer call the dropout will help the CNN perform well. Dropout layer is placed in between the fc layers and this randomly drops the connection with a set probability which will help us in training the CNN better.

Our CNN architecture , but at the end we will add a dropout between the fc layers.

Without wasting anymore time we will get into the code.

```
import torch
import torchvision
# data loading and transforming
from torchvision.datasets import FashionMNIST
from torch.utils.data import DataLoader
from torchvision import transforms
# The output of torchvision datasets are PILImage images of range [0, 1].
# We transform them to Tensors for input into a CNN
## Define a transform to read the data in as a tensor
data_transform = transforms.ToTensor()
# choose the training and test datasets
train_data = FashionMNIST(root='./data', train=True,
download=True, transform=data_transform)
test_data = FashionMNIST(root='./data', train=False,
download=True, transform=data_transform)
# Print out some stats about the training and test data
print('Train data, number of images: ', len(train_data))
print('Test data, number of images: ', len(test_data))
# prepare data loaders, set the batch_size
batch_size = 20
train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_data, batch_size=batch_size, shuffle=True)
# specify the image classes
classes = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']
For visualizing the Data
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
# obtain one batch of training images
dataiter = iter(train_loader)
images, labels = dataiter.next()
images = images.numpy()
# plot the images in the batch, along with the corresponding labels
fig = plt.figure(figsize=(25, 4))
for idx in np.arange(batch_size):
ax = fig.add_subplot(2, batch_size/2, idx+1, xticks=[], yticks=[])
ax.imshow(np.squeeze(images[idx]), cmap='gray')
ax.set_title(classes[labels[idx]])
# Defining the CNN
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
# 1 input image channel (grayscale), 10 output channels/feature maps
# 3x3 square convolution kernel
## output size = (W-F)/S +1 = (28-3)/1 +1 = 26
# the output Tensor for one image, will have the dimensions: (10, 26, 26)
# after one pool layer, this becomes (10, 13, 13)
self.conv1 = nn.Conv2d(1, 10, 3)
# maxpool layer
# pool with kernel_size=2, stride=2
self.pool = nn.MaxPool2d(2, 2)
# second conv layer: 10 inputs, 20 outputs, 3x3 conv
## output size = (W-F)/S +1 = (13-3)/1 +1 = 11
# the output tensor will have dimensions: (20, 11, 11)
# after another pool layer this becomes (20, 5, 5); 5.5 is rounded down
self.conv2 = nn.Conv2d(10, 20, 3)
# 20 outputs * the 5*5 filtered/pooled map size
self.fc1 = nn.Linear(20*5*5, 50)
# dropout with p=0.4
self.fc1_drop = nn.Dropout(p=0.4)
# finally, create 10 output channels (for the 10 classes)
self.fc2 = nn.Linear(50, 10)
# define the feedforward behavior
def forward(self, x):
# two conv/relu + pool layers
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
# prep for linear layer
# this line of code is the equivalent of Flatten in Keras
x = x.view(x.size(0), -1)
# two linear layers with dropout in between
x = F.relu(self.fc1(x))
x = self.fc1_drop(x)
x = self.fc2(x)
# final output
return x
# instantiate and print your Net
net = Net()
print(net)
import torch.optim as optim
# using cross entropy whcih combines softmax and NLL loss
criterion = nn.CrossEntropyLoss()
# stochastic gradient descent with a small learning rate and some momentum
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
# Training the CNN
def train(n_epochs):
loss_over_time = [] # to track the loss as the network trains
for epoch in range(n_epochs): # loop over the dataset multiple times
running_loss = 0.0
for batch_i, data in enumerate(train_loader):
# get the input images and their corresponding labels
inputs, labels = data
# zero the parameter (weight) gradients
optimizer.zero_grad()
# forward pass to get outputs
outputs = net(inputs)
# calculate the loss
loss = criterion(outputs, labels)
# backward pass to calculate the parameter gradients
loss.backward()
# update the parameters
optimizer.step()
# print loss statistics
# to convert loss into a scalar and add it to running_loss, we use .item()
running_loss += loss.item()
if batch_i % 1000 == 999: # print every 1000 batches
avg_loss = running_loss/1000
# record and print the avg loss over the 1000 batches
loss_over_time.append(avg_loss)
print('Epoch: {}, Batch: {}, Avg. Loss: {}'.format(epoch + 1, batch_i+1, avg_loss))
running_loss = 0.0
print('Finished Training')
return loss_over_time
# define the number of epochs to train for
n_epochs = 30 # start small to see if your model works, initially
# call train
training_loss = train(n_epochs)
# visualize the loss as the network trained
plt.plot(training_loss)
plt.xlabel('1000\'s of batches')
plt.ylabel('loss')
plt.ylim(0, 2.5) # consistent scale
plt.show()
# obtain one batch of test images
dataiter = iter(test_loader)
images, labels = dataiter.next()
# get predictions
preds = np.squeeze(net(images).data.max(1, keepdim=True)[1].numpy())
images = images.numpy()
# plot the images in the batch, along with predicted and true labels
fig = plt.figure(figsize=(25, 4))
for idx in np.arange(batch_size):
ax = fig.add_subplot(2, batch_size/2, idx+1, xticks=[], yticks=[])
ax.imshow(np.squeeze(images[idx]), cmap='gray')
ax.set_title("{} ({})".format(classes[preds[idx]], classes[labels[idx]]),
color=("green" if preds[idx]==labels[idx] else "red"))
```

This is how we build a simple CNN. Just in case you wanna catch up attached below is my LinkedIn profile link. Feel free to connect.