Spiking neurons#
Contrary to rate-coded neurons, the use of spiking neurons requires the additional definition of a spike condition (the criteria defining the emission of a spike, typically when the membrane potential exceeds a threshold) and reset equations, governing the evolution of all variables after a spike is emitted.
Built-in neurons#
ANNarchy provides standard spiking neuron models, similar to the ones defined in PyNN (http://neuralensemble.org/docs/PyNN/reference/neuronmodels.html).
Their definition (parameters, equations) are described in Specific Neurons. The classes can be used directly when creating the populations (no need to instantiate them). Example:
pop = Population(geometry = 1000, neuron = Izhikevich)
User-defined neurons#
Let's consider a simple leaky integrate-and-fire spiking neuron model (LIF) using a voltage-gated excitatory conductance:
where \(v(t)\) is the membrane potential, \(\tau\) is the membrane time constant (in milliseconds), \(E_r\) the resting potential, \(E_e\) the target potential for excitatory synapses and \(g_\text{exc}(t)\) the total current induced by excitatory synapses.
This neural model can be defined in ANNarchy by:
LIF = Neuron(
parameters="""
tau = 10.0 : population
Er = -60.0 : population
Ee = 0.0 : population
T = -45.0 : population
""",
equations="""
tau * dv/dt = (Er - v) + g_exc *(Ee- v) : init = 0.0
""",
spike = "v > T",
reset = "v = Er",
refractory = 5.0
)
As for rate-coded neurons, the parameters are defined in the
parameters
description, here globally for the population. equations
contains the description of the ODE followed by the membrane potential.
The additional information to provide is:
spike
: a boolean condition on a single variable (typically the membrane potential) deciding when a spike is emitted.reset
: the modifications to the neuron's variables after a spike is emitted (typically, clamping the membrane potential to its reset potential).refractory
: optionally a refractory period in ms.
Spike condition#
The spike condition is a single constraint definition. You may use the different available comparison operators (>, \<, ==, etc) on a single neuron variable, using as many parameters as you want.
The use of assignment statements or ODEs will lead to an error. Conditional statements can be used. Example:
parameters="""
...
T = -45.0
""",
equations="""
prev_v = v
noise = Uniform (-5.0, 5.0)
tau*dv/dt = E - v + g_exc
""",
spike = """
(v > T + noise) and (prev_v < T + noise)
"""
Reset#
Here you define the variables which should be set to certain values
after a spike occured. Any assignment statements is allowed (=
, +=
,
etc), but the use of ODEs is not possible, as the reset is performed
only once at the end of the time step.
Example:
reset = """
v = Er
u += 0.1
"""
Conductances#
Contrary to rate-coded neurons, spiking neurons use conductance
variables to encode the received inputs, not weighted sums. In ANNarchy,
the conductances are defined by g_
followed by the target name. For
example, if a population receives excitatory input (target exc
) from
another one, you can access the total conductance provoked by exc
spikes with:
tau * dv/dt + v = g_exc
The dynamics of the conductance can be specified after its usage in the membrane potential equation.
- The default behaviour for conductances is an instantaneous reset (or infinitely fast exponential decay). In practice, this means that all incoming spikes are summed up (weighted by the synaptic efficiency) at the beginning of a simulation step, and the resulting conductance is reset to 0.0 at the end of the step. This default behaviour is equivalent to :
LIF = Neuron(
parameters=""" ... """,
equations="""
tau * dv/dt = (Er - v) + g_exc *(Ee- v) : init = 0.0
g_exc = 0.0
""",
spike = " ... ",
reset = " ... "
)
Incoming spikes increase g_exc
and can provoke a post-synaptic spike
at the next step, but leave no trace beyond that point.
- Most models however use exponentially decaying synapses, where the conductance decays with a short time constant after a spike is received. This behavior should be explicitely specified in the neuron's equations:
LIF = Neuron(
parameters=""" ... """,
equations="""
tau * dv/dt = (Er - v) + g_exc *(Ee- v) : init = 0.0
tau_exc * dg_exc/dt = - g_exc
""",
spike = " ... ",
reset = " ... "
)
g_exc
is increased by incoming spikes, and slowly decays back to 0.0
until the next spikes arrive.
Refractory period#
The refractory period in milliseconds is specified by the refractory
parameter of Neuron
.
LIF = Neuron (
parameters = """ ... """,
equations = """ ... """,
spike = """ ... """,
reset = """
v = c
u += d
""",
refractory = 5.0
)
The refractory
argument can be a floating value or the name of a
parameter/variable (string).
If dt = 0.1
, this means that the equations
will not be evaluated for
50 consecutive steps after a spike is emitted, except for the
conductances (starting with g_
) which are evaluated normally during
the refractory period (the neuron is not \"deaf\", it only is frozen in
a refractory state).
refractory
becomes an attribute of a spiking Population
object, so
it can be set specifically for a population even when omitted in the
neuron definition:
LIF = Neuron (
parameters = " ... ",
equations = " ... ",
spike = " ... ",
reset = """
v = c
u += d
"""
)
pop = Population(geometry = 1000, neuron = LIF)
pop.refractory = Uniform(1.0, 10.0)
It can be either a single value, a RandomDistribution
object or a
Numpy array of the same size/geometry as the population.
Instantaneous firing rate#
Method 1: ISI
Spiking neurons define an additional variable t_last
which represents
the timestamp (in ms) of the last emitted spike (updated at the end of
the reset
statement). The time elapsed since the last spike is then
t - t_last
.
This can be used to update the instantaneous firing rate of a neuron, by
inverting the inter-spike interval (ISI) during the reset
statement
following the emission of a spike:
neuron = Neuron(
parameters = "tau = 20.0; tauf = 1000.",
equations = """
tau * dv/dt + v = ...
tauf * df/dt = -f
""",
spike = "v > 1.0",
reset = """
v = 0.0
f = 1000./(t - t_last)
"""
)
Here, a leaky integrator on f is needed to 1) smooth the firing rate and 2) slowly decay to 0 when the neuron stops firing. This method reflects very fast changes in the firing rate, but is also very sensible to noise.
Method 2: Window
A more stable way to compute the firing rate of a neuron is to count at
each time step the number of spikes emitted during a sliding temporal
window (of 100 ms or 1s for example). By default, spiking neurons only
record the time of the last spike they emitted (t_last
), so this
mechanism has to be explicitely enabled by calling the
compute_firing_rate()
method of the desired population:
pop = Population(100, Izhikevich)
pop.compute_firing_rate(window=1000.0)
The window
argument represents the period in milliseconds over which
the spikes will be counted. The resulting firing rate (in Hz) will be
stored in the local variable r
(as for rate-coded neurons), which can
be accessed by the neuron itself or by incoming and outgoing synapse
(pre.r
and post.r
).
If the method has not been called, the variable r
of a spiking neuron
will be constantly 0.0.
Warning
The window method is not available on CUDA yet.