Challenge

Implement and deploy CNN model in real-time using python on Fashion MNIST dataset

Introduction

Humans are a brilliant natural system which is having the great capability of viewing and observing multiple images in a short span of time, then consume and deduce from them without even realizing that how the actual process is completed. But this case is not at all similar with machines or systems.

Aim and Objectives

The main aim to plan and strategize a solution by understanding the basic idea of image processing for better understanding of the underlying concepts and then to get a vision of how to feed an image in such a manner that the machine or system can consume it to help and give a fruitful output.

Any image is a cumulative arrangement of dots called pixels and the pixels are arranged in a special order to represent an image. If the order structure or color of a pixel is modified in whatsoever way, the representation of image would be altered as well. So elaborate work has to be done on the implementation of CNN model.

About the Dataset

Here the dataset provided is based on certain fashion components, it is a dataset of images—consisting of a training set of 60,000 examples and a test set of 10,000 examples. Each example is a 28x28 grayscale image, associated with a label from 10 classes.

Data Description

1. Each image is 28 pixels in height and 28 pixels in width, for a total of 784 pixels in total.

2. Each pixel has a single pixel-value associated with it, indicating the lightness or darkness of that pixel, with higher numbers meaning darker. This pixel-value is an integer between 0 and 255.

3. The training and test data sets have 785 columns.

4. The first column consists of the class labels (see above), and represents the article of clothing.

5. The rest of the columns contain the pixel-values of the associated image.

To locate a pixel on the image, suppose that we have decomposed x as x = i * 28 + j, where i and j are integers between 0 and 27. The pixel is located on row i and column j of a 28 x 28 matrix. For example, pixel31 indicates the pixel that is in the fourth column from the left, and the second row from the top, as in a ascii-diagram.

Processing

Importing the libraries

import numpy as np
import pandas as pd
from tensorflow import keras 
from tensorflow.keras.utils import to_categorical

from tensorflow.keras.models import Sequential 
from tensorflow.keras.layers import Dense,Dropout,Activation,Flatten
from tensorflow.keras.layers import Conv2D,MaxPooling2D,BatchNormalization
from tensorflow.keras.losses import categorical_crossentropy
from sklearn.metrics import accuracy_score
from tensorflow.keras.regularizers import l2
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from sklearn.metrics import classification_report,confusion_matrix
import matplotlib.pyplot as plt
import seaborn as sns

import warnings
warnings.filterwarnings('ignore')

Importing the dataset

train_data = pd.read_csv('fashion-mnist_train.csv')
train_data.shape

(60000, 785)

test_data = pd.read_csv('fashion-mnist_test.csv')
test_data.shape

(10000, 785)

train_data.head()

  • The table above displays the first 5 rows of the data frame. Each row of this data frame contains information
    about an "image".
  • The first column named label identifies the clothing item that is depicted in the image.
  • The other 784 columns named pixel represent the image.

As we can see in above preview the mini dataset of 5 images is a matrix with 5 rows and 785 columns. Displaying it as matrix is not very informative as each cell is a pixel and as such is not human-readable. To better understand what each pixel represents, we need to convert it to a weighted form.

train_data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 60000 entries, 0 to 59999
Columns: 785 entries, label to pixel784
dtypes: int64(785)
memory usage: 359.3 MB
  • The dataframe statistics indicate that there are 60,000 rows and 785 features in the training dataset.
  • Each row represents an image that will be used during model training.

Unique values in label column of training dataset

train_data['label'].unique()

array([2, 9, 6, 0, 3, 4, 5, 8, 7, 1], dtype=int64)

Counting number of images for each label class

train_data['label'].value_counts()
2    6000
9    6000
6    6000
0    6000
3    6000
4    6000
5    6000
8    6000
7    6000
1    6000
Name: label, dtype: int64

6,000 images associated with each label, it is balanced dataset

Separating independent and dependent variables for train and test data

train_x = train_data.drop(columns=['label'])
y_train = train_data['label']
test_x = test_data.drop(columns=['label'])
y_test = test_data['label']
train_x.shape, y_train.shape ,test_x.shape,y_test.shape

((60000, 784), (60000,), (10000, 784), (10000,))

  • These are not in proper shape.
  • For keras input shape size shoud be 4D.


