Skip to content

Visualizing Spike Activity and Accuracy

The nwave SDK provides two utility functions for understanding model behaviour:

  • plot_spike_raster(spks, sample_idx) — shows which neurons fire at which timestep, giving an intuitive view of network activity
  • accuracy(spk, targets) — measures classification accuracy by summing spikes over time and taking the argmax across output neurons
import torch
import torch.nn as nn
from nwavesdk.layers import H1v2Synapse, H1v2Layer, prepare_net
from nwavesdk.utils import plot_spike_raster
from nwavesdk.metrics import accuracy
N_IN, N_HIDDEN, N_OUT, DT = 16, 12, 4, 1e-3

class VisualizationNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.syn1 = H1v2Synapse(N_IN,     N_HIDDEN, device="cpu")
        self.lyr1 = H1v2Layer(N_HIDDEN, taus=10e-3, dt=DT, layer_topology="FF", device="cpu")
        self.syn2 = H1v2Synapse(N_HIDDEN, N_OUT,    device="cpu")
        self.lyr2 = H1v2Layer(N_OUT,    taus=10e-3, dt=DT, layer_topology="FF", device="cpu")

    def forward(self, x):
        prepare_net(self)
        spk1_list, spk2_list = [], []
        for t in range(x.shape[1]):
            cur = self.syn1(x[:, t, :])
            spk1, _ = self.lyr1(cur)
            cur = self.syn2(spk1)
            spk2, _ = self.lyr2(cur)
            spk1_list.append(spk1)
            spk2_list.append(spk2)
        return torch.stack(spk1_list, dim=1), torch.stack(spk2_list, dim=1)

model = VisualizationNet()
model.eval()

BATCH, T = 4, 80
x = (torch.rand(BATCH, T, N_IN) > 0.8).float()

with torch.no_grad():
    spk_hidden, spk_out = model(x)

print(f"Hidden spikes: {spk_hidden.shape}")
print(f"Output spikes: {spk_out.shape}")
Hidden spikes: torch.Size([4, 80, 12])
Output spikes: torch.Size([4, 80, 4])
# Raster plot: each row is a neuron, each dot is a spike.
# Pass all spike layers as a list to see the full network activity.
plot_spike_raster([spk_hidden, spk_out], sample_idx=0)

png

# accuracy(spk, targets):
#   sums spikes over the time dimension → argmax gives the predicted class
#   targets: integer class labels, shape (batch,)

# Use a larger batch so the result reliably lands near chance (1/N_OUT = 25%).
# With only 4 samples there is a ~32% chance of getting 0% by bad luck.
torch.manual_seed(0)
x_eval   = (torch.rand(200, T, N_IN) > 0.8).float()
targets  = torch.randint(0, N_OUT, (200,))

with torch.no_grad():
    _, spk_eval = model(x_eval)

acc = accuracy(spk_eval, targets)
print(f"Accuracy on synthetic targets: {acc:.2%}")
print(f"Expected near chance: {1/N_OUT:.2%}  (random weights, {N_OUT} classes)")
Accuracy on synthetic targets: 18.50%
Expected near chance: 25.00%  (random weights, 4 classes)

Further reading