Digit recognition using CNN and MNIST Data

Author: Iqbal Hossain (dated: 1st Nov, 2019)

Load data, pre-process data and define model

In [1]:
from keras.datasets import mnist
from keras.models import load_model
from keras.utils import to_categorical
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPooling2D


img_rows, img_cols = 28, 28

# load train and test dataset
def load_dataset():
    (train_x, train_y), (test_x, test_y) = mnist.load_data()
        
    # reshape dataset to have a single channel
    train_x = train_x.reshape((train_x.shape[0], img_rows, img_cols, 1))
    test_x = test_x.reshape((test_x.shape[0], img_rows, img_cols, 1))
    
    # one hot encode target values
    train_y = to_categorical(train_y)
    test_y = to_categorical(test_y)
    
    return train_x, train_y, test_x, test_y


# scale pixels
def prep_pixels(train, test):
    # convert from integers to floats
    train_norm = train.astype('float32')
    test_norm = test.astype('float32')
    # normalize to range 0-1
    train_norm = train_norm / 255.0
    test_norm = test_norm / 255.0
    # return normalized images
    return train_norm, test_norm


# define cnn model
def define_model():
    model = Sequential()
    model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(img_rows, img_cols, 1)))
    model.add(MaxPooling2D((2, 2)))
    model.add(Conv2D(64, (3, 3), activation='relu'))
    model.add(MaxPooling2D((2, 2)))
    model.add(Dropout(0.2))
    model.add(Flatten())
    model.add(Dense(128, activation='relu'))
    model.add(Dropout(0.2))
    model.add(Dense(10, activation='softmax'))
    model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
    return model

# load dataset
train_x, train_y, test_x, test_y = load_dataset()
train_x, test_x = prep_pixels(train_x, test_x)
Using TensorFlow backend.

Train model and save model

In [6]:
# define model
model = define_model()

# fit model
epoch_data = model.fit(train_x, train_y, epochs=10, batch_size=64, verbose=1, validation_data=(test_x, test_y))

score = model.evaluate(test_x, test_y, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])

model.save('en_digit_recog_model.h5')
Train on 60000 samples, validate on 10000 samples
Epoch 1/10
60000/60000 [==============================] - 47s 776us/step - loss: 0.1879 - accuracy: 0.9418 - val_loss: 0.0500 - val_accuracy: 0.9836
Epoch 2/10
60000/60000 [==============================] - 46s 770us/step - loss: 0.0619 - accuracy: 0.9814 - val_loss: 0.0389 - val_accuracy: 0.9867
Epoch 3/10
60000/60000 [==============================] - 40s 674us/step - loss: 0.0453 - accuracy: 0.9858 - val_loss: 0.0299 - val_accuracy: 0.9901
Epoch 4/10
60000/60000 [==============================] - 46s 762us/step - loss: 0.0372 - accuracy: 0.9880 - val_loss: 0.0291 - val_accuracy: 0.9903
Epoch 5/10
60000/60000 [==============================] - 39s 652us/step - loss: 0.0303 - accuracy: 0.9902 - val_loss: 0.0273 - val_accuracy: 0.9907
Epoch 6/10
60000/60000 [==============================] - 40s 672us/step - loss: 0.0256 - accuracy: 0.9917 - val_loss: 0.0252 - val_accuracy: 0.9925
Epoch 7/10
60000/60000 [==============================] - 40s 671us/step - loss: 0.0217 - accuracy: 0.9930 - val_loss: 0.0268 - val_accuracy: 0.9914
Epoch 8/10
60000/60000 [==============================] - 40s 662us/step - loss: 0.0198 - accuracy: 0.9938 - val_loss: 0.0244 - val_accuracy: 0.9939
Epoch 9/10
60000/60000 [==============================] - 41s 685us/step - loss: 0.0178 - accuracy: 0.9942 - val_loss: 0.0235 - val_accuracy: 0.9929
Epoch 10/10
60000/60000 [==============================] - 41s 677us/step - loss: 0.0163 - accuracy: 0.9942 - val_loss: 0.0260 - val_accuracy: 0.9919
Test loss: 0.02599468217090507
Test accuracy: 0.9919000267982483

Load model and test predict

In [16]:
from keras.preprocessing.image import load_img
from keras.preprocessing.image import img_to_array
from keras.models import load_model
import numpy as np

model = load_model("en_digit_recog_model.h5")

def predict_image(files):
    images = []
    
    for f in files:
        img = load_img(f, color_mode="grayscale", target_size=(28, 28))
        # convert to array
        img = img_to_array(img)
        # reshape into a single sample with 1 channel
        img = img.reshape(1, 28, 28, 1)
        # prepare pixel data
        img = img.astype('float32')
        img = img / 255.0
        images.append(img)
    
    # predict the class
    digits = model.predict_classes(np.vstack(images), batch_size=len(images))
    return digits
        
print(predict_image(["digit_4.png", "digit_5.png"]))

[4 5] 

4.png 5.png

View Model Accuracy

In [7]:
import matplotlib.pyplot as plt
plt.plot(epoch_data.history['accuracy'])
plt.plot(epoch_data.history['val_accuracy'])
plt.title('Model accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()