Reshaping the data

x_train = train_x.values.reshape(train_x.shape[0],28,28,1) 
x_test = test_x.values.reshape(test_x.shape[0],28,28,1) 
print('x_train shape',x_train.shape)
print('x_test shape',x_test.shape)
print('y_train shape',y_train.shape)
print('y_test shape',y_test.shape)
x_train shape (60000, 28, 28, 1)
x_test shape (10000, 28, 28, 1)
y_train shape (60000,)
y_test shape (10000,)


Feature Scaling

  • Each image is 28 pixels in height and 28 pixels in width, for a total of 784 pixels in total.
  • The 784 pixelXXX column values in each row contain brightness information for each pixel in the 28x28 grayscale image.
  • Each pixel has a single pixel-value associated with it, indicating the lightness or darkness of that pixel,
    with higher numbers meaning darker.
  • This pixel-value is an integer between 0(black) and 255(white).Values in between represent different shades of gray.
  • To normalize the values, we therefore need to divide each pixelXXX cell by 255.

Normalizing train & test data between 0 to 1

x_train = x_train/255
x_test = x_test/255

Visualizing the images

y_train.unique()
array([2, 9, 6, 0, 3, 4, 5, 8, 7, 1], dtype=int64)

Numeric labels are not that meaningful in a visualization, we'll map them to a textual representation
0 => T-shirt/top,1 => Trouser,2 => Pullover,3 => Dress,4 => Coat,5 => Sandal,6 => Shirt,7 => Sneaker,8 => Bag,9 => Ankle boot
class_labels = ['T shirt/top','Trouser','Pullover','Dress','Coat','Sandal','Shirt','Sneaker','Bag','Ankle boot']

Set figure size

plt.figure(figsize = (10,10))

Showing randomly 20 images from training dsataset

j=1
for i in np.random.randint(0,6000,20):
    plt.subplot(6,5,j)
    j+=1
    plt.xticks([])
    plt.yticks([])
    plt.imshow(x_train[i],cmap = plt.cm.binary)
    plt.title('{}/{}'.format(class_labels[y_train[i]],y_train[i]))

Train-test split dataset

from sklearn.model_selection import train_test_split
x_train,x_val,y_train,y_val = train_test_split(x_train,y_train,test_size = 0.2,random_state=42)
x_train.shape , y_train.shape

((48000, 28, 28, 1), (48000,))

x_val.shape , y_val.shape

((12000, 28, 28, 1), (12000,))

Convolutional Neural Network - Model Building

model = keras.models.Sequential([
                                keras.layers.Conv2D(filters = 32,kernel_size = 3,padding = 'valid',activation = 'relu',input_shape = [28,28,1]),
                                keras.layers.MaxPooling2D(pool_size = (2,2)),
                                keras.layers.Conv2D(filters = 64,kernel_size = 3,padding = 'same',activation = 'relu'),
                                keras.layers.MaxPooling2D(pool_size = (2,2)),
                                keras.layers.Flatten(),
                                keras.layers.Dense(units=256, activation='relu'),
                                keras.layers.Dropout(0.5),                  
                                keras.layers.Dense(units = 128,activation = 'relu'),
                                keras.layers.Dropout(0.10),
                                keras.layers.Dense(units = 10,activation = 'softmax')])

Model summary

model.summary()

Model compile

model.compile(optimizer = 'adam',loss = 'sparse_categorical_crossentropy',metrics = ['accuracy'])

Train

history = model.fit(x_train,y_train,epochs = 15,batch_size = 512,verbose = 1 , validation_data = (x_val,y_val))

List of all the data in history

print(history.history.keys())

dict_keys(['loss', 'accuracy', 'val_loss', 'val_accuracy'])

Plotting accuracy and loss of the model

