nn-js · MNIST digit classifier

How the network reads a handwritten digit

A fully connected network turns 784 pixel brightnesses into 10 probabilities. Each layer multiplies the previous layer by a weight matrix, adds a bias, and applies an activation. Below, real test image #0 (a 7) flows through the trained model. It predicts 7 with 100.00% confidence.

Test image #0 (28 × 28)flattened row by row into784 numbers between 0 and 10123456789100.0%Input layer784 pixelsshowing 12 bright pixelsHidden layer 1256 neurons · ReLUshowing 12 most activeHidden layer 2128 neurons · ReLUshowing 12 most activeOutput layer10 neurons · softmaxone per digitW1 · 256×784200,960 paramsW2 · 128×25632,896 paramsW3 · 10×1281,290 paramsP(digit)
positive weight negative weight line opacity = |weight| strongly active quiet
235,146 trainable parameters · 98.17% test accuracy1 / 5

One forward pass

Every layer is a matrix multiply plus a simple non-linearity

Hidden layers use ReLU (max(0, z)), so a neuron either stays silent or passes its signal on. For any given digit, only part of the network lights up. The output layer uses softmax to turn 10 scores into probabilities that sum to 1.

The math, with shapes

xpixels / 255784
h₁ = ReLU(W₁x + b₁)first hidden layer256
h₂ = ReLU(W₂h₁ + b₂)second hidden layer128
p = softmax(W₃h₂ + b₃)pᵢ = eᶻⁱ / Σ eᶻʲ10
prediction = argmax(p)most likely digit1

How it learned the weights

1 · Forward pass64 images in,probabilities out2 · Losscross-entropy:−log P(correct digit)3 · Backpropagationchain rule gives∂loss/∂w for every weight4 · Adam updatenudge each weightagainst its gradient860 batches per epoch × 15 epochs ≈ 12,900 updates

During training, 20% of hidden neurons are randomly switched off on each step (dropout). This stops the network from relying on any single neuron.

Hidden activity for image #0

Hidden layer 1: 66 of 256 neurons fire

Hidden layer 2: 51 of 128 neurons fire

silent (ReLU output 0) weak strong

Each square is one neuron, in index order. A different digit lights up a different pattern. The output layer reads these patterns to decide which digit it sees.

Shapes are per image. Training runs 64 images at a time.2 / 5

Inside hidden layer 1

What the first layer learned to look for

Each neuron in hidden layer 1 has 784 weights, one per pixel, so its weights can be drawn as a 28×28 image. Blue pixels push the neuron to fire when ink is there. Red pixels hold it back. Together they act as stroke and edge detectors. These are the 60 neurons with the largest weights.

#2
#4
#5
#7
#8
#32
#35
#36
#39
#43
#48
#52
#55
#66
#67
#69
#77
#78
#82
#84
#96
#102
#107
#108
#112
#114
#115
#116
#118
#126
#130
#131
#139
#141
#143
#144
#145
#150
#151
#157
#166
#170
#171
#173
#178
#180
#182
#184
#189
#201
#204
#211
#213
#222
#232
#236
#250
#252
#253
#255
negative weight (inhibits) 0 positive (excites)
Each map is scaled to its own largest |weight|.3 / 5

Results on 10,000 unseen test images

Predictions, and where it gets confused

The network never saw these images during training. It gets 9,817 of 10,000 right (98.17%). Most mistakes are on digits that are genuinely ambiguous or badly written.

Sample predictions: 12 correct, then the first 4 mistakes

0123456789
7 · 100.0%
0123456789
1 · 100.0%
0123456789
1 · 100.0%
0123456789
7 · 98.7%
0123456789
0 · 100.0%
0123456789
9 · 99.8%
0123456789
2 · 100.0%
0123456789
6 · 90.1%
0123456789
0 · 100.0%
0123456789
5 · 100.0%
0123456789
7 · 100.0%
0123456789
0 · 100.0%
0123456789
✕ 6 · true 5
0123456789
✕ 2 · true 4
0123456789
✕ 3 · true 9
0123456789
✕ 7 · true 2

Confusion matrix: off-diagonal cells are errors

Predicted digitTrue digit0011223344556677889997311122112031227410191152599415231695431215213186942132343940316711100525124421395431227215989

Diagonal cells (gray) count correct answers. Darker blue means more errors. For example, the cell at row 4, column 9 shows that 15 images of a 4 were read as a 9.

Bars show the softmax probability for each digit. Red marks a wrong prediction.4 / 5

Training run

How it improved, epoch by epoch

One epoch is one pass over the 55,000 training images. Loss keeps falling, but validation accuracy levels off after a few epochs. The model saved to disk is the one with the best validation accuracy (epoch 8).

98.17%
test accuracy
98.50%
best validation accuracy (epoch 8)
235,146
trainable parameters
15
epochs · Adam, lr 0.001, batch 64

Training loss (cross-entropy)

0.000.100.200.3013579111315Epoch0.03

Validation accuracy (axis starts at 96%)

96.0%96.5%97.0%97.5%98.0%98.5%99.0%13579111315Epoch98.5%
Validation set: 5,000 images held out from the training data.5 / 5