#!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).
import numpy as np
import matplotlib.pyplot as plt
import ANNarchy as ann
ANNarchy 5.0 (5.0.0) on darwin (posix).
We define a leaky integrator rate-coded neuron and a small population:
= ann.Neuron(
LeakyIntegratorNeuron = dict(
parameters = 10.0 ,
tau = ann.Parameter(0.0),
baseline
),= [
equations "tau * dr/dt + r = baseline", min=0.0),
ann.Variable(
]
)
= ann.Network()
net
= net.create(50, 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 = dict(T = ann.Parameter(10000, type='int')),
parameters
= ann.Variable(
equations "age = if pre.r * post.r > 1.0 : 0 else : age + 1",
= 0,
init type=int
),
= ann.Pruning("age > T", proba = 0.1),
pruning
= ann.Creating("pre.r * post.r > 1.0", proba = 0.5, w = 0.01),
creating
)
= net.connect(pop, pop, 'exc', StructuralPlasticSynapse)
proj = 0.01, probability=0.1) proj.fixed_probability(weights
<ANNarchy.core.Projection.Projection at 0x13a4c2420>
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() net.
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
):
# Start structural plasticity
=100.0)
proj.start_creating(period=100.0)
proj.start_pruning(period
# Save the initial connectivity matrix
= proj.connectivity_matrix() initial_weights
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.
# Let structural plasticity over several trials
for trial in range(20):
# Activate the first subpopulation
25].baseline = ann.Uniform(0.5, 1.5)
pop[:
# Simulate for 1s
1000.)
net.simulate(
# Reset the population
= 0.0
pop.baseline 100.)
net.simulate(
# Activate the second subpopulation
25:].baseline = ann.Uniform(0.5, 1.5)
pop[
# Simulate for 1s
1000.)
net.simulate(
# Reset the population
= 0.0
pop.baseline 100.)
net.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:
=(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()
Synapses can be also created/pruned externally from python, using Dendrite.create_synapse()
and Dendrite.prune_synapse()
.
Here we add a single synapse in a quadrant of the connectivity matrix where no synapses existed:
# Add a synapse
10).create_synapse(rank=30, w=0.01)
proj.dendrite(
# Inspect the final connectivity matrix
= proj.connectivity_matrix()
weights_after_insertion
=(12, 8))
plt.figure(figsize121)
plt.subplot(
plt.imshow(final_weights)'Connectivity matrix before')
plt.title(122)
plt.subplot(
plt.imshow(weights_after_insertion)'Connectivity matrix after')
plt.title( plt.show()
# Remove the synapse
10).prune_synapse(rank=30)
proj.dendrite(
# Inspect the final connectivity matrix
= proj.connectivity_matrix()
weights_after_deletion
=(12, 8))
plt.figure(figsize121)
plt.subplot(
plt.imshow(weights_after_insertion)'Connectivity matrix before')
plt.title(122)
plt.subplot(
plt.imshow(weights_after_deletion)'Connectivity matrix after')
plt.title( plt.show()