Deep Learning Project – Handwritten Digit Recognition using Python

Free Machine Learning courses with 130+ real-time projects Start Now!!

Python Deep Learning Project

To make machines more intelligent, the developers are diving into machine learning and deep learning techniques. A human learns to perform a task by practicing and repeating it again and again so that it memorizes how to perform the tasks. Then the neurons in his brain automatically trigger and they can quickly perform the task they have learned. Deep learning is also very similar to this. It uses different types of neural network architectures for different types of problems. For example – object recognition, image and sound classification, object detection, image segmentation, etc.

This is the 11th project in the DataFlair’s series of 20 Python projects. I suggest you to bookmark the previous projects:

  1. Fake News Detection Python Project 
  2. Parkinson’s Disease Detection Python Project 
  3. Color Detection Python Project
  4. Speech Emotion Recognition Python Project 
  5. Breast Cancer Classification Python Project
  6. Age and Gender Detection Python Project 
  7. Handwritten Digit Recognition Python Project
  8. Chatbot Python Project
  9. Driver Drowsiness Detection Python Project
  10. Traffic Signs Recognition Python Project
  11. Image Caption Generator Python Project

What is Handwritten Digit Recognition?

The handwritten digit recognition is the ability of computers to recognize human handwritten digits. It is a hard task for the machine because handwritten digits are not perfect and can be made with many different flavors. The handwritten digit recognition is the solution to this problem which uses the image of a digit and recognizes the digit present in the image.

About the Python Deep Learning Project

python deep learning project - handwritten digit recognition

In this article, we are going to implement a handwritten digit recognition app using the MNIST dataset. We will be using a special type of deep neural network that is Convolutional Neural Networks. In the end, we are going to build a GUI in which you can draw the digit and recognize it straight away.

Prerequisites

The interesting Python project requires you to have basic knowledge of Python programming, deep learning with Keras library and the Tkinter library for building GUI.

Install the necessary libraries for this project using this command:

pip install numpy, tensorflow, keras, pillow,

The MNIST dataset

This is probably one of the most popular datasets among machine learning and deep learning enthusiasts. The MNIST dataset contains 60,000 training images of handwritten digits from zero to nine and 10,000 images for testing. So, the MNIST dataset has 10 different classes. The handwritten digits images are represented as a 28×28 matrix where each cell contains grayscale pixel value.

Download the full source code for the project

Building Python Deep Learning Project on Handwritten Digit Recognition

Below are the steps to implement the handwritten digit recognition project:

1. Import the libraries and load the dataset

First, we are going to import all the modules that we are going to need for training our model. The Keras library already contains some datasets and MNIST is one of them. So we can easily import the dataset and start working with it. The mnist.load_data() method returns us the training data, its labels and also the testing data and its labels.

import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras import backend as K

# the data, split between train and test sets
(x_train, y_train), (x_test, y_test) = mnist.load_data()

print(x_train.shape, y_train.shape)

2. Preprocess the data

The image data cannot be fed directly into the model so we need to perform some operations and process the data to make it ready for our neural network. The dimension of the training data is (60000,28,28). The CNN model will require one more dimension so we reshape the matrix to shape (60000,28,28,1).

x_train = x_train.reshape(x_train.shape[0], 28, 28, 1)
x_test = x_test.reshape(x_test.shape[0], 28, 28, 1)
input_shape = (28, 28, 1)

# convert class vectors to binary class matrices
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)

x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')

3. Create the model

Now we will create our CNN model in Python data science project. A CNN model generally consists of convolutional and pooling layers. It works better for data that are represented as grid structures, this is the reason why CNN works well for image classification problems. The dropout layer is used to deactivate some of the neurons and while training, it reduces offer fitting of the model. We will then compile the model with the Adadelta optimizer.

batch_size = 128
num_classes = 10
epochs = 10

model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3),activation='relu',input_shape=input_shape))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))

model.compile(loss=keras.losses.categorical_crossentropy,optimizer=keras.optimizers.Adadelta(),metrics=['accuracy'])

4. Train the model

The model.fit() function of Keras will start the training of the model. It takes the training data, validation data, epochs, and batch size.

It takes some time to train the model. After training, we save the weights and model definition in the ‘mnist.h5’ file.

hist = model.fit(x_train, y_train,batch_size=batch_size,epochs=epochs,verbose=1,validation_data=(x_test, y_test))
print("The model has successfully trained")

model.save('mnist.h5')
print("Saving the model as mnist.h5")

5. Evaluate the model

We have 10,000 images in our dataset which will be used to evaluate how good our model works. The testing data was not involved in the training of the data therefore, it is new data for our model. The MNIST dataset is well balanced so we can get around 99% accuracy.

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

6. Create GUI to predict digits

Now for the GUI, we have created a new file in which we build an interactive window to draw digits on canvas and with a button, we can recognize the digit. The Tkinter library comes in the Python standard library. We have created a function predict_digit() that takes the image as input and then uses the trained model to predict the digit.

