#!pip install ANNarchy
Structural plasticity
As simple example showing how to use structural plasticity (creation/pruning of synapses) in a rate-coded network (spiking networks work similarly).
First, the structural plasticity mechanisms must be allowed in setup()
:
import numpy as np
import ANNarchy as ann
ann.clear()
# Compulsory to allow structural plasticity
=True) ann.setup(structural_plasticity
ANNarchy 4.8 (4.8.2) on darwin (posix).
We define a leaky integrator rate-coded neuron and a small population:
= ann.Neuron(
LeakyIntegratorNeuron ="""
parameters tau = 10.0 : population
baseline = 0.0
""",
= """
equations tau * dr/dt + r = baseline + sum(exc) : min=0.0
"""
)= ann.Population(100, LeakyIntegratorNeuron) pop
Structural plasticity has two components: creation of synapses and pruning (removal) under certain conditions. These conditions are defined in the synapse type itself in the pruning
and creating
arguments:
= ann.Synapse(
StructuralPlasticSynapse = " T = 10000 : int, projection ",
parameters = """
equations age = if pre.r * post.r > 1.0 :
0
else :
age + 1 : init = 0, int""",
= "age > T : proba = 0.2",
pruning = "pre.r * post.r > 1.0 : proba = 0.1, w = 0.01",
creating
)
= ann.Projection(pop, pop, 'exc', StructuralPlasticSynapse)
proj = 0.01, probability=0.1) proj.connect_fixed_probability(weights
<ANNarchy.core.Projection.Projection at 0x129a6c980>
These conditions must be boolean values, which when True
may trigger the creation/pruning of a synapse. The flag proba
gives the probability by which the synapse will actually be created/pruned.
- When
creating
isTrue
, a synapse that did not exist will be created with the provided probability. Its weight will take the value provided by the flagw
(0.01), the other variables take their default value. - When
pruning
isTrue
, a synapse that exists will be deleted with the given probability.
The pruning
condition can depend on any pre-synaptic, post-synaptic or synaptic variable. The creating
condition can only depend on pre- or post-synaptic conditions, as the synapse does not exist yet.
Apart from these two fields, the synapse is a regular synapse, one could also define synaptic plasticity mechanisms and so on.
We finally create a sparse projection within the population, with 10% connectivity.
compile() ann.
Compiling ... OK
The creation and pruning have to be explicitly started before a simulation, as they are very expensive computationally. The period
argument states how often the conditions will be checked (avoid using dt
):
=100.0)
proj.start_creating(period=100.0) proj.start_pruning(period
To see the effect of structural plasticity, one alternatively activates one half of the population by setting a high baseline (mimicking corrrelated inputs). As neurons in one half will be activated at the same time, they will create synapses between each other. Between the two halves, the neurons are never co-activated, so the existing synapses will slowly die out.
# Save the initial connectivity matrix
= proj.connectivity_matrix()
initial_weights
# Let structural plasticity over several trials
= 100
num_trials for trial in range(num_trials):
# Activate the first subpopulation
50].baseline = 1.0
pop[:# Simulate for 1s
1000.)
ann.simulate(# Reset the population
= 0.0
pop.baseline 100.)
ann.simulate(# Activate the second subpopulation
50:].baseline = 1.0
pop[# Simulate for 1s
1000.)
ann.simulate(# Reset the population
= 0.0
pop.baseline 100.)
ann.simulate(
# Inspect the final connectivity matrix
= proj.connectivity_matrix() final_weights
We can check the effect of structural plasticity by looking at the connectivity matrix before and after the stimulation:
import matplotlib.pyplot as plt
=(12, 8))
plt.figure(figsize121)
plt.subplot(
plt.imshow(initial_weights)'Connectivity matrix before')
plt.title(122)
plt.subplot(
plt.imshow(final_weights)'Connectivity matrix after')
plt.title( plt.show()