Skip to main content
The examples/mnist directory shows how to use ggml for both training and inference on the MNIST handwritten digit dataset. Two model architectures are provided: a fully connected network and a convolutional network.
Training in ggml is a work-in-progress and not production-ready. These examples are intended for learning purposes.

Model architectures

Fully connected

Two dense layers with 784 → 500 → 10 units. Trained with PyTorch and exported to GGUF, or trained directly in ggml.

Convolutional (CNN)

Two convolutional layers followed by a dense output layer. Trained with TensorFlow and exported to GGUF, or trained directly in ggml.

Model structure

The mnist_model struct holds all weights and contexts for both architectures:
Key constants:

Getting the data

The dataset is downloaded automatically when you run the Python training scripts. You can also download it manually from HuggingFace.
Downloads from the original Yann LeCun website are frequently throttled. Use HuggingFace instead.

Fully connected network

Train with PyTorch

Train a fully connected model in PyTorch and save it as a GGUF file:
Expected output:

Evaluate with ggml

The evaluator prints a random test image as ASCII art, the model’s prediction for that image, and aggregate accuracy over the full test set:

Train with ggml

You can also train the fully connected model directly in ggml:
The resulting GGUF file can then be evaluated with mnist-eval as shown above.

Convolutional network

Train with TensorFlow

Expected output:

Evaluate with ggml

Train with ggml

Hardware acceleration

Both mnist-train and mnist-eval are backend-agnostic. You can select a specific backend by appending its name:
The model uses the named backend as primary and falls back to CPU for any operations the backend does not support.

Batch configuration

Gradient accumulation is used during training via separate logical and physical batch sizes:
The logical batch size controls gradient update frequency; the physical batch size controls parallelism and memory usage. Any multiple works as long as MNIST_NBATCH_LOGICAL % MNIST_NBATCH_PHYSICAL == 0.

Web demo

The evaluation code can be compiled to WebAssembly using Emscripten:
Serve the output files with a local HTTP server:
Open the link in your browser. Draw a digit on the canvas and the model predicts it, or click Random to pull an image from the test set.
Neural networks are susceptible to distributional shift. Digits that look significantly different from the MNIST training data (e.g. not centred) may be misclassified.