Then we create the App class which is responsible for building the GUI for our app. We create a canvas where we can draw by capturing the mouse event and with a button, we trigger the predict_digit() function and display the results.

Here’s the full code for our gui_digit_recognizer.py file:

from keras.models import load_model
from tkinter import *
import tkinter as tk
import win32gui
from PIL import ImageGrab, Image
import numpy as np

model = load_model('mnist.h5')

def predict_digit(img):
    #resize image to 28x28 pixels
    img = img.resize((28,28))
    #convert rgb to grayscale
    img = img.convert('L')
    img = np.array(img)
    #reshaping to support our model input and normalizing
    img = img.reshape(1,28,28,1)
    img = img/255.0
    #predicting the class
    res = model.predict([img])[0]
    return np.argmax(res), max(res)

class App(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)

        self.x = self.y = 0

        # Creating elements
        self.canvas = tk.Canvas(self, width=300, height=300, bg = "white", cursor="cross")
        self.label = tk.Label(self, text="Thinking..", font=("Helvetica", 48))
        self.classify_btn = tk.Button(self, text = "Recognise", command =         self.classify_handwriting) 
        self.button_clear = tk.Button(self, text = "Clear", command = self.clear_all)

        # Grid structure
        self.canvas.grid(row=0, column=0, pady=2, sticky=W, )
        self.label.grid(row=0, column=1,pady=2, padx=2)
        self.classify_btn.grid(row=1, column=1, pady=2, padx=2)
        self.button_clear.grid(row=1, column=0, pady=2)

        #self.canvas.bind("<Motion>", self.start_pos)
        self.canvas.bind("<B1-Motion>", self.draw_lines)

    def clear_all(self):
        self.canvas.delete("all")

    def classify_handwriting(self):
        HWND = self.canvas.winfo_id() # get the handle of the canvas
        rect = win32gui.GetWindowRect(HWND) # get the coordinate of the canvas
        im = ImageGrab.grab(rect)

        digit, acc = predict_digit(im)
        self.label.configure(text= str(digit)+', '+ str(int(acc*100))+'%')

    def draw_lines(self, event):
        self.x = event.x
        self.y = event.y
        r=8
        self.canvas.create_oval(self.x-r, self.y-r, self.x + r, self.y + r, fill='black')

app = App()
mainloop()

Screenshots:

python machine learning project output as number 2

python machine learning project output as number 5

python project output as number 6

Summary

In this article, we have successfully built a Python deep learning project on handwritten digit recognition app. We have built and trained the Convolutional neural network which is very effective for image classification purposes. Later on, we build the GUI where we draw a digit on the canvas then we classify the digit and show the results.

Want to get hired as a Python expert? Practice the 150+ Python Interview Questions by DataFlair

Do share your views regarding the intermediate Python project in the comment section.

Did you like this article? If Yes, please give DataFlair 5 Stars on Google

follow dataflair on YouTube

