def make_classification_network(self, number_of_stimuli, network_name): if network_name not in self.networks: network_size = number_of_stimuli * self.number_of_neurons count_mat = np.zeros((int(self.stimulus_duration / ms * 10), network_size), int) target = b2.NeuronGroup(N=number_of_stimuli, model=self.eqs, threshold='v>threshold', reset='v=0', namespace={'tau': self.tau, 'threshold': self.threshold}) driving = b2.SpikeGeneratorGroup(N=network_size, indices=[0], times=[0 * ms]) # counts = b2.TimedArray(values=_count_mat, dt=b2.defaultclock.dt) synapses = b2.Synapses(source=driving, target=target, model='w: 1', on_pre='v+=w*counts(t, i)') i = np.arange(network_size) j = np.repeat(range(number_of_stimuli), self.number_of_neurons) synapses.connect(j=j, i=i) synapses.w = np.tile(self.weights, reps=number_of_stimuli) spikes = b2.SpikeMonitor(target, record=True) voltage = b2.StateMonitor(target, 'v', record=True) net = b2.Network([target, driving, synapses, spikes, voltage]) net.store() self.networks[network_name] = dict(net=net, count_mat=count_mat, synapses=synapses, v_mon=voltage, spike_mon=spikes, number_of_stimuli=number_of_stimuli, driving=driving) else: self.networks[network_name]['synapses'].w = np.tile(self.weights, reps=number_of_stimuli)
def set_syn_input(self, target, time): '''adding sync inputs at some time points''' ext_in = bb.SpikeGeneratorGroup(1, [(0, time)], self.network.clock) C_syne = bb.Synapses(ext_in, target, model='w:siemens', pre='ge+=w') C_syne.connect_random(ext_in, target, sparseness=1.) C_syne.w = 30. * self.g_ee self.network.add(ext_in, C_syne)
def run(TSTOP=250, group_size=100, g_time=150, neuron_n=1000, linear=True, ext_w=0.2, inh_w=0.2): """Run a simulation and return the resulting spiketrain""" # Basic equation of the model eq = """dv/dt = -gamma*v + I0 : volt Ie : volt Ii : volt """ thetaU = 16 * mV tauM = 8 * ms gamma = 1 / tauM I0 = 17.6 * mV / tauM #Build the group of neuron to use G = br2.NeuronGroup(neuron_n, threshold="v>thetaU", reset="v=0*mV", method='euler', model=eq) #Record the spikes from this group spikes = br2.SpikeMonitor(G) #Build stimulation stim = br2.SpikeGeneratorGroup(1, [0], [g_time]*ms - br2.defaultclock.dt) stim_syn = br2.Synapses(stim, G, on_pre="v += 2*thetaU") stim_syn.connect(i=0, j=np.arange(group_size)) br2.magic_network.schedule = ['start', 'groups', 'synapses', 'thresholds', 'resets', 'end'] connections = np.random.rand(1000, 1000) < 0.3 exc_or_inh = np.random.rand(1000, 1000) < 0.5 exc_i, exc_j = (connections & exc_or_inh).nonzero() inh_i, inh_j = (connections & ~exc_or_inh).nonzero() if linear: G.run_regularly(''' v += Ie + Ii Ie = 0*mV Ii = 0*mV ''', when='after_synapses') else: G.run_regularly(''' v += clip(Ie, 0*mV, 2*mV) + clip(2*(Ie-2*mV), 0*mV, 4*mV) + Ii Ie = 0*mV Ii = 0*mV ''', when='after_synapses') dt = br2.defaultclock.dt exc_syn = br2.Synapses(G, G, on_pre='Ie += %s*mV' % (ext_w), delay=5*ms-dt) inh_syn = br2.Synapses(G, G, on_pre='Ii -= %s*mV' % (inh_w), delay=5*ms-dt) exc_syn.connect(i=exc_i, j=exc_j) inh_syn.connect(i=inh_i, j=inh_j) #Set random initial conditions G.v = np.random.rand(neuron_n) * 16 * mV br2.run(TSTOP * ms) return spikes
def events_generator(snn, dvsEventsList): xmax = int(numpy.max(snn.x) + 1) ymax = int(numpy.max(snn.y) + 1) times = dvsEventsList[0] * brian2.ms indices = dvsEventsList[1] + xmax * dvsEventsList[2] #print(indices) N = xmax * ymax #print(N) return brian2.SpikeGeneratorGroup(N, indices, times), times, indices
def main4(plot=True): # what if we want to keep the input spike exactly the same throughout different taus? # Solution: We run PoissonGroup once, store all the spikes, and use the stored spikes across the multiple runs bs.start_scope() num_inputs = 100 input_rate = 10 * bs.Hz w = 0.1 tau_range = bs.linspace(1, 10, 30) * bs.ms output_rates = [] P = bs.PoissonGroup(num_inputs, rates=input_rate) p_monitor = bs.SpikeMonitor(P) one_second = 1 * bs.second """ Note that in the code above, we created Network objects. The reason is that in the loop, if we just called run it would try to simulate all the objects, including the Poisson neurons P, and we only want to run that once. We use Network to specify explicitly which objects we want to include. """ net = bs.Network(P, p_monitor) net.run(one_second) # keeps a copy of the spikes that are generated by the PoissonGroup during that explicit run earlier spikes_i = p_monitor.i spikes_t = p_monitor.t # Construct network that we run each time sgg = bs.SpikeGeneratorGroup(num_inputs, spikes_i, spikes_t) eqs = ''' dv/dt = -v/tau : 1 ''' G = bs.NeuronGroup(1, eqs, threshold='v>1', reset='v=0', method='exact') S = bs.Synapses(sgg, G, on_pre='v += w') S.connect() # fully connected network g_monitor = bs.SpikeMonitor(G) # store the current state of the network net = bs.Network(sgg, G, S, g_monitor) net.store() for tau in tau_range: net.restore() net.run(one_second) output_rates.append(g_monitor.num_spikes / bs.second) if plot: plt.clf() plt.plot(tau_range / bs.ms, output_rates) plt.xlabel(r'$\tau$ (ms)') plt.ylabel('Firing Rate (spikes/s)') # there is much less noise compared to before where we used different PoissonGroup everytime plt.show()
def construct_feedforward_input(NTWK, target_pop, afferent_pop,\ t, rate_array,\ verbose=False, SEED=1): """ This generates an input asynchronous from post synaptic neurons to post-synaptic neurons POPS and AFFERENCE_ARRAY should be 1D arrrays as their is only one source population 'pop_for_conductance' is the string identifying the source conductance that will be incremented by the afferent input !! """ Model = NTWK['Model'] # extract parameters of the afferent input Nsyn = Model['p_' + afferent_pop + '_' + target_pop] * Model['N_' + afferent_pop] Qsyn = Model['Q_' + afferent_pop + '_' + target_pop] #finding the target pop in the brian2 objects ipop = np.argwhere(NTWK['POPULATIONS'] == target_pop).flatten()[0] if Nsyn > 0: if verbose: print('drawing Poisson process for afferent input [...]') indices, times = set_spikes_from_time_varying_rate(\ t, rate_array,\ NTWK['POPS'][ipop].N, Nsyn, SEED=(SEED+2)**2%100) spikes = brian2.SpikeGeneratorGroup(NTWK['POPS'][ipop].N, indices, times) pre_increment = 'G' + afferent_pop + target_pop + ' += w' synapse = brian2.Synapses(spikes, NTWK['POPS'][ipop], on_pre=pre_increment,\ model='w:siemens') synapse.connect('i==j') synapse.w = Qsyn * brian2.nS NTWK['PRE_SPIKES'].append(spikes) NTWK['PRE_SYNAPSES'].append(synapse) else: print('Nsyn = 0 for', afferent_pop + '_' + target_pop)
def make_plot_network(self): count_mat = np.zeros((int(self.stimulus_duration / ms * 10), self.number_of_neurons), int) target = b2.NeuronGroup(N=1, model=self.eqs, threshold='v>threshold', reset='v=0', namespace={'tau': self.tau, 'threshold': self.threshold}) driving = b2.SpikeGeneratorGroup(N=self.number_of_neurons, indices=[0], times=[0 * ms]) synapses = b2.Synapses(source=driving, target=target, model='w: 1', on_pre='v+=w*counts(t, i)') synapses.connect(i=range(number_of_neurons), j=[0] * number_of_neurons) synapses.w = self.weights spikes = b2.SpikeMonitor(target, record=True) voltage = b2.StateMonitor(target, 'v', record=True) net = b2.Network([target, driving, synapses, spikes, voltage]) net.store() self.networks['plot'] = dict(net=net, synapses=synapses, count_mat=count_mat, v_mon=voltage, spike_mon=spikes, driving=driving)
def make_train_network(self, batch_size, network_name): if network_name not in self.networks: network_size = batch_size * self.number_of_neurons target = b2.NeuronGroup(N=network_size, model=self.eqs, namespace={'tau': self.tau}) driving = b2.SpikeGeneratorGroup(N=network_size, indices=[0], times=[0 * ms]) count_mat = np.zeros((int(self.stimulus_duration / ms * 10), network_size), int) synapses = b2.Synapses(driving, target, 'w: 1', on_pre='v+=1*counts(t, i)') synapses.connect(condition='i==j') synapses.w = np.tile(self.weights, reps=batch_size) voltage = b2.StateMonitor(target, 'v', record=True) net = b2.Network([target, driving, synapses, voltage]) net.store() self.networks[network_name] = dict(net=net, count_mat=count_mat, synapses=synapses, v_mon=voltage, number_of_stimuli=batch_size, driving=driving) else: self.networks[network_name]['synapses'].w = np.tile(self.weights, reps=batch_size)
def set_noisy_input(self, target, time, sigma=0., mcoef=30): '''adding sync inputs at some time points with normal jitter distribution sigma mcoef is the strength of stimulation ''' #print time, sigma t0 = time - 6. * sigma # mean delay is set to 6*sigma ext_in = bb.SpikeGeneratorGroup(1, [0], [t0], clock=nn.network.clock) C_syne = bb.Synapses(ext_in, self.Pe, model='w:siemens', on_pre='ge+=w') for n in target: C_syne.connect(i=0, j=self.Pe[n]) C_syne.w = mcoef * self.g_ee #C_syne.delay=np.random.uniform(0,sigma,len(target)) if sigma > 0.: C_syne.delay = np.random.normal(6. * sigma, sigma, len(target)) else: C_syne.delay = np.zeros(len(target)) self.network.add(ext_in, C_syne)
td = ev.read_dataset(test_file) td.data = np.unique(td.data) # # check whether there is False # counter = 0 # for i in td.data: # if i[2] == False: # counter = counter +1 flat_indices = (td.data.x * td.width) + td.data.y br.start_scope() pos_spikes = br.SpikeGeneratorGroup(td.width * td.height, flat_indices[td.data.p == True], td.data.ts[td.data.p == True] * br.ms) neg_spikes = br.SpikeGeneratorGroup(td.width * td.height, flat_indices[td.data.p == False], td.data.ts[td.data.p == False] * br.ms) # input layer Input_Neurons = br.NeuronGroup(td.width * td.height, eqs, threshold='v>0 or v<-0', reset='v = 0', method='euler') # hidden layer Hidden_Neurons = br.NeuronGroup(50, eqs, threshold='v>' + str(threshold_val) +
def construct_feedforward_input(NTWK, target_pop, afferent_pop,\ t, rate_array,\ AFF_TO_POP_MATRIX=None, additional_spikes={'indices':[], 'times':[]}, verbose=False, SEED=1): """ This generates an input asynchronous from post synaptic neurons to post-synaptic neurons POPS and AFFERENCE_ARRAY should be 1D arrrays as their is only one source population 'pop_for_conductance' is the string identifying the source conductance that will be incremented by the afferent input !! if AFF_TO_POP_MATRIX then fixed pre-pop number: see "poisson_generator.py" """ Model = NTWK['Model'] # Synapses number ? Nsyn = Model['p_' + afferent_pop + '_' + target_pop] * Model['N_' + afferent_pop] if Nsyn > 0: # if non-zero projection [...] # extract parameters of the afferent input Qsyn = Model['Q_' + afferent_pop + '_' + target_pop] #finding the target pop in the brian2 objects ipop = np.argwhere(NTWK['POPULATIONS'] == target_pop).flatten()[0] if verbose: print('drawing Poisson process for afferent input [...]') indices, times, pre_indices,\ pre_times = spikes_from_time_varying_rate(\ t, rate_array,\ NTWK['POPS'][ipop].N, Nsyn, AFF_TO_POP_MATRIX=AFF_TO_POP_MATRIX, SEED=(SEED+2)**2%100) # adding the additional spikes indices = np.concatenate([indices, additional_spikes['indices']]) times = np.concatenate([times, additional_spikes['times']]) # insuring no more than one prespike per bin indices, times = deal_with_multiple_spikes_per_bin(indices, times, t, verbose=verbose) # incorporating into Brian2 objects spikes = brian2.SpikeGeneratorGroup(NTWK['POPS'][ipop].N, indices, times * brian2.ms) # sorted = True, see "deal_with_multiple_spikes_per_bin" pre_increment = 'G' + afferent_pop + target_pop + ' += w' synapse = brian2.Synapses(spikes, NTWK['POPS'][ipop], on_pre=pre_increment,\ model='w:siemens') synapse.connect('i==j') synapse.w = Qsyn * brian2.nS NTWK['PRE_SPIKES'].append(spikes) NTWK['PRE_SYNAPSES'].append(synapse) else: print('Nsyn = 0 for', afferent_pop + '_' + target_pop) spikes, synapse, indices, times = None, None, [], [] # storing quantities: if 'iRASTER_PRE' in NTWK.keys(): NTWK['iRASTER_PRE'].append(indices) NTWK['tRASTER_PRE'].append(times) else: # we create the key NTWK['iRASTER_PRE'] = [indices] NTWK['tRASTER_PRE'] = [times] if 'iRASTER_PRE_in_terms_of_Pre_Pop' in NTWK.keys(): NTWK['iRASTER_PRE_in_terms_of_Pre_Pop'].append(pre_indices) NTWK['tRASTER_PRE_in_terms_of_Pre_Pop'].append(pre_times) else: # we create the key NTWK['iRASTER_PRE_in_terms_of_Pre_Pop'] = [pre_indices] NTWK['tRASTER_PRE_in_terms_of_Pre_Pop'] = [pre_times]
def __groups(self): inputs_hidden = br.SpikeGeneratorGroup(self.N_inputs, indices=np.asarray([]), times=np.asarray([]) * br.ms, name='input_hidden') hidden = br.NeuronGroup(self.N_hidden, \ model='''dv/dt = ((-gL*(v - El)) + D) / (Cm*second) : 1 gL = 30 : 1 (shared) El = -70 : 1 (shared) vt = 20 : 1 (shared) Cm = 3.0 : 1 (shared) D : 1''', method='rk2', refractory=0*br.ms, threshold='v>=vt', reset='v=El', name='hidden', dt=self.dta) inputs_out = br.SpikeGeneratorGroup(self.N_hidden, indices=np.asarray([]), times=np.asarray([]) * br.ms, name='input_out') output = br.NeuronGroup(self.N_output, \ model='''dv/dt = ((-gL*(v - El)) + D) / (Cm*second) : 1 gL = 30 : 1 (shared) El = -70 : 1 (shared) vt = 20 : 1 (shared) Cm = 3.0 : 1 (shared) D : 1''', method='rk2', refractory=0*br.ms, threshold='v>=vt', reset='v=El', name='output', dt=self.dta) #hidden = br.Subgroup(neurons, 0, self.N_hidden, name='hidden') #output = br.Subgroup(neurons, self.N_hidden, self.N_hidden+self.N_output, name='output') Sh = br.Synapses(inputs_hidden, hidden, model=''' tl : second tp : second tau1 = 0.0025 : second (shared) tau2 = 0.000625 : second (shared) tauL = 0.010 : second (shared) tauLp = 0.1*tauL : second (shared) w : 1 up = (sign(t - tp) + 1.0) / 2 : 1 ul = (sign(t - tl - 3*ms) + 1.0) / 2 : 1 u = (sign(t) + 1.0) / 2 : 1 c = 100*exp((tp - t)/tau1) - exp((tp - t)/tau2) : 1 f = w*c : 1 D_post = w*c*ul : 1 (summed) ''', pre='tp=t', post='tl=t', name='synapses_hidden', dt=self.dta) So = br.Synapses( inputs_out, output, model='''tl : second tp : second tau1 = 0.0025 : second (shared) tau2 = 0.000625 : second (shared) tauL = 0.010 : second (shared) tauLp = 0.1*tauL : second (shared) w : 1 up = (sign(t - tp) + 1.0) / 2 : 1 ul = (sign(t - tl - 3*ms) + 1.0) / 2 : 1 u = (sign(t) + 1.0) / 2 : 1 c = 100*exp((tp - t)/tau1) - exp((tp - t)/tau2) : 1 f = w*c : 1 D_post = w*c*ul : 1 (summed) ''', pre='tp=t', post='tl=t', name='synapses_output', dt=self.dta) #Rh = br.Synapses(hidden, hidden, pre='c_post=0', name='winner_take_all_a', dt=self.dta) #Ro = br.Synapses(output, output, pre='c_post=0', name='winner_take_all_b', dt=self.dta) #Rh.connect('i!=j') #Ro.connect('i!=j') Sh.connect('True') So.connect('True') Sh.w[:, :] = '(1000*rand()+1750)' So.w[:, :] = '(1000*rand()+1750)' #So.w[0, 1] = '700' Sh.tl[:, :] = '-1*second' Sh.tp[:, :] = '-1*second' So.tl[:, :] = '-1*second' So.tp[:, :] = '-1*second' hidden.v[:] = -70 output.v[:] = -70 M = br.StateMonitor(output, 'v', record=True, name='monitor_v') N = br.StateMonitor(So, 'c', record=True, name='monitor_o_c') #O = br.StateMonitor(S, 'tp', record=True, name='monitor_o') #F = br.StateMonitor(S, 'f', record=True, name='monitor_f') Th = br.SpikeMonitor(hidden, variables='v', name='crossings_h') To = br.SpikeMonitor(output, variables='v', name='crossings_o') self.net_hidden = br.Network(inputs_hidden, hidden, Sh, Th) self.net_out = br.Network(inputs_out, output, So, M, N, To) self.actual = self.net_out['crossings_o'].all_values()['t'] self.net_hidden.store() self.net_out.store()
def construct_feedforward_input(NTWK, target_pop, afferent_pop,\ t, rate_array,\ additional_spikes={'indices':[], 'times':[]}, additional_spikes_in_terms_of_pre_pop={'indices':[], 'times':[]}, verbose=False, SEED=1): """ This generates an input asynchronous from post synaptic neurons to post-synaptic neurons POPS and AFFERENCE_ARRAY should be 1D arrrays as their is only one source population 'pop_for_conductance' is the string identifying the source conductance that will be incremented by the afferent input !! """ Model = NTWK['Model'] # Synapses number ? Nsyn = Model['p_' + afferent_pop + '_' + target_pop] * Model['N_' + afferent_pop] if Nsyn > 0: # if non-zero projection [...] # extract parameters of the afferent input Qsyn = Model['Q_' + afferent_pop + '_' + target_pop] #finding the target pop in the brian2 objects ipop = np.argwhere(NTWK['POPULATIONS'] == target_pop).flatten()[0] if verbose: print('drawing Poisson process for afferent input [...]') indices, times = spikes_from_time_varying_rate(t, rate_array,\ NTWK['POPS'][ipop].N, Nsyn, SEED=(SEED+2)**2%100) # adding the additional spikes (1) indices = np.concatenate([indices, additional_spikes['indices']]) times = np.concatenate([times, additional_spikes['times']]) # adding the additional spikes (2) if len(additional_spikes_in_terms_of_pre_pop['indices']) > 0: try: Matrix = NTWK['M_conn_' + afferent_pop + '_' + target_pop] indices2, times2 = translate_aff_spikes_into_syn_target_events( np.array(additional_spikes_in_terms_of_pre_pop['indices'], dtype=int), additional_spikes_in_terms_of_pre_pop['times'], Matrix) except KeyError: print(""" ------------------------------------------------- Need to construct the afference to use this, with: ntwk.build_fixed_afference(NTWK, ['AffExc'], ['Exc', 'Inh', 'DsInh']) """) else: indices2, times2 = [], [] indices = np.concatenate( [indices, indices2, additional_spikes['indices']]) times = np.concatenate([times, times2, additional_spikes['times']]) # insuring no more than one prespike per bin # indices, times = deal_with_multiple_spikes_per_bin(indices, times, t, verbose=verbose) # incorporating into Brian2 objects spikes = brian2.SpikeGeneratorGroup(NTWK['POPS'][ipop].N, indices, times * brian2.ms) # sorted = True, see "deal_with_multiple_spikes_per_bin" pre_increment = 'G' + afferent_pop + target_pop + ' += w' synapse = brian2.Synapses(spikes, NTWK['POPS'][ipop], on_pre=pre_increment,\ model='w:siemens') synapse.connect('i==j') synapse.w = Qsyn * brian2.nS NTWK['PRE_SPIKES'].append(spikes) NTWK['PRE_SYNAPSES'].append(synapse) else: print('Nsyn = 0 for', afferent_pop + '_' + target_pop) spikes, synapse, indices, times, pre_indices, pre_times = None, None, [], [], [], [] # afferent array NTWK['Rate_%s_%s' % (afferent_pop, target_pop)] = rate_array # storing quantities: if 'iRASTER_PRE' in NTWK.keys(): NTWK['iRASTER_PRE'].append(indices) NTWK['tRASTER_PRE'].append(times) else: # we create the key NTWK['iRASTER_PRE'] = [indices] NTWK['tRASTER_PRE'] = [times]
def prespecified_spike_neurons(n_neurons, spike_indices, spike_times): neurons = b2.SpikeGeneratorGroup( N=n_neurons, indices=spike_indices, times=spike_times) return neurons
tau1 = 5.00 * br.ms tau2 = 1.25 * br.ms #Ni = br.NeuronGroup(3, '''dv/dt = (vt - vr)/period : volt (unless refractory) # period: second # fire_once: boolean''', \ # threshold='v>vt', reset='v=vr', # refractory='fire_once') #Ni.period = [1, 1, 7] * br.ms #Ni.fire_once[:] = [True] * 3 indices = np.asarray([0]) times = np.asarray([6]) * br.ms Ni = br.SpikeGeneratorGroup(3, indices=indices, times=times) #Nh = br.NeuronGroup(1, model="""dv/dt=(gtot-v)/(10*ms) : 1 # gtot : 1""") Nh = br.NeuronGroup(1, model="""v = I :1 I : 1""") S = br.Synapses(Ni, Nh, model='''tl : second alpha=exp((tl - t)/tau1) - exp((tl - t)/tau2) : 1 w : 1 I_post = w*alpha : 1 (summed) ''', pre='tl+=t - tl') S.connect('True') S.w[:, :] = '(80+rand())'
t = time.time() samples, labels = convert_all_samples(orig_samples) print(f'Conversion took {sec_to_str(time.time()-t)}') # %% threshold = 0.3 weights = np.random.normal(0, 1e-3, num_neurons) init_w = weights.copy() t = time.time() print('Setting up network') duration = 500 tau = 2 * ms count = np.zeros((duration * 10, num_samples * num_neurons), int) count[(samples['times'] * 10).astype(int), samples['inds'].astype(int)] = samples['counts'] eqs = 'dv/dt = -v / tau : 1' target = b2.NeuronGroup(num_samples, eqs, threshold='v>threshold', reset='v=0') driving = b2.SpikeGeneratorGroup(num_samples * num_neurons, samples['inds'], samples['times'] * ms) counts = b2.TimedArray(count, dt=b2.defaultclock.dt) synapses = b2.Synapses(driving, target, 'w: 1', on_pre='v+=w*counts(t, i)') i = np.arange(num_samples * num_neurons) j = np.array([[i] * num_neurons for i in range(num_samples)]).flatten() synapses.connect(j=j, i=i) synapses.w = np.tile(weights, num_samples) s = b2.SpikeMonitor(target, record=True) print(f'Finished network setup, took {sec_to_str(time.time()-t)}') b2.run(duration * ms) decision = s.count != 0 correct = decision == labels print(correct.mean())
def __init__( self, weights: np.ndarray, weights_in: np.ndarray, dt: float = 0.1 * ms, noise_std: float = 0 * mV, refractory=0 * ms, neuron_params=None, syn_params=None, integrator_name: str = "rk4", name: str = "unnamed", ): """ Construct a spiking recurrent layer with IAF neurons, with a Brian2 back-end :param weights: np.array NxN weight matrix :param weights_in: np.array 1xN input weight matrix. :param refractory: float Refractory period after each spike. Default: 0ms :param neuron_params: dict Parameters to over overwriting neuron defaulst :param syn_params: dict Parameters to over overwriting synapse defaulst :param integrator_name: str Integrator to use for simulation. Default: 'exact' :param name: str Name for the layer. Default: 'unnamed' """ warn("RecDynapseBrian: This layer is deprecated.") # - Call super constructor super().__init__( weights=weights, dt=np.asarray(dt), noise_std=np.asarray(noise_std), name=name, ) # - Input weights must be provided assert weights_in is not None, "weights_in must be provided." # - Warn that nosie is not implemented if noise_std != 0: print("WARNING: Noise is currently not implemented in this layer.") # - Set up spike source to receive spiking input self._input_generator = b2.SpikeGeneratorGroup( self.size, [0], [0 * second], dt=np.asarray(dt) * second) # - Handle unit of dt: if no unit provided, assume it is in seconds dt = np.asscalar(np.array(dt)) * second ### --- Neurons # - Set up reservoir neurons self._neuron_group = teiliNG( N=self.size, equation_builder=teiliDPIEqts(num_inputs=2), name="reservoir_neurons", refractory=refractory, method=integrator_name, dt=dt, ) # - Overwrite default neuron parameters if neuron_params is not None: self._neuron_group.set_params( dict(dTeiliNeuronParam, **neuron_params)) else: self._neuron_group.set_params(dTeiliNeuronParam) ### --- Synapses # - Add recurrent synapses (all-to-all) self._rec_synapses = teiliSyn( self._neuron_group, self._neuron_group, equation_builder=teiliDPISynEqts, method=integrator_name, dt=dt, name="reservoir_recurrent_synapses", ) self._rec_synapses.connect() # - Add source -> reservoir synapses (one-to-one) self._inp_synapses = teiliSyn( self._input_generator, self._neuron_group, equation_builder=teiliDPISynEqts, method=integrator_name, dt=np.asarray(dt) * second, name="receiver_synapses", ) # Each spike generator neuron corresponds to one reservoir neuron self._inp_synapses.connect("i==j") # - Overwrite default synapse parameters if syn_params is not None: self._rec_synapses.set_params(neuron_params) self._inp_synapses.set_params(neuron_params) # - Add spike monitor to record layer outputs self._spike_monitor = b2.SpikeMonitor(self._neuron_group, record=True, name="layer_spikes") # - Call Network constructor self._net = b2.Network( self._neuron_group, self._rec_synapses, self._input_generator, self._inp_synapses, self._spike_monitor, name="recurrent_spiking_layer", ) # - Record neuron / synapse parameters # automatically sets weights via setters self.weights = weights self.weights_in = weights_in # - Store "reset" state self._net.store("reset")
def __init__( self, weights: Union[np.ndarray, int] = None, dt: float = 0.1 * ms, noise_std: float = 0 * mV, tau_syn: float = 5 * ms, synapse_eq=eqSynapseExp, integrator_name: str = "rk4", name: str = "unnamed", ): """ Construct an exponential synapse layer (spiking input), with a Brian2 backend :param weights: np.array MxN weight matrix int Size of layer -> creates one-to-one conversion layer :param dt: float Time step for state evolution. Default: 0.1 ms :param noise_std: float Std. dev. of noise added to this layer. Default: 0 :param tau_syn: float Output synaptic time constants. Default: 5ms :param synapse_eq: Brian2.Equations set of synapse equations for receiver. Default: exponential :param integrator_name: str Integrator to use for simulation. Default: 'exact' :param name: str Name for the layer. Default: 'unnamed' """ warn( "FFExpSynBrian - This layer is deprecated. You can use FFExpSyn or FFExpSynTorch instead." ) # - Provide default dt if dt is None: dt = 0.1 * ms # - Provide default weight matrix for one-to-one conversion if isinstance(weights, int): weights = np.identity(weights, "float") # - Call super constructor super().__init__(weights=weights, dt=dt, noise_std=noise_std, name=name) # - Set up spike source to receive spiking input self._input_generator = b2.SpikeGeneratorGroup( self.size_in, [0], [0 * second], dt=np.asarray(dt) * second ) # - Set up layer receiver nodes self._neuron_group = b2.NeuronGroup( self.size, synapse_eq, refractory=False, method=integrator_name, dt=np.asarray(dt) * second, name="receiver_neurons", ) # - Add source -> receiver synapses self._inp_synapses = b2.Synapses( self._input_generator, self._neuron_group, model="w : 1", on_pre="I_syn_post += w*amp", method=integrator_name, dt=np.asarray(dt) * second, name="receiver_synapses", ) self._inp_synapses.connect() # - Add current monitors to record reservoir outputs self._state_monitor = b2.StateMonitor( self._neuron_group, "I_syn", True, name="receiver_synaptic_currents" ) # - Call Network constructor self._net = b2.Network( self._input_generator, self._neuron_group, self._inp_synapses, self._state_monitor, name="ff_spiking_to_exp_layer", ) # - Record layer parameters, set weights self.weights = weights self.tau_syn = tau_syn # - Store "reset" state self._net.store("reset")
''' }, on_event={ 'pre': 'spike', 'inh_done': 'stop_inhibition' }) S_inhibit.connect(condition='i!=j', p=1) print("done") # ------------- # Input Stimuli # ------------- print("Loading input stimuli... ", end='', flush=True) stimuli = np.load(stimuli_filename) times = [a * b.second for a in stimuli[0]] G_in = b.SpikeGeneratorGroup(1, indices=stimuli[1], times=times) print("done") # ----------------------- # Creating input Synapses # ------------------------ print("Preparing input synapse... ", end='', flush=True) model = ''' w : 1 dApre/dt = -Apre/tau_Apre : 1 (event-driven) dApost/dt = -Apost/tau_Apost : 1 (event-driven) ''' stdp_pre = ''' v_post = (v_post + w*int(not_inhibited))*int(v_post <= v_max - w) + v_max*int(v_post > v_max-w); Apre = Apre_reset; w -= Apost*int(w > w_min + Apost) + w_min*int(w <= w_min + Apost)'''
def __init__(self, num_neurons, tau, threshold, duration=500): # TODO: Include t_max and v_max variables in the brian model, have them updated per-spike and try to create a custom event when t=t(end) to update the model weights # self.duration = duration * ms self.num_neurons = num_neurons self.threshold = threshold self.tau = tau * ms # Helper variables self._count_mat = np.zeros((duration * 10, self.num_neurons), int) # Synaptic efficacies self.weights = np.random.normal(0, 1e-3, num_neurons) # Model definition b2.start_scope() eqs = 'dv/dt = -v / tau: 1' self.counts = b2.TimedArray(self._count_mat, dt=b2.defaultclock.dt) # Evaluation network self.target = b2.NeuronGroup(1, eqs, threshold='v>threshold', reset='v=0', namespace={ 'tau': self.tau, 'threshold': self.threshold }) self.driving = b2.SpikeGeneratorGroup(self.num_neurons, [0], [0] * ms) self.spike_response = 'v+=w*counts(t, i)' self.synapses = b2.Synapses(self.driving, self.target, 'w: 1', on_pre=self.spike_response) self.synapses.connect(i=list(range(self.num_neurons)), j=0) self.synapses.w = self.weights self.voltage = b2.StateMonitor(self.target, 'v', record=True) self.spikes = b2.SpikeMonitor(self.target, record=True) self.net = b2.Network(self.target, self.driving, self.synapses, self.voltage, self.spikes) self.net.store() # Training network self.target_train = b2.NeuronGroup(self.num_neurons, eqs, namespace={'tau': self.tau}) self.driving_train = b2.SpikeGeneratorGroup(self.num_neurons, [0], [0] * ms) self.train_response = 'v+=1*counts(t, i)' self.synapses_train = b2.Synapses(self.driving_train, self.target_train, 'w: 1', on_pre=self.train_response) self.synapses_train.connect(condition='i==j') self.synapses_train.w = self.weights self.voltage_train = b2.StateMonitor(self.target_train, 'v', record=True) self.net_train = b2.Network(self.target_train, self.driving_train, self.synapses_train, self.voltage_train) self.net_train.store() self.debug_0 = 0 # For debugging problematic samples