A simple neural network from scratch in C++ for MNIST digit classification, built with OpenCV matrices.
MazeNet implements a small multi-layer perceptron without deep learning frameworks. It is designed for learning how neural networks work internally: forward propagation, softmax, cross-entropy loss, backpropagation, gradient descent, and model parameter saving.
MazeNet trains a fully connected neural network on the MNIST handwritten digit dataset.
Input image → Flatten 784 values → Hidden layer → ReLU → Output layer → Softmax
28 x 28 784 128 10 classes
The model learns to classify digits from 0 to 9.
- Neural network implemented from scratch in C++
- OpenCV
cv::Matused for matrix operations - MNIST
.idxdataset loader - Fully connected MLP architecture
- ReLU activation
- Softmax output
- Categorical cross-entropy loss
- Manual backpropagation
- Mini-batch gradient descent
- Accuracy evaluation
- Model parameter export to
.yml - CMake build support
- Simple
run.shscript for quick training
Default architecture:
784 → 128 → 10
| Layer | Size | Activation |
|---|---|---|
| Input | 784 | - |
| Hidden | 128 | ReLU |
| Output | 10 | Softmax |
Default hyperparameters are defined in include/config.hpp:
# define in_size 784
# define hide_size 128
# define out_size 10
# define l_rate 0.005
# define total_epochs 10
# define batch_size 64MazeNet/
├── include/
│ ├── config.hpp # Hyperparameters and model settings
│ ├── mnist.hpp # MNIST dataset reader declarations
│ ├── model.hpp # MazeNet model class
│ └── utils.hpp # Math/helper function declarations
├── src/
│ ├── main.cpp # Training loop and evaluation
│ ├── mnist.cpp # MNIST IDX file reader
│ ├── model.cpp # Forward/backward propagation
│ └── utils.cpp # Activation, loss, matrix helpers
├── dataset.tar.xz # Compressed MNIST dataset files
├── CMakeLists.txt # CMake build configuration
├── run.sh # Quick build/run script
└── README.md
The project expects MNIST IDX files inside a dataset/ directory.
If you use the included archive, extract it first:
tar -xf dataset.tar.xzExpected paths:
dataset/
├── train-images.idx3-ubyte
├── train-labels.idx1-ubyte
├── t10k-images.idx3-ubyte
└── t10k-labels.idx1-ubyte
If the official test files are not available, the code can fall back to an 80/20 split from the training dataset.
chmod +x run.sh
./run.shmkdir build
cd build
cmake ..
make -j$(nproc)
./mazeOn macOS, use:
make -j$(sysctl -n hw.ncpu)During training, MazeNet prints progress, loss, and accuracy:
Start training loop ...
Epoch 1 [==============================] 100%
Loss : 0.7421
Accuracy : 81.35%
----------------------------------------
Epoch 2 [==============================] 100%
Loss : 0.4218
Accuracy : 88.72%
----------------------------------------
After training, learned parameters are saved to:
trained_model.yml
The file contains:
w1
b1
w2
b2
MazeNet implements the basic neural-network training pipeline manually.
z1 = X · W1 + b1
a1 = ReLU(z1)
z2 = a1 · W2 + b2
ŷ = Softmax(z2)
Categorical Cross-Entropy
dZ2 = ŷ - y
dW2 = a1ᵀ · dZ2
db2 = mean(dZ2)
dA1 = dZ2 · W2ᵀ
dZ1 = dA1 * ReLU'(z1)
dW1 = Xᵀ · dZ1
db1 = mean(dZ1)
W = W - learning_rate * gradient
b = b - learning_rate * gradient
- C++17 compatible compiler
- CMake
- OpenCV
Ubuntu / Debian example:
sudo apt update
sudo apt install build-essential cmake libopencv-devYou can change model and training settings in:
include/config.hpp
Example:
# define l_rate 0.005
# define total_epochs 10
# define batch_size 64Increase epochs for longer training:
# define total_epochs 30Change hidden layer size:
# define hide_size 256