WriteRHand-MNIST
Four handwritten-digit classifiers whose mathematical core was implemented from scratch (NumPy; PyTorch only as a tensor library for the MLP, no autograd) for a university Pattern Recognition course. They are educational models, not production OCR. Code, tests and report: https://github.com/TranTrinhNhan1/WriteRHand. Live demo (runs the models in the browser): see the repository README.
- Gaussian Naive Bayes - per-class, per-pixel Gaussian likelihoods with MLE parameters and log-space inference.
- Softmax regression - multiclass logistic regression, softmax + cross-entropy, mini-batch gradient descent, L2.
- Multilayer perceptron - fully connected ReLU network, hand-written backpropagation, momentum SGD, early stopping.
- AdaBoost (SAMME) - multiclass AdaBoost (SAMME) over weighted histogram decision trees.
Intended use and limitations
- Recognise a single, centred, 28x28 handwritten digit (white on black), MNIST style.
- Not trained on other scripts, multiple digits, noisy photographs or non-centred input; the demo therefore crops and centres drawings with the MNIST recipe, but robustness is limited.
- Accuracy numbers below are for MNIST only. Naive Bayes is weak by design (independence assumption). AdaBoost scores are weighted vote shares, not calibrated probabilities.
Data and preprocessing (mnist-global-standardize-v2-stratified)
- MNIST: 60 000 training + 10 000 test images. Training set split with a seeded stratified
split into 50000 train / 10000 validation (split fingerprint
52cc8206ff96f56d, seed 42); the official 10 000 test images are used only for final reporting. - Pixels / 255, then
x = (p - mean) / (std + eps)withmean = 0.130635,std = 0.308079,eps = 1e-8(computed on the training portion only). The ONNX graphs contain this step: feed rawpixelsin [0, 1], shape[N, 784], readprobabilities[N, 10].
Results (measured, CPU)
Hyper-parameters were chosen on the validation split only. Time columns: wall-clock fit time on
the full 50 000-image train split and median latency of a single-image predict
(CPU: 13th Gen Intel(R) Core(TM) i7-13620H, 16 logical cores, PyTorch threads: 8).
| Model | Train acc % | Val acc % | Test acc % | Test macro-F1 % | Fit (s) | 1-image latency (ms) |
|---|---|---|---|---|---|---|
| Gaussian NB | 80.13 | 79.67 | 81.32 | 81.16 | 0.4 | 0.076 |
| Softmax regression | 93.62 | 92.15 | 92.52 | 92.42 | 12.7 | 0.010 |
| MLP | 99.87 | 98.18 | 98.24 | 98.23 | 11.0 | 0.042 |
| AdaBoost-SAMME | 100.00 | 97.59 | 97.60 | 97.58 | 817.9 | 18.705 |
Files
| file | format | size | exported vs Python: argmax agreement / max prob. diff | test images checked |
|---|---|---|---|---|
models/naive_bayes.onnx |
onnx | 62 KiB | 100.00% / 1.8e-04 | 10,000 |
models/softmax.onnx |
onnx | 31 KiB | 100.00% / 3.4e-06 | 10,000 |
models/mlp.onnx |
onnx | 2094 KiB | 100.00% / 1.9e-06 | 10,000 |
models/adaboost.json |
json | 15607 KiB | 100.00% / 0.0e+00 | 1,000 |
python/*.npz hold the original weights (BaseClassifier.load), test_vectors.json raw test
digits with expected outputs, results.json all benchmark numbers used by the website.
Training procedure
See the repository: uv run python -m src prepare | tune | train | baselines | export | upload.
Experiment tracking: Weights & Biases (offline fallback). Seeds are fixed; runs are reproducible on
the same hardware/library versions (git commit fa51c49c8079469287591cbd9b6e9f2186d1ee63).
AI-assisted development
Parts of this code, the tests, the export pipeline and the website were produced with the help of an AI coding assistant (Claude Code) and reviewed/run by the project authors, as disclosed in the course report.
License
No license has been chosen by the authors yet (educational project). MNIST is provided by Y. LeCun, C. Cortes and C. J. C. Burges.
Citation
LeCun, Y., Bottou, L., Bengio, Y., Haffner, P. (1998). Gradient-based learning applied to document recognition. Proceedings of the IEEE 86(11), 2278-2324.