Feedforward SNNs process one timestep at a time (no inter-step communication). Recurrent SNNs have connections between timesteps, enabling temporal dynamics. Add gating mechanisms (inspired by LSTMs) to SNNs, and you get powerful temporal learning with neuromorphic efficiency.
Recurrent SNN Architecture
Standard SNN:
x_t → Neuron → spike_t
(no memory between timesteps)
Recurrent SNN:
x_t + hidden_{t-1} → Neuron → spike_t, hidden_t
(hidden state carries information forward)
Implementation: Spiking LSTM-like Unit
import torch
import torch.nn as nn
class RecurrentLIFCell(nn.Module):
def __init__(self, input_size, hidden_size, leak=0.99):
super().__init__()
self.input_size = input_size
self.hidden_size = hidden_size
self.leak = leak
# Input to hidden
self.W_x = nn.Linear(input_size, hidden_size)
# Hidden to hidden (recurrence)
self.W_h = nn.Linear(hidden_size, hidden_size)
# Membrane potential
self.V = None
def forward(self, x, hidden=None):
"""
x: (batch, input_size)
hidden: (batch, hidden_size) previous state
Returns: spike (batch, hidden_size), new_hidden
"""
if hidden is None:
hidden = torch.zeros(x.size(0), self.hidden_size, device=x.device)
if self.V is None:
self.V = torch.zeros_like(hidden)
# Input current + recurrent input
current = self.W_x(x) + self.W_h(hidden)
# Integrate
self.V = self.leak * self.V + current
# Generate spike
spike = (self.V >= 1.0).float()
# Reset
self.V = self.V * (1 - spike)
return spike, spike # spike becomes new hidden state
class RecurrentSNN(nn.Module):
def __init__(self, input_size, hidden_size, output_size, num_layers=2):
super().__init__()
self.num_layers = num_layers
self.hidden_size = hidden_size
# Recurrent layers
self.cells = nn.ModuleList([
RecurrentLIFCell(
input_size if i == 0 else hidden_size,
hidden_size,
leak=0.99
)
for i in range(num_layers)
])
# Output layer
self.output = nn.Linear(hidden_size, output_size)
def forward(self, x):
"""
x: (batch, seq_len, input_size)
Returns: (batch, output_size)
"""
batch_size, seq_len, input_size = x.shape
# Process sequence
hidden = [torch.zeros(batch_size, self.hidden_size) for _ in range(self.num_layers)]
outputs = []
for t in range(seq_len):
x_t = x[:, t, :] # (batch, input_size)
# Forward through layers
for layer_idx, cell in enumerate(self.cells):
spike, hidden[layer_idx] = cell(x_t if layer_idx == 0 else spike, hidden[layer_idx])
# Decode output
output = self.output(spike)
outputs.append(output)
# Average over time
final_output = torch.stack(outputs, dim=1).mean(dim=1)
return final_output
# Training
snn = RecurrentSNN(input_size=28*28, hidden_size=128, output_size=10, num_layers=2)
optimizer = torch.optim.Adam(snn.parameters(), lr=1e-3)
criterion = nn.CrossEntropyLoss()
for epoch in range(10):
for images, labels in train_loader:
# Convert image to spike train (Poisson)
spike_train = (torch.rand(images.size(0), 20, 28*28) < images.unsqueeze(1) / 255.0).float()
output = snn(spike_train)
loss = criterion(output, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
Temporal Pattern Learning
Recurrent SNNs can learn patterns like:
- Sequences (speech, time series)
- Spatiotemporal events (video, action)
- Context-dependent decisions
Conclusion
Recurrent SNNs add temporal dynamics to spiking networks. Combining recurrence with surrogate gradients enables training complex temporal models with neuromorphic efficiency. These networks are the future of event-based sensor processing. Next: neuromorphic hardware (Intel Loihi, IBM TrueNorth).

