Counting spikes

Dear all,

As SNNs are mainly driven by efficient computation and power constrained systems, I would like to know how I could decode the spike frequency of each neuron for a certain input to get a ballpark figure on the network’s power consumption.

Does someone know how to plot spike counts or to record number of spikes during simulation per neuron or per layer?

Hi sjoks,

You can record the number of spikes with a probe, like:

with nengo.Network() as net:
    ens = nengo.Ensemble(...)
    my_spike_probe = nengo.Probe(ens.neurons)

...

with nengo.Simulator(net) as sim:
    sim.run(1.0) # run for one second
    my_spike_counts = np.sum(sim.data[my_spike_probe] > 0, axis=0)

Let me know if this helps!

1 Like

Thanks! So to get the average spike activity per neuron, I would do np.average(np.sum…) ?

Hi sjoks,

‘Average spike activity’ is a little more nuanced so I’ll add the caveat that this is how you get the average activity given your input.

When you probe ens.neurons and read the data after running the simulation you will get an array of shape (n_steps, n_neurons). Since the neurons will react differently to different inputs, this array will give the activity given the specific input signal passed in during the simulation.

What Kris wrote above gives you the total number of spikes for each neuron because you are summing across the time dimension where the activity is greater than zero.

To get the average number of steps of activity, given the current input, you need to divide by the total number of steps, which is determined by how long you run your sim for and what you set dt on your nengo.Simulator() object.

For example, if you set up your simulation as:

   sim.run(1)

You will run the simulation for 500 steps (1 sec / 0.002 sec). More simply, you can get the total number of steps from sim.data[my_spike_probe].shape[0]

Hello @kfrenette,

From your code, it seems that ‘my_spike_counts’ only contains the number of spiking neurons, but not the number of spikes emitted by these neurons.

Can you please confirm?

Hi @duzzi, and welcome to the Nengo forums! :smiley:

The code @kfrenette posted does indeed report the number of spikes emitted by each neuron over the course of the entire Nengo simulation. The format of the data returned by sim.data[my_spike_probe] is:

  • A num_timesteps x n_neurons numpy array where,
  • One row for each timestep
  • One column for each neuron in the probed network.
  • A spike is indicated as a value of 1/sim.dt (where sim.dt defaults to 0.001s, so a spike would be indicated by a value of 1000)

Thus, np.sum(sim.data[my_spike_probe] > 0, axis=0) (specifically the axis=0 part) accumulates all of the spikes along the first axis, resulting in an array that is 1 x n_neurons in size.

As an example this code generates a 5-neuron ensemble and probes the spike outputs:

import nengo
import numpy as np
from nengo.dists import Choice

with nengo.Network(seed=0) as net:
    ens = nengo.Ensemble(
        5,
        1,
        encoders=Choice([[1]]),
        max_rates=Choice([200]),
    )
    p_spike = nengo.Probe(ens.neurons)


with nengo.Simulator(net) as sim:
    sim.run(1.0)  # run for one second
    spike_count = np.sum(sim.data[p_spike] > 0, axis=0)

And the code np.sum(sim.data[p_spike] > 0, axis=0) results in: [103 127 114 0 54]
Which indicates the first neuron spiked 103 times, the second 127 times, the third 114 times, the fourth didn’t spike at all, and fifth only spiked 54 times.

Hello @xchoo,

Thank you for the explanation.

By exploring the simulation data, I get a maximum value that is above 1000. If I understand correctly, this means that the neuron spiked twice:

my_data = sim.data[my_spike_probe]
print(np.max(my_data)) // returns 1999.999

However, computing np.sum(my_data>0) will only account for one spike instead of two, as it will make no difference between neuron values of 1000 and 2000.

Did I understand correctly? If so, a better solution would be:

dt = 0.001            //default
spike_value = 1/dt    //1000
num_spikes = np.sum(sim.data[my_spike_probe]/spike_value, axis=0)  

print(num_spikes)   // spikes per neuron

That’s correct! In Nengo, some neuron types can spike more than once per timestep.

Yes you did. The original code was written only with the default LIF neuron type in mind (which does not spike more than once per timestep), and does not account for neurons that can spike more than once per timestep. Your proposed solution does address this issue.

1 Like