I built this to understand how neural networks actually work. The math behind a multi-layer perceptron is surprisingly kinda simple - matrix multiplies, ReLU, softmax, chain rule, but frameworks like PyTorch abstract all of it away behind nn.Module and autograd. So I decided to write everything from scratch: forward pass, backpropagation, gradient descent, all of it.
I also trained a CNN using PyTorch for comparison, to see how much spatial awareness/features matter for image classification.
Try it yourself
Draw a digit below. Both models classify it in real-time, entirely in your browser.
Loading weights…
Loading weights…
Draw a digit to see CNN feature maps
Architecture
MLP (from scratch)
A 4-layer fully connected network:
- Input: 784 neurons (28×28 pixels, flattened)
- Hidden layers: 3 × 256 neurons with ReLU
- Output: 10 neurons with softmax
CNN
The CNN uses spatial structure that the MLP throws away by flattening:
- Conv1: 32 filters (3×3), BatchNorm, ReLU, MaxPool
- Conv2: 32 filters (3×3), BatchNorm, ReLU, MaxPool
- FC: 800 → 10
Convolutional layers detect local patterns like edges and curves that are translation-invariant. For example, a “7” gets recognized whether it’s drawn in the center or corner.
Training
MLP: trained for 5 epochs with Xavier weight initialization, learning rate 0.5 with cosine annealing, batch size 128. Cross-entropy loss implemented from scratch. The entire training loop: forward pass, backpropagation, weight updates, was written without any automatic differentiation. Gradients derived by hand and computed explicitly for each layer.
CNN: standard PyTorch training with Adam optimizer, dropout (0.25), 45 epochs.
Results
| Model | Demo Accuracy | Parameters |
|---|---|---|
| MLP (from scratch) | 97.76% | ~397K |
| CNN (PyTorch) | 96.58% | ~18K |
The CNN in the repo achieves 99.31% when fully trained. The demo runs a lighter checkpoint to keep browser inference fast. Both models run entirely in your browser using pure TypeScript. No server, no ONNX, no WebAssembly.
Test Samples
Some digits from the MNIST test set.
Loading samples…
Confusion Matrices
Which digits does each model mix up?
Loading confusion matrix…