def build_network():
    global fig_num

    neuron_groups['e'] = b.NeuronGroup(n_e_total, neuron_eqs_e, threshold=v_thresh_e, \
          refractory=refrac_e, reset=scr_e, compile=True, freeze=True)
    neuron_groups['i'] = b.NeuronGroup(n_e_total, neuron_eqs_i, threshold=v_thresh_i, \
         refractory=refrac_i, reset=v_reset_i, compile=True, freeze=True)

    for name in population_names:
        print '...Creating neuron group:', name

        # get a subgroup of size 'n_e' from all exc
        neuron_groups[name + 'e'] = neuron_groups['e'].subgroup(conv_features *
                                                                n_e)
        # get a subgroup of size 'n_i' from the inhibitory layer
        neuron_groups[name + 'i'] = neuron_groups['i'].subgroup(conv_features *
                                                                n_e)

        # start the membrane potentials of these groups 40mV below their resting potentials
        neuron_groups[name + 'e'].v = v_rest_e - 40. * b.mV
        neuron_groups[name + 'i'].v = v_rest_i - 40. * b.mV

    print '...Creating recurrent connections'

    for name in population_names:
        neuron_groups['e'].theta = np.load(
            os.path.join(best_weights_dir,
                         '_'.join(['theta_A', ending + '_best.npy'])))

        for conn_type in recurrent_conn_names:
            if conn_type == 'ei':
                # create connection name (composed of population and connection types)
                conn_name = name + conn_type[0] + name + conn_type[1]
                # create a connection from the first group in conn_name with the second group
                connections[conn_name] = b.Connection(
                    neuron_groups[conn_name[0:2]],
                    neuron_groups[conn_name[2:4]],
                    structure='sparse',
                    state='g' + conn_type[0])

                # instantiate the created connection
                for feature in xrange(conv_features):
                    for n in xrange(n_e):
                        connections[conn_name][feature * n_e + n,
                                               feature * n_e + n] = 10.4

            elif conn_type == 'ie':
                # create connection name (composed of population and connection types)
                conn_name = name + conn_type[0] + name + conn_type[1]

                # load weight matrix
                weight_matrix = np.load(
                    os.path.join(best_weights_dir,
                                 '_'.join([conn_name, ending, 'best.npy'])))

                # create a connection from the first group in conn_name with the second group
                connections[conn_name] = b.Connection(
                    neuron_groups[conn_name[0:2]],
                    neuron_groups[conn_name[2:4]],
                    structure='sparse',
                    state='g' + conn_type[0])

                # define the actual synaptic connections and strengths
                for feature in xrange(conv_features):
                    for other_feature in xrange(conv_features):
                        if feature != other_feature:
                            for n in xrange(n_e):
                                connections[conn_name][feature * n_e + n,
                                                       other_feature * n_e +
                                                       n] = inhibition_level

        print '...Creating monitors for:', name

        # spike rate monitors for excitatory and inhibitory neuron populations
        rate_monitors[name + 'e'] = b.PopulationRateMonitor(
            neuron_groups[name + 'e'],
            bin=(single_example_time + resting_time) / b.second)
        rate_monitors[name + 'i'] = b.PopulationRateMonitor(
            neuron_groups[name + 'i'],
            bin=(single_example_time + resting_time) / b.second)
        spike_counters[name + 'e'] = b.SpikeCounter(neuron_groups[name + 'e'])

        # record neuron population spikes if specified
        if record_spikes and do_plot:
            spike_monitors[name + 'e'] = b.SpikeMonitor(neuron_groups[name +
                                                                      'e'])
            spike_monitors[name + 'i'] = b.SpikeMonitor(neuron_groups[name +
                                                                      'i'])

    if record_spikes and do_plot:
        b.figure(fig_num, figsize=(8, 6))
        b.ion()
        b.subplot(211)
        b.raster_plot(spike_monitors['Ae'],
                      refresh=1000 * b.ms,
                      showlast=1000 * b.ms,
                      title='Excitatory spikes per neuron')
        b.subplot(212)
        b.raster_plot(spike_monitors['Ai'],
                      refresh=1000 * b.ms,
                      showlast=1000 * b.ms,
                      title='Inhibitory spikes per neuron')
        b.tight_layout()

        fig_num += 1

    # creating Poission spike train from input image (784 vector, 28x28 image)
    for name in input_population_names:
        input_groups[name + 'e'] = b.PoissonGroup(n_input, 0)
        rate_monitors[name + 'e'] = b.PopulationRateMonitor(
            input_groups[name + 'e'],
            bin=(single_example_time + resting_time) / b.second)

    # creating connections from input Poisson spike train to excitatory neuron population(s)
    for name in input_connection_names:
        print '\n...Creating connections between', name[0], 'and', name[1]

        # for each of the input connection types (in this case, excitatory -> excitatory)
        for conn_type in input_conn_names:
            # saved connection name
            conn_name = name[0] + conn_type[0] + name[1] + conn_type[1]

            # get weight matrix depending on training or test phase
            weight_matrix = np.load(
                os.path.join(best_weights_dir,
                             '_'.join([conn_name, ending + '_best.npy'])))

            # create connections from the windows of the input group to the neuron population
            input_connections[conn_name] = b.Connection(input_groups['Xe'], neuron_groups[name[1] + conn_type[1]], \
                structure='sparse', state='g' + conn_type[0], delay=True, max_delay=delay[conn_type][1])

            for feature in xrange(conv_features):
                for n in xrange(n_e):
                    for idx in xrange(conv_size**2):
                        input_connections[conn_name][convolution_locations[n][idx], feature * n_e + n] = \
                                weight_matrix[convolution_locations[n][idx], feature * n_e + n]

            if do_plot:
                plot_2d_input_weights()
                fig_num += 1

    print '\n'
