Conductance-based spiking networks (COBA, PING) need one extra ingredient to train at all: a single flag, --v-grad-dampen. This article is the deep dive on why it is needed and what it does, derived from the discrete equations the code runs. For the surrounding recipe — BPTT, the spike surrogate, the loss, optimiser, readout, and regulariser — see the Training article; this one assumes that background.
In plain English. The E and I cells form a loop that makes the network oscillate at gamma (≈25 Hz). Training sends the gradient backward around that same loop, and each time a neuron crosses its spike threshold the surrogate hands the gradient a large multiplier. The loop is traversed once per gamma cycle — only about five times in a 200 ms trial — but each pass multiplies by a factor well above one (the surrogate slope enters squared), so a handful of passes is enough to overflow to NaN. The forward simulation stays bounded because the spike reset clamps each cell every cycle; the gradient sidesteps that reset, so forward stability buys nothing backward. The fix, --v-grad-dampen, divides the voltage gradient by a constant at every step, shrinking the loop’s multiplier below one — and thanks to a straight-through trick it changes only the gradient, never the simulation. The rest of this article proves each of those claims from the discrete equations.
Naive BPTT through a 2000-step COBA/PING trial reaches NaN within a few batches. This article establishes the failure and its remedy from the discrete equations the code runs — no step omitted. The plan is: write the one-step map, differentiate it exactly (Lemma 1), propagate the gradient backward (the recursion), show the recurrent loop forces that gradient to diverge geometrically (Proposition 1), and show that scaling the per-step voltage gradient by makes the loop a contraction while leaving the forward trajectory untouched (Proposition 2).
Index the timesteps at ms. Each cell holds a state . With reversal potentials , capacitance , leak , synaptic decays and , threshold and reset , the step is exactly (lif_step_expeuler, exp_synapse):
where is the not-refractory gate, and the membrane decay and rest point are built from the post-update conductances :
The timing matters and is taken from the code: the spike in (S) is read from the current voltage , drives the conductance one step later in (C), and that conductance sets the voltage in (V). So one synaptic edge — presynaptic voltage to postsynaptic voltage — spans one timestep.
Differentiate (S), (C), (V) entry by entry. The spike surrogate gives the spike derivative
From (C), the conductance partials are a self-decay and a presynaptic-voltage coupling obtained by chaining (1):
From (V), with held, the membrane self-term is the decay; and differentiating (P) gives the conductance-to-voltage term (, , ):
the last step being the leading order in (using ). Define identically with . Collecting (1)–(3), the one-step Jacobian on , with the cross-cell coupling in the lower-left block, is
The single subtlety, and it is decisive below: the reset in (V) is a torch.where, so on any cell that spikes or is refractory the output is the constant and the membrane self-term is gated to zero. We write this as the factor on the entry: at a spike (gradient through the cell’s own membrane is cut), otherwise. Crucially multiplies only the membrane self-term — it does not touch the spike output in (1)–(2), which is evaluated at before the reset.
Let . Reverse-mode autodiff is exactly the linear recursion
So the gradient that reaches step is governed by the product of one-step Jacobians, and . Whether this is benign or catastrophic is decided by the voltage component of (J) chained through the recurrent wiring.
Claim. In a network with a recurrent E→I→E loop, the voltage gradient grows geometrically in the number of gamma cycles traversed — not in the number of timesteps. A 200 ms trial holds only cycles against steps; the danger is that each cycle multiplies by a large factor, not that there are many cycles.
Proof. Compose (2) and (3): the gradient carried from a postsynaptic voltage at to a presynaptic voltage at across one synapse is the product of the conductance-coupling and the membrane term,
Traverse the loop once: across (edge gain ), then across (edge gain ). Over one round trip the -voltage gradient maps to itself with the loop gain
The factor appears once per gamma cycle. Each population fires a single synchronous volley per cycle, so the two large kicks (one for , one for ) occur together once per loop traversal and nowhere else; between volleys the per-step Jacobians are the mild sub-unit decays , which merely carry the gradient along without amplifying it. So (4) collapses, across cycles, to the scalar recursion , giving after cycles
Worked example (default PING init). Take the released constants: ms, , nF, nF, , mV, mV at the crossing, ms (), ms (), and order-µS coupling , µS. The two edge gains (5) are
so the loop gain is . Over the cycles of a 200 ms trial — not the steps — the voltage gradient is amplified by
A unit gradient seeded at the readout thus returns to scaled by ; summed over the batch and compounded across successive optimiser steps it crosses the fp32 ceiling () and the loss becomes NaN within a few batches. The blow-up is robust: even if threshold spread cuts the effective tenfold (each edge , so ), and — still divergent. The compounding is per cycle, not per step. ∎
Why the forward pass does not blow up the same way. The forward orbit is bounded because the reset (V) slams each spiking cell to every cycle — that is the gate in (J), a strong per-cycle contraction. But in (6) is built only from the spike-output edges (5), i.e. from evaluated before the reset; the gate sits on the membrane self-term and never enters the loop product. So the backward loop bypasses precisely the contraction that bounds the forward orbit. Forward stability and backward divergence are not in contradiction: they travel different paths through (J), and the straight-through reset is what separates them.
The flag --v-grad-dampen inserts, before the reset, the operation dv = _scale_grad(dv, 1/γ) where is the membrane increment in (V). The primitive
is the identity in the forward pass () but multiplies the backward gradient through by . Re-differentiating (V) with so scaled changes two partials of (J):
The membrane self-term stays bounded by 1 (for it tends to 1 — the slow integration pathway is preserved, not crushed), while every voltage←conductance edge — and therefore every loop edge (5) — is divided by . The loop gain (6) becomes
so the backward loop is a contraction, , as soon as
By (8) the forward trajectory is bitwise identical with or without the flag, so this is a pure modification of the gradient, not of the dynamics. ∎
In code this is the single line _scale_grad(dv, 1.0 / v_grad_dampen) in the LIF step. Since for an order-unity loop constant , the threshold (11) scales like , consistent with the recipes: for the unitless standard SNN and for COBA/PING (used by exp025 and downstream), whose larger conductance-scale loop constant demands the larger .
The in (9) lands on every voltage←conductance gradient, not only the recurrent loop. The feedforward input also enters through (the term in (C)), so the input-weight gradient is suppressed by the same factor: damping trades a slice of the legitimate learning signal for stability. Hence the operating rule — take the smallest satisfying (11), i.e. the smallest value that prevents overflow. Too large a can therefore quietly cap achievable accuracy by starving the input layer of gradient. Distinct from gradient clipping, which rescales the assembled parameter gradient after the fact: damping reshapes the recursion (4) term by term, before any parameter gradient is formed. Tightening (11) per-layer on long-trial tasks is open work.
Prediction. The mechanism implies the flag is load-bearing only when the loop exists: the same network should train with damping fully off when run as COBA (, loop open), but fail as PING () — every optimiser step’s gradient going non-finite and being skipped, leaving the network frozen at chance.