163 Responses

  1. Felipe says:

    It makes the same…. it does not worw!

    • Santosh says:

      To improve the accuracy, I have done following steps:
      Preprocess the images and make it similar to the images in test data. You need to create bounding box around digit, crop it and resize it 18×18. Now add padding of 5px all around to make image size: 28×28

      Apart from that, you need to create your own training & testing dataset.

      Machine learning is all about training, testing and hit & trial.

  2. Alessandro says:

    Hello,

    I have tried to run your code but at line
    model.add(Conv2D(32, kernel_size=(3, 3),activation=’relu’,input_shape=input_shape))
    it gives me the following error:
    TypeError: ‘NoneType’ object is not iterable

    thank you for your help

  3. adiu says:

    there is not win32gui in Mac, what can I use instead?
    your helps are appreciated.

  4. adiu says:

    There is not win32gui in Mac. What can I do instead?
    your helps are appreciated.

  5. Durgesh R Pandey says:

    Can you please mention proper information about software with code stepwise explained

  6. vivek says:

    in which editor all this code is written?

    • Durgesh R Pandey says:

      I did this project but it shows
      DLL load failed while importing _pywrap_tensorflow_internal:A dynamic link library (DLL) initialisation routine failed.
      If any one has suggestions please inform us

  7. Josh says:

    I’m using Linux Ubuntu, so I don’t have the ability to import win32gui. How can I modify the code to work on Linux in the gui_digit_recognizer.py file?

  8. Ayesha Iftikhar says:

    I have created the project using this code but it doesn’t give the appropriate results, how can I train the modal fastly because I have a very tight deadline for my project

  9. sue says:

    am facing the same challenge please assist am failing to get the results.

  10. Meghana Nuli says:

    can u provide report for this project

  11. Simon says:

    It would be excellent to have a technical report that shows how the code works. Step by step.. Especially for Ubuntu OS.
    Thank you Sir !

  12. Divyam says:

    I trained the model with 99% accuracy. But it does not perform well when testing with gui. Can you please help.

  13. Hithaishi Ramakrishna says:

    define num_classes before the first encounter

  14. Hithaishi Ramakrishna says:

    @Rohan Kumar can you please explain what is the percentage that is displayed while recognising the digit. and why it changes evrytime?

  15. Aniket dhanwate says:

    till how much digit we can recognize the numbers ?

  16. shivam says:

    num_classes not define error is showing again and again what should i do from preprocess the data

  17. Samriddh Singh says:

    Hey, I learnt the model is working fine, here the GUI is causing issue, in the dataset on which the model is being deployed has a white background and white event, however, the MNIST dataset is reverse of that.
    Solution to get correct output-
    1.)Line 25 change bg to black
    *self.canvas = tk.Canvas(self, width=300, height=300, bg = “black”, cursor=”cross”)*

    2.)Line 48 change the fill to white-
    *self.canvas.create_oval(self.x-r, self.y-r, self.x + r, self.y + r, fill=’white’)*

  18. Narendra Kharche says:

    In python3.8.5 I am getting the error that ModuleNotFoundError: No module named ‘win32gui’ Then i installed pip install pywin32 and gives same error. Pls. try to sort it.
    Regards

  19. Brandon says:

    I was able to get around this by modifying the classify_handwriting function:

    def classify_handwriting(self):
    # get the coordinate of the canvas
    a = self.canvas.winfo_rootx()
    b = self.canvas.winfo_rooty()
    c = a + self.canvas.winfo_width()
    d = b + self.canvas.winfo_height()
    rect = (a + 4, b + 4, c – 4, d – 4)
    print(rect)
    im = ImageGrab.grab(rect)

    digit, acc = predict_digit(im)
    self.label.configure(text=str(digit) + ‘, ‘ + str(int(acc * 100)) + ‘%’)

    The interface appears to be working correctly but the model does not predict the correct number, and most times does not change the predicted digit even when drawing a new/different number. I’ve tried the solution above that suggested changing the black/white and saw no change.

  20. TechDream says:

    Me,Too,Can you help me?thanks.

  21. TechDream says:

    I trained the model with 99% accuracy. But it does not perform well when testing with gui. Can you please help.

  22. Abdul Mannan says:

    I have a problem that I do not have the NVidia GPU to run he tensor flow library and other pre requisites,
    Can someone help?

  23. NIKHILKUMAR Cheela says:

    Can i Get this project report

  24. Ahmad Siar says:

    x_train = x_train.reshape(x_train.shape[0], 28, 28, 1)
    x_test = x_test.reshape(x_test.shape[0], 28, 28, 1)
    input_shape = (28, 28, 1)

    # convert class vectors to binary class matrices
    y_train = keras.utils.to_categorical(y_train, num_classes)
    y_test = keras.utils.to_categorical(y_test, num_classes)

    x_train = x_train.astype(‘float32’)
    x_test = x_test.astype(‘float32’)
    x_train /= 255
    x_test /= 255
    print(‘x_train shape:’, x_train.shape)
    print(x_train.shape[0], ‘train samples’)
    print(x_test.shape[0], ‘test samples’)

    when I run the above code I receive the following error

    NameError Traceback (most recent call last)
    in
    4
    5 # convert class vectors to binary class matrices
    —-> 6 y_train = keras.utils.to_categorical(y_train, num_classes)
    7 y_test = keras.utils.to_categorical(y_test, num_classes)
    8

    NameError: name ‘num_classes’ is not defined

    • White says:

      you need to define num_classes like :
      y_train = tensorflow.keras.utils.to_categorical(y_train, num_classes=10)
      y_test = tensorflow.keras.utils.to_categorical(y_test, num_classes=10)

  25. shahrukh khan says:

    ok i’ll fixed it;p

  26. Saqib says:

    instead of num_classes put 10

  27. yao yong says:

    There are a few things i want to comments
    1) the model is too complex, the training accuracy is very high, but the test results is very low
    2) img better invert, img=PIL.ImageOps.invert(img)
    3)img data need to convert to float 32
    4) to test the function, better write as the training set, you random writing may be not include in the train dataset.

  28. YAO YONG says:

    a simple model will give a good results.

    model=Sequential()
    model.add(Dense(512, activation=’relu’, input_shape=(28 * 28,)))
    model.add(Dense(10, activation=’softmax’))

  29. Akshay Ramgude says:

    You are awesome

  30. anand says:

    Hi,

    I have written your model and saved it, with epoch 10, after 10th cycle the accuracy was 84, instead of implementing GUI, i took paint and drew numbers and i tried to read them with pillow PIL, after that i tried to predict that pic with my model but the model is predicting wrong. Why? how to format the image so that it can predict well?

Leave a Reply

Your email address will not be published. Required fields are marked *