class ConvolutionalSpikingNN(object):
	'''
	Object which represents a convolutional spiking neural network.
	'''

	def __init__(mode, connectivity, weight_dependence, post_pre, conv_size, conv_stride, conv_features, weight_sharing, lattice_structure, random_inhibition_prob, top_percent):
		'''
		Network initialization.
		'''

		# setting input parameters
		this.mode = mode
		this.connectivity = connectivity
		this.weight_dependence = weight_dependence
		this.post_pre = post_pre
		this.conv_size = conv_size
		this.conv_features = conv_features
		this.weight_sharing = weight_sharing
		this.lattice_structure = lattice_structure
		this.random_inhibition_prob = random_inhibition_prob

		# load training or testing data
		if mode == 'train':
		    start = time.time()
		    this.data = get_labeled_data(MNIST_data_path + 'training')
		    end = time.time()
		    print 'time needed to load training set:', end - start
		else:
		    start = time.time()
		    this.data = get_labeled_data(MNIST_data_path + 'testing', bTrain = False)
		    end = time.time()
		    print 'time needed to load test set:', end - start

		# set parameters for simulation based on train / test mode
		if test_mode:
			weight_path = top_level_path + 'weights/conv_patch_connectivity_weights/'
			this.num_examples = 10000 * 1
			this.do_plot_performance = False
			ee_STDP_on = False
		else:
			weight_path = top_level_path + 'random/conv_patch_connectivity_random/'
			this.num_examples = 60000 * 1
			this.do_plot_performance = True
			ee_STDP_on = True

		# plotting or not
		do_plot = True

		# number of inputs to the network
		this.n_input = 784
		this.n_input_sqrt = int(math.sqrt(n_input))

		# number of neurons parameters
		this.n_e = ((n_input_sqrt - conv_size) / conv_stride + 1) ** 2
		this.n_e_total = n_e * conv_features
		this.n_e_sqrt = int(math.sqrt(n_e))
		this.n_i = n_e
		this.conv_features_sqrt = int(math.sqrt(conv_features))

		# time (in seconds) per data example presentation and rest period in between, used to calculate total runtime
		this.single_example_time = 0.35 * b.second
		this.resting_time = 0.15 * b.second
		runtime = num_examples * (single_example_time + resting_time)

		# set the update interval
		if test_mode:
			this.update_interval = num_examples
		else:
			this.update_interval = 100

		# rest potential parameters, reset potential parameters, threshold potential parameters, and refractory periods
		v_rest_e, v_rest_i = -65. * b.mV, -60. * b.mV
		v_reset_e, v_reset_i = -65. * b.mV, -45. * b.mV
		v_thresh_e, v_thresh_i = -52. * b.mV, -40. * b.mV
		refrac_e, refrac_i = 5. * b.ms, 2. * b.ms

		# dictionaries for weights and delays
		weight, delay = {}, {}

		# populations, connections, saved connections, etc.
		input_population_names = [ 'X' ]
		population_names = [ 'A' ]
		input_connection_names = [ 'XA' ]
		save_conns = [ 'XeAe', 'AeAe' ]

		# weird and bad names for variables, I think
		input_conn_names = [ 'ee_input' ]
		recurrent_conn_names = [ 'ei', 'ie', 'ee' ]
		
		# setting weight, delay, and intensity parameters
		weight['ee_input'] = (conv_size ** 2) * 0.175
		delay['ee_input'] = (0 * b.ms, 10 * b.ms)
		delay['ei_input'] = (0 * b.ms, 5 * b.ms)
		input_intensity = start_input_intensity = 2.0

		# time constants, learning rates, max weights, weight dependence, etc.
		tc_pre_ee, tc_post_ee = 20 * b.ms, 20 * b.ms
		nu_ee_pre, nu_ee_post = 0.0001, 0.01
		wmax_ee = 1.0
		exp_ee_post = exp_ee_pre = 0.2
		w_mu_pre, w_mu_post = 0.2, 0.2

		# setting up differential equations (depending on train / test mode)
		if test_mode:
			scr_e = 'v = v_reset_e; timer = 0*ms'
		else:
			tc_theta = 1e7 * b.ms
			theta_plus_e = 0.05 * b.mV
			scr_e = 'v = v_reset_e; theta += theta_plus_e; timer = 0*ms'

		offset = 20.0 * b.mV
		v_thresh_e = '(v>(theta - offset + ' + str(v_thresh_e) + ')) * (timer>refrac_e)'

		# equations for neurons
		neuron_eqs_e = '''
				dv/dt = ((v_rest_e - v) + (I_synE + I_synI) / nS) / (100 * ms)  : volt
				I_synE = ge * nS *         -v                           : amp
				I_synI = gi * nS * (-100.*mV-v)                          : amp
				dge/dt = -ge/(1.0*ms)                                   : 1
				dgi/dt = -gi/(2.0*ms)                                  : 1
				'''
		if test_mode:
			neuron_eqs_e += '\n  theta      :volt'
		else:
			neuron_eqs_e += '\n  dtheta/dt = -theta / (tc_theta)  : volt'

		neuron_eqs_e += '\n  dtimer/dt = 100.0 : ms'

		neuron_eqs_i = '''
				dv/dt = ((v_rest_i - v) + (I_synE + I_synI) / nS) / (10*ms)  : volt
				I_synE = ge * nS *         -v                           : amp
				I_synI = gi * nS * (-85.*mV-v)                          : amp
				dge/dt = -ge/(1.0*ms)                                   : 1
				dgi/dt = -gi/(2.0*ms)                                  : 1
				'''

		# creating dictionaries for various objects
		this.neuron_groups = {}
		this.input_groups = {}
		this.connections = {}
		this.input_connections = {}
		this.stdp_methods = {}
		this.rate_monitors = {}
		this.spike_monitors = {}
		this.spike_counters = {}

		# creating excitatory, inhibitory populations
		this.neuron_groups['e'] = b.NeuronGroup(n_e_total, neuron_eqs_e, threshold=v_thresh_e, refractory=refrac_e, reset=scr_e, compile=True, freeze=True)
		this.neuron_groups['i'] = b.NeuronGroup(n_e_total, neuron_eqs_i, threshold=v_thresh_i, refractory=refrac_i, reset=v_reset_i, compile=True, freeze=True)

		# creating subpopulations of excitatory, inhibitory neurons
		for name in population_names:
			print '...creating neuron group:', name

			# get a subgroup of size 'n_e' from all exc
			neuron_groups[name + 'e'] = neuron_groups['e'].subgroup(conv_features * n_e)
			# get a subgroup of size 'n_i' from the inhibitory layer
			neuron_groups[name + 'i'] = neuron_groups['i'].subgroup(conv_features * n_e)

			# start the membrane potentials of these groups 40mV below their resting potentials
			neuron_groups[name + 'e'].v = v_rest_e - 40. * b.mV
			neuron_groups[name + 'i'].v = v_rest_i - 40. * b.mV

		print '...creating recurrent connections'

		for name in population_names:
			# if we're in test mode / using some stored weights
			if mode == 'test' or weight_path[-8:] == 'weights/conv_patch_connectivity_weights/':
				# load up adaptive threshold parameters
				neuron_groups['e'].theta = np.load(weight_path + 'theta_A' + '_' + ending +'.npy')
			else:
				# otherwise, set the adaptive additive threshold parameter at 20mV
				neuron_groups['e'].theta = np.ones((n_e_total)) * 20.0 * b.mV

			for conn_type in recurrent_conn_names:
				if conn_type == 'ei':
					# create connection name (composed of population and connection types)
					conn_name = name + conn_type[0] + name + conn_type[1]
					# create a connection from the first group in conn_name with the second group
					connections[conn_name] = b.Connection(neuron_groups[conn_name[0:2]], neuron_groups[conn_name[2:4]], structure='sparse', state='g' + conn_type[0])
					# instantiate the created connection
					for feature in xrange(conv_features):
						for n in xrange(n_e):
							connections[conn_name][feature * n_e + n, feature * n_e + n] = 10.4

				elif conn_type == 'ie':
					# create connection name (composed of population and connection types)
					conn_name = name + conn_type[0] + name + conn_type[1]
					# create a connection from the first group in conn_name with the second group
					connections[conn_name] = b.Connection(neuron_groups[conn_name[0:2]], neuron_groups[conn_name[2:4]], structure='sparse', state='g' + conn_type[0])
					# instantiate the created connection
					for feature in xrange(conv_features):
						for other_feature in xrange(conv_features):
							if feature != other_feature:
								for n in xrange(n_e):
									connections[conn_name][feature * n_e + n, other_feature * n_e + n] = 17.4

					if random_inhibition_prob != 0.0:
						for feature in xrange(conv_features):
							for other_feature in xrange(conv_features):
								for n_this in xrange(n_e):
									for n_other in xrange(n_e):
										if n_this != n_other:
											if b.random() < random_inhibition_prob:
												connections[conn_name][feature * n_e + n_this, other_feature * n_e + n_other] = 17.4

				elif conn_type == 'ee':
					# create connection name (composed of population and connection types)
					conn_name = name + conn_type[0] + name + conn_type[1]
					# get weights from file if we are in test mode
					if mode == 'test':
						weight_matrix = get_matrix_from_file(weight_path + conn_name + '_' + ending + '.npy', conv_features * n_e, conv_features * n_e)
					# create a connection from the first group in conn_name with the second group
					connections[conn_name] = b.Connection(neuron_groups[conn_name[0:2]], neuron_groups[conn_name[2:4]], structure='sparse', state='g' + conn_type[0])
					# instantiate the created connection
					if connectivity == 'all':
						for feature in xrange(conv_features):
							for other_feature in xrange(conv_features):
								if feature != other_feature:
									for this_n in xrange(n_e):
										for other_n in xrange(n_e):
											if is_lattice_connection(n_e_sqrt, this_n, other_n):
												if mode == 'test':
													connections[conn_name][feature * n_e + this_n, other_feature * n_e + other_n] = weight_matrix[feature * n_e + this_n, other_feature * n_e + other_n]
												else:
													connections[conn_name][feature * n_e + this_n, other_feature * n_e + other_n] = (b.random() + 0.01) * 0.3

					elif connectivity == 'pairs':
						for feature in xrange(conv_features):
							if feature % 2 == 0:
								for this_n in xrange(n_e):
									for other_n in xrange(n_e):
										if is_lattice_connection(n_e_sqrt, this_n, other_n):
											if mode == 'test':
												connections[conn_name][feature * n_e + this_n, (feature + 1) * n_e + other_n] = weight_matrix[feature * n_e + this_n, (feature + 1) * n_e + other_n]
											else:
												connections[conn_name][feature * n_e + this_n, (feature + 1) * n_e + other_n] = (b.random() + 0.01) * 0.3
							elif feature % 2 == 1:
								for this_n in xrange(n_e):
									for other_n in xrange(n_e):
										if is_lattimode == 'test'ce_connection(n_e_sqrt, this_n, other_n):
											if mode == 'test':
												connections[conn_name][feature * n_e + this_n, (feature - 1) * n_e + other_n] = weight_matrix[feature * n_e + this_n, (feature - 1) * n_e + other_n]
											else:
												connections[conn_name][feature * n_e + this_n, (feature - 1) * n_e + other_n] = (b.random() + 0.01) * 0.3

					elif connectivity == 'none':
						pass

			# if STDP from excitatory -> excitatory is on and this connection is excitatory -> excitatory
			if ee_STDP_on and 'ee' in recurrent_conn_names:
				stdp_methods[name + 'e' + name + 'e'] = b.STDP(connections[name + 'e' + name + 'e'], eqs=eqs_stdp_ee, pre=eqs_stdp_pre_ee, post=eqs_stdp_post_ee, wmin=0., wmax=wmax_ee)

			print '...creating monitors for:', name

			# spike rate monitors for excitatory and inhibitory neuron populations
			rate_monitors[name + 'e'] = b.PopulationRateMonitor(neuron_groups[name + 'e'], bin=(single_example_time + resting_time) / b.second)
			rate_monitors[name + 'i'] = b.PopulationRateMonitor(neuron_groups[name + 'i'], bin=(single_example_time + resting_time) / b.second)
			spike_counters[name + 'e'] = b.SpikeCounter(neuron_groups[name + 'e'])

			# record neuron population spikes if specified
			spike_monitors[name + 'e'] = b.SpikeMonitor(neuron_groups[name + 'e'])
			spike_monitors[name + 'i'] = b.SpikeMonitor(neuron_groups[name + 'i'])

		if do_plot:
			b.figure(fig_num)
			fig_num += 1
			b.ion()
			b.subplot(211)
			b.raster_plot(spike_monitors['Ae'], refresh=1000 * b.ms, showlast=1000 * b.ms)
			b.subplot(212)
			b.raster_plot(spike_monitors['Ai'], refresh=1000 * b.ms, showlast=1000 * b.ms)

		# creating lattice locations for each patch
		if connectivity == 'all':
			lattice_locations = {}
			for this_n in xrange(conv_features * n_e):
				lattice_locations[this_n] = [ other_n for other_n in xrange(conv_features * n_e) if is_lattice_connection(n_e_sqrt, this_n % n_e, other_n % n_e) ]
		elif connectivity == 'pairs':
			lattice_locations = {}
			for this_n in xrange(conv_features * n_e):
				lattice_locations[this_n] = []
				for other_n in xrange(conv_features * n_e):
					if this_n // n_e % 2 == 0:
						if is_lattice_connection(n_e_sqrt, this_n % n_e, other_n % n_e) and other_n // n_e == this_n // n_e + 1:
							lattice_locations[this_n].append(other_n)
					elif this_n // n_e % 2 == 1:
						if is_lattice_connection(n_e_sqrt, this_n % n_e, other_n % n_e) and other_n // n_e == this_n // n_e - 1:
							lattice_locations[this_n].append(other_n)
		elif connectivity == 'none':
			lattice_locations = {}

		# setting up parameters for weight normalization between patches
		num_lattice_connections = sum([ len(value) for value in lattice_locations.values() ])
		weight['ee_recurr'] = (num_lattice_connections / conv_features) * 0.15

		# creating Poission spike train from input image (784 vector, 28x28 image)
		for name in input_population_names:
			input_groups[name + 'e'] = b.PoissonGroup(n_input, 0)
			rate_monitors[name + 'e'] = b.PopulationRateMonitor(input_groups[name + 'e'], bin=(single_example_time + resting_time) / b.second)

		# creating connections from input Poisson spike train to convolution patch populations
		for name in input_connection_names:
			print '\n...creating connections between', name[0], 'and', name[1]
			
			# for each of the input connection types (in this case, excitatory -> excitatory)
			for conn_type in input_conn_names:
				# saved connection name
				conn_name = name[0] + conn_type[0] + name[1] + conn_type[1]

				# get weight matrix depending on training or test phase
				if mode == 'test':
					weight_matrix = get_matrix_from_file(weight_path + conn_name + '_' + ending + '.npy', n_input, conv_features * n_e)

				# create connections from the windows of the input group to the neuron population
				input_connections[conn_name] = b.Connection(input_groups['Xe'], neuron_groups[name[1] + conn_type[1]], structure='sparse', state='g' + conn_type[0], delay=True, max_delay=delay[conn_type][1])
				
				if mode == 'test':
					for feature in xrange(conv_features):
						for n in xrange(n_e):
							for idx in xrange(conv_size ** 2):
								input_connections[conn_name][convolution_locations[n][idx], feature * n_e + n] = weight_matrix[convolution_locations[n][idx], feature * n_e + n]
				else:
					for feature in xrange(conv_features):
						for n in xrange(n_e):
							for idx in xrange(conv_size ** 2):
								input_connections[conn_name][convolution_locations[n][idx], feature * n_e + n] = (b.random() + 0.01) * 0.3

			# if excitatory -> excitatory STDP is specified, add it here (input to excitatory populations)
			if ee_STDP_on:
				print '...creating STDP for connection', name
				
				# STDP connection name
				conn_name = name[0] + conn_type[0] + name[1] + conn_type[1]
				# create the STDP object
				stdp_methods[conn_name] = b.STDP(input_connections[conn_name], eqs=eqs_stdp_ee, pre=eqs_stdp_pre_ee, post=eqs_stdp_post_ee, wmin=0., wmax=wmax_ee)

		print '\n'
    # STDP rule (post-pre, no weight dependence)
    eqs_stdp_pre_ee = 'pre = 1.; w -= nu_ee_pre * post'
    eqs_stdp_post_ee = 'w += nu_ee_post * pre; post = 1.'

    eqs_stdp_pre_AeAe = 'pre += 1.; w -= nu_AeAe_pre * post'
    eqs_stdp_post_AeAe = 'w += nu_AeAe_post * pre; post += 1.'

    print '\n'

    # set ending of filename saves
    ending = '_'.join([ str(conv_size), str(conv_stride), str(conv_features), str(n_e), \
         str(num_train), str(random_seed), str(normalize_inputs),
         str(proportion_grow), str(noise_const) ])

    b.ion()
    fig_num = 1

    # creating dictionaries for various objects
    neuron_groups, input_groups, connections, input_connections, stdp_methods, \
     rate_monitors, spike_monitors, spike_counters, output_numbers = {}, {}, {}, {}, {}, {}, {}, {}, {}

    # creating convolution locations inside the input image
    convolution_locations = {}
    for n in xrange(n_e):
        convolution_locations[n] = [ ((n % n_e_sqrt) * conv_stride + (n // n_e_sqrt) * n_input_sqrt * \
            conv_stride) + (x * n_input_sqrt) + y for y in xrange(conv_size) for x in xrange(conv_size) ]

    # instantiating neuron "vote" monitor
    result_monitor = np.zeros(
        (update_interval * num_tests, conv_features, n_e))
        dv/dt = ((v_rest_i - v) + (I_synE+I_synI) / nS) / (10*ms)  : volt
        I_synE = ge * nS *         -v                           : amp
        I_synI = gi * nS * (-85.*mV-v)                          : amp
        dge/dt = -ge/(1.0*ms)                                   : 1
        dgi/dt = -gi/(2.0*ms)                                  : 1
        '''
eqs_stdp_ee = '''
                post2before                            : 1.0
                dpre/dt   =   -pre/(tc_pre_ee)         : 1.0
                dpost1/dt  = -post1/(tc_post_1_ee)     : 1.0
                dpost2/dt  = -post2/(tc_post_2_ee)     : 1.0
            '''
eqs_stdp_pre_ee = 'pre = 1.; w -= nu_ee_pre * post1'
eqs_stdp_post_ee = 'post2before = post2; w += nu_ee_post * pre * post2before; post1 = 1.; post2 = 1.'
    
b.ion()
fig_num = 1
neuron_groups = {}
input_groups = {}
connections = {}
stdp_methods = {}
rate_monitors = {}
spike_monitors = {}
spike_counters = {}
result_monitor = np.zeros((update_interval,n_e))

neuron_groups['e'] = b.NeuronGroup(n_e*len(population_names), neuron_eqs_e, threshold= v_thresh_e, refractory= refrac_e, reset= scr_e, 
                                   compile = True, freeze = True)
neuron_groups['i'] = b.NeuronGroup(n_i*len(population_names), neuron_eqs_i, threshold= v_thresh_i, refractory= refrac_i, reset= v_reset_i, 
                                   compile = True, freeze = True)
Example #5
0
def build_network():
    global fig_num, assignments

    neuron_groups['e'] = b.NeuronGroup(n_e_total,
                                       neuron_eqs_e,
                                       threshold=v_thresh_e,
                                       refractory=refrac_e,
                                       reset=scr_e,
                                       compile=True,
                                       freeze=True)
    neuron_groups['i'] = b.NeuronGroup(n_e_total,
                                       neuron_eqs_i,
                                       threshold=v_thresh_i,
                                       refractory=refrac_i,
                                       reset=v_reset_i,
                                       compile=True,
                                       freeze=True)

    for name in population_names:
        print '...Creating neuron group:', name

        # get a subgroup of size 'n_e' from all exc
        neuron_groups[name + 'e'] = neuron_groups['e'].subgroup(conv_features *
                                                                n_e)
        # get a subgroup of size 'n_i' from the inhibitory layer
        neuron_groups[name + 'i'] = neuron_groups['i'].subgroup(conv_features *
                                                                n_e)

        # start the membrane potentials of these groups 40mV below their resting potentials
        neuron_groups[name + 'e'].v = v_rest_e - 40. * b.mV
        neuron_groups[name + 'i'].v = v_rest_i - 40. * b.mV

    print '...Creating recurrent connections'

    for name in population_names:
        # if we're in test mode / using some stored weights
        if test_mode:
            # load up adaptive threshold parameters
            if save_best_model:
                neuron_groups['e'].theta = np.load(
                    os.path.join(best_weights_dir,
                                 '_'.join(['theta_A', ending + '_best.npy'])))
            else:
                neuron_groups['e'].theta = np.load(
                    os.path.join(end_weights_dir,
                                 '_'.join(['theta_A', ending + '_end.npy'])))
        else:
            # otherwise, set the adaptive additive threshold parameter at 20mV
            neuron_groups['e'].theta = np.ones((n_e_total)) * 20.0 * b.mV

        for conn_type in recurrent_conn_names:
            if conn_type == 'ei':
                # create connection name (composed of population and connection types)
                conn_name = name + conn_type[0] + name + conn_type[1]
                # create a connection from the first group in conn_name with the second group
                connections[conn_name] = b.Connection(
                    neuron_groups[conn_name[0:2]],
                    neuron_groups[conn_name[2:4]],
                    structure='sparse',
                    state='g' + conn_type[0])

                # instantiate the created connection
                for feature in xrange(conv_features):
                    for n in xrange(n_e):
                        connections[conn_name][feature * n_e + n,
                                               feature * n_e + n] = 10.4

            elif conn_type == 'ie':
                # create connection name (composed of population and connections types)
                conn_name = name + conn_type[0] + name + conn_type[
                    1] + '_' + ending
                # create a connection from the first group in conn_name with the second group
                connections[conn_name] = b.Connection(
                    neuron_groups[conn_name[0:2]],
                    neuron_groups[conn_name[2:4]],
                    structure='sparse',
                    state='g' + conn_type[0])
                # instantiate the created connection with the 'weightMatrix' loaded from file
                for feature in xrange(conv_features):
                    for other_feature in xrange(conv_features):
                        if feature != other_feature:
                            for n in xrange(n_e):
                                connections[conn_name][feature * n_e + n,
                                                       other_feature * n_e +
                                                       n] = 17.4

        print '...Creating monitors for:', name

        # spike rate monitors for excitatory and inhibitory neuron populations
        rate_monitors[name + 'e'] = b.PopulationRateMonitor(
            neuron_groups[name + 'e'],
            bin=(single_example_time + resting_time) / b.second)
        rate_monitors[name + 'i'] = b.PopulationRateMonitor(
            neuron_groups[name + 'i'],
            bin=(single_example_time + resting_time) / b.second)
        spike_counters[name + 'e'] = b.SpikeCounter(neuron_groups[name + 'e'])

        # record neuron population spikes if specified
        if record_spikes or plot:
            spike_monitors[name + 'e'] = b.SpikeMonitor(neuron_groups[name +
                                                                      'e'])
            spike_monitors[name + 'i'] = b.SpikeMonitor(neuron_groups[name +
                                                                      'i'])

    if record_spikes and plot:
        b.figure(fig_num, figsize=(8, 6))

        fig_num += 1

        b.ion()
        b.subplot(211)
        b.raster_plot(spike_monitors['Ae'],
                      refresh=1000 * b.ms,
                      showlast=1000 * b.ms,
                      title='Excitatory spikes per neuron')
        b.subplot(212)
        b.raster_plot(spike_monitors['Ai'],
                      refresh=1000 * b.ms,
                      showlast=1000 * b.ms,
                      title='Inhibitory spikes per neuron')
        b.tight_layout()

    # creating Poission spike train from input image (784 vector, 28x28 image)
    for name in input_population_names:
        input_groups[name + 'e'] = b.PoissonGroup(n_input, 0)
        rate_monitors[name + 'e'] = b.PopulationRateMonitor(
            input_groups[name + 'e'],
            bin=(single_example_time + resting_time) / b.second)

    # creating connections from input Poisson spike train to excitatory neuron population(s)
    for name in input_connection_names:
        print '\n...Creating connections between', name[0], 'and', name[1]

        # for each of the input connection types (in this case, excitatory -> excitatory)
        for conn_type in input_conn_names:
            # saved connection name
            conn_name = name[0] + conn_type[0] + name[1] + conn_type[1]

            # get weight matrix depending on training or test phase
            if test_mode:
                if save_best_model:
                    weight_matrix = np.load(
                        os.path.join(
                            best_weights_dir,
                            '_'.join([conn_name, ending + '_best.npy'])))
                else:
                    weight_matrix = np.load(
                        os.path.join(
                            end_weights_dir,
                            '_'.join([conn_name, ending + '_end.npy'])))

            # create connections from the windows of the input group to the neuron population
            input_connections[conn_name] = b.Connection(input_groups['Xe'], neuron_groups[name[1] + conn_type[1]], \
                structure='sparse', state='g' + conn_type[0], delay=True, max_delay=delay[conn_type][1])

            if test_mode:
                for feature in xrange(conv_features):
                    for n in xrange(n_e):
                        for idx in xrange(conv_size**2):
                            input_connections[conn_name][convolution_locations[n][idx], feature * n_e + n] = \
                                    weight_matrix[convolution_locations[n][idx], feature * n_e + n]
            else:
                for feature in xrange(conv_features):
                    for n in xrange(n_e):
                        for idx in xrange(conv_size**2):
                            input_connections[conn_name][
                                convolution_locations[n][idx],
                                feature * n_e + n] = (b.random() + 0.01) * 0.3

            if test_mode:
                if plot:
                    plot_weights_and_assignments(assignments)
                    fig_num += 1

        # if excitatory -> excitatory STDP is specified, add it here (input to excitatory populations)
        if not test_mode:
            print '...Creating STDP for connection', name

            # STDP connection name
            conn_name = name[0] + conn_type[0] + name[1] + conn_type[1]
            # create the STDP object
            stdp_methods[conn_name] = b.STDP(input_connections[conn_name], eqs=eqs_stdp_ee, \
                pre=eqs_stdp_pre_ee, post=eqs_stdp_post_ee, wmin=0., wmax=wmax_ee)

    print '\n'
Example #6
0
    def __init__(self,
                 n_input=784,
                 conv_size=16,
                 conv_stride=4,
                 conv_features=50,
                 connectivity='all',
                 weight_dependence=False,
                 post_pre=True,
                 weight_sharing=False,
                 lattice_structure='4',
                 random_lattice_prob=0.0,
                 random_inhibition_prob=0.0):
        '''
		Constructor for the spiking convolutional neural network model.

		n_input: (flattened) dimensionality of the input data
		conv_size: side length of convolution windows used
		conv_stride: stride (horizontal and vertical) of convolution windows used
		conv_features: number of convolution features (or patches) used
		connectivity: connection style between patches; one of 'none', 'pairs', all'; more to be added
		weight_dependence: whether to use weight STDP with weight dependence
		post_pre: whether to use STDP with both post- and pre-synpatic traces
		weight_sharing: whether to impose that all neurons within a convolution patch share a common set of weights
		lattice_structure: lattice connectivity pattern between patches; one of 'none', '4', '8', and 'all'
		random_lattice_prob: probability of adding random additional lattice connections between patches
		random_inhibition_prob: probability of adding random additional inhibition edges from the inhibitory to excitatory population
		'''
        self.n_input, self.conv_size, self.conv_stride, self.conv_features, self.connectivity, self.weight_dependence, \
         self.post_pre, self.weight_sharing, self.lattice_structure, self.random_lattice_prob, self.random_inhibition_prob = \
         n_input, conv_size, conv_stride, conv_features, connectivity, weight_dependence, post_pre, weight_sharing, lattice_structure, \
         random_lattice_prob, random_inhibition_prob

        # number of inputs to the network
        self.n_input_sqrt = int(math.sqrt(self.n_input))
        self.n_excitatory_patch = (
            (self.n_input_sqrt - self.conv_size) / self.conv_stride + 1)**2
        self.n_excitatory = self.n_excitatory_patch * self.conv_features
        self.n_excitatory_patch_sqrt = int(math.sqrt(self.n_excitatory_patch))
        self.n_inhibitory_patch = self.n_excitatory_patch
        self.n_inhibitory = self.n_excitatory
        self.conv_features_sqrt = int(math.ceil(math.sqrt(self.conv_features)))

        # time (in seconds) per data example presentation and rest period in between
        self.single_example_time = 0.35 * b.second
        self.resting_time = 0.15 * b.second

        # set update intervals
        self.update_interval = 100
        self.weight_update_interval = 10
        self.print_progress_interval = 10

        # rest potential parameters, reset potential parameters, threshold potential parameters, and refractory periods
        v_rest_e, v_rest_i = -65. * b.mV, -60. * b.mV
        v_reset_e, v_reset_i = -65. * b.mV, -45. * b.mV
        v_thresh_e, v_thresh_i = -52. * b.mV, -40. * b.mV
        refrac_e, refrac_i = 5. * b.ms, 2. * b.ms

        # time constants, learning rates, max weights, weight dependence, etc.
        tc_pre_ee, tc_post_ee = 20 * b.ms, 20 * b.ms
        nu_ee_pre, nu_ee_post = 0.0001, 0.01
        exp_ee_post = exp_ee_pre = 0.2
        w_mu_pre, w_mu_post = 0.2, 0.2

        # parameters for neuron equations
        tc_theta = 1e7 * b.ms
        theta_plus = 0.05 * b.mV
        scr_e = 'v = v_reset_e; theta += theta_plus; timer = 0*ms'
        offset = 20.0 * b.mV
        v_thresh_e = '(v>(theta - offset + ' + str(
            v_thresh_e) + ')) * (timer>refrac_e)'

        # equations for neurons
        neuron_eqs_e = '''
				dv / dt = ((v_rest_e - v) + (I_synE + I_synI) / nS) / (100 * ms)  : volt
				I_synE = ge * nS * - v  : amp
				I_synI = gi * nS * (-100. * mV - v)  : amp
				dge / dt = -ge / (1.0*ms)  : 1
				dgi / dt = -gi / (2.0*ms)  : 1
				dtheta / dt = -theta / (tc_theta)  : volt
				dtimer / dt = 100.0  : ms
			'''

        neuron_eqs_i = '''
				dv/dt = ((v_rest_i - v) + (I_synE + I_synI) / nS) / (10*ms)  : volt
				I_synE = ge * nS *         -v                           : amp
				I_synI = gi * nS * (-85.*mV-v)                          : amp
				dge/dt = -ge/(1.0*ms)                                   : 1
				dgi/dt = -gi/(2.0*ms)                                  : 1
			'''

        # STDP synaptic traces
        eqs_stdp_ee = '''
				dpre / dt = -pre / tc_pre_ee : 1.0
				dpost / dt = -post / tc_post_ee : 1.0
			'''

        # dictionaries for weights and delays
        self.weight, self.delay = {}, {}

        # setting weight, delay, and intensity parameters
        self.weight['ee_input'] = (conv_size**2) * 0.175
        self.delay['ee_input'] = (0 * b.ms, 10 * b.ms)
        self.delay['ei_input'] = (0 * b.ms, 5 * b.ms)
        self.input_intensity = self.start_input_intensity = 2.0
        self.wmax_ee = 1.0

        # populations, connections, saved connections, etc.
        self.input_population_names = ['X']
        self.population_names = ['A']
        self.input_connection_names = ['XA']
        self.save_connections = ['XeAe', 'AeAe']
        self.input_connection_names = ['ee_input']
        self.recurrent_connection_names = ['ei', 'ie', 'ee']

        # setting STDP update rule
        if weight_dependence:
            if post_pre:
                eqs_stdp_pre_ee = 'pre = 1.; w -= nu_ee_pre * post * w ** exp_ee_pre'
                eqs_stdp_post_ee = 'w += nu_ee_post * pre * (wmax_ee - w) ** exp_ee_post; post = 1.'

            else:
                eqs_stdp_pre_ee = 'pre = 1.'
                eqs_stdp_post_ee = 'w += nu_ee_post * pre * (wmax_ee - w) ** exp_ee_post; post = 1.'

        else:
            if post_pre:
                eqs_stdp_pre_ee = 'pre = 1.; w -= nu_ee_pre * post'
                eqs_stdp_post_ee = 'w += nu_ee_post * pre; post = 1.'

            else:
                eqs_stdp_pre_ee = 'pre = 1.'
                eqs_stdp_post_ee = 'w += nu_ee_post * pre; post = 1.'

        print '\n'

        # for filesaving purposes
        stdp_input = ''
        if self.weight_dependence:
            stdp_input += 'weight_dependence_'
        else:
            stdp_input += 'no_weight_dependence_'
        if self.post_pre:
            stdp_input += 'post_pre'
        else:
            stdp_input += 'no_post_pre'
        if self.weight_sharing:
            use_weight_sharing = 'weight_sharing'
        else:
            use_weight_sharing = 'no_weight_sharing'

        # set ending of filename saves
        self.ending = self.connectivity + '_' + str(self.conv_size) + '_' + str(self.conv_stride) + '_' + str(self.conv_features) + \
             '_' + str(self.n_excitatory_patch) + '_' + stdp_input + '_' + \
             use_weight_sharing + '_' + str(self.lattice_structure) + '_' + str(self.random_lattice_prob) + \
             '_' + str(self.random_inhibition_prob)

        self.fig_num = 1

        # creating dictionaries for various objects
        self.neuron_groups, self.input_groups, self.connections, self.input_connections, self.stdp_methods, self.rate_monitors, \
         self.spike_monitors, self.spike_counters, self.output_numbers = {}, {}, {}, {}, {}, {}, {}, {}, {}

        # creating convolution locations inside the input image
        self.convolution_locations = {}
        for n in xrange(self.n_excitatory_patch):
            self.convolution_locations[n] = [ ((n % self.n_excitatory_patch_sqrt) * self.conv_stride + (n // self.n_excitatory_patch_sqrt) \
                      * self.n_input_sqrt * self.conv_stride) + (x * self.n_input_sqrt) + y \
                      for y in xrange(self.conv_size) for x in xrange(self.conv_size) ]

        # instantiating neuron spike / votes monitor
        self.result_monitor = np.zeros(
            (self.update_interval, self.conv_features,
             self.n_excitatory_patch))

        # creating overarching neuron populations
        self.neuron_groups['e'] = b.NeuronGroup(self.n_excitatory, neuron_eqs_e, threshold=v_thresh_e, \
                     refractory=refrac_e, reset=scr_e, compile=True, freeze=True)
        self.neuron_groups['i'] = b.NeuronGroup(self.n_inhibitory, neuron_eqs_i, threshold=v_thresh_i, \
                     refractory=refrac_i, reset=v_reset_i, compile=True, freeze=True)

        # create neuron subpopulations
        for name in self.population_names:
            print '...creating neuron group:', name

            # get a subgroup of size 'n_e' from all exc
            self.neuron_groups[name + 'e'] = self.neuron_groups['e'].subgroup(
                self.conv_features * self.n_excitatory_patch)
            # get a subgroup of size 'n_i' from the inhibitory layer
            self.neuron_groups[name + 'i'] = self.neuron_groups['i'].subgroup(
                self.conv_features * self.n_excitatory_patch)

            # start the membrane potentials of these groups 40mV below their resting potentials
            self.neuron_groups[name + 'e'].v = v_rest_e - 40. * b.mV
            self.neuron_groups[name + 'i'].v = v_rest_i - 40. * b.mV

        print '...creating recurrent connections'

        for name in self.population_names:
            # set the adaptive additive threshold parameter at 20mV
            self.neuron_groups['e'].theta = np.ones(
                (self.n_excitatory)) * 20.0 * b.mV

            for connection_type in self.recurrent_connection_names:
                if connection_type == 'ei':
                    # create connection name (composed of population and connection types)
                    connection_name = name + connection_type[
                        0] + name + connection_type[1]
                    # create a connection from the first group in conn_name with the second group
                    self.connections[connection_name] = b.Connection(self.neuron_groups[connection_name[0:2]], \
                            self.neuron_groups[connection_name[2:4]], structure='sparse', state='g' + conn_type[0])
                    # instantiate the created connection
                    for feature in xrange(self.conv_features):
                        for n in xrange(self.n_excitatory_patch):
                            self.connections[conn_name][feature * self.n_excitatory_patch + n, \
                                    feature * self.n_excitatory_patch + n] = 10.4

                elif connection_type == 'ie':
                    # create connection name (composed of population and connection types)
                    connection_name = name + connection_type[
                        0] + name + connection_type[1]
                    # create a connection from the first group in conn_name with the second group
                    self.connections[connection_name] = b.Connection(self.neuron_groups[connection_name[0:2]], \
                            self.neuron_groups[connection_name[2:4]], structure='sparse', state='g' + conn_type[0])
                    # instantiate the created connection
                    for feature in xrange(self.conv_features):
                        for other_feature in xrange(self.conv_features):
                            if feature != other_feature:
                                for n in xrange(self.n_excitatory_patch):
                                    self.connections[connection_name][feature * self.n_excitatory_patch + n, \
                                          other_feature * self.n_excitatory_patch + n] = 17.4

                    # adding random inhibitory connections as specified
                    if self.random_inhibition_prob != 0.0:
                        for feature in xrange(self.conv_features):
                            for other_feature in xrange(self.conv_features):
                                for n_this in xrange(self.n_excitatory_patch):
                                    for n_other in xrange(
                                            self.n_excitatory_patch):
                                        if n_this != n_other:
                                            if b.random(
                                            ) < self.random_inhibition_prob:
                                                self.connections[connection_name][feature * self.n_excitatory_patch + n_this, \
                                                  other_feature * self.n_excitatory_patch + n_other] = 17.4

                elif connection_type == 'ee':
                    # create connection name (composed of population and connection types)
                    connection_name = name + connection_type[
                        0] + name + connection_type[1]
                    # create a connection from the first group in conn_name with the second group
                    self.connections[connection_name] = b.Connection(self.neuron_groups[connection_name[0:2]], \
                       self.neuron_groups[connection_name[2:4]], structure='sparse', state='g' + connection_type[0])
                    # instantiate the created connection
                    if self.connectivity == 'all':
                        for feature in xrange(self.conv_features):
                            for other_feature in xrange(self.conv_features):
                                if feature != other_feature:
                                    for this_n in xrange(
                                            self.n_excitatory_patch):
                                        for other_n in xrange(
                                                self.n_excitatory_patch):
                                            if is_lattice_connection(
                                                    self.
                                                    n_excitatory_patch_sqrt,
                                                    this_n, other_n):
                                                self.connections[connection_name][feature * self.n_excitatory_patch + this_n, \
                                                  other_feature * self.n_excitatory_patch + other_n] = \
                                                    (b.random() + 0.01) * 0.3

                    elif self.connectivity == 'pairs':
                        for feature in xrange(self.conv_features):
                            if feature % 2 == 0:
                                for this_n in xrange(self.n_excitatory_patch):
                                    for other_n in xrange(
                                            self.n_excitatory_patch):
                                        if is_lattice_connection(
                                                self.n_excitatory_patch_sqrt,
                                                this_n, other_n):
                                            self.connections[connection_name][feature * self.n_excitatory_patch + this_n, \
                                              (feature + 1) * self.n_excitatory_patch + other_n] = (b.random() + 0.01) * 0.3
                            elif feature % 2 == 1:
                                for this_n in xrange(self.n_excitatory_patch):
                                    for other_n in xrange(
                                            self.n_excitatory_patch):
                                        if is_lattice_connection(
                                                self.n_excitatory_patch_patch,
                                                this_n, other_n):
                                            self.connections[connection_name][feature * self.n_excitatory_patch + this_n, \
                                              (feature - 1) * self.n_excitatory_patch + other_n] = (b.random() + 0.01) * 0.3

                    elif connectivity == 'linear':
                        for feature in xrange(self.conv_features):
                            if feature != self.conv_features - 1:
                                for this_n in xrange(self.n_excitatory_patch):
                                    for other_n in xrange(
                                            self.n_excitatory_patch):
                                        if is_lattice_connection(
                                                self.n_excitatory_patch_sqrt,
                                                this_n, other_n):
                                            self.connections[connection_name][feature * self.n_excitatory_patch + this_n, \
                                              (feature + 1) * self.n_excitatory_patch + other_n] = \
                                                 (b.random() + 0.01) * 0.3
                            if feature != 0:
                                for this_n in xrange(self.n_excitatory_patch):
                                    for other_n in xrange(
                                            self.n_excitatory_patch):
                                        if is_lattice_connection(
                                                self.n_excitatory_patch_sqrt,
                                                this_n, other_n):
                                            self.connections[connection_name][feature * self.n_excitatory_patch + this_n, \
                                              (feature - 1) * self.n_excitatory_patch + other_n] = \
                                                 (b.random() + 0.01) * 0.3

                    elif self.connectivity == 'none':
                        pass

            # if STDP from excitatory -> excitatory is on and this connection is excitatory -> excitatory
            if 'ee' in self.recurrent_conn_names:
                self.stdp_methods[name + 'e' + name + 'e'] = b.STDP(self.connections[name + 'e' + name + 'e'], \
                            eqs=eqs_stdp_ee, pre=eqs_stdp_pre_ee, \
                            post=eqs_stdp_post_ee, wmin=0., wmax=self.wmax_ee)

            print '...creating monitors for:', name

            # spike rate monitors for excitatory and inhibitory neuron populations
            self.rate_monitors[name + 'e'] = b.PopulationRateMonitor(self.neuron_groups[name + 'e'], \
                      bin=(self.single_example_time + self.resting_time) / b.second)
            self.rate_monitors[name + 'i'] = b.PopulationRateMonitor(self.neuron_groups[name + 'i'], \
                      bin=(self.single_example_time + self.resting_time) / b.second)
            self.spike_counters[name + 'e'] = b.SpikeCounter(
                self.neuron_groups[name + 'e'])

            # record neuron population spikes
            self.spike_monitors[name + 'e'] = b.SpikeMonitor(
                self.neuron_groups[name + 'e'])
            self.spike_monitors[name + 'i'] = b.SpikeMonitor(
                self.neuron_groups[name + 'i'])

        if do_plot:
            b.figure(self.fig_num)
            fig_num += 1
            b.ion()
            b.subplot(211)
            b.raster_plot(self.spike_monitors['Ae'],
                          refresh=1000 * b.ms,
                          showlast=1000 * b.ms)
            b.subplot(212)
            b.raster_plot(self.spike_monitors['Ai'],
                          refresh=1000 * b.ms,
                          showlast=1000 * b.ms)

        # specifying locations of lattice connections
        self.lattice_locations = {}
        if self.connectivity == 'all':
            for this_n in xrange(self.conv_features * self.n_excitatory_patch):
                self.lattice_locations[this_n] = [ other_n for other_n in xrange(self.conv_features * self.n_excitatory_patch) \
                        if is_lattice_connection(self.n_excitatory_patch_sqrt, \
                        this_n % self.n_excitatory_patch, other_n % self.n_excitatory_patch) ]
        elif self.connectivity == 'pairs':
            for this_n in xrange(self.conv_features * self.n_excitatory_patch):
                self.lattice_locations[this_n] = []
                for other_n in xrange(self.conv_features *
                                      self.n_excitatory_patch):
                    if this_n // self.n_excitatory_patch % 2 == 0:
                        if is_lattice_connection(self.n_excitatory_patch_sqrt, this_n % self.n_excitatory_patch, \
                               other_n % self.n_excitatory_patch) and \
                               other_n // self.n_excitatory_patch == this_n // self.n_excitatory_patch + 1:
                            self.lattice_locations[this_n].append(other_n)
                    elif this_n // self.n_excitatory_patch % 2 == 1:
                        if is_lattice_connection(self.n_excitatory_patch_sqrt, this_n % self.n_excitatory_patch, \
                               other_n % self.n_excitatory_patch) and \
                               other_n // self.n_excitatory_patch == this_n // self.n_excitatory_patch - 1:
                            self.lattice_locations[this_n].append(other_n)
        elif self.connectivity == 'linear':
            for this_n in xrange(self.conv_features * self.n_excitatory_patch):
                self.lattice_locations[this_n] = []
                for other_n in xrange(conv_features * self.n_excitatory_patch):
                    if this_n // self.n_excitatory_patch != self.conv_features - 1:
                        if is_lattice_connection(self.n_excitatory_patch_sqrt, this_n % self.n_excitatory_patch, \
                               other_n % self.n_excitatory_patch) and \
                               other_n // self.n_excitatory_patch == this_n // self.n_excitatory_patch + 1:
                            self.lattice_locations[this_n].append(other_n)
                    elif this_n // self.n_excitatory_patch != 0:
                        if is_lattice_connection(self.n_excitatory_patch_sqrt, this_n % self.n_excitatory_patch, \
                               other_n % self.n_excitatory_patch) and \
                               other_n // self.n_excitatory_patch == this_n // self.n_excitatory_patch - 1:
                            self.lattice_locations[this_n].append(other_n)

        # setting up parameters for weight normalization between patches
        num_lattice_connections = sum(
            [len(value) for value in lattice_locations.values()])
        self.weight['ee_recurr'] = (num_lattice_connections /
                                    self.conv_features) * 0.15

        # creating Poission spike train from input image (784 vector, 28x28 image)
        for name in self.input_population_names:
            self.input_groups[name + 'e'] = b.PoissonGroup(self.n_input, 0)
            self.rate_monitors[name + 'e'] = b.PopulationRateMonitor(self.input_groups[name + 'e'], \
                       bin=(self.single_example_time + self.resting_time) / b.second)

        # creating connections from input Poisson spike train to convolution patch populations
        for name in self.input_connection_names:
            print '\n...creating connections between', name[0], 'and', name[1]

            # for each of the input connection types (in this case, excitatory -> excitatory)
            for connection_type in self.input_conn_names:
                # saved connection name
                connection_name = name[0] + connection_type[0] + name[
                    1] + connection_type[1]

                # create connections from the windows of the input group to the neuron population
                self.input_connections[connection_name] = b.Connection(self.input_groups['Xe'], \
                    self.neuron_groups[name[1] + connection_type[1]], structure='sparse', \
                    state='g' + connection_type[0], delay=True, max_delay=self.delay[connection_type][1])

                for feature in xrange(self.conv_features):
                    for n in xrange(self.n_excitatory_patch):
                        for idx in xrange(self.conv_size**2):
                            self.input_connections[connection_name][self.convolution_locations[n][idx], \
                                 feature * self.n_excitatory_patch + n] = (b.random() + 0.01) * 0.3

            # if excitatory -> excitatory STDP is specified, add it here (input to excitatory populations)
            print '...creating STDP for connection', name

            # STDP connection name
            connection_name = name[0] + connection_type[0] + name[
                1] + connection_type[1]
            # create the STDP object
            self.stdp_methods[connection_name] = b.STDP(self.input_connections[connection_name], \
              eqs=eqs_stdp_ee, pre=eqs_stdp_pre_ee, post=eqs_stdp_post_ee, wmin=0., wmax=self.wmax_ee)

        print '\n'
Example #7
0
    def run(self):
        #------------------------------------------------------------------------------ 
        # run the simulation and set inputs
        #------------------------------------------------------------------------------ 
        start = time.time()
        previousSpikeCount = np.zeros((self.nE,len(self.populationNames)))
        currentSpikeCount = np.zeros((self.nE,len(self.populationNames)))
        
        if self.recordSpikes:
            b.figure()
            b.ion()
            b.subplot(411)
            b.raster_plot(self.spikeMonitors['Ae'], refresh=1000*b.ms, showlast=1000*b.ms)
            b.subplot(412)
            b.raster_plot(self.spikeMonitors['Be'], refresh=1000*b.ms, showlast=1000*b.ms)
            b.subplot(413)
            b.raster_plot(self.spikeMonitors['Ce'], refresh=1000*b.ms, showlast=1000*b.ms)
            b.subplot(414)
            b.raster_plot(self.spikeMonitors['He'], refresh=1000*b.ms, showlast=1000*b.ms)
        
#         realTimeMonitor = None
#         realTimeMonitor = rltmMon.RealtimeConnectionMonitor(self.connections['HeAe'], cmap=cm.get_cmap('gist_rainbow'), 
#                                                             wmin=0, wmax=self.wmaxEE, clock=Clock(1000*b.ms))
        
        for j in xrange(int(self.numExamples)):            
            if self.restingTime or j==0:
                for i,name in enumerate(self.inputPopulationNames):
                    rates = np.ones(self.nE)  * 0
                    self.inputGroups[name+'e'].rate = rates
                self.net.run(self.restingTime)#, report='text')
                
            if j%self.normalization_interval == 0:
                self.normalizeWeights()
                
            print 'set new rates of the inputs'
            self.setNewInput(self,j)
                    
                    
            print 'run number:', j+1, 'of', int(self.numExamples)
            self.net.run(self.singleExampleTime)#, report='text')
            for i,name in enumerate(self.populationNames):
                name += 'e'
                currentSpikeCount[:,i] = np.asarray(self.spikeCounters[name].count[:]) - previousSpikeCount[:,i]
            #     print currentSpikeCount,  np.asarray(spikeCounters['Ce'].count[:]), previousSpikeCount
                previousSpikeCount[:,i] = np.copy(self.spikeCounters[name].count[:])
                self.resultMonitor[j,i] = self.computePopVector(currentSpikeCount[:,i])
                print name, 'pop. activity: ', self.resultMonitor[j,i], ', spikecount:', sum(currentSpikeCount[:,i])
            
            for i,name in enumerate(self.inputPopulationNames):
                print name, 'pop. activity: ', (self.popValues[j,i])
                
                    
            if not self.testMode:
                if self.numExamples <= 1000:
                    if j%100==0 and not j==0:
                        self.saveConnections(str(j))
                else:
                    if j%10000==0 and not j==0:
                        self.saveConnections(str(j))
            
        end = time.time()
        print 'time needed to simulate:', end - start
        
        
        #------------------------------------------------------------------------------ 
        # save results
        #------------------------------------------------------------------------------ 
        print 'save results'
        
        if self.testMode:
            np.savetxt(self.dataPath + 'activity/resultPopVecs' + str(self.numExamples) + '.txt', self.resultMonitor)
            np.savetxt(self.dataPath + 'activity/spikeCount' + str(self.gaussian_peak_low) + '.txt', 
                       self.spikeCounters['Ae'].count[:]/(self.singleExampleTime*int(self.numExamples)))
            np.savetxt(self.dataPath + 'activity/inputSpikeCount' + str(self.gaussian_peak_low) + '.txt', 
                       self.spikeCounters['Xe'].count[:]/(self.singleExampleTime*int(self.numExamples)))
            np.savetxt(self.dataPath + 'activity/popVecs' + str(self.numExamples) + '.txt', self.popValues)
        else:
            self.saveConnections(str(j))
            self.normalizeWeights()
            self.saveConnections()
Example #8
0
 def run(self):
     #------------------------------------------------------------------------------ 
     # run the simulation and set inputs
     #------------------------------------------------------------------------------ 
     previousSpikeCount = np.zeros((self.nE, self.numAllPops))
     currentSpikeCount = np.zeros((self.nE, self.numAllPops))
     if self.saveSpikeCountsPerExample:
         self.spikeCounts=np.zeros((self.numExamples, self.nE, self.numAllPops))
     
     if self.realTimePlotting and self.recordSpikes:
         b.ion()
         fig = b.figure(1)
         b.raster_plot(self.spikeMonitors['Ae'])
 
     if self.ending=='':
         initJ = 0
     else:
         initJ = int(self.ending)
     for j in xrange(int(self.numExamples)):            
         if self.restingTime or j==0:
             for i,name in enumerate(self.inputPopulationNames):
                 rates = np.ones(self.nE)  * 0
                 self.inputGroups[name+'e'].rate = rates
             self.net.run(self.restingTime)
             
         if j%self.normalization_interval == 0:
             self.normalizeWeights()
             
         print 'set new rates of the inputs'
         self.setNewInput(self,j)
                 
         print 'run number:', j+1, 'of', int(self.numExamples)
         self.net.run(self.singleExampleTime)
         for i,name in enumerate(self.populationNames):
             name += 'e'
             currentSpikeCount[:,i] = np.asarray(self.spikeCounters[name].count[:]) - previousSpikeCount[:,i]
             previousSpikeCount[:,i] = np.copy(self.spikeCounters[name].count[:])
             self.resultMonitor[j,i] = self.computePopVector(currentSpikeCount[:,i])
             print name, 'pop. activity: ', self.resultMonitor[j,i], ', spikecount:', sum(currentSpikeCount[:,i])
             if self.saveSpikeCountsPerExample:
                 self.spikeCounts[j,:,i] = currentSpikeCount[:,i]
                 
         for i,name in enumerate(self.inputPopulationNames):
             print name, 'pop. activity: ', (self.popValues[j,i])
             name += 'e'
             currentSpikeCount[:,i+self.numPops] = np.asarray(self.spikeCounters[name].count[:]) - previousSpikeCount[:,i+self.numPops]
             previousSpikeCount[:,i+self.numPops] = np.copy(self.spikeCounters[name].count[:])
             self.resultMonitor[j,i+self.numPops] = self.computePopVector(currentSpikeCount[:,i+self.numPops])
             if self.saveSpikeCountsPerExample:
                 self.spikeCounts[j,:,i+self.numPops] = currentSpikeCount[:,i+self.numPops]
             
                 
         if not self.testMode:
             if self.numExamples <= 1000:
                 if (j+1)%100==0 and not j==0:
                     self.saveConnections(str(j+initJ+1))
             else:
                 if (j+1)%5000==0 and not j==0:
                     self.saveConnections(str(j+initJ+1))
                     
         if self.realTimePlotting and self.recordSpikes:
             b.raster_plot(self.spikeMonitors['Ae'], showlast=1000*b.ms)
             fig.canvas.draw()
         
     
     #------------------------------------------------------------------------------ 
     # save results
     #------------------------------------------------------------------------------ 
     print 'save results'
     
     if self.testMode:
         np.savetxt(self.dataPath + 'activity/resultPopVecs' + str(self.numExamples) + '.txt', self.resultMonitor)
         np.savetxt(self.dataPath + 'activity/popVecs' + str(self.numExamples) + '.txt', self.popValues)
         for name in self.spikeCounters:
             np.savetxt(self.dataPath + 'activity/spikeCount' + name + '.txt', 
                        self.spikeCounters[name].count[:]/(self.singleExampleTime*int(self.numExamples)))
         if self.saveSpikeCountsPerExample:
             np.save(self.dataPath + 'activity/spikeCountPerExample', self.spikeCounts)
     else:
         self.saveConnections(str(self.numExamples+initJ))
         self.normalizeWeights()
         self.saveConnections()
    def run(self):
        #------------------------------------------------------------------------------ 
        # run the simulation and set inputs
        #------------------------------------------------------------------------------ 
        previousSpikeCountB = np.zeros(self.nE)
        previousSpikeCountC = np.zeros(self.nE)
        self.resultMonitor = np.zeros((self.numExamples,len(self.populationNames)))
        start = time.time()
        
        if self.recordSpikes:
            b.figure()
            b.ion()
            b.subplot(211)
            b.raster_plot(self.spikeMonitors['He'], refresh=1000*b.ms, showlast=1000*b.ms)
            b.subplot(212)
            b.raster_plot(self.spikeMonitors['Hi'], refresh=1000*b.ms, showlast=1000*b.ms)
        
#         realTimeMonitor = None
#         realTimeMonitor = rltmMon.RealtimeConnectionMonitor(self.connections['HeAe'], cmap=cm.get_cmap('gist_rainbow'), 
#                                                             wmin=0, wmax=self.wmaxEE, clock=Clock(1000*b.ms))
        
        
        for j in xrange(int(self.numExamples)):            
            if self.restingTime or j==0:
                for i,name in enumerate(self.inputPopulationNames):
                    rates = np.ones(self.nE)  * 0
                    self.inputGroups[name+'e'].rate = rates
                self.net.run(self.restingTime)#, report='text')
                
            if j%self.normalization_interval == 0:
                self.normalizeWeights()
                
            print 'set new rates of the inputs'
            self.popValues = [0]*len(self.inputPopulationNames)
            for i,name in enumerate(self.inputPopulationNames):
                if name == 'X':
                    self.popValues[i] = np.random.rand();
                    rates = self.createTopoInput(self.nE, self.popValues[i])
                    self.resultMonitor[j,0] = self.popValues[i]
                else:
                    if self.testMode:
                        rates = np.ones(self.nE)  * 0
                    elif name == 'Y':
                        self.popValues[i] = (self.popValues[0]*2) % 1.
                        rates = self.createTopoInput(self.nE, self.popValues[i])
                    elif name == 'Z':
                        self.popValues[i] = (self.popValues[0]**2) % 1.
                        rates = self.createTopoInput(self.nE, self.popValues[i])
                if self.testMode:
                    rates += noise
                self.inputGroups[name+'e'].rate = rates 
                    
                    
            print 'run number:', j+1, 'of', int(self.numExamples)
            self.net.run(self.singleExampleTime)#, report='text')
            currentSpikeCountB = np.asarray(self.spikeCounters['Be'].count[:]) - previousSpikeCountB
            currentSpikeCountC = np.asarray(self.spikeCounters['Ce'].count[:]) - previousSpikeCountC
        #     print currentSpikeCount,  np.asarray(spikeCounters['Ce'].count[:]), previousSpikeCount
            previousSpikeCountB = np.copy(self.spikeCounters['Be'].count[:])
            previousSpikeCountC = np.copy(self.spikeCounters['Ce'].count[:])
            self.resultMonitor[j,1] = self.computePopVector(currentSpikeCountB)
            self.resultMonitor[j,2] = self.computePopVector(currentSpikeCountC)
            difference = np.abs((self.resultMonitor[j,0]**2)%1. - self.resultMonitor[j,2])
            if difference > 0.5:
                difference = 1-difference
            print 'Pop. activity: ', self.resultMonitor[j,2], ', Desired activity: ', (self.resultMonitor[j,0]**2)%1., ', Difference: ', difference
            
                
                    
            if not self.testMode:
                if self.numExamples <= 1000:
                    if j%100 == 0:
                        self.saveConnections(str(j))
                else:
                    if j%1000 == 0:
                        self.saveConnections(str(j))
            
        end = time.time()
        print 'time needed to simulate:', end - start
        
        
        #------------------------------------------------------------------------------ 
        # save results
        #------------------------------------------------------------------------------ 
        print 'save results'
        
        if self.testMode:
            np.savetxt(self.dataPath + 'activity/resultPopVecs' + str(self.numExamples) + '.txt', self.resultMonitor)
        else:
            self.saveConnections(str(j))
            self.normalizeWeights()
            self.saveConnections()
def build_network():
    global fig_num

    neuron_groups['e'] = b.NeuronGroup(n_e_total,
                                       neuron_eqs_e,
                                       threshold=v_thresh_e,
                                       refractory=refrac_e,
                                       reset=scr_e,
                                       compile=True,
                                       freeze=True)
    neuron_groups['i'] = b.NeuronGroup(n_e_total,
                                       neuron_eqs_i,
                                       threshold=v_thresh_i,
                                       refractory=refrac_i,
                                       reset=v_reset_i,
                                       compile=True,
                                       freeze=True)

    for name in ['A']:
        print '...Creating neuron group:', name

        # get a subgroup of size 'n_e' from all exc
        neuron_groups[name + 'e'] = neuron_groups['e'].subgroup(conv_features *
                                                                n_e)
        # get a subgroup of size 'n_i' from the inhibitory layer
        neuron_groups[name + 'i'] = neuron_groups['i'].subgroup(conv_features *
                                                                n_e)

        # start the membrane potentials of these groups 40mV below their resting potentials
        neuron_groups[name + 'e'].v = v_rest_e - 40. * b.mV
        neuron_groups[name + 'i'].v = v_rest_i - 40. * b.mV

    print '...Creating recurrent connections'

    for name in ['A']:
        neuron_groups['e'].theta = np.load(
            os.path.join(best_weights_dir,
                         '_'.join(['theta_A', ending + '_best.npy'])))

        for conn_type in ['ei', 'ie']:
            if conn_type == 'ei':
                # create connection name (composed of population and connection types)
                conn_name = name + conn_type[0] + name + conn_type[1]
                # create a connection from the first group in conn_name with the second group
                connections[conn_name] = b.Connection(neuron_groups[conn_name[0:2]], \
                    neuron_groups[conn_name[2:4]], structure='sparse', state='g' + conn_type[0])
                # instantiate the created connection
                for feature in xrange(conv_features):
                    for n in xrange(n_e):
                        connections[conn_name][feature * n_e + n,
                                               feature * n_e + n] = 10.4

            elif conn_type == 'ie' and not remove_inhibition:
                # create connection name (composed of population and connection types)
                conn_name = name + conn_type[0] + name + conn_type[1]
                # create a connection from the first group in conn_name with the second group
                connections[conn_name] = b.Connection(neuron_groups[conn_name[0:2]], \
                    neuron_groups[conn_name[2:4]], structure='sparse', state='g' + conn_type[0])
                # define the actual synaptic connections and strengths
                for feature in xrange(conv_features):
                    if inhib_scheme in ['far', 'strengthen']:
                        for other_feature in set(range(conv_features)) - set(
                                neighbor_mapping[feature]):
                            if inhib_scheme == 'far':
                                for n in xrange(n_e):
                                    connections[conn_name][feature * n_e + n,
                                                           other_feature *
                                                           n_e + n] = 17.4

                            elif inhib_scheme == 'strengthen':
                                if n_e == 1:
                                    x, y = feature // np.sqrt(
                                        n_e_total), feature % np.sqrt(
                                            n_e_total)
                                    x_, y_ = other_feature // np.sqrt(
                                        n_e_total), other_feature % np.sqrt(
                                            n_e_total)
                                else:
                                    x, y = feature // np.sqrt(
                                        conv_features), feature % np.sqrt(
                                            conv_features)
                                    x_, y_ = other_feature // np.sqrt(
                                        conv_features
                                    ), other_feature % np.sqrt(conv_features)

                                for n in xrange(n_e):
                                    connections[conn_name][feature * n_e + n, other_feature * n_e + n] = \
                                        min(17.4, inhib_const * np.sqrt(euclidean([x, y], [x_, y_])))

                    elif inhib_scheme == 'increasing':
                        for other_feature in xrange(conv_features):
                            if n_e == 1:
                                x, y = feature // np.sqrt(
                                    n_e_total), feature % np.sqrt(n_e_total)
                                x_, y_ = other_feature // np.sqrt(
                                    n_e_total), other_feature % np.sqrt(
                                        n_e_total)
                            else:
                                x, y = feature // np.sqrt(
                                    conv_features), feature % np.sqrt(
                                        conv_features)
                                x_, y_ = other_feature // np.sqrt(
                                    conv_features), other_feature % np.sqrt(
                                        conv_features)

                            if feature != other_feature:
                                for n in xrange(n_e):
                                    connections[conn_name][feature * n_e + n, other_feature * n_e + n] = \
                                        min(17.4, inhib_const * np.sqrt(euclidean([x, y], [x_, y_])))

                    else:
                        raise Exception(
                            'Expecting one of "far", "increasing", or "strengthen" for argument "inhib_scheme".'
                        )

        # spike rate monitors for excitatory and inhibitory neuron populations
        rate_monitors[name + 'e'] = b.PopulationRateMonitor(
            neuron_groups[name + 'e'],
            bin=(single_example_time + resting_time) / b.second)
        rate_monitors[name + 'i'] = b.PopulationRateMonitor(
            neuron_groups[name + 'i'],
            bin=(single_example_time + resting_time) / b.second)
        spike_counters[name + 'e'] = b.SpikeCounter(neuron_groups[name + 'e'])

        # record neuron population spikes if specified
        if record_spikes:
            spike_monitors[name + 'e'] = b.SpikeMonitor(neuron_groups[name +
                                                                      'e'])
            spike_monitors[name + 'i'] = b.SpikeMonitor(neuron_groups[name +
                                                                      'i'])

    if record_spikes and do_plot:
        if reset_state_vars:
            time_window = single_example_time * 1000
        else:
            time_window = (single_example_time + resting_time) * 1000

        b.figure(fig_num, figsize=(8, 6))
        b.ion()
        b.subplot(211)
        b.raster_plot(spike_monitors['Ae'],
                      refresh=time_window * b.ms,
                      showlast=time_window * b.ms,
                      title='Excitatory spikes per neuron')
        b.subplot(212)
        b.raster_plot(spike_monitors['Ai'],
                      refresh=time_window * b.ms,
                      showlast=time_window * b.ms,
                      title='Inhibitory spikes per neuron')
        b.tight_layout()

        fig_num += 1

    # creating Poission spike train from input image (784 vector, 28x28 image)
    for name in ['X']:
        input_groups[name + 'e'] = b.PoissonGroup(n_input, 0)
        rate_monitors[name + 'e'] = b.PopulationRateMonitor(
            input_groups[name + 'e'],
            bin=(single_example_time + resting_time) / b.second)

    # creating connections from input Poisson spike train to convolution patch populations
    for name in ['XA']:
        print '\n...Creating connections between', name[0], 'and', name[1]

        # for each of the input connection types (in this case, excitatory -> excitatory)
        for conn_type in ['ee_input']:
            # saved connection name
            conn_name = name[0] + conn_type[0] + name[1] + conn_type[1]

            # get weight matrix depending on training or test phase
            weight_matrix = np.load(
                os.path.join(best_weights_dir,
                             '_'.join([conn_name, ending + '_best.npy'])))

            # create connections from the windows of the input group to the neuron population
            input_connections[conn_name] = b.Connection(input_groups['Xe'], neuron_groups[name[1] + \
              conn_type[1]], structure='sparse', state='g' + conn_type[0], delay=True, max_delay=delay[conn_type][1])

            for feature in xrange(conv_features):
                for n in xrange(n_e):
                    for idx in xrange(conv_size**2):
                        input_connections[conn_name][convolution_locations[n][idx], feature * n_e + n] = \
                             weight_matrix[convolution_locations[n][idx], feature * n_e + n]

            if do_plot:
                plot_2d_input_weights()
                fig_num += 1