Getting started

Creating a neural network

spikelearn instantiates a network using the SpikingNet class as follows

[1]:
from spikelearn import SpikingNet
[2]:
snn = SpikingNet()

A SpikingNet object contains layers, synapses, and inputs. You can also define outputs that are returned at each timestep to track the status of the network. Let’s start creating a single Layer of leaky integrate and fire neurons:

[3]:
from spikelearn.neurons import LIFLayer
[4]:
layer = LIFLayer(20, 4)

this creates a layer comprising 20 neurons with a leakage time equal to 4 timesteps. Next, we add it to the SpikingNet object:

[5]:
snn.add_layer(layer, "neuron_layer")

The add_layer method requires two arguments: the layer object, and a name that we will use to refer to this layer.

The second type of object that we can have inside a SpikingNet is an external input. Inputs provide the interface with the extenral world.

[6]:
snn.add_input("my_input")

Much like the neuron layer, each input requires a name. The next step is to create a synapse connecting the inputs to our layer. In order to do that, we need first to create a synapse object:

[7]:
from spikelearn import StaticSynapse
import numpy as np
[8]:
W = np.random.random((20,10))
syn = StaticSynapse(10, 20, W)

This creates a static synapse connecting 10 presynaptic neurons to 20 postsynaptic neurons through a 2D array of static weights W. Now we can use this synapse to connect our input and our neuron layer in the SpikingNet object:

[9]:
snn.add_synapse("neuron_layer", syn, "my_input")

When calling add_synapse, we add the postsynaptic layer first, followed by the synapse object, and the presynaptic neuron. We can have synapses with more than one type of presynaptic neuron. Also, the name of the layers must exist.

Defining outputs and running the network

In order to track the state of the network we need to define outputs:

[10]:
snn.add_output("neuron_layer")

Now we are ready to run the network. Here we are going to drive the neurons with a constant input for just a few timesteps:

[11]:
u = np.random.random(10)
[12]:
for _ in range(15):
    s = snn(u)
    print(s)

[array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0.])]
[array([1., 1., 1., 1., 1., 1., 1., 0., 0., 1., 1., 1., 1., 1., 1., 0., 1.,
       1., 0., 1.])]
[array([0., 0., 0., 0., 0., 0., 0., 1., 1., 0., 0., 0., 0., 0., 0., 1., 0.,
       0., 1., 0.])]
[array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0.])]
[array([1., 1., 1., 1., 1., 1., 1., 0., 0., 1., 1., 1., 1., 1., 1., 0., 1.,
       1., 0., 1.])]
[array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0.])]
[array([0., 0., 0., 0., 0., 0., 0., 1., 1., 0., 0., 0., 0., 0., 0., 1., 0.,
       0., 1., 0.])]
[array([1., 1., 1., 1., 1., 1., 1., 0., 0., 1., 1., 1., 1., 1., 1., 0., 1.,
       1., 0., 1.])]
[array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0.])]
[array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0.])]
[array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
       1., 1., 1.])]
[array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0.])]
[array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0.])]
[array([1., 1., 1., 1., 1., 1., 1., 0., 0., 1., 1., 1., 1., 1., 1., 0., 1.,
       1., 0., 1.])]
[array([0., 0., 0., 0., 0., 0., 0., 1., 1., 0., 0., 0., 0., 0., 0., 1., 0.,
       0., 1., 0.])]

At each timestep, the SpikingNet object returns a list with all the outputs, in this case a list with the outputs of our spiking neuron layer. In this case, a value of 1 indicated that the neuron is spiking, 0 otherwise.