Core¶
Network¶
TeiliNetwork
is a subclass of brian2.Network
. It does the same thing plus some additional methods for convenience.
There are properties to get all monitors
, Neurons
and Connections
that were added to the Network.
Like in Brian2, there is an add
method to which all Groups
have to be added, for usage, please refer to the teili examples (in particular neuron_synapse_tutorial) and to the Brian2 documentation ().
Groups¶
Neurons¶
Neurons
is a subclass of brian2.NeuronGroup
and can be used in the same way.
Have a look at neuron_synapse_tutorial for an introduction.
In teili there are different ways to initialize a Neurons
object:
import os
from teili.core.groups import Neurons
from teili.models.neuron_models import DPI
from teili.models.builder.neuron_equation_builder import NeuronEquationBuilder
# the teili way
G = Neurons(100, equation_builder=DPI(num_inputs=2))
# from a static file
path = os.path.expanduser("~")
model_path = os.path.join(path, "teiliApps", "equations", "")
neuron_model = NeuronEquationBuilder.import_eq(
filename=model_path + 'DPI.py', num_inputs=2)
G = Neurons(100, equation_builder=neuron_model)
# or the brian2 way
G = Neurons(100, model='dv/dt = -v / tau : 1')
As in brian2 we provide a Neuron
class which inherits from brian2’s NeuronGroup
class.
The required keyword arguments are the same as described in brian2’s neuron tutorial.
See below a example use case of pre-defined neuron_models
.
For static neuron_model
usage please refer to
teiliApps/tutorials/neuron_synapse_import_eq_tutorial.py
.
from teili import Neurons
from teili.models.neuron_models import DPI as neuron_model
test_neurons = Neurons(2, equation_builder=neuron_model(num_inputs=2),
name="test_neurons")
where num_inputs defines how many distinct inputs the NeuronGroup
is expecting.
This allows us to potentially treat each synaptic connection as independent and not to
perform a linear summation before each current is injected into the neuron.
For many simulations this is an unnecessary feature as most models expect a linear summation
of all synaptic inputs.
By defining the number of inputs explicitly, however, one can study branch specific inputs
with a distribution of synaptic time constants which are asynchronously integrated.
Each model, whether Neuron
or Connection
is internally generated dynamically
using the EquationBuilder. For more details please refer to NeuronEquationBuilder.
An example of the neuron_model
class is shown below:
class DPI(NeuronEquationBuilder):
"""This class provides you with all equations to simulate a current-based
exponential, adaptive leaky integrate and fire neuron as implemented on
the neuromorphic chips by the NCS group. The neuron model follows the DPI neuron
which was published in 2014 (Chicca et al. 2014).
"""
def __init__(self, num_inputs=1):
"""This initializes the NeuronEquationBuilder with DPI neuron model.
Args:
num_inputs (int, optional): Description
"""
NeuronEquationBuilder.__init__(self, base_unit='current', adaptation='calcium_feedback',
integration_mode='exponential', leak='leaky',
position='spatial', noise='none')
self.add_input_currents(num_inputs)
The NeuronEquationBuilder
has the following keyword arguments:
base_unit: Either set to
current
orvoltage
depending whether you want to simulate current-based hardware neuron modelsadaptation: Toggles spike-frequency adaptation mechanism in
neuron_model
. Can either be set toNone
orcalcium_feedback
.integration_mode: Can be set to
linear
,quadratic
orexponential
leak: Toggles leaky integration. Possible values are
leaky
ornon_leaky
.position: Adds positional x, y attribute to neuron in order to spatially arrange the neurons. Once the
neuron_model
has these attributes the user can access and set them byneuron_obj.x
.noise: Adds constant noise to
neuron_model
The reason behind this is that the EquationBuilder
has access to a set of templates defined in teili/models/builder/templates/
such that the same neuron model can easily be simulated with and without leak for example. Of course we offer the possibility of a work-around so that statically defined models can be simulated. For details please refer to the tutorial
For more information please consult the EquationBuilder section. Let’s connect neurons to one another.
Connections¶
The Connections
class is a subclass of brian2.Synapses
and can be used in the same way.
Have a look at neuron_synapse_tutorial for an introduction.
In teili there are different ways to initialize a Connections
object:
import os
from teili.core.groups import Connections
from teili.models.synapse_models import DPISyn
from teili.models.builder.synapse_equation_builder import SynapseEquationBuilder
# the teili way
S = Connections(pre_neuron, post_neuron,
equation_builder=DPISyn(), name="synapse_name")
# from a static file
path = os.path.expanduser("~")
model_path = os.path.join(path, "teiliApps", "equations", "")
synapse_model = = SynapseEquationBuilder.import_eq(
model_path + 'DPISyn.py')
S = Connections(pre_neuron, post_neuron,
equation_builder=synapse_model, name="synapse_name")
# or the brian2 way
S = Connections(pre_neuron, post_neuron, model='w : volt', on_pre='v += w')
As in brian2 we provide a Connections
class which inherits from brian2’s Synapses
class.
The required keyword arguments are the same as described in brian2’s synapse tutorial.
See below a example use case of pre-defined synapse_models
.
For static synapse_model
usage please refer to
~/teiliApps/tutorials/neuron_synapse_builderobj_tutorial.py
.
from teili.core.groups import Neurons, Connections
from teili.models.synapse_models import DPISyn as syn_model
test_synapse = Connections(test_neurons1, test_neurons2,
equation_builder=syn_model(),
name="test_synapse")
Each model, whether Neuron
or Connection
is internally generated dynamically
using the EquationBuilder. For more details please refer to NeuronEquationBuilder or SynapseEquationBuilder
An example of the synapse_model
class is shown below:
class DPISyn(SynapseEquationBuilder):
"""This class provides you with all the equations to simulate a Differential Pair
Integrator (DPI) synapse as published in Chicca et al. 2014.
"""
def __init__(self):
"""This class provides you with all the equations to simulate a Differential Pair
Integrator (DPI) synapse as published in Chicca et al. 2014.
"""
SynapseEquationBuilder.__init__(self, base_unit='DPI',
plasticity='non_plastic')
The SynapseEquationBuilder
has the following keyword arguments:
base_unit: Set to
current
orconductance
depending whether you want to simulate current-based hardware neuron models. This keyword argument can also be set toDPI
orDPIShunting
for specific hardware model simulation.kernel: Can be set to
exponential
,alpha
orresonant
which ultimately sets the shapes of the EPSC and IPSC.plasticity: This keyword argument lets you easily generate any
synapse_model
with either anstdp
orfusi
learning rule.
The reason behind this is that the EquationBuilder
has access to a set of templates defined in teili/models/builder/templates/
such that the same synapse_model
can easily be simulated with and without plasticity or with different plasticity rules for example.
Of course we offer the possibility of a work-around so that statically defined models can be simulated.
For details please refer to the plasticity tutorial
Note
TBA Contributing guide for new templates
Tags¶
Each TeiliGroup
has an attribute called _tags
. For more information please see here for more detailed explanation of how to set and get tags from Groups
.
Tags should be set as the network expands and the functionality changes. Tags are defined as:
mismatch: (bool) Flag to indicate if mismatch is present in the
Group
noise: (bool) Noise input, noise connection or noise presence
level: (int) Level of BuildingBlock in the hierarchy. A WTA BuildingBlock which is connected directly to a sensor array is level 1. An OCTA BuildinBlock, however, is level 2 as it consists of level 1 WTAs
sign: (str : exc/inh/None) Sign on neuronal population. Following Dale law.
target_sign: (str : exc/inh/None) Sign of target population. None if not applicable.
num_inputs: (int) Number of inputs in Neuron population. None if not applicable.
bb_type: (str : WTA/ OCTA/ 3-WAY) Building block type.
group_type: (str : Neuron/Connection/ SpikeGen) Group type
connection_type: (str : rec/lateral/fb/ff/None) Connection type
Setting Tags¶
Tags can be set: .. code-block:: python
test_wta._set_tags({‘custom_tag’ : custom_tag }}, target_group)
Getting Tags¶
Specific groups can be filtered using specific tags:
test_wta.get_groups({'group_type': 'SpikeGenerator'})
All tags of a group can be obtained by:
test_wta.print_tags('n_exc')
Device Mismatch¶
Mismatch is an inherent property of analog VLSI devices due to fabrication variability 1. The effect of mismatch on chip behavior can be studied, for example, with Monte Carlo simulations 2.
Thus, if you are simulating neuron and synapse models of neuromorphic chips, e.g. the DPI neuron (DPI) and the DPI synapse (DPISyn), you might also want to simulate device mismatch.
To this end, the class method add_mismatch()
allows you to add a Gaussian distributed mismatch with mean equal to the current parameter value and standard deviation set as a fraction of the current parameter value.
As an example, once Neurons
and Connections
are created, device mismatch can be added to some selected parameters (e.g. Itau and refP for the DPI neuron) by specifying a dictionary with parameter names as keys
and standard deviation as values
, as shown in the example below.
If no dictionary is passed to add_mismatch()
20% mismatch will be added to all variables except for variables that are found in teili/models/parameters/no_mismatch_parameter.py
.
import numpy as np
from brian2 import seed
from teili.core.groups import Neurons
from teili.models.neuron_models import DPI
test_neurons = Neurons(100, equation_builder=DPI(num_inputs=2))
Let’s assume that the estimated mismatch distribution has a standard deviation of 10% of the current value for both parameters. Then:
mismatch_param = {'Itau': 0.1, 'refP': 0.1}
test_neurons.add_mismatch(mismatch_param, seed=10)
This will change the current parameter values by drawing random values from the specified Gaussian distribution.
If you set the mismatch seed in the input parameters, the random samples will be reproducible across simulations.
Note
Note that self.add_mismatch()
will automatically truncate the Gaussian distribution
at zero for the lower bound. This will prevent neuron or synapse parameters (which
are mainly transistor currents for the DPI model) from being set to negative values. No upper bound is specified by default.
However, if you want to manually specify the lower bound and upper bound of the mismatch
Gaussian distribution, you can use the method _add_mismatch_param()
, as shown below.
With old_param being the current parameter value, this will draw samples from a Gaussian distribution with the following parameters:
mean: old_param
standard deviation: std * old_param
lower bound: lower * std * old_param + old_param
upper bound: upper * std * old_param + old_param
import numpy as np
from brian2 import seed
from teili.core.groups import Neurons
from teili.models.neuron_models import DPI
test_neurons = Neurons(100, equation_builder=DPI(num_inputs=2))
test_neurons._add_mismatch_param(param='Itau', std=0.1, lower=-0.2, upper = 0.2)
Note
that this option allows you to add mismatch only to one parameter at a time.
- 1
Sheik, Sadique, Elisabetta Chicca, and Giacomo Indiveri. “Exploiting device mismatch in neuromorphic VLSI systems to implement axonal delays.” Neural Networks (IJCNN), The 2012 International Joint Conference on. IEEE, 2012.
- 2
Hung, Hector, and Vladislav Adzic. “Monte Carlo simulation of device variations and mismatch in analog integrated circuits.” Proc. NCUR 2006 (2006): 1-8.