Skip to content

Tutorial 42: Spike-Level Debugging

When your SNN gives wrong answers, the spike debugger tells you where and why. Record full execution traces, compare two runs, find the first divergence point, and trace causal spike chains backward through time.

Why Spike-Level Debugging

Standard debugging (print loss, check gradients) tells you that training isn't working. Spike debugging tells you why:

Symptom Standard Debug Spike Debug
Loss doesn't decrease "Gradients are small" "Layer 2 is dead: 90% neurons never fire"
Accuracy plateaus "Try different LR" "Neurons 34-67 have identical spike patterns"
Hardware mismatch "Output differs" "First divergence at t=142, neuron 7, dV=0.003"

1. Record an Execution Trace

Python
from sc_neurocore.debug import SpikeTracer
from sc_neurocore.network.population import Population
from sc_neurocore.network.network import Network
from sc_neurocore.network.stimulus import PoissonInput
from sc_neurocore.network.monitor import SpikeMonitor
from sc_neurocore.neurons.models.hodgkin_huxley import HodgkinHuxleyNeuron

pop = Population(HodgkinHuxleyNeuron, n=10, label="hh")
drive = PoissonInput(n=10, rate_hz=200.0, weight=8.0, dt=0.001, seed=42)
net = Network(pop, drive, SpikeMonitor(pop))

tracer = SpikeTracer(net)
trace = tracer.run(duration=0.05, dt=0.001)
print(f"{trace.n_neurons} neurons, {trace.n_steps} steps, {trace.spike_count} spikes")

The trace records every neuron's membrane voltage, input current, and spike times at every timestep.

2. Inspect a Single Neuron

Python
nt = trace.neuron_trace(0)
print(f"Neuron 0: {len(nt['spike_times'])} spikes")
print(f"  Voltage range: [{nt['voltages'].min():.1f}, {nt['voltages'].max():.1f}]")
print(f"  Mean input current: {nt['currents'].mean():.2f}")

3. Find Divergence Between Two Runs

Compare Python vs Verilog, or float32 vs Q8.8:

Python
from sc_neurocore.debug import find_divergence

pop2 = Population(HodgkinHuxleyNeuron, n=10, label="hh2")
net2 = Network(
    pop2,
    PoissonInput(n=10, rate_hz=200.0, weight=8.0, dt=0.001, seed=99),
    SpikeMonitor(pop2),
)
trace2 = SpikeTracer(net2).run(duration=0.05, dt=0.001)

div = find_divergence(trace, trace2)
if div:
    print(f"First divergence at t={div.timestep}, neuron={div.neuron_id}")
    print(f"  Voltage diff: {div.voltage_diff:.6f}")

4. Trace Causal Chain

Why did neuron 0 fire? Trace backward through synaptic inputs:

Python
from sc_neurocore.debug import causal_chain

spike_t = trace.spike_times(0)
if len(spike_t) > 0:
    chain = causal_chain(trace, neuron_id=0, timestep=int(spike_t[0]), max_depth=5)
    for depth, e in enumerate(chain):
        indent = "  " * depth
        print(f"{indent}t={e.timestep}, neuron={e.neuron_id}, "
              f"I={e.input_current:.2f}, spike={'yes' if e.spiked else 'no'}")

Use Cases

Scenario Tool
ANN-to-SNN conversion divergence find_divergence()
Hardware verification (Python vs Verilog) find_divergence()
Dead/saturated neuron diagnosis neuron_trace()
Unexpected firing patterns causal_chain()
Q8.8 precision analysis find_divergence()

References

  • Brette et al. (2007). "Simulation of networks of spiking neurons: A review of tools and strategies." J. Comp. Neurosci.