def plot_training_hist(history):
    '''Function to plot history for accuracy and loss'''
    
    fig, ax = plt.subplots(1, 2, figsize=(10,4))
    
    # first plot
    ax[0].plot(history.history['accuracy'])
    ax[0].plot(history.history['val_accuracy'])
    ax[0].set_title('Model Accuracy')
    ax[0].set_xlabel('epoch')
    ax[0].set_ylabel('accuracy')
    ax[0].legend(['train', 'validation'], loc='best')
    
    # second plot
    ax[1].plot(history.history['loss'])
    ax[1].plot(history.history['val_loss'])
    ax[1].set_title('Model Loss')
    ax[1].set_xlabel('epoch')
    ax[1].set_ylabel('loss')
    ax[1].legend(['train', 'validation'], loc='best')
    
plot_training_hist(history)

Test Model

np.argmax(model.predict(np.expand_dims(x_test[0],axis = 0)).round(2)) 
#test on single test image(predicted label)
0
y_test[0] #actual label of above image

0

Testing on all test images

y_pred = model.predict(x_test).round(2)
y_pred
array([[1.  , 0.  , 0.  , ..., 0.  , 0.  , 0.  ],
       [0.  , 1.  , 0.  , ..., 0.  , 0.  , 0.  ],
       [0.01, 0.  , 0.87, ..., 0.  , 0.  , 0.  ],
       ...,
       [0.  , 0.  , 0.  , ..., 0.  , 1.  , 0.  ],
       [0.  , 0.  , 0.  , ..., 0.  , 1.  , 0.  ],
       [0.  , 1.  , 0.  , ..., 0.  , 0.  , 0.  ]], dtype=float32)

Model evaluation

model.evaluate(x_test,y_test)
[0.2102140635251999, 0.9229000210762024]

Visualize output

plt.figure(figsize = (16,30))

Comparing randomly actual and predicted labels from test data

j=1
for i in np.random.randint(0,1000,10):
    plt.subplot(10,5,j);j+=1
    plt.xticks([])
    plt.yticks([])
    plt.imshow(x_test[i].reshape(28,28),cmap = 'Greys')
    plt.title('Actual = {} / {}  npredicted = {} / {}'.format(class_labels[y_test[i]],y_test[i],class_labels[np.argmax(y_pred[i])],np.argmax(y_pred[i])))

Confusion Matrix

from sklearn.metrics import confusion_matrix

y_predicted_labels = [np.argmax(label) for label in y_pred]
cm = confusion_matrix(y_test,y_predicted_labels)

print('confusion_matrix:n',cm)
confusion_matrix:
 [[900   0  16  11   0   0  68   0   5   0]
 [  2 983   1  12   0   1   1   0   0   0]
 [ 12   0 881  12  47   0  44   0   4   0]
 [ 13   3   3 949  17   0  15   0   0   0]
 [  1   0  30  24 899   0  46   0   0   0]
 [  0   0   0   0   0 980   0  13   1   6]
 [133   2  46  28  63   0 719   0   9   0]
 [  0   0   0   0   0   5   0 961   0  34]
 [  3   1   2   0   2   1   2   2 986   1]
 [  0   0   0   0   0   1   0  27   0 972]]


Plotting the confusion matrix

plt.figure(figsize=(10,7))
sns.heatmap(cm,annot = True,fmt = 'd',xticklabels=class_labels, yticklabels=class_labels)

Classification report

cl_report = classification_report(y_test,y_predicted_labels , target_names = class_labels)
print(cl_report)
              precision    recall  f1-score   support

 T-shirt/top       0.85      0.90      0.87      1000
     Trouser       0.99      0.98      0.99      1000
    Pullover       0.90      0.88      0.89      1000
       Dress       0.92      0.95      0.93      1000
        Coat       0.87      0.90      0.89      1000
      Sandal       0.99      0.98      0.99      1000
       Shirt       0.80      0.72      0.76      1000
     Sneaker       0.96      0.96      0.96      1000
         Bag       0.98      0.99      0.98      1000
  Ankle boot       0.96      0.97      0.97      1000

    accuracy                           0.92     10000
   macro avg       0.92      0.92      0.92     10000
weighted avg       0.92      0.92      0.92     10000

We can say from above report:

  • Trouser, sandal, bag, ankle boot model performance is very good.
  • Shirt model performance is not very good comparatively
Your portfolio, next

Ship work like this
in your own course.

Talk to a career counsellor

Free 20-minute call. We'll map the right course to where you want to work.

By submitting you agree to our Terms and Privacy Policy.