Exploring STDP parameters through one network

Description of problem

I am trying to run a model with two layers, learning weigh through STDP rules. The goal is to make bunch of ten neurons per layer, connected in an all-to-all fashion, and each of these 10x10 groups of neurons would be submitted to STDP rule independently, and with different parameters. In one run, this would allow me to see changes depending on the STDP parameters in a glimpse.
However, when defining my synapses, it seems that the STDP parameters variation that I want to explore are not taken into account. All the group of neurons have the same Apre and Apost/Apre, although I did not define them this way.

I also have trouble accessing the values of the STDP parameters after the model has ran.

Thanks in advance !

Minimal code to reproduce problem

############################## imports
from brian2 import *
from brian2hears import *
from pygame import mixer
from datetime import datetime
from datetime import datetime
import numpy as np
import pandas as pd
import os
import xlrd
import random
import pickle

############################## sounds used for training
chosen_level = 65
soundbase = β€˜PURETONES’ # PURETONES/LOCAL/DESRA/ESC50

if soundbase==β€˜PURETONES’:
n_repeat_sounds = 4
minimal_duration = 500 # duration of the sounds you want to give to the network ,in ms
duration_silence = 20 # silence before and after each sound display
sequence = silence(duration=duration_silencems)
my_silence = silence(duration=duration_silence
ms, samplerate=44.1kHz)
#
fqs = [98
1.05946**ind for ind in np.arange(0,70,1)]
fqs = np.repeat(fqs,n_repeat_sounds) # the sound base is played n times
np.random.shuffle(fqs)
for ind_fq in fqs:
sound= tone(ind_fqHz,minimal_durationms)
sound_ramp = sound.ramp(when = β€˜both’, duration = 10ms)
sequence = Sound.sequence(sequence,sound_ramp, my_silence)
#
sequence.level = chosen_level
dB
duration=sequence.duration

############################## parameters of the layers

transmission is not instantaneous

tau_syn = 5*ms

parameters for the cochlea (C) and auditory nerve (AN)

N_PRE = 10 # number of hair cells and AN fibers
cf = erbspace(100Hz,5000Hz, N_PRE) # center frequencies for the inner hair cells (IHC) of the C
tau_AN = 10*ms
R_AN = 1#*ohm
v_rest_AN = -0.070#mvolt
eqs_AN = β€˜β€™β€™
dv/dt = (R_AN
I_AN+v_rest_AN-v)/tau_AN : 1 (unless refractory)
β€˜β€™β€™
eqs_AN_syn = (Equations(eqs_AN) + Equations(β€˜dI_AN/dt = -I_AN/tau_syn : 1’) )

parameters for the auditory primary cortex (AI_1)

N_POST = 10 # number of cells in A1
tau_AI_1 = 10ms
R_AI_1 = 1 #ohm
v_rest_AI_1 = -0.070
I_AI = 0
eqs_AI_1 = β€˜β€™β€™
dv/dt = (R_AI_1
I_AI_1 +v_rest_AI_1-v)/tau_AI_1 : 1 (unless refractory)
β€˜β€™β€™
eqs_AI_syn_1 = (Equations(eqs_AI_1) + Equations(β€˜dI_AI_1/dt = -I_AI_1/tau_syn : 1’) )

parameters for the inhibitory layer

I_inh = 0
tau_inh = 1ms
R_inh = 1 #ohm
v_rest_inh = -0.070
eqs_inh = β€˜β€™β€™
dv/dt = (R_inh
I_inh+v_rest_inh-v)/tau_inh : 1
β€˜β€™β€™
############################## parameters of the STDP
taupost = 20*ms
taupre = taupost
wmax = 0.04
Apre_to_explore = np.array((0.00001,0.1))
Apostpre_to_explore = np.array((1,4))
nb_param_Apre = len(Apre_to_explore)
nb_param_Apostpre = len(Apostpre_to_explore)
Apre_to_explore = np.repeat(Apre_to_explore, nb_param_Apostpre)
Apostpre_to_explore = np.tile(Apostpre_to_explore, nb_param_Apre)

N_POST_multiple = N_POSTnb_param_Aprenb_param_Apostpre
N_PRE_multiple = N_PREnb_param_Aprenb_param_Apostpre
cf_multiple = np.repeat(array(cf),nb_param_Apre*nb_param_Apostpre, axis=0)*Hz

############################## run the network

cochlea

gfb_small= Gammatone(sequence, cf)
ihc_small = FunctionFilterbank(gfb_small,lambda x: 3clip(x, 0, Inf))
gfb= Gammatone(sequence, cf_multiple)
ihc = FunctionFilterbank(gfb,lambda x: 3
clip(x, 0, Inf))

