Skip to content

JeremiahM37/snnc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

snnc

snnc is a small inference runtime for spiking neural networks (SNNs), written in C11 and depending only on the C standard library. The engine is a single translation unit (snn.c, snn.h); a command-line tool and a C library API are provided. Simulation is synchronous (clock-driven) and feedforward.

The neuron dynamics follow the discrete-time leaky integrate-and-fire formulation used by snnTorch, and are cross-validated against it step by step (see Validation).

Model and simulation

A network is a sequence of dense layers. Each layer multiplies its input by a weight matrix, adds a bias to obtain an input current I, and updates one neuron per output unit. Four neuron models are available:

  • Leaky integrate-and-fire (LIF) with membrane potential V, decay β ∈ (0,1), and threshold θ:

    V[t+1] = β·V[t] + I[t] − S[t]·θ ,     S[t] = 1 if V[t] > θ else 0
    

    Reset is either by subtraction (V −= θ) or to a fixed value (V = V_reset). The subtraction is carried on the stored membrane, matching snnTorch's reset_delay=False convention, so a membrane left above threshold does not immediately re-fire.

  • Integrate-and-fire (IF), i.e. LIF with β = 1. Its time-averaged firing rate is a clipped-linear function of the input current, which is the basis of ANN-to-SNN conversion.

  • Izhikevich (2003), the two-variable model, integrated with two half Euler steps per timestep for numerical stability.

  • Non-spiking integrator, which accumulates membrane potential without firing; useful as a readout layer producing smooth logits.

Network input is encoded onto layer 0 by direct current injection, Poisson rate coding, deterministic rate coding, or latency (time-to-first-spike). Output is decoded as a spike count, the final membrane potential, or the first-spike time. The choices and their trade-offs are documented with citations in RESEARCH.md; the file format and internals are in DESIGN.md.

Validation

The relevant question for a runtime like this is whether its dynamics are correct, not merely self-consistent. tests/xval_snntorch.py drives snnc and snnTorch's Leaky neuron with identical weights and input currents, then compares the complete membrane trace and spike train at every timestep. Across LIF and IF, both reset modes, and single- and multi-input layers, the membrane potentials agree to floating-point rounding (maximum absolute error ≈ 5×10⁻⁷) with no spike-timing disagreements over roughly 50,000 step comparisons.

This cross-check found a real bug during development: reset-by-subtraction was being applied one step too early relative to snnTorch, which changes the spike train whenever the membrane stays above threshold across consecutive steps. The runtime was corrected to match the reference.

The C test suite (tests/test_snn.c, run natively and under AddressSanitizer and UndefinedBehaviorSanitizer) adds analytical checks against closed-form oracles — sub-threshold steady state V∞ = I/(1−β), the discrete inter-spike interval, and the IF firing period ⌈θ/I⌉ — together with hand-built logic gates and a two-layer XOR, encoder and decoder behaviour, serialization round-trips, and rejection of malformed model files.

Building

make            # build the snnc CLI (C11 compiler only)
make test       # C suite, natively and under ASan/UBSan
make demo       # train a ReLU MLP on XOR, convert to an SNN, run it
make xval       # cross-validate against snnTorch (requires the venv below)

The cross-validation needs snnTorch and PyTorch, which are not required to build or use the runtime:

python3 -m venv env && env/bin/pip install snntorch torch
make xval XVAL_PY=env/bin/python

Usage

Command line:

snnc info model.snn                  # architecture and parameters
snnc run  model.snn --steps 64 1 0   # inference on the input vector (1, 0)
snnc run  model.snn --input vec.csv  # input read from a file

Library:

snn_model *m = snn_model_new(2);
snn_layer_init(&m->layers[0], 784, 128, SNN_LIF);
snn_layer_init(&m->layers[1], 128,  10, SNN_NONSPIKING);
/* fill m->layers[i].weights / .bias, set thresholds, then: */
snn_model_finalize(m);

snn_state *s = snn_state_new(m);
float scores[10];
int label = snn_infer(s, input, 32, scores);   /* runs 32 steps, returns argmax */

snn_step() advances a single timestep for streaming use; snn_save_file / snn_load_file persist a model in the SNN1 binary format. The loader is bounds-checked and rejects malformed input rather than reading out of bounds.

ANN-to-SNN example

examples/xor.c trains a small ReLU multilayer perceptron on XOR with ordinary backpropagation, applies data-based per-layer normalization, and converts it to an IF-neuron network with a non-spiking readout. The converted spiking network reproduces the XOR truth table, a check that the conversion preserves a non-linearly-separable decision boundary.

Scope

The runtime covers feedforward dense layers with synchronous simulation. Convolutional and recurrent topologies, event-driven scheduling, on-device training, and fixed-point inference are out of scope; the SNN1 format reserves space to add some of these later.

References

Key sources are listed in RESEARCH.md. The neuron equations and reset semantics follow Eshraghian et al., Training Spiking Neural Networks Using Lessons from Deep Learning (snnTorch); the ANN-to-SNN rate equivalence follows Diehl et al. (2015) and Rueckauer et al. (2017); the Izhikevich model is from Izhikevich (2003).

License

MIT. Copyright (c) 2026 Jeremiah Mackey.

About

Single-file C inference runtime for spiking neural networks, cross-validated against snnTorch

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors