WriteRHand
Six image classifiers (each also as an augmented variant) whose mathematical core was implemented from scratch (NumPy; PyTorch only as a tensor library, no autograd, no nn.Module, no F.conv2d) for a university Pattern Recognition course, trained separately on three 28x28 datasets: MNIST, Fashion-MNIST and EMNIST Digits. They are educational models, not production OCR. Code, tests and report: https://github.com/TranTrinhNhan1/WriteRHand. The live demo and the Model Execution Explorer run these files in the browser.
- 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.
- Linear SVM - one-vs-rest linear SVM, hinge loss, sub-gradient mini-batch descent, L2; outputs scores, not probabilities.
- Multilayer perceptron - fully connected ReLU network, hand-written backpropagation, momentum SGD, early stopping.
- Convolutional network - two Conv-ReLU-MaxPool stages and a linear head; hand-written im2col convolution, pooling and backpropagation.
- AdaBoost (SAMME) - multiclass AdaBoost (SAMME) over weighted histogram decision trees.
- Gaussian Naive Bayes (augmented) - per-class, per-pixel Gaussian likelihoods with MLE parameters and log-space inference. Same architecture, trained on the original images plus randomly rotated (up to 30 degrees), shifted and scaled copies; compared side by side with the plain model.
- Softmax regression (augmented) - multiclass logistic regression, softmax + cross-entropy, mini-batch gradient descent, L2. Same architecture, trained on the original images plus randomly rotated (up to 30 degrees), shifted and scaled copies; compared side by side with the plain model.
- Linear SVM (augmented) - one-vs-rest linear SVM, hinge loss, sub-gradient mini-batch descent, L2; outputs scores, not probabilities. Same architecture, trained on the original images plus randomly rotated (up to 30 degrees), shifted and scaled copies; compared side by side with the plain model.
- Multilayer perceptron (augmented) - fully connected ReLU network, hand-written backpropagation, momentum SGD, early stopping. Same architecture, trained on the original images plus randomly rotated (up to 30 degrees), shifted and scaled copies; compared side by side with the plain model.
- Convolutional network (augmented) - two Conv-ReLU-MaxPool stages and a linear head; hand-written im2col convolution, pooling and backpropagation. Same architecture, trained on the original images plus randomly rotated (up to 30 degrees), shifted and scaled copies; compared side by side with the plain model.
- AdaBoost (SAMME) (augmented) - multiclass AdaBoost (SAMME) over weighted histogram decision trees. Same architecture, trained on the original images plus randomly rotated (up to 30 degrees), shifted and scaled copies; compared side by side with the plain model.
Intended use and limitations
- A model is only meaningful for the dataset it was trained on: the Fashion-MNIST models output clothing classes, the MNIST/EMNIST models digit classes. No cross-dataset claim is made unless a result table says so explicitly.
- Drawings are cropped and centred with the MNIST recipe, but robustness to hand-drawn input is limited. Naive Bayes is weak by design (independence assumption). AdaBoost scores are weighted vote shares, not calibrated probabilities.
Input / output contract (mnist-global-standardize-v2-stratified)
Feed raw pixels in [0, 1], shape [N, 784] (row-major 28x28); the graph standardises
internally and returns probabilities [N, 10]. Extra optional outputs expose intermediate
tensors for the explorer; the layer graph, shapes and parameter files are described per model in
manifest.json (trace, schema writerhand.trace/1; see docs/TRACE_CONTRACT.md in the code
repository). They never change probabilities.
Results (measured, CPU)
Hyper-parameters were chosen on the validation split only; test accuracy is reported once for the
final configuration. Times: wall-clock fit time on the 50 000-image train split and median latency
of a single-image predict.
MNIST (mnist)
Classes: 0 = 0, 1 = 1, 2 = 2, 3 = 3, 4 = 4, 5 = 5, 6 = 6, 7 = 7, 8 = 8, 9 = 9.
Split: 50000 train / 10000 validation (stratified, seed 42,
fingerprint 52cc8206ff96f56d) / 10000 official test. Normalisation
mean = 0.130635, std = 0.308079 (training portion only). CPU:
13th Gen Intel(R) Core(TM) i7-13620H, 16 logical cores.
| 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 |
| CNN | 99.40 | 98.65 | 98.80 | 98.79 | 143.0 | 0.315 |
Fashion-MNIST (fashion_mnist)
Classes: 0 = T-shirt/top, 1 = Trouser, 2 = Pullover, 3 = Dress, 4 = Coat, 5 = Sandal, 6 = Shirt, 7 = Sneaker, 8 = Bag, 9 = Ankle boot.
Split: 50000 train / 10000 validation (stratified, seed 42,
fingerprint 81af3b61a9090ad5) / 10000 official test. Normalisation
mean = 0.285887, std = 0.352934 (training portion only). CPU:
13th Gen Intel(R) Core(TM) i7-13620H, 16 logical cores.
| Model | Train acc % | Val acc % | Test acc % | Test macro-F1 % | Fit (s) | 1-image latency (ms) |
|---|---|---|---|---|---|---|
| Gaussian NB | 67.66 | 68.22 | 67.27 | 66.03 | 0.7 | 0.128 |
| Softmax regression | 87.27 | 85.83 | 84.27 | 84.18 | 12.8 | 0.009 |
| MLP | 93.44 | 89.36 | 88.59 | 88.55 | 80.1 | 0.063 |
| AdaBoost-SAMME | 95.74 | 85.33 | 84.74 | 84.88 | 529.2 | 16.390 |
| CNN | 91.15 | 88.64 | 88.49 | 88.48 | 209.0 | 0.550 |
EMNIST Digits (emnist_digits)
Classes: 0 = 0, 1 = 1, 2 = 2, 3 = 3, 4 = 4, 5 = 5, 6 = 6, 7 = 7, 8 = 8, 9 = 9.
Split: 50000 train / 10000 validation (stratified, seed 42,
fingerprint da8f39a40d251249) / 40000 official test. Normalisation
mean = 0.173357, std = 0.331788 (training portion only). CPU:
13th Gen Intel(R) Core(TM) i7-13620H, 16 logical cores.
| Model | Train acc % | Val acc % | Test acc % | Test macro-F1 % | Fit (s) | 1-image latency (ms) |
|---|---|---|---|---|---|---|
| Gaussian NB | 80.73 | 80.82 | 80.03 | 80.13 | 0.5 | 0.079 |
| Softmax regression | 94.69 | 94.03 | 93.81 | 93.81 | 4.7 | 0.010 |
| MLP | 99.84 | 98.48 | 98.36 | 98.36 | 7.1 | 0.032 |
| AdaBoost-SAMME | 99.98 | 97.72 | 97.38 | 97.38 | 249.1 | 7.414 |
| CNN | 99.02 | 98.69 | 98.64 | 98.64 | 48.8 | 0.286 |
Files (bundle 498c0162fab833d6)
| file | format | size | sha256 (prefix) | exported vs Python: argmax agreement / max prob. diff |
|---|---|---|---|---|
mnist/models/naive_bayes.onnx |
onnx | 62 KiB | 50893c25c18d |
100.00% / 1.4e-04 |
mnist/models/softmax.onnx |
onnx | 31 KiB | 9a183cded622 |
100.00% / 3.4e-06 |
mnist/models/svm.onnx |
onnx | 31 KiB | b5f8b2ac916f |
100.00% / 1.9e-06 |
mnist/models/mlp.onnx |
onnx | 2094 KiB | 9ada8d972350 |
100.00% / 1.7e-06 |
mnist/models/cnn.onnx |
onnx | 223 KiB | e3b9ff33eb90 |
100.00% / 7.2e-07 |
mnist/models/adaboost.bin |
binary | 9457 KiB | b2e057c149a1 |
100.00% / 0.0e+00 |
mnist/models/naive_bayes_aug.onnx |
onnx | 62 KiB | d911b4b13ff6 |
100.00% / 5.4e-05 |
mnist/models/softmax_aug.onnx |
onnx | 31 KiB | 6acbd393663a |
100.00% / 1.9e-06 |
mnist/models/svm_aug.onnx |
onnx | 31 KiB | a586e5d0b05e |
100.00% / 1.2e-06 |
mnist/models/mlp_aug.onnx |
onnx | 2094 KiB | 68c670fc5656 |
100.00% / 2.3e-06 |
mnist/models/cnn_aug.onnx |
onnx | 223 KiB | 950ed872e489 |
100.00% / 1.1e-06 |
mnist/models/adaboost_aug.bin |
binary | 10958 KiB | 3516a5c916a5 |
100.00% / 0.0e+00 |
fashion_mnist/models/naive_bayes.onnx |
onnx | 62 KiB | 041a169223e1 |
100.00% / 1.9e-04 |
fashion_mnist/models/softmax.onnx |
onnx | 31 KiB | e4c3ec64b69b |
100.00% / 2.6e-06 |
fashion_mnist/models/mlp.onnx |
onnx | 2094 KiB | b1c9ff06ec96 |
100.00% / 1.3e-06 |
fashion_mnist/models/cnn.onnx |
onnx | 51 KiB | 7f0ff912a294 |
100.00% / 9.5e-07 |
fashion_mnist/models/adaboost.bin |
binary | 1275 KiB | 6c0dce63fce9 |
100.00% / 0.0e+00 |
emnist_digits/models/naive_bayes.onnx |
onnx | 62 KiB | 6f51b3b218eb |
100.00% / 1.0e-04 |
emnist_digits/models/softmax.onnx |
onnx | 31 KiB | 414d2d6bec36 |
100.00% / 4.6e-06 |
emnist_digits/models/mlp.onnx |
onnx | 1591 KiB | 2368023bf014 |
100.00% / 1.5e-06 |
emnist_digits/models/cnn.onnx |
onnx | 51 KiB | 3761b6d0cab2 |
100.00% / 1.1e-06 |
emnist_digits/models/adaboost.bin |
binary | 1359 KiB | 80e8a3d99590 |
100.00% / 0.0e+00 |
python/*.npz hold the original weights (BaseClassifier.load), test_vectors.json raw test
images with expected outputs, results.json the benchmark numbers used by the website.
Training procedure
See the repository: uv run python -m src prepare | tune | train | baselines | export | upload
(--dataset mnist|fashion_mnist|emnist_digits). Experiment tracking: Weights & Biases (offline
fallback). Seeds are fixed (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 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). Datasets: MNIST (LeCun et al.), Fashion-MNIST (Xiao et al., MIT), EMNIST (Cohen et al.).
Citation
LeCun, Y., Bottou, L., Bengio, Y., Haffner, P. (1998). Gradient-based learning applied to document recognition. Xiao, H., Rasul, K., Vollgraf, R. (2017). Fashion-MNIST. Cohen, G. et al. (2017). EMNIST.