start_scope()

create the AN NeuronGroup (projection of ihc cells on AN)

G_PRE = FilterbankGroup(ihc, β€˜I_AN’, eqs_AN_syn, threshold = β€˜v>-0.060’, reset = β€˜v = -0.070’, method = β€˜euler’, refractory = 5*ms)
G_PRE.v = -0.070

create the AI_1 neuron group (LIF neurons)

G_POST = NeuronGroup(N_POST_multiple, eqs_AI_syn_1, threshold = β€˜v>-0.060’, reset = β€˜v = -0.070’, method = β€˜euler’, refractory = 5*ms)
G_POST.v = -0.070

create the inhibitory interneurons InterN_1

InterN = NeuronGroup(N_POST_multiple, eqs_inh,threshold = β€˜v>-0.069’, reset = β€˜v = -0.070’, method = β€˜exact’)
InterN.v = -0.070

initial_weights = numpy.random.random_sample(N_PRE*N_POST)*wmax

synapses_1

STPD learning synapses from AN to AI_1

liste_synapses=[]
liste_suivi_synapses = []
for ind_boucle, ind_N in enumerate(np.arange(0,N_POST_multiple,N_POST)):
Apre = Apre_to_explore [ind_boucle]
Apost = -Apretaupre/taupostApostpre_to_explore[ind_boucle]
liste_synapses.append(Synapses(G_PRE, G_POST,
β€˜β€™β€™
w : 1
dapre/dt = -apre/taupre : 1 (event-driven)
dapost/dt = -apost/taupost : 1 (event-driven)
β€˜β€™β€™,
on_pre=’’’
I_AI_1 += w
apre += Apre
w = clip(w+apost, 0, wmax)
β€˜β€™β€™,
on_post=’’’
apost += Apost
w = clip(w+apre, 0, wmax)
β€˜β€™β€™))
liste_synapses[ind_boucle].connect(i=np.tile(np.arange(ind_N, ind_N+10,1),N_PRE),j=np.repeat(np.arange(ind_N, ind_N+10,1),N_PRE))
liste_synapses[ind_boucle].w = initial_weights
liste_suivi_synapses.append(StateMonitor(liste_synapses[ind_boucle], β€˜w’, record=True))

G_POST excitates the inhibitory layer InterN_1

G_POST_to_inhlayer = Synapses(G_POST, InterN,β€˜w:1’,

          on_pre='''
          v_post += 0.1
          ''')

G_POST_to_inhlayer.connect(condition = β€˜i!=j’)
G_POST_to_inhlayer.w=1

inhibitory layer InterN_1 inhibits G_POST_1 except from the incoming neuron

inhlayer_to_G_POST = Synapses(InterN, G_POST,β€˜w:1’,

          on_pre='''
          v_post = -0.07
          ''')

inhlayer_to_G_POST.connect(condition=β€˜i==j’)
inhlayer_to_G_POST.w=1

#monitors of the AN
mon_pre = StateMonitor(G_PRE, [β€˜I_AN’, β€˜v’], record=True, clock=G_PRE.clock)
spike_mon_pre = SpikeMonitor(G_PRE)

monitors of the AI

mon_post = StateMonitor(G_POST, [β€˜v’], record=True, clock=G_POST.clock)
spike_mon_post = SpikeMonitor(G_POST)

#run the magic network
net=Network(G_PRE, G_POST,liste_synapses,liste_suivi_synapses,mon_pre,spike_mon_pre,mon_post,spike_mon_post)
net.run(duration, profile = True, report = β€œtext”, report_period = 20*second)

Hi @sblain . I don’t have time to look into this in detail before next week (I think there is a more efficient way to implement things), but here’s a first hint. The problem in your code seems to be that each of your different Synapses objects refers to the variables Apre and Apost, but by default Brian resolves references to external variables only once, at the end of your script when you call run (see Namespaces β€” Brian 2 2.5.0.3 documentation). This means that all of the synapses will use the same value (the final values you set in the loop). You can work around this, by adding a namespaces dictionary to the respective Synapses objects, i.e. Synapses(G_PRE, G_POST, ..., namespace={'Apre': Apre_to_explore[ind_boucle], ...). In that case, you will have to mention all the external variables the Synapses object references in its namespace argument, though. I.e. not only Apre and Apost, but also taupre, taupost, and wmax.

Hope that helps, best
Marcel

1 Like

Hi @mstimberg,

It helps a lot, thanks, problem solved, it now works as expected :smile:
I couldn’t understand where the Synapses object looked for the parameters.

Thank you for such fast answer!
Best,
SalomΓ©