Model Zoo¶
Module: sc_neurocore.model_zoo
Sub-modules: configs (10 architecture builders), pretrained (weight loader)
Family: Pre-configured network-level SNN architectures
Purpose: One-call construction of complete, runnable spiking neural networks
Overview¶
The Model Zoo provides factory functions that return fully wired
Network objects — populations, projections, stimuli, and monitors —
ready for net.run(duration). Each architecture is parameterised from
a published neuroscience reference and uses biologically plausible
parameter values from the cited papers.
No trained weight files are shipped with the architecture builders.
Weights use random initialisation (Xavier/Glorot or uniform). The
separate load_pretrained() function loads pre-initialised .npz
weight files for three classifier architectures.
from sc_neurocore.model_zoo import brunel_balanced_network
net = brunel_balanced_network(n_exc=800, n_inh=200)
net.run(1.0) # 1 second simulation
print(net.spike_monitors[0].count)
Architectures¶
1. mnist_classifier¶
Reference: Zenke & Ganguli, Neural Computation 30(6), 2018 (SuperSpike) Topology: 784 → n_hidden → 10 feedforward Neuron model: StochasticLIFNeuron (all layers)
| Component | Count | Notes |
|---|---|---|
| Populations | 3 | input (784), hidden (configurable), output (10) |
| Projections | 2 | input→hidden, hidden→output |
| Stimuli | 1 | PoissonInput(784, rate=500Hz, weight=2.0) |
| Monitors | 2 | output_spikes, hidden_spikes |
Parameters:
- n_hidden (int, default=128): Hidden layer size
- LIF params: τ_mem=10ms, v_threshold=1.0, v_rest=0.0, v_reset=0.0, noise_std=0.0
- Weight scaling: Xavier-uniform — w_ih = √(2/784) × 20, w_ho = √(2/n_hidden) × 20
- Connection probability: 0.3 (input→hidden), 0.5 (hidden→output)
Intended use: Feedforward classification of rate-coded MNIST digits. The Poisson input layer encodes pixel intensities as spike rates. The hidden layer performs nonlinear feature extraction. The output layer provides a winner-take-all readout (highest firing neuron = predicted digit).
2. dvs_gesture_classifier¶
Reference: Amir et al., CVPR 2017 (IBM DVS128 gesture recognition) Topology: 256 → 256 → n_classes feedforward Neuron model: StochasticLIFNeuron (all layers)
| Component | Count | Notes |
|---|---|---|
| Populations | 3 | input (256), hidden (256), output (n_classes) |
| Projections | 2 | input→hidden, hidden→output |
| Stimuli | 1 | PoissonInput(256, rate=800Hz, weight=2.0) |
| Monitors | 1 | gesture_spikes (output only) |
Parameters:
- n_classes (int, default=11): Number of gesture classes (DVS128 has 11)
- Weight: w_ih=0.5, w_ho=0.8 (uniform, not Xavier)
- Connection probability: 0.2 (input→hidden), 0.4 (hidden→output)
Intended use: Event-camera gesture classification. The 256-neuron input layer represents 16×16 spatial pixels of a DVS128 event stream. Poisson input at 800 Hz simulates realistic event rates from dynamic gestures.
3. shd_speech_classifier¶
Reference: Cramer et al., IEEE TNNLS 33(7), 2022 (Spiking Heidelberg Digits) Topology: 700 → 256 (recurrent) → 20 Neuron model: StochasticLIFNeuron (all layers)
| Component | Count | Notes |
|---|---|---|
| Populations | 3 | input (700), recurrent (256), output (20) |
| Projections | 3 | input→rec, rec→rec (recurrent), rec→output |
| Stimuli | 1 | PoissonInput(700, rate=500Hz, weight=2.0) |
| Monitors | 2 | shd_output_spikes, shd_recurrent_spikes |
Key design features: - Recurrent connectivity: The rec→rec projection (weight=0.15, p=0.1) creates temporal memory — the recurrent layer integrates information across time, critical for speech recognition. - Longer time constant: Recurrent layer uses τ_mem=20ms (vs input τ_mem=10ms), allowing slower integration dynamics that match speech timescales. - 20-class output: Corresponds to the 20 spoken digits in the SHD dataset (0–9 in German and English).
4. brunel_balanced_network¶
Reference: Brunel, J. Comput. Neurosci. 8(3), 2000, Sec. 2 Topology: Sparse random E/I with 4:1 ratio Neuron model: StochasticLIFNeuron (excitatory and inhibitory)
| Component | Count | Notes |
|---|---|---|
| Populations | 2 | excitatory (n_exc), inhibitory (n_inh) |
| Projections | 4 | E→E, E→I, I→E, I→I (full 2×2 matrix) |
| Stimuli | 2 | PoissonInput for E and I populations (1000Hz, weight=2.0) |
| Monitors | 2 | exc_spikes, inh_spikes |
Parameters:
- n_exc (int, default=800): Excitatory neurons
- n_inh (int, default=200): Inhibitory neurons
- g (float, default=5.0): Inhibitory strength ratio (|J_I| = g × J_E)
- eta (float, default=2.0): External rate / threshold rate
- Connection probability: ε=0.1 (sparse, from Table 1)
- Synaptic delay: 1.5 ms (all projections)
- J_E = 0.1, J_I = −g × J_E = −0.5 (default)
Dynamical regimes (Brunel 2000, Fig. 8): - g=3, η=2: Asynchronous irregular (AI) - g=5, η=2: Synchronous irregular (SI) — default - g=6, η=4: Synchronous regular (SR) - g=8, η=1: Slow oscillation (SO)
Key property: The balance between excitation and inhibition (g > 1) creates irregularity — individual neurons fire irregularly (CV ≈ 1) despite the network being in a stationary state. This is the hallmark of balanced network dynamics observed in cortex.
5. cortical_column¶
Reference: Potjans & Diesmann, Cerebral Cortex 24(3), 2014 Topology: 4-layer column (L2/3, L4, L5, L6) with E+I per layer Neuron models: PospischilNeuron (excitatory RS), GolombFSNeuron (inhibitory FS)
| Component | Count | Notes |
|---|---|---|
| Populations | 8 | 4 layers × 2 (E+I) |
| Projections | 15 | 12 intra-layer (3 per layer) + 3 inter-layer feedforward |
| Stimuli | 1 | PoissonInput(L4_E, rate=800Hz, weight=8.0) thalamic drive |
| Monitors | 8 | one per population |
Layer sizes (scaled to ~5% of original):
| Layer | E neurons | I neurons |
|---|---|---|
| L2/3 | 50 | 15 |
| L4 | 50 | 15 |
| L5 | 50 | 10 |
| L6 | 50 | 10 |
Intra-layer connectivity (per layer): - E→I: weight=2.0, probability=0.2 - I→E: weight=−3.0, probability=0.2 - E→E: weight=1.0, probability=0.1
Feedforward (inter-layer): - L4_E → L23_E (thalamocortical relay) - L23_E → L5_E (corticofugal output) - L5_E → L6_E (deep layer feedback) - All: weight=1.5, probability=0.1
Key design: Thalamic drive enters L4 (the granular layer), propagates upward to L2/3 (superficial), downward to L5 (output) and L6 (feedback). This matches the canonical cortical microcircuit.
Parameters:
- n_layers (int, default=6, effective max=4): Number of layers to include
- PospischilNeuron params: g_m=0.07 (slow M-type current for regular spiking)
6. central_pattern_generator¶
Reference: Ijspeert, Neural Networks 21(4), 2008, Sec. 3 Topology: Half-centre oscillator pairs with inter-pair phase coupling Neuron model: HindmarshRoseNeuron (bursting)
| Component | Count | Notes |
|---|---|---|
| Populations | 2 × n_oscillators | flexor + extensor per oscillator, 5 neurons each |
| Projections | 3 × n_oscillators | 2 mutual inh + 1 inter-oscillator coupling |
| Stimuli | 2 × n_oscillators | PoissonInput per half-centre (800Hz, weight=5.0) |
| Monitors | 2 × n_oscillators | one per half-centre |
Parameters:
- n_oscillators (int, default=4): Number of oscillator pairs (4 = quadruped)
- HindmarshRose params: b=3.0, r=0.005, s=4.0 (bursting regime)
- Mutual inhibition: weight=−2.0, probability=0.8 (within pair)
- Inter-oscillator coupling: weight=1.0, probability=0.5 (excitatory, circular)
How it works: 1. Each oscillator pair consists of a flexor and extensor half-centre 2. Mutual inhibition (−2.0) ensures alternation: when flexor bursts, extensor is suppressed, and vice versa 3. Inter-oscillator coupling (flex[i] → flex[i+1]) creates phase lag between adjacent pairs, producing walk/trot/gallop gaits 4. Circular topology: last oscillator couples back to first
Locomotion gaits (set by coupling weight and phase lag): - Walk: π/2 phase lag between adjacent limbs - Trot: π phase lag between diagonal limbs - Gallop: near-synchronous fore/hind
7. decision_making_circuit¶
Reference: Wang, Neuron 36(5), 2002, Fig. 1 Topology: Two competing excitatory pools + shared inhibition (attractor) Neuron models: HodgkinHuxleyNeuron (excitatory), WangBuzsakiNeuron (inhibitory)
| Component | Count | Notes |
|---|---|---|
| Populations | 4 | pool_A, pool_B, nonselective, inhibitory |
| Projections | 9 | A→A, B→B, A→I, B→I, I→A, I→B, NS→A, NS→B, NS→I |
| Stimuli | 3 | PoissonInput for A, B, nonselective |
| Monitors | 2 | pool_A_spikes, pool_B_spikes |
Parameters:
- n_per_pool (int, default=240): Neurons per selective pool
- Pool A/B drive: 800Hz, weight=15.0
- Nonselective drive: 600Hz, weight=10.0
- n_nonsel = max(10, n_per_pool // 6)
- n_inh = max(15, n_per_pool // 4)
Connectivity weights: - Within-pool recurrent: 3.0 (potentiated NMDA-like) - Pool→Inhibitory: 2.0 - Inhibitory→Pool: −4.0 (cross-inhibition via shared I pool) - Nonselective→All: 1.0
Attractor dynamics: Potentiated recurrent excitation within each pool creates bistable attractors. When one pool "wins" (receives slightly more input), its firing rate increases, which drives the shared inhibitory pool, which suppresses the competing pool — positive feedback leading to a categorical decision. This is the neural basis of perceptual decision-making as modelled by Wang 2002 and Wong & Wang 2006.
8. working_memory_circuit¶
Reference: Compte et al., J. Neurophysiol. 84(3), 2000 Topology: Ring attractor with NMDA-based persistent activity Neuron models: CompteWMNeuron (excitatory), WangBuzsakiNeuron (inhibitory)
| Component | Count | Notes |
|---|---|---|
| Populations | 2 | excitatory (80%), inhibitory (20%) |
| Projections | 4 | E→E (ring), E→I, I→E, I→I |
| Stimuli | 1 | PoissonInput(n_exc, rate=800Hz, weight=5.0) |
| Monitors | 2 | wm_exc_spikes, wm_inh_spikes |
Parameters:
- n_neurons (int, default=500): Total neurons (80% E, 20% I)
- CompteWMNeuron params: g_nmda=0.165, g_ampa=0.005, τ_nmda=100ms, Mg²⁺=1.0
- E→E: ring_topology with k nearest neighbours, weight=0.5
- E→I: weight=2.0, probability=0.3
- I→E: weight=−3.0, probability=0.3
- I→I: weight=−2.0, probability=0.2
Ring topology: The E→E projection uses distance-dependent connectivity
via ring_topology(n_exc, k, weight). Each neuron connects to its k
nearest neighbours in both directions on the ring. This creates a bump
attractor: a localised pattern of activity that persists after a transient
cue, encoding a remembered spatial location.
NMDA kinetics: The slow τ_nmda=100ms time constant is critical for persistent activity — it provides temporal integration long enough to sustain the bump without external drive. The Mg²⁺ block voltage-dependence creates the nonlinearity needed for bistability.
9. auditory_processing¶
Reference: Goodman & Brette, Front. Neurosci. 4, 2010 Topology: Cochlear → onset detection → integration Neuron models: HodgkinHuxleyNeuron (cochlear, integration), WangBuzsakiNeuron (onset)
| Component | Count | Notes |
|---|---|---|
| Populations | 3 | cochlear (n_channels), onset (n_channels), integration (n_channels//2) |
| Projections | 3 | cochlear→onset, onset→onset (lateral inh), onset→integration |
| Stimuli | 1 | PoissonInput(n_channels, rate=800Hz, weight=15.0) targets cochlear |
| Monitors | 2 | cochlear_spikes, integration_spikes |
Parameters:
- n_channels (int, default=32): Tonotopic frequency channels
- cochlear→onset: weight=3.0, probability=0.4
- onset→onset: weight=−2.0, probability=0.2 (lateral inhibition)
- onset→integration: weight=3.0, probability=0.3
Processing pipeline: 1. Cochlear layer: HH neurons model auditory nerve fibre dynamics. Each neuron represents one frequency channel of a gammatone filterbank. 2. Onset layer: WangBuzsaki fast-spiking neurons with lateral inhibition (−2.0) detect sound onsets — only transient changes pass through. 3. Integration layer: HH neurons pool across onset channels, creating a spectro-temporal representation for downstream decoding.
Lateral inhibition: The onset→onset inhibitory connectivity sharpens frequency selectivity and implements a temporal derivative: constant tones are suppressed, onsets/offsets are amplified. This matches the function of bushy cells in the cochlear nucleus.
10. visual_cortex_v1¶
Reference: Hubel & Wiesel, J. Physiol. 160, 1962; Carandini & Heeger, Nat. Rev. Neurosci. 13, 2012 Topology: Orientation-tuned simple cells → complex cells + cross-orientation inhibition Neuron models: HodgkinHuxleyNeuron (simple), WangBuzsakiNeuron (complex)
| Component | Count | Notes |
|---|---|---|
| Populations | 2 × n_orientation | n_orient simple + n_orient complex |
| Projections | n_orient + n_orient×(n_orient−1) | feedforward + cross-orientation |
| Stimuli | n_orientation | PoissonInput per simple cell population |
| Monitors | 2 × n_orientation | one per population |
Parameters:
- n_orientation (int, default=8): Number of orientation channels
- n_per_orientation (int, default=50): Neurons per simple cell population
- n_complex = max(1, n_per_orientation // 2)
- Simple→complex: weight=3.0, probability=0.5 (feedforward)
- Cross-orientation: weight = −1/(1+dist), probability=0.1
Cross-orientation inhibition: Weight decreases with orientation distance: - Adjacent (dist=1): w = −1/2 = −0.500 - Two apart (dist=2): w = −1/3 = −0.333 - Three apart (dist=3): w = −1/4 = −0.250 - Furthest (dist=4, for 8 orientations): w = −1/5 = −0.200
This implements the normalization model of Carandini & Heeger (2012): each orientation suppresses non-preferred orientations proportional to their similarity, sharpening tuning curves and creating contrast invariance.
Simple→complex cell transformation: Simple cells are orientation-tuned and phase-sensitive. Complex cells pool over phase (via the feedforward projection) to achieve phase invariance — they respond to their preferred orientation regardless of the bar's position within their receptive field.
Pretrained Weight Loading¶
Module: sc_neurocore.model_zoo.pretrained
Function: load_pretrained(name: str) → Network
Loads pre-initialised weights from .npz files in
sc_neurocore/model_zoo/weights/. The architecture is built via the
corresponding builder function, then the Projection CSR data is overwritten
with dense-to-sparse converted weight matrices.
Available pretrained models¶
| Name | Builder | Weight file | Projections loaded |
|---|---|---|---|
"mnist" |
mnist_classifier() |
mnist_784_128_10.npz |
W0 (784→128), W1 (128→10) |
"shd" |
shd_speech_classifier() |
shd_700_256_20.npz |
W0 (700→256), W_rec (256→256), W1 (256→20) |
"dvs_gesture" |
dvs_gesture_classifier() |
dvs_256_256_11.npz |
W0 (256→256), W1 (256→11) |
Weight format: Dense numpy arrays stored in .npz, shape (fan_in, fan_out).
Converted to CSR via scipy.sparse.csr_matrix for efficient sparse-matrix
vector multiplication during projection propagation.
Pretrained archives are loaded with numpy pickle support disabled. The loader rejects missing or unexpected archive members, non-2-D arrays, shape mismatches, complex or object arrays, and non-finite values before overwriting projection weights.
Spiking correction: Weights use Xavier/Glorot with spiking correction factor 0.5 (Zenke & Ganguli 2018). This accounts for the fact that SNN gradients are noisier than ANN gradients due to the non-differentiable spike function.
from sc_neurocore.model_zoo.pretrained import load_pretrained
net = load_pretrained("mnist")
net.run(0.1)
print(net.spike_monitors[0].count)
Error handling:
- Unknown name → ValueError with list of available models
- Missing weight file → FileNotFoundError
Infrastructure Pipeline¶
All 10 architectures produce a Network object with the standard pipeline:
model_zoo.configs.<builder>()
├── Population(NeuronModel, n, label, params)
│ └── step_all(current) → binary spike vector
├── Projection(source, target, weight, probability, ...)
│ └── propagate(src_spikes) → target_currents (CSR matrix-vector)
├── PoissonInput(n, rate_hz, weight)
│ └── get_current(t, dt) → stochastic current array
├── SpikeMonitor(population, label)
│ ├── .count → total spikes
│ ├── .spike_times → timestep array
│ └── .spike_trains → per-neuron timestep dict
└── Network.run(duration, dt, backend)
├── backend="python": pure-Python event loop
├── backend="rust": Rust engine (if all models supported)
└── backend="auto": Rust when available, else Python
Simulation loop (per timestep): 1. Zero all current buffers 2. Apply stimuli (PoissonInput → target population current) 3. Propagate spikes through projections (CSR matrix-vector) 4. Step all populations (current → spikes) 5. Record spikes in monitors 6. Update plasticity (if any) 7. Apply FIM feedback (if fim_lambda > 0)
Seed determinism: All builders use seed=42. Two identical calls
produce identical spike counts and spike trains.
Performance¶
Measured on Intel Xeon E5-2620v4 (ML350 Gen8), Python 3.12, backend="python".
| Architecture | Neurons | Throughput (neuron-steps/s) | Duration tested |
|---|---|---|---|
| mnist (n_hidden=16) | 810 | ~75K | 50ms |
| dvs (n_classes=4) | 516 | ~70K | 50ms |
| shd | 976 | ~55K | 50ms |
| brunel (50/12) | 62 | ~120K | 50ms |
| cortical (2 layers) | 130 | ~15K | 50ms |
| cpg (2 oscillators) | 20 | ~18K | 50ms |
| decision (n_per_pool=10) | 37 | ~20K | 50ms |
| wm (n_neurons=50) | 50 | ~12K | 50ms |
| auditory (n_ch=8) | 20 | ~25K | 50ms |
| v1 (n_orient=2, n_per=5) | 15 | ~30K | 50ms |
Bottleneck analysis: - Feedforward LIF networks (mnist, dvs, shd) are fastest — simple neuron model, no recurrence overhead - Biophysical models (cortical, cpg, decision, wm) are 3–5× slower due to multi-compartment HH/HR dynamics with sub-stepping - Network size scales linearly: projections dominate at large N
Rust backend: Currently not available for model_zoo configs because all
configs use PoissonInput stimuli, and the Rust engine (_can_use_rust())
returns False when stimuli are present. This is a design limitation —
PoissonInput generation happens in Python and cannot be dispatched to Rust.
Neuron Model Summary¶
| Architecture | Excitatory | Inhibitory |
|---|---|---|
| mnist | StochasticLIFNeuron | — |
| dvs | StochasticLIFNeuron | — |
| shd | StochasticLIFNeuron | — |
| brunel | StochasticLIFNeuron | StochasticLIFNeuron |
| cortical | PospischilNeuron (RS) | GolombFSNeuron (FS) |
| cpg | HindmarshRoseNeuron | HindmarshRoseNeuron |
| decision | HodgkinHuxleyNeuron | WangBuzsakiNeuron |
| wm | CompteWMNeuron (NMDA) | WangBuzsakiNeuron |
| auditory | HodgkinHuxleyNeuron | WangBuzsakiNeuron |
| v1 | HodgkinHuxleyNeuron | WangBuzsakiNeuron |
Test Coverage¶
| Category | Tests | What is verified |
|---|---|---|
| Construction | 10 | Each builder returns Network |
| Topology | 30 | Population counts, projection wiring, monitor counts, stimulus attachment |
| Neuron types | 12 | Correct model class per population (PospischilNeuron, GolombFSNeuron, etc.) |
| Analytical | 15 | Xavier weight scaling, inhibition ratio |
| Dynamics | 10 | Every config produces spikes under Poisson drive |
| Scaling | 20 | Parameter sweeps (n_hidden, n_classes, n_layers, g, n_oscillators, n_per_pool, n_neurons, n_channels, n_orientation) |
| Performance | 10 | Network throughput > threshold for all configs |
| Pretrained | 8 | Load mnist/shd/dvs, weights differ from default, all produce spikes, unknown name raises ValueError |
| Cross-cutting | 70 | All 10 configs × 7 properties: populations≥2, projections≥1, monitors≥1, stimuli≥1, seed determinism, spike_count analysis, per-neuron ISI |
| Total | 201 |
See tests/test_model_zoo.py.
Findings¶
-
All 10 configs produce spikes under default Poisson drive within 100ms. No silent networks. This confirms that all parameter values from the published references are within the spiking regime for the implemented neuron models.
-
Seed determinism holds for all configs. Two identical calls with seed=42 produce identical spike counts. This is critical for reproducible experiments and regression testing.
-
Xavier scaling verified analytically. The mnist_classifier uses w = √(2/fan_in) × 20 for both projections. This matches Zenke & Ganguli 2018 Table 1 (with the ×20 scaling factor for spiking networks).
-
Brunel inhibition ratio exact. |J_I| = g × J_E to machine precision for all tested g values (3.0, 5.0, 8.0).
-
Cross-orientation inhibition distance-dependent. Measured weights confirm w = −1/(1+d) formula: closer orientations receive stronger suppression, matching the normalization model.
-
Recurrent tau differentiation in SHD. The recurrent layer uses τ_mem=20ms vs input τ_mem=10ms, verified by comparing neuron parameters. This longer time constant provides the temporal integration necessary for speech processing.
-
Working memory ring is self-recurrent. The E→E projection source and target are the same population, confirming ring attractor topology.
-
CPG mutual inhibition verified. Flexor→extensor and extensor→flexor both carry weight=−2.0, ensuring alternating burst dynamics.
-
Pretrained weights differ from default. The loaded .npz weights are not identical to the default Xavier initialisation, confirming that the weight loading pipeline successfully overwrites the defaults.
-
Rust backend unavailable for all configs. Every config uses PoissonInput, which disables the Rust backend. This is a known limitation — the Rust engine does not support stimulus injection.