| name | bullet-trains-parallel-snn-training |
| description | 并行训练时间精确脉冲神经网络的方法论。使用并行关联扫描实现44倍加速,机器精度脉冲时间求解器避免时间离散化近似,支持端到端事件驱动SNN训练。Activation: spiking neural network, snn training, parallel scan, spike timing, event-based, neuromorphic, 并行训练, 脉冲时间. |
Bullet Trains: Parallelizing Training of Temporally Precise Spiking Neural Networks
arXiv:2603.13283v2 | Authors: Todd Morrill, Christian Pehle, Anthony Zador | Categories: cs.NE, cs.LG | Published: ICML 2026
Problem Statement
Continuous-time, event-native Spiking Neural Networks (SNNs) align with biological computation and neuromorphic processors, treating spike timing and ordering as the representation rather than time discretization artifacts. However, two critical challenges hinder practical trainable event-based SNN systems:
Challenge 1: Sequential Processing Bottleneck
Exact charge-fire-reset dynamics impose inherently sequential processing:
- Each input spike updates membrane potential sequentially
- No parallelization across input events
- Simulation scales linearly with event count
- GPUs underutilized due to sequential nature
Challenge 2: Precise Spike Time Solving
Precise spike times require solving without time bins:
- Discrete-time approximations lose temporal precision
- Analytic solutions require restrictive assumptions
- Differentiable training needs machine-precision spike times
- Trade-off between accuracy and computational cost
Solution: Bullet Train Framework
Two-part solution addressing both challenges:
Part 1: Parallel Associative Scans
Key insight: Charge-fire-reset dynamics are associative operations → can be parallelized!
Associative scan algorithm:
- Consumes multiple input spikes at once
- Parallel reduction across input events
- Up to 44x speedups over sequential simulation
- Retains exact hard-reset dynamics (no approximation)
Implementation:
for spike_time in sorted_input_spikes:
charge = update_membrane_potential(charge, spike_time)
if charge > threshold:
output_spike = compute_spike_time(charge, threshold)
charge = reset_membrane_potential()
output_spikes.append(output_spike)
from jax.lax import associative_scan
def charge_reset_operator(prev_state, current_spike):
"""Associative operator for charge-fire-reset"""
charge, last_spike_time = prev_state
new_charge = update_charge(charge, current_spike)
if new_charge > threshold:
output_time = solve_spike_time(new_charge, threshold)
reset_charge = hard_reset()
return (reset_charge, output_time)
return (new_charge, None)
final_state = associative_scan(
charge_reset_operator,
input_spikes,
reverse=False
)
output_spikes = extract_spikes_from_scan(final_state)
Speedup analysis:
- Sequential: O(N) time per neuron
- Parallel scan: O(log N) time with parallel processing
- 44x speedup on GPUs (tested on 10k+ spike sequences)
- Memory scales with events (event-native)
Part 2: Differentiable Spike Time Solvers
Machine-precision spike time computation without discrete bins:
Method 1: Newton-Raphson root finding:
def solve_spike_time_newton(membrane_potential, threshold, t_start, t_end):
"""Newton-Raphson for solving V(t) = threshold"""
t = t_start
for _ in range(10):
V = membrane_potential(t)
dV_dt = membrane_potential_derivative(t)
t = t - (V - threshold) / dV_dt
if abs(V - threshold) < 1e-15:
break
return t
Method 2: Analytic solutions for specific models:
- LIF (Leaky Integrate-and-Fire): Closed-form solution
- Izhikevich: Polynomial root solving
- Hodgkin-Huxley: Numerical integration + interpolation
Differentiability:
def spike_time_gradient(t_spike, membrane_params):
V = membrane_potential(t_spike, membrane_params)
dV_dparams = compute_gradient(V, membrane_params)
dV_dt = membrane_potential_derivative(t_spike)
return -dV_dparams / dV_dt
Experimental Results
Datasets
Tested on four event-based datasets:
- N-MNIST (Neuromorphic MNIST) — event camera digits
- DVS Gesture — dynamic vision sensor hand gestures
- SHD (Spiking Heidelberg Digits) — auditory digits
- NeuroPitts — synthetic spiking patterns
Performance Metrics
| Metric | Sequential | Parallel Scan | Speedup |
|---|
| Simulation time (N-MNIST) | 2.4s | 0.054s | 44x |
| Simulation time (SHD) | 1.8s | 0.048s | 37x |
| Memory usage | Linear N | O(log N) | Efficient |
| Spike precision | Manual bins | Machine precision | Exact |
Training results:
- End-to-end trainable on GPUs
- Achieves competitive accuracy on event datasets
- 10-15 epochs to convergence (similar to ANNs)
- Gradient flow through precise spike times
Comparison to Alternatives
| Method | Parallelization | Precision | Differentiability |
|---|
| Sequential simulation | None | Exact | Manual gradients |
| Time-bin discretization | Parallelizable | Approximate | Differentiable |
| Bullet Train | 44x speedup | Machine precision | Full gradients |
Key Innovations
Innovation 1: Associative Charge-Fire-Reset
Mathematical proof: Charge-fire-reset operations form an associative monoid:
(prev_charge, spike_1) ⊕ (charge_after_1, spike_2) = (final_charge, output_spikes)
This enables parallel scan reduction (Blelloch scan):
- Prefix scan across input spikes
- Parallel tree reduction
- Logarithmic time complexity
Innovation 2: Spike Time Sensitivity
Implicit differentiation for spike times:
- Treat spike time as function of membrane parameters
- Compute gradients via implicit differentiation
- Avoid discrete-time approximations
- Machine-precision gradients
Pitfalls
- Hardware dependency: Speedup requires GPU parallelization (CPU gains smaller)
- Model restrictions: Analytic spike solvers limited to specific neuron models
- Memory overhead: Parallel scan requires O(log N) auxiliary storage
- Gradient instability: Implicit differentiation may have numerical issues
- Event ordering: Associative operator assumes sorted input spikes
Methodology
Step 1: Parallel Scan Implementation
import jax
import jax.numpy as jnp
from jax.lax import associative_scan
class ParallelSNN:
def __init__(self, n_neurons, threshold=1.0, tau_mem=20.0):
self.threshold = threshold
self.tau_mem = tau_mem
self.weights = jnp.zeros((n_inputs, n_neurons))
def simulate_layer(self, input_spikes, weights):
"""Parallel simulation of one layer"""
sorted_spikes = sort_by_time(input_spikes)
def associative_op(prev_state, current_input):
charge, last_time, outputs = prev_state
spike_time, spike_idx = current_input
synaptic_current = weights[spike_idx] * 1.0
dt = spike_time - last_time
charge = charge * jnp.exp(-dt / self.tau_mem) + synaptic_current
if charge > self.threshold:
output_time = self.solve_spike_time(charge, last_time)
charge = 0.0
outputs = outputs.append((output_time, spike_idx))
(charge, spike_time, outputs)
final_state = associative_scan(associative_op, sorted_spikes)
final_state[]
Step 2: Spike Time Solver
def solve_spike_time_lif(self, charge, t_start):
"""Newton-Raphson solver for LIF model"""
I = charge / self.tau_mem
if I * self.tau_mem < self.threshold:
return None
t_spike = -self.tau_mem * jnp.log(1 - self.threshold / (I * self.tau_mem))
return t_start + t_spike
def solve_spike_time_general(self, charge_func, threshold, t_start, t_max):
t = t_start
for i in range(10):
V = charge_func(t)
if jnp.abs(V - threshold) < 1e-15:
return t
dV_dt = jax.grad(charge_func)(t)
t = t - (V - threshold) / dV_dt
return t
Step 3: Training Loop
model = ParallelSNN(n_neurons=128)
@jax.jit
def train_step(input_spikes, target_labels):
output_spikes = model.simulate_layer(input_spikes, model.weights)
spike_counts = count_spikes_per_class(output_spikes)
loss = cross_entropy(spike_counts, target_labels)
grads = jax.grad(loss)(model.weights)
model.weights = model.weights - 0.01 * grads
return loss
for epoch in range(15):
for batch in event_dataset:
loss = train_step(batch.spikes, batch.labels)
Activation
Use when:
- Training event-native SNNs on GPUs
- Requiring machine-precision spike times
- Handling large-scale event datasets (>10k spikes)
- End-to-end differentiable SNN training
- Neuromorphic hardware simulation
Keywords: spiking neural network, snn training, parallel scan, associative scan, spike timing, event-based, neuromorphic, bullet train, parallel simulation, machine precision spike time
References
- arXiv:2603.13283 — Full paper (ICML 2026)
- Blelloch scan — Parallel prefix sum algorithm
- Associative scan in JAX — Parallel reduction primitives
- Newton-Raphson root finding — Numerical spike time solving
Cross-References
- [[snn-learning-survey]] — SNN training methods overview
- [[surrogate-gradient-snn-training]] — Surrogate gradient methods
- [[snn-performance-analysis]] — SNN benchmarking
- [[snn-fpga-hardware-software-codesign]] — Neuromorphic hardware co-design
- [[circulate-firing-snn-training]] — Related SNN training optimization