Menu

Version 0.0.3

GradieX Documentation

Single-precision arithmetic, OpenMP simd pragmas on the hot loops, mini-batch gradient accumulation, and a derivative lookup that ties each activation and loss to its own derivative.

Status

Everything builds. The engine compiles clean, the C++ suite passes 91 checks under AddressSanitizer and UBSan, and the Python package builds and passes its own suites. The bindings were ported to the float engine and gained a matplotlib plotting layer. See Build Status.

Build Status

TargetCommandResult
C++ engineclang++ -std=c++20 -O2 main.cpp -o mainBuilds — 0 errors, 18 warnings under -Wall -Wextra
The demo./mainRuns — exit 0, and prints nothing; see below
C++ tests./tests/run_tests.shPasses — 91 checks, also clean under --asan
Python modulepip install .Builds — gradiex-0.0.3, with numpy and matplotlib
Python testspython3 python/test_bindings.pyPasses — bindings, guards, C++/Python parity
Plotting testspython3 python/test_plotting.pyPasses — every diagram, headless

The 18 warnings are 17 instances of 'restrict' type qualifier on return type has no effect plus one unused parameter. They are benign but load-bearing in an odd way — see The __restrict__ return qualifier. tests/run_tests.sh already passes -Wno-ignored-qualifiers.

The demo is silent

main.cpp calls train() without the verbose argument, which now defaults to false, and it no longer calls the removed printAllLayers(). So the binary trains 10,000 epochs and prints nothing at all. Pass true as the sixth argument, or read lossBuffer, to see anything.

Getting Started

Header-only, one translation unit, as in v0.0.2:

clang++ -std=c++20 -O2 main.cpp -o main
./main

To get anything out of the #pragma omp simd directives, OpenMP must be enabled:

clang++ -std=c++20 -O2 -fopenmp-simd main.cpp -o main   # Apple clang
g++-14  -std=c++20 -O3 -fopenmp      main.cpp -o main   # GCC
clang++ -std=c++20 -O3 -fopenmp      main.cpp -o main   # LLVM clang + libomp
Use -fopenmp-simd

Apple clang — the default c++ on macOS — rejects -fopenmp, but accepts -fopenmp-simd, which enables exactly the directives core/ uses and needs no runtime library. Without one of them the pragmas are silently ignored: no error, no warning, no vectorisation. The flag is worth up to 2.4× on wide layers — see SIMD Pragmas.

What Changed Since v0.0.2

v0.0.2v0.0.3
Scalar typedoublefloat throughout the engine
Vectorisation#pragma GCC unroll 4#pragma omp simd, with reduction clauses on the dot product
Gradientsassigned (=), applied immediatelyaccumulated (+=), then scaled and applied
Trainingper-sample SGDmini-batch SGD — Network(..., int batches)
Derivativespassed in by the caller, uncheckedlooked up from the forward function via fetchAssociatedDerivative
Layer constructor7 arguments5 — the two derivatives are derived
addHiddenLayer / addOutputLayer8 arguments6
computeLossalways squared error, ignoring the configured losscalls the configured loss — fixes v0.0.2 known bug 1
Scratch padsinputSize * width, only width usedwidth — fixes v0.0.2 known bug 7
Activationssigmoid, relu, leakyRelu, tanh, swish, gelu, softmaxthe same, plus identity
Lossesmse, mae, huber, bce, cce, fused softmax+CCEunchanged
Epoch loggingunconditional std::coutverbose flag, default off
Removed—Layer::print, Network::printAllLayers, Network::runEpoch, Network::backwardPass
Commented out—Network::predict
Testspresent, several fail by designported — 91 checks, all passing
Python bindingsbuild and workported to float; training delegated to the engine
Plotting—seven matplotlib diagrams, light and dark
Shufflingnoneper-epoch, seeded, inside train()
Seeded initnoneinitializers::setSeed / gradiex.seed

The full v0.0.2 reference is at v0.0.2 → C++ Library, and the three-version comparison is on the versions page.

Plots

New in v0.0.3: the Python package ships a matplotlib layer. net.train(..., plot=True) draws the loss curve when training finishes, and seven further diagrams cover the architecture, the weights, the fit and the loss surface. Every one renders in light and dark.

A four-panel dashboard: the layer graph, the training loss curve, per-layer weight histograms, and the learned decision boundary over the test set. A four-panel dashboard: the layer graph, the training loss curve, per-layer weight histograms, and the learned decision boundary over the test set.
net.plot_summary(X, Y) on the two-moons example — a 2 → 16 → 16 → 1 network at 100 % test accuracy. The full gallery is on the Python Library page.

Reference

The C++ Library
The header-only engine in core/. The float signatures, the SIMD pragmas, gradient accumulation and batching, the derivative lookup, and what is still open.

The Python Library
The gradiex package: install, the API, what the binding guarantees the C++ API does not, and the plot gallery — loss curves, architecture diagrams, decision boundaries, weight maps and 3‑D loss landscapes.

Performance
Benchmarks against v0.0.2 on a shared harness: 1.2–3.2× per sample, 1.7–5.5× with mini-batching, and what the -fopenmp-simd flag is worth at each layer width.

If you are looking for something specific:

At a Glance

ItemValue
LanguageC++20
Scalar typefloat throughout the engine
DependenciesNone. OpenMP is optional and, when absent, silently inert.
LayoutHeader-only; core/ compiles into the caller
Object modelNetwork → Layer → flat vectors
TrainingMini-batch stochastic gradient descent
Activationsidentity, sigmoid, relu, leaky_relu, tanh, swish, gelu, softmax
Lossesmse, mae, huber, binary cross entropy, cross entropy, fused softmax + CCE
Initializerszeros, xavier, he
Python bindingpybind11 — gradiex, with matplotlib plotting
Tests91 checks, passing under ASan and UBSan
Translation unitsOne only — two will not link; see ODR
Build statusBuilds — 0 errors, 18 warnings
LicenseMIT

Project State

v0.0.3 keeps v0.0.2's flat memory layout and changes what runs over it. Three things drive the release: halving the width of every scalar so twice as much fits in cache and a vector register holds eight lanes instead of four; annotating the hot loops so a compiler will vectorise them; and restoring mini-batching, which the v0.0.2 rewrite dropped and v0.0.1 had.

Two v0.0.2 defects are fixed along the way. computeLoss now calls the layer's configured loss instead of always summing squared error, and the scratch pads are sized width rather than inputSize * width. A third is addressed in design: fetchAssociatedDerivative derives the derivative from the forward function, so a caller can no longer pair sigmoid with reluDerivative. That lookup works for five of the eight activations — see Derivative Lookup.

What remains is reach rather than correctness. The engine builds and trains; python/ and tests/ were never touched, so the release has no automated verification at all — the gradient check, the zero-allocation assertion and the binding tests are all sitting in double-typed files that no longer compile. The new batching path has never been asserted against anything. Porting the suite is the highest-value work left; see Test Suite.

Version metadata

Fixed in v0.0.3: pyproject.toml and the extension both report 0.0.3, so gradiex.__version__ finally matches the directory it ships in. In 0.0.1/ and 0.0.2/ it still reads 0.0.1.