# MNIST Examples for GGML This directory contains simple examples of how to use GGML for training and inference using the [MNIST dataset](https://yann.lecun.com/exdb/mnist/). All commands listed in this README assume the working directory to be `examples/mnist`. Please note that training in GGML is a work-in-progress and not production ready. ## Obtaining the data A description of the dataset can be found on [Yann LeCun's website](https://yann.lecun.com/exdb/mnist/). While it is also in principle possible to download the dataset from this website these downloads are frequently throttled and it is recommended to use [HuggingFace](https://huggingface.co/datasets/ylecun/mnist) instead. The dataset will be downloaded automatically when running `mnist-train-fc.py`. ## Fully connected network For our first example we will train a fully connected network. To train a fully connected model in PyTorch and save it as a GGUF file, run: ```bash $ python3 mnist-train-fc.py mnist-fc-f32.gguf ... Test loss: 0.066377+-0.010468, Test accuracy: 97.94+-0.14% Model tensors saved to mnist-fc-f32.gguf: fc1.weight (500, 784) fc1.bias (500,) fc2.weight (10, 500) fc2.bias (10,) ``` The training script includes an evaluation of the model on the test set. To evaluate the model on the CPU using GGML, run: ```bash $ ../../build/bin/mnist-eval mnist-fc-f32.gguf data/MNIST/raw/t10k-images-idx3-ubyte data/MNIST/raw/t10k-labels-idx1-ubyte ________________________________________________________ ________________________________________________________ ________________________________________________________ ________________________________________________________ __________________________________####__________________ ______________________________########__________________ __________________________##########____________________ ______________________##############____________________ ____________________######________####__________________ __________________________________####__________________ __________________________________####__________________ ________________________________####____________________ ______________________________####______________________ ________________________##########______________________ ______________________########__####____________________ ________________________##__________##__________________ ____________________________________##__________________ __________________________________##____________________ __________________________________##____________________ ________________________________##______________________ ____________________________####________________________ __________##____________######__________________________ __________##############________________________________ ________________####____________________________________ ________________________________________________________ ________________________________________________________ ________________________________________________________ ________________________________________________________ ggml_cuda_init: GGML_CUDA_FORCE_MMQ: no ggml_cuda_init: GGML_CUDA_FORCE_CUBLAS: no ggml_cuda_init: found 1 CUDA devices: Device 0: NVIDIA GeForce RTX 3090, compute capability 8.6, VMM: yes mnist_model: using CUDA0 (NVIDIA GeForce RTX 3090) as primary backend mnist_model: unsupported operations will be executed on the following fallback backends (in order of priority): mnist_model: - CPU (AMD Ryzen 9 5950X 16-Core Processor) mnist_model_init_from_file: loading model weights from 'mnist-fc-f32.gguf' mnist_model_init_from_file: model arch is mnist-fc mnist_model_init_from_file: successfully loaded weights from mnist-fc-f32.gguf main: loaded model in 109.44 ms mnist_model_eval: model evaluation on 10000 images took 76.92 ms, 7.69 us/image main: predicted digit is 3 main: test_loss=0.066379+-0.009101 main: test_acc=97.94+-0.14% ``` In addition to the evaluation on the test set the GGML evaluation also prints a random image from the test set as well as the model prediction for said image. To train a fully connected model on the CPU using GGML run: ``` bash $ ../../build/bin/mnist-train mnist-fc mnist-fc-f32.gguf data/MNIST/raw/train-images-idx3-ubyte data/MNIST/raw/train-labels-idx1-ubyte ``` It can then be evaluated with the same binary as above. ## Convolutional network To train a convolutional network using TensorFlow run: ```bash $ python3 mnist-train-cnn.py mnist-cnn-f32.gguf ... Test loss: 0.047947 Test accuracy: 98.46% GGUF model saved to 'mnist-cnn-f32.gguf' ``` The saved model can be evaluated on the CPU using the `mnist-eval` binary: ```bash $ ../../build/bin/mnist-eval mnist-fc-f32.gguf data/MNIST/raw/t10k-images-idx3-ubyte data/MNIST/raw/t10k-labels-idx1-ubyte ________________________________________________________ ________________________________________________________ ________________________________________________________ ________________________________________________________ ________________________________________________________ ______________________________________##________________ ______________________________________##________________ ______________________________________##________________ ____________________________________##__________________ __________________________________####__________________ __________________________________##____________________ ________________________________##______________________ ______________________________##________________________ ____________________________####________________________ ____________________________##__________________________ __________________________##____________________________ ________________________##______________________________ ______________________##________________________________ ____________________####________________________________ ____________________##__________________________________ __________________##____________________________________ ________________##______________________________________ ________________________________________________________ ________________________________________________________ ________________________________________________________ ________________________________________________________ ________________________________________________________ ________________________________________________________ ggml_cuda_init: GGML_CUDA_FORCE_MMQ: no ggml_cuda_init: GGML_CUDA_FORCE_CUBLAS: no ggml_cuda_init: found 1 CUDA devices: Device 0: NVIDIA GeForce RTX 3090, compute capability 8.6, VMM: yes mnist_model: using CUDA0 (NVIDIA GeForce RTX 3090) as primary backend mnist_model: unsupported operations will be executed on the following fallback backends (in order of priority): mnist_model: - CPU (AMD Ryzen 9 5950X 16-Core Processor) mnist_model_init_from_file: loading model weights from 'mnist-cnn-f32.gguf' mnist_model_init_from_file: model arch is mnist-cnn mnist_model_init_from_file: successfully loaded weights from mnist-cnn-f32.gguf main: loaded model in 91.99 ms mnist_model_eval: model evaluation on 10000 images took 267.61 ms, 26.76 us/image main: predicted digit is 1 main: test_loss=0.047955+-0.007029 main: test_acc=98.46+-0.12% ``` Like with the fully connected network the convolutional network can also be trained using GGML: ``` bash $ ../../build/bin/mnist-train mnist-cnn mnist-cnn-f32.gguf data/MNIST/raw/train-images-idx3-ubyte data/MNIST/raw/train-labels-idx1-ubyte ``` As always, the evaluation is done using `mnist-eval` and like with the fully connected network the GGML graph is exported to `mnist-cnn-f32.ggml`. ## Hardware Acceleration Both the training and evaluation code is agnostic in terms of hardware as long as the corresponding GGML backend has implemented the necessary operations. A specific backend can be selected by appending the above commands with a backend name. The compute graphs then schedule the operations to preferentially use the specified backend. Note that if a backend does not implement some of the necessary operations a CPU fallback is used instead which may result in bad performance. ## Web demo The evaluation code can be compiled to WebAssembly using [Emscripten](https://emscripten.org/) (may need to re-login to update `$PATH` after installation). First, copy the GGUF file of either of the trained models to `examples/mnist` and name it `mnist-f32.gguf`. Copy the test set to `examples/mnist` and name it `t10k-images-idx3-ubyte`. Symlinking these files will *not* work! Compile the code like so: ```bash $ cd ../../ $ mkdir -p build-em $ emcmake cmake .. -DGGML_BUILD_EXAMPLES=ON \ -DCMAKE_C_FLAGS="-pthread -matomics -mbulk-memory" \ -DCMAKE_CXX_FLAGS="-pthread -matomics -mbulk-memory" $ make mnist ``` The compilation output is copied into `examples/mnist/web`. To run it, you need an HTTP server. For example: ``` bash $ python3 examples/mnist/server.py Serving directory '/home/danbev/work/ai/ggml/examples/mnist/web' at http://localhost:8000 Application context root: http://localhost:8000/ ``` The web demo can then be accessed via the link printed on the console. Simply draw a digit on the canvas and the model will try to predict what it's supposed to be. Alternatively, click the "Random" button to retrieve a random digit from the test set. Be aware that like all neural networks the one we trained is susceptible to distributional shift: if the numbers you draw look different than the ones in the training set (e.g. because they're not centered) the model will perform comparatively worse. An online demo can be accessed [here](https://mnist.ggerganov.com).