Background
← Back to Portfolio/Explainable AI

Pulsatrix: Explainability-First Deep Learning in C++

October 2, 2026•2 weeks project

Open-source C++ deep learning library where every layer implements Layer-wise Relevance Propagation, with post-hoc explainers, mechanistic interpretability, reinforcement learning, neuro-symbolic tools and CUDA/HIP acceleration

Pulsatrix heatmap gallery comparing eight explainers on a misclassified MNIST digit

Gradient, Grad-CAM and four LRP rule presets on one confident mistake (a 5 classified as a 6), rendered by Pulsatrix's native visualizer

Project Overview

Pulsatrix is an open-source (MIT) deep learning library written in C++ and built around one rule: explainability is part of what it means to be a layer. Every module has to implement propagate_relevance(). It's a pure virtual function on the Module base class, so a layer without Layer-wise Relevance Propagation (LRP) won't compile.

On top of that core sit post-hoc explainers, mechanistic interpretability tools, a reinforcement learning stack, neuro-symbolic components and a native visualization layer. All of it runs on CPU, NVIDIA (CUDA) and AMD (HIP/ROCm) GPUs.

Technical Architecture

Core

  • Tensor with an autograd computation graph, SGD and Adam, and the standard losses.
  • A DeviceBackend interface with CPU, CUDA and HIP implementations. The two GPU backends compile from a single shared kernel source.
  • 29 modules, including Linear, Conv2D, pooling, normalization layers, RNN/LSTM/GRU, multi-head attention, transformer blocks, Mamba, RetNet, RWKV and fuzzy-logic operators.

Explainability

  • LRP in every layer:
    • Linear and Conv2D support the ε, γ, α-β (including z⁺) and ZBox rules, assignable per layer through Zennit-style composites.
    • Recurrent layers use Arras et al.'s rules, attention uses AttnLRP and Mamba uses MambaLRP.
  • Whole-model API: LRP::explain() runs the forward pass, seeds relevance at a target class (or a target against a contrast class) and returns an attribution. It's also available from Python.
  • Post-hoc explainers: KernelSHAP, LIME, Partial Dependence, Saliency, Integrated Gradients and Grad-CAM.
  • Mechanistic interpretability: activation patching, linear probes with negative controls, sparse autoencoders and circuit graphs.

Beyond Supervised Learning

  • Reinforcement learning: DQN/Double DQN, REINFORCE, A2C, PPO, SAC and GFlowNets.
  • Neuro-symbolic: fuzzy-logic modules with satisfaction losses, plus a Datalog engine whose proofs can themselves be explained with LRP, through to the input of a neural predicate.

Verification

The library was built with an AI coding agent following a test-first loop, so verification was treated as part of the deliverable rather than an afterthought:

  • External LRP references: whole-model LRP matches Zennit 1.0.0 (MLP and CNN, across its rule presets) and LXT 2.1 AttnLRP (attention and transformer blocks) to within 1e-5. The pinned environment that generates the reference values ships with the repo.
  • Captum references: Saliency, Integrated Gradients and Grad-CAM are checked against values generated with Captum.
  • Conservation tests: relevance must add up across each layer. Where it provably doesn't (attention), the gap is measured and reported instead of hidden.
  • GPU vs CPU equivalence: every module's forward pass, backward pass and LRP on the GPU is compared with the CPU. Full training runs (MLP, CNN, recurrent, state-space and DQN) must end with the same weights on both.
  • Around 2,000 tests pass on CPU, NVIDIA and AMD hardware.

Key Results

  • A small CNN trained on real MNIST reaches 96% held-out accuracy in about a minute on a CPU, and its predictions are explained pixel by pixel. That includes a confidently wrong one, which accuracy alone would never reveal.
  • PPO and Double DQN agents learn CartPole from scratch in about a second each on a CPU.
  • The full library compiles to a 2.8 MB static library with no Python runtime, for deployments where the explanations need to travel with the model.

Future Enhancements

  • Explanations for RL agents ("why did the agent take this action?") built on the same LRP tooling.
  • Broader external LRP validation, covering recurrent and state-space rules.
  • Automated circuit discovery for the mechanistic interpretability tools.

Key Metrics

LRP-Capable Modules29

Every module implements relevance propagation, or it doesn't compile

LRP Reference Error≤ 1e-5

Maximum deviation from Zennit 1.0.0 and LXT 2.1 (AttnLRP) on whole models

Tests2,000+

Passing on CPU and on both CUDA and ROCm GPUs

GPU BackendsCUDA + HIP

Forward, backward and LRP for every module, from one shared kernel source

Library Size2.8 MB

Static library; a train-and-explain program is about 160 KB

Technologies

C++17CMakeCUDAHIP / ROCmcuBLAS / hipBLASGoogleTestDear ImGuiImPlotpybind11Doxygen

Overview

Challenge

Explainability is usually bolted onto deep learning after the fact: Python tools cover only some layer types, leave users to write their own relevance rules, and stay behind when a model is deployed somewhere Python can't follow

Solution

Built a C++ library where explainability is part of the layer contract: every module must implement relevance propagation to compile, with Zennit-compatible LRP rules, a whole-model LRP API, post-hoc and mechanistic tools, and CPU, CUDA and HIP backends that share one kernel source

Impact

A ~2.8 MB library that trains and explains models from MLPs to transformers, state-space models and RL agents, with LRP validated against Zennit and LXT to within 1e-5 and around 2,000 tests passing on CPU, NVIDIA and AMD GPUs

Tags

explainable ailayer-wise relevance propagationc++deep learninggpumechanistic interpretabilityreinforcement learningneuro-symbolic aiopen source