def run(self, simtime): if self.simulation is None: self.simulation = nemo.Simulation(self.net, self.conf) arrays_sources = [] for source in spikes_array_list: if isinstance(source.celltype, SpikeSourceArray): arrays_sources.append(source) for t in numpy.arange(self.time, self.time + simtime, self.dt): spikes = [] currents = [] for source in arrays_sources: if source.player.next_spike == t: source.player.update() spikes += [source] for recorder in recorder_list: if recorder.variable is "spikes": recorder._add_spike(self._fired, self.t) if recorder.variable is "v": recorder._add_vm(self.t) if recorder.variable is "gsyn": recorder._add_gsyn(self.t) self._fired = self.sim.step(spikes, currents) self.time += self.dt if self.stdp: self.simulation.apply_stdp(self.dt)
def simple_network(self): net = IzNetwork() net.add_neuron(0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) net.add_neuron(1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) net.add_synapse(0, 1, 1, 5.0, False) net.add_synapse(1, 0, 1, 5.0, False) return (net, nemo.Simulation(net, nemo.Configuration()))
def run_random(ncount, scount, duration=1000): """ Construct a randomly connected network with n neurons each of which connects to m postsynaptic neurons. Inputs: ncount -- Number of neurons scount -- Number of synapses duration -- Duration of the simulation, in milliseconds """ print "configure" conf = nemo.Configuration() print "construct" net = construct_random(ncount, scount) print "create simulation" sim = nemo.Simulation(net, conf) print "run simulation" for t in range(duration): # with firing and current stimulus fired = sim.step([2, 4, 5], [(6, 20.0), (7, -5.0)]) print t, ":", fired
def test_set_neuron(self): """ The set_neuron method supports either vector or scalar input. This test calls set_synapse in a large number of ways, checking for catastrophics failures in the boost::python layer """ net = IzNetwork() ncount = 1000 net.add_neuron(range(ncount), 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) for test in range(1000): self.check_neuron_function(net.set_neuron, ncount=1000) sim = nemo.Simulation(net, nemo.Configuration()) for test in range(1000): self.check_neuron_function(sim.set_neuron, ncount=1000)
def test_sim_set_neuron_vector(self): """ Test for failures in vector/scalar form of set_neuron The set_neuron_parameter methods supports either vector or scalar input. This test calls this function in a large number of ways, checking for catastrophics failures in the boost::python layer """ net = IzNetwork() conf = nemo.Configuration() pop = range(1000) for n in pop: net.add_neuron(n, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) sim = nemo.Simulation(net, conf) self.check_set_neuron_vector(sim, pop)
def compress(self): global _created_connection DelayConnection.compress(self) # check that limitations are met if _created_connection: raise NotImplementedError( "Current version only supports a single connection.") _created_connection = True if self.source is not self.target: raise NotImplementedError( "Current version only supports a single group.") if not isinstance(self.W[0, :], SparseConnectionVector): raise NotImplementedError( "Current version only supports sparse matrix types.") # now upload to nemo self.nemo_net = nemo.Network() if pycuda is not None: self.nemo_use_gpu = True else: self.nemo_use_gpu = False # create dummy neurons self.nemo_input_neuron_idx = self.nemo_net.add_neuron_type('Input') self.nemo_net.add_neuron(self.nemo_input_neuron_idx, range(len(self.source))) # create synapses for i in xrange(len(self.source)): Wrow = self.W[i, :] Wdelay = self.delay[i, :] ind = asarray(Wrow.ind) delay = asarray(Wdelay / ms, dtype=int) + 1 weight = asarray(Wrow, dtype=float32) if len(ind): #self.nemo_net.add_synapse(i, ind, delay, weight, False) self.nemo_net.add_synapse(i, ind.tolist(), delay.tolist(), weight.tolist(), False) # configure self.nemo_conf = nemo.Configuration() if self.nemo_use_gpu: self.nemo_conf.set_cuda_backend(0) else: self.nemo_conf.set_cpu_backend() # simulation object self.nemo_sim = nemo.Simulation(self.nemo_net, self.nemo_conf)
def run_random(ncount, scount, duration=1000): print "configure" conf = nemo.Configuration() print "construct" net = construct_random(ncount, scount) print "create simulation" sim = nemo.Simulation(net, conf) print "run simulation" for t in range(duration): # with firing and current stimulus # fired = sim.step([2, 4, 5], [(6, 20.0), (7, -5.0)]) fired = sim.step() print t, ":", fired # Read back a few synapse values. ids = sim.get_synapses_from(0) print sim.get_targets(ids) print sim.get_delays(ids) print sim.get_weights(ids) print sim.get_plastic(ids)
def prepare(self): global _created_network if _created_network: raise NotImplementedError( "Current version only supports a single network object.") _created_network = True Network.prepare(self) if hasattr(self, 'clocks') and len(self.clocks) > 1: raise NotImplementedError( "Current version only supports a single clock.") if pycuda is not None: self.nemo_use_gpu = True # self.nemo_use_gpu = False # log_warn('brian.experimental.cuda.briantonemo', # 'GPU available but not yet supported, using CPU.') else: self.nemo_use_gpu = False # add a NetworkOperation that will be used to carry out the propagation # by NeMo. The individual Connection objects push their spikes into a # global queue (this is done by NemoNetworkConnectionPropagate) and then # the NemoNetworkPropagate NetworkOperation object propagates the # accumulated effect of the spikes to the target NeuronGroup objects. nemo_propagate = NemoNetworkPropagate(self, self.clock) self.nemo_propagate = nemo_propagate # we add this object to the network and don't need to prepare() again # because we rebuild the update schedule below. self.add(nemo_propagate) # create virtual neurons for Nemo, the virtual neurons are either source # neurons or target neurons. For each Connection, we create a group of # source neurons (or re-use if it has already been created), and a # group of target neurons. Each target group and target variable has # a corresponding virtual group. In all cases, we work with the _owner # of the NeuronGroup so that we don't create multiple groups for each # subgroup. print 'Nemo network virtual neuron groups:' self.group_offset = group_offset = {} total_neurons = 0 self.nemo_managed_connections = [] self.nemo_propagate_targets = [] network_ops_to_remove = [] all_connections = [] for C in self.connections: if isinstance(C, MultiConnection): all_connections.extend(C.connections) else: all_connections.append(C) for C in all_connections: # We handle only Connection and DelayConnection objects. For the CPU # version at least, we can rely on Brian to fall back to its # default behaviour otherwise. if C.__class__ is not DelayConnection and C.__class__ is not Connection: continue # Nemo cannot handle modulation, so we check for this case if C._nstate_mod is not None: log_warn( "brian.experimental.cuda.briantonemo", "Synaptic modulation is not supported in Nemo, skipped this Connection." ) continue # Add the source neuron group G = C.source._owner if id(G) not in group_offset: group_offset[id(G)] = total_neurons print '- Source group, length', len(G), 'indices %d:%d' % ( total_neurons, total_neurons + len(G)) total_neurons += len(G) # Add the (target neuron group, target variable) virtual group key = (id(C.target._owner), C.nstate) if key not in group_offset: group_offset[key] = total_neurons varname = get_connection_variable(C) print '- Target group, length', len( G), 'variable', varname, 'indices %d:%d' % ( total_neurons, total_neurons + len(G)) target_offset = total_neurons targetslice = slice(target_offset, target_offset + len(C.target)) targetvar = C.target._S[C.nstate] self.nemo_propagate_targets.append( (varname, targetvar, targetslice)) total_neurons += len(C.target) self.nemo_managed_connections.append(C) if C.__class__ is DelayConnection: network_ops_to_remove.append(C.delayed_propagate) self.total_neurons = total_neurons # now upload to nemo self.nemo_net = nemo.Network() # create dummy synapse type self.synapse_type = self.nemo_net.add_synapse_type() self.nemo_propagate.synapse_type = self.synapse_type # create dummy neurons self.nemo_input_neuron_idx = self.nemo_net.add_neuron_type( 'Input', [self.synapse_type]) self.nemo_net.add_neuron(self.nemo_input_neuron_idx, range(total_neurons)) # add connections and upload synapses to nemo total_synapses = 0 print 'Nemo network synapses:' for C in self.nemo_managed_connections: # We handle subgrouping using the source and target offset source_offset = group_offset[id( C.source._owner)] + C.source._origin target_offset = group_offset[(id( C.target._owner), C.nstate)] + C.target._origin dt = C.source.clock.dt # We replace the propagate method of the Connection with a nemo # version, which adds the spikes to a dynamic stack in the # NemoNetworkPropagate object, which is called after the connections # have been processed by Brian. Note that this way of doing things # only works for the CPU, for the GPU we will need to replace # do_propagate instead. C.propagate = NemoNetworkConnectionPropagate(self, source_offset) # create synapses this_connection_synapses = 0 for i in xrange(len(C.source)): # Need to handle Connection/DelayConnection, and sparse/dense # matrix types Wrow = C.W[i, :] if C.__class__ is DelayConnection: Wdelay = C.delay[i, :] else: Wdelay = zeros(len(Wrow)) if isinstance(Wrow, SparseConnectionVector): ind = (Wrow.ind + target_offset) else: ind = range(target_offset, target_offset + len(Wrow)) delay = (1 + asarray(Wdelay / dt, dtype=int)) # Need to update this when NeMo gets support for longer delays if self.nemo_use_gpu and amax(delay) > 512: raise NotImplementedError( "Current version of NeMo with GPU backend has a maximum delay of 512 steps." ) if not self.nemo_use_gpu and amax(delay) > 64: raise NotImplementedError( "Current version of NeMo with CPU backend has a maximum delay of 64 steps." ) weight = asarray(Wrow, dtype=float32) total_synapses += len(weight) this_connection_synapses += len(weight) if len(ind): self.nemo_net.add_synapse(self.synapse_type, i + source_offset, ind, delay, weight, False) print '-', C.__class__.__name__, print 'from source group of', len(C.source), 'neurons', print 'to target group of', len(C.target), 'neurons,', print 'variable %s,' % get_connection_variable(C), print 'matrix type %s,' % C.W.__class__.__name__, print 'number of synapses', this_connection_synapses # debug print the propagation targets print 'Nemo network propagation targets:' for varname, targetvar, targetslice in self.nemo_propagate_targets: print '- Variable', varname, 'indices %d:%d' % (targetslice.start, targetslice.stop) # remove the delayed_propagate functions which are used by # DelayConnection and will already have been inserted into the network # at this point (as they are in the contained_objects of # DelayConnection). for k, v in self._operations_dict.iteritems(): v = [f for f in v if not f in network_ops_to_remove] self._operations_dict[k] = v # We changed lots of propagate functions so we need to rebuild the # update schedule to make use of them self._build_update_schedule() print 'Nemo network total neurons:', total_neurons print 'Nemo network total synapses:', total_synapses # configure self.nemo_conf = nemo.Configuration() if self.nemo_use_gpu: self.nemo_conf.set_cuda_backend(0) else: self.nemo_conf.set_cpu_backend() # simulation object self.nemo_sim = nemo.Simulation(self.nemo_net, self.nemo_conf)
net = nemo.Network() # Excitatory neurons for nidx in range(800): r = random.random()**2 c = -65.0+15*r d = 8.0 - 6.0*r net.add_neuron(nidx, 0.02, 0.2, c, d, 5.0, 0.2*c, c) targets = range(1000) weights = [0.5*random.random() for tgt in targets] net.add_synapse(nidx, targets, 1, weights, False) # Inhibitory neurons for nidx in range(800,1000): nidx = 800 + n r = random.random() a = 0.02+0.08*r b = 0.25-0.05*r c = -65.0 net.add_neuron(nidx, a, b, c, 2.0, 2.0, b*c, c) targets = range(1000) weights = [-random.random() for tgt in targets] net.add_synapse(nidx, targets, 1, weights, False) conf = nemo.Configuration() sim = nemo.Simulation(net, conf) for t in range(1000): fired = sim.step() print t, ":", fired
def test_get_synapse(self): """ Test scalar and vector form of synapse getters Synapse getters have both scalar and vector forms. To test these, construct a network with fixed connectivity where all synapse properties are functions of the source and target, then read back and verify that the values are as expected. """ def delay(source, target): return 1 + ((source + target) % 20) def plastic(source, target): return (source + target) % 1 == 0 def weight(source, target): return float(source) + float(target) ncount = 100 net = IzNetwork() for src in range(ncount): net.add_neuron(src, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) for tgt in range(src + 1): net.add_synapse(src, tgt, delay(src, tgt), weight(src, tgt), plastic(src, tgt)) conf = nemo.Configuration() sim = nemo.Simulation(net, conf) def check_scalar(x, known_source, sid, source, target): self.assertEqual(known_source, source) self.assertEqual(x.get_synapse_delay(sid), delay(source, target)) self.assertEqual(x.get_synapse_weight(sid), weight(source, target)) self.assertEqual(x.get_synapse_plastic(sid), plastic(source, target)) def check(x): for src in range(ncount): all_synapses = x.get_synapses_from(src) # read a random number of these out-of-order n_queried = random.randint(1, len(all_synapses)) queried = random.sample(all_synapses, n_queried) if len(queried) == 1: queried = queried[0] sources = x.get_synapse_source(queried) targets = x.get_synapse_target(queried) if n_queried == 1: check_scalar(x, src, queried, sources, targets) else: for (sid, qsrc, tgt) in zip(queried, sources, targets): check_scalar(x, src, sid, qsrc, tgt) def check_iterator(x): # Make synapse getter can deal with the iterator returned by the # the synapse query for src in range(ncount): srcs = x.get_synapse_source(x.get_synapses_from(src)) check(net) check(sim) check_iterator(net) check_iterator(sim)
def test_get_synapses_from_unconnected(self): net = IzNetwork() net.add_neuron(0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) self.assertEqual(len(net.get_synapses_from(0)), 0) sim = nemo.Simulation(net, nemo.Configuration()) self.assertEqual(len(sim.get_synapses_from(0)), 0)