Skip to content

Commit 96715ca

Browse files
authored
Merge pull request #49 from SpiNNakerManchester/stdp_alpha_example
Add STDP example with alpha synapses
2 parents 88925a8 + 83317c7 commit 96715ca

1 file changed

Lines changed: 157 additions & 0 deletions

File tree

examples/simple_STDP.py

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
# Copyright (c) 2020 The University of Manchester
2+
#
3+
# This program is free software: you can redistribute it and/or modify
4+
# it under the terms of the GNU General Public License as published by
5+
# the Free Software Foundation, either version 3 of the License, or
6+
# (at your option) any later version.
7+
#
8+
# This program is distributed in the hope that it will be useful,
9+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
# GNU General Public License for more details.
12+
#
13+
# You should have received a copy of the GNU General Public License
14+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
15+
16+
"""
17+
A simple example of using STDP.
18+
19+
A single post-synaptic neuron fires at a constant rate. We connect several
20+
pre-synaptic neurons to it, each of which fires spikes with a fixed time
21+
lag or time advance with respect to the post-synaptic neuron.
22+
The weights of these connections are small, so they will not
23+
significantly affect the firing times of the post-synaptic neuron.
24+
We plot the amount of potentiation or depression of each synapse as a
25+
function of the time difference.
26+
27+
Adapted from http://neuralensemble.org/docs/PyNN/examples/simple_STDP.html
28+
to run on SpiNNaker, but with alpha-synapses rather than conductance neurons;
29+
the weights involved are too low to be resolved using fixed-point arithmetic,
30+
so some alteration of parameters is necessary to get a similar effect.
31+
"""
32+
33+
import numpy
34+
import spynnaker8 as sim
35+
# from quantities import ms
36+
from pyNN.utility.plotting import Figure, Panel, DataTable
37+
import matplotlib.pyplot as plt
38+
39+
# === Parameters ============================================================
40+
41+
firing_period = 100.0 # (ms) interval between spikes
42+
cell_parameters = {
43+
"tau_m": 10.0, # (ms)
44+
"v_thresh": -50.0, # (mV)
45+
"v_reset": -60.0, # (mV)
46+
"v_rest": -60.0, # (mV)
47+
"cm": 1.0, # (nF)
48+
"tau_refrac": firing_period / 2, # (ms) long period to prevent bursting
49+
}
50+
n = 60 # number of synapses / number of presynaptic neurons
51+
delta_t = 1.0 # (ms) time between firing of neighbouring neurons
52+
t_stop = 10 * firing_period + n * delta_t
53+
delay = 3.0 # (ms) synaptic time delay
54+
55+
# === Set up the simulator ==================================================
56+
57+
sim.setup(timestep=0.1, min_delay=delay, max_delay=delay)
58+
59+
# === Build the network =====================================================
60+
61+
62+
def build_spike_sequences(period, duration, n, delta_t):
63+
"""
64+
Return a spike time generator for `n` neurons (spike sources), where
65+
all neurons fire with the same period, but neighbouring neurons have a
66+
relative firing time difference of `delta_t`.
67+
"""
68+
def spike_time_gen(i):
69+
"""Spike time generator. `i` should be an array of indices."""
70+
return [numpy.arange(
71+
period + j * delta_t, duration, period) for j in (i - n // 2)]
72+
return spike_time_gen
73+
74+
75+
spike_sequence_generator = build_spike_sequences(
76+
firing_period, t_stop, n, delta_t)
77+
78+
spike_sequence = spike_sequence_generator(numpy.arange(n))
79+
80+
# presynaptic population
81+
p1 = sim.Population(n, sim.SpikeSourceArray(spike_times=spike_sequence),
82+
label="presynaptic")
83+
# single postsynaptic neuron
84+
p2 = sim.Population(1, sim.IF_curr_alpha(**cell_parameters),
85+
initial_values={"v": cell_parameters["v_reset"]},
86+
label="postsynaptic")
87+
# drive to the postsynaptic neuron, ensuring it fires at exact multiples of
88+
# the firing period
89+
p3 = sim.Population(
90+
1, sim.SpikeSourceArray(spike_times=numpy.arange(
91+
firing_period - delay, t_stop, firing_period)),
92+
label="driver")
93+
94+
# we set the initial weights to be small, to avoid perturbing the firing
95+
# times of the postsynaptic neurons
96+
stdp_model = sim.STDPMechanism(
97+
timing_dependence=sim.SpikePairRule(
98+
tau_plus=20.0, tau_minus=20.0, A_plus=0.05, A_minus=0.06),
99+
weight_dependence=sim.AdditiveWeightDependence(w_min=0, w_max=1.0),
100+
weight=0.5, delay=delay)
101+
connections = sim.Projection(p1, p2, sim.AllToAllConnector(), stdp_model)
102+
103+
# the connection weight from the driver neuron is very strong, to ensure the
104+
# postsynaptic neuron fires at the correct times
105+
driver_connection = sim.Projection(p3, p2, sim.OneToOneConnector(),
106+
sim.StaticSynapse(weight=10.0, delay=delay))
107+
108+
# === Instrument the network =================================================
109+
110+
p1.record('spikes')
111+
p2.record(['spikes', 'v'])
112+
113+
# === Run the simulation =====================================================
114+
115+
sim.run(t_stop)
116+
117+
# === Save the results, optionally plot a figure =============================
118+
119+
presynaptic_spikes = p1.get_data('spikes').segments[0]
120+
postsynaptic_spikes = p2.get_data('spikes').segments[0]
121+
postsynaptic_v = p2.get_data('v').segments[0]
122+
print("Post-synaptic spike times: %s" % postsynaptic_spikes.spiketrains[0])
123+
124+
weights = connections.get(["weight"], "list")
125+
final_weights = numpy.array([w[-1] for w in weights])
126+
deltas = delta_t * numpy.arange(n // 2, -n // 2, -1)
127+
print("Final weights: %s" % final_weights)
128+
plasticity_data = DataTable(deltas, final_weights)
129+
130+
Figure(
131+
# raster plot of the presynaptic neuron spike times
132+
Panel(presynaptic_spikes.spiketrains,
133+
yticks=True, markersize=0.2, xlim=(0, t_stop)),
134+
# membrane potential of the postsynaptic neuron
135+
Panel(postsynaptic_v.filter(name='v')[0],
136+
ylabel="Membrane potential (mV)",
137+
data_labels=[p2.label], xticks=True, yticks=True, xlim=(0, t_stop)),
138+
# evolution of the synaptic weights with time
139+
# Panel(weights, xticks=True, yticks=True, xlabel="Time (ms)",
140+
# legend=False, xlim=(0, t_stop)),
141+
# scatterplot of the final weight of each synapse against the relative
142+
# timing of pre- and postsynaptic spikes for that synapse
143+
Panel(plasticity_data,
144+
xticks=True, yticks=True, xlim=(-n / 2 * delta_t, n / 2 * delta_t),
145+
ylim=(0.9 * final_weights.min(), 1.1 * final_weights.max()),
146+
xlabel="t_post - t_pre (ms)", ylabel="Final weight (nA)"),
147+
title="Simple STDP example",
148+
annotations="Simulated with {}".format(sim.name())
149+
)
150+
151+
# figure_filename = "simple_STDP.png"
152+
# plt.savefig(figure_filename)
153+
plt.show()
154+
155+
# === Clean up and quit =======================================================
156+
157+
sim.end()

0 commit comments

Comments
 (0)