Handwritten digit classifier

A small neural network trained on the MNIST dataset of handwritten digits. Draw a number below and see what it thinks you wrote. Everything runs in your browser.

Draw one digit, large and centered
?
Loading the model…
What the model sees: your drawing shrunk to 28×28 pixels and centered, like the training images.

Background

The MNIST dataset contains 70,000 images of handwritten digits, written by thousands of high school students and US Postal Service employees. Due to the diverse handwriting styles, some images are even difficult for humans to read correctly. This kind of neural network has been used for decades by banks, governments, and other organizations around the world.

How it works

Each image is a 28×28 grayscale picture of a single digit. Before your drawing reaches the model, it goes through these steps so the model knows what it's looking at:

  1. Crop around the area you actually drew on.
  2. Scale it down to a rectangle, keeping the longer side at 20 pixels.
  3. Center it on a 28×28 canvas.
  4. Scale pixel values between 0 and 1 based on brightness and make a list containing each value.

Then, the model outputs a probability for each digit, shown in the bars above.

The model

A fully connected network built with Keraswith the trained weights exported to a JSON file. The network runs using Javascript in your browser, with no machine learning library needed.

LayerSizeActivation
Input784 pixels–
Hidden10 unitsReLU
Hidden10 unitsReLU
Output10 classesSoftmax

Trained for 10 epochs on 54,000 images with the Adam optimizer (learning rate 0.01), holding out 10% for validation. It reaches 92.7% accuracy on the 10,000-image test set.

Where it struggles

With only two hidden layers of 10 units, the network is deliberately small. Drawings made with a mouse or finger also look different from the scanned handwriting it learned from. Because of different ways of writing digits, misclassifications for certain digits are common. Try drawing digits diferently to see how the model responds(4 with an open top, 2 with a loop, etc...). A convolutional network, which looks at local patterns of pixels instead of each pixel independently, would handle these cases much better.