A minimal, from-scratch C++ inference engine for running ONNX models—demonstrated on the classic MNIST digit recognition task. Inspired by Build Your Own Inference Engine.
Install these before building:
make installTrain your model:
make trainmacOS (Apple Silicon):
brew install protobuf pkg-config
export PKG_CONFIG_PATH="/opt/homebrew/opt/protobuf/lib/pkgconfig:/opt/homebrew/opt/abseil/lib/pkgconfig:$PKG_CONFIG_PATH"Linux (Ubuntu):
sudo apt-get install protobuf-compiler libprotobuf-dev pkg-configDownload ONNX proto file if not already present:
curl -O https://raw.githubusercontent.com/onnx/onnx/main/onnx/onnx-ml.protoGenerate C++ files:
protoc --cpp_out=src/ onnx-ml.protoYou should already or now have src/onnx-ml.pb.h and src/onnx-ml.pb.cc.
make allTo use CUDA:
make all USE_CUDA=1Run:
./inference_engine models/mnist_model.onnx inputs/image_0.ubyteYou should see output like:
Predicted class: 7
You can visualize .ubyte images using the provided Python script:
make show-imageThis opens a window showing the digit image (should be 28x28, grayscale).
make benchmarkto use CUDA:
make benchmark USE_CUDA=1Run benchmark:
./benchmark models/mnist_model.onnx inputs/Results of running 10,000 sequential inference requests.
Iteration 1:
Total inference time: 5894.52 ms
Average inference time per run: 0.589452 ms
Iteration 2:
Total inference time: 5768.79 ms
Average inference time per run: 0.576879 ms
Iteration 3:
Total inference time: 5908.36 ms
Average inference time per run: 0.590836 ms
Averaging them, we can run about 1707 inferences per second.
MIT License. See LICENSE for details.