def set_axons(self, board, nxsdk_board, spike_input): """Initialize the axon map for this object. Parameters ---------- board : Board The nengo_loihi object representing the Loihi board. nxsdk_board : NxsdkBoard The nxsdk object representing the Loihi board. spike_input : SpikeInput The SpikeInput containing information about which axons are to be targeted. """ assert len(self.axon_map) == 0 input_idxs = np.arange(spike_input.n_neurons) for axon in spike_input.axons: axon_type = axon.pop_type assert axon_type in (0, 32), "Only discrete and pop32 supported" tchip_idx, tcore_idx, tsyn_ids = board.find_synapse(axon.target) tchip = d_get(nxsdk_board, b'bjJDaGlwcw==')[tchip_idx] tcore = d_get(tchip, b'bjJDb3Jlcw==')[tcore_idx] spikes = axon.map_spikes(input_idxs) for input_idx, spike in zip(input_idxs, spikes): if spike is not None: taxon_idx = int(spike.axon_id) taxon_id = int(tsyn_ids[taxon_idx]) self.axon_map.setdefault(input_idx, []).append( self.LoihiAxon( axon_type=axon_type, chip_id=tchip.id, core_id=tcore.id, axon_id=taxon_id, atom=spike.atom, ))
def build_board(board, use_snips=False, seed=None): n_chips = board.n_chips n_cores_per_chip = board.n_cores_per_chip n_synapses_per_core = board.n_synapses_per_core nxsdk_board = NxsdkBoard( board.board_id, n_chips, n_cores_per_chip, n_synapses_per_core ) # add our own attribute for storing our spike generator assert not hasattr(nxsdk_board, "global_spike_generator") nxsdk_board.global_spike_generator = None if use_snips else SpikeGen(nxsdk_board) # custom attr for storing SpikeInputs (filled in build_input) assert not hasattr(nxsdk_board, "spike_inputs") nxsdk_board.spike_inputs = {} # build inputs for input in board.inputs: build_input(nxsdk_board, board, input) # build all chips assert len(board.chips) == len(d_get(nxsdk_board, b"bjJDaGlwcw==")) rng = np.random.RandomState(seed) for chip, nxsdk_chip in zip(board.chips, d_get(nxsdk_board, b"bjJDaGlwcw==")): logger.debug("Building chip %s", chip) seed = rng.randint(npext.maxint) build_chip(nxsdk_chip, chip, seed=seed) # build probes logger.debug("Building %d probes", len(board.probes)) for probe in board.probes: build_probe(nxsdk_board, board, probe, use_snips=use_snips) return nxsdk_board
def build_probe(nxsdk_board, board, probe, use_snips): key_map = {"current": "u", "voltage": "v", "spiked": "spike"} assert probe.key in key_map, "probe key not found" key = key_map[probe.key] assert probe not in board.probe_map if use_snips: probe_snip = ProbeSnip(key) board.probe_map[probe] = probe_snip else: board.probe_map[probe] = [] assert len(probe.target) == len(probe.slice) == len(probe.weights) for k, target in enumerate(probe.target): chip_idx, core_idx, block_idx, compartment_idxs, _ = board.find_block(target) assert chip_idx is not None, "Could not find probe target on board" nxsdk_chip = d_get(nxsdk_board, b"bjJDaGlwcw==")[chip_idx] nxsdk_core = d_get(nxsdk_chip, b"bjJDb3Jlcw==")[core_idx] r = compartment_idxs[probe.slice[k]] if use_snips: probe_snip.chip_idx.append(chip_idx) probe_snip.core_id.append(d_get(nxsdk_core, b"aWQ=")) probe_snip.compartment_idxs.append(r) else: nxsdk_probe = d_get(nxsdk_board, b"bW9uaXRvcg==", b"cHJvYmU=")( d_get(nxsdk_core, b"Y3hTdGF0ZQ=="), r, key ) board.probe_map[probe].append(nxsdk_probe)
def build_board(board, seed=None): n_chips = board.n_chips n_cores_per_chip = board.n_cores_per_chip n_synapses_per_core = board.n_synapses_per_core nxsdk_board = NxsdkBoard(board.board_id, n_chips, n_cores_per_chip, n_synapses_per_core) # add our own attribute for storing our spike generator assert not hasattr(nxsdk_board, 'global_spike_generator') nxsdk_board.global_spike_generator = SpikeGen(nxsdk_board) # custom attr for storing SpikeInputs (filled in build_input) assert not hasattr(nxsdk_board, 'spike_inputs') nxsdk_board.spike_inputs = {} # build all chips assert len(board.chips) == len(d_get(nxsdk_board, b'bjJDaGlwcw==')) rng = np.random.RandomState(seed) for chip, nxsdk_chip in zip(board.chips, d_get(nxsdk_board, b'bjJDaGlwcw==')): logger.debug("Building chip %s", chip) seed = rng.randint(npext.maxint) build_chip(nxsdk_chip, chip, seed=seed) return nxsdk_board
def build_chip(nxsdk_chip, chip, seed=None): assert len(chip.cores) == len(d_get(nxsdk_chip, b'bjJDb3Jlcw==')) rng = np.random.RandomState(seed) for core, nxsdk_core in zip(chip.cores, d_get(nxsdk_chip, b'bjJDb3Jlcw==')): logger.debug("Building core %s", core) seed = rng.randint(npext.maxint) build_core(nxsdk_core, core, seed=seed)
def run_steps(self, steps, blocking=True): assert self.connected, "Interface is not built" # start the board running the desired number of steps d_get(self.nxsdk_board, b"cnVu")(steps, **{d(b"YVN5bmM="): not blocking}) # connect snips if self.use_snips and not self.snips.connected: self.snips.connect(self.nxsdk_board)
def run_steps(self, steps, blocking=True): if self.use_snips and self.nengo_io_h2c is None: self.create_io_snip() # NOTE: we need to call connect() after snips are created self.connect() d_get(self.nxsdk_board, b'cnVu')(steps, **{ d(b'YVN5bmM='): not blocking })
def __init__(self, model, board, nxsdk_board, max_spikes_per_step): self.max_spikes_per_step = max_spikes_per_step self.model = model self.error_chip_map = {} # maps synapses to core/chip locations for errors self.probe_data = OrderedDict() self.tmp_snip_dir = tempfile.TemporaryDirectory() self.host_snip = HostSnip(self.tmp_snip_dir.name) self.chip_snips = [] # Map from probe to information to get outputs of that probe. Each tuple has: # - chip_idx: the index of a chip to get information from # - output_slice: a slice of outputs for the probe # - n_packed_spikes: the number of spikes that have been "packed" to a dense # storage format (if 0, the spikes have not been packed). # There will be at least one entry per chip that the probe gets output from, # and possibly more if the outputs cannot be represented with one slice. self.snip_range = {} for idx, chip in enumerate(board.chips): self.chip_snips.append(ChipSnips(idx, chip, self.tmp_snip_dir.name)) for core in chip.cores: if core.learning_coreid is None: continue for synapse in core.blocks[0].synapses: self.error_chip_map[synapse] = (idx, core.learning_coreid) for probe in model.probes: self.probe_data[probe] = [] pinfo = board.probe_map[probe] for target_idx, block in enumerate(probe.target): chip_idx = pinfo.chip_idx[target_idx] self.chip_snips[chip_idx].prepare_for_probe(block, pinfo, target_idx) self.snip_range[probe] = pinfo.snip_range for chip_snip in self.chip_snips: chip_snip.create(nxsdk_board, self.max_spikes_per_step) self.host_snip.create(nxsdk_board, self.chip_snips) for chip_snip in self.chip_snips: d_get(chip_snip.input_channel, b"Y29ubmVjdA==")( self.host_snip.snip, chip_snip.io_snip ) d_get(chip_snip.output_channel, b"Y29ubmVjdA==")( chip_snip.io_snip, self.host_snip.snip ) self.bytes_per_step = self.packet_bytes * sum( chip_snip.n_output_packets for chip_snip in self.chip_snips )
def chip2host(self, probes_receivers): increment = None for probe, receiver in probes_receivers.items(): nxsdk_probes = self.probe_map[probe] outputs = [ np.column_stack( [ d_get(p, b"dGltZVNlcmllcw==", b"ZGF0YQ==")[self.sent_steps :] for p in nxsdk_probe ] ) for nxsdk_probe in nxsdk_probes ] if len(outputs) > 0: x = probe.weight_outputs(outputs) if increment is None: increment = len(x) assert increment == len(x), "All x need same number of steps" for j in range(len(x)): receiver.receive(self.dt * (self.sent_steps + j + 2), x[j]) if increment is not None: self.sent_steps += increment
def _chip2host_monitor(self, probes_receivers): increment = None for probe, receiver in probes_receivers.items(): assert not probe.use_snip nxsdk_probe = self.board.probe_map[probe] x = np.column_stack([ d_get(p, b'dGltZVNlcmllcw==', b'ZGF0YQ==')[self._chip2host_sent_steps:] for p in nxsdk_probe ]) assert x.ndim == 2 if len(x) > 0: if increment is None: increment = len(x) assert increment == len(x), "All x need same number of steps" if probe.weights is not None: x = np.dot(x, probe.weights) for j in range(len(x)): receiver.receive( self.model.dt * (self._chip2host_sent_steps + j + 2), x[j]) if increment is not None: self._chip2host_sent_steps += increment
def build_probe(nxsdk_core, core, block, probe, compartment_idxs): key_map = {'current': 'u', 'voltage': 'v', 'spiked': 'spike'} assert probe.key in key_map, "probe key not found" key = key_map[probe.key] nxsdk_board = d_get(nxsdk_core, b'cGFyZW50', b'cGFyZW50') r = compartment_idxs[probe.slice] if probe.use_snip: probe.snip_info = dict(core_id=d_get(nxsdk_core, b'aWQ='), compartment_idxs=r, key=key) else: p = d_get(nxsdk_board, b'bW9uaXRvcg==', b'cHJvYmU=')(d_get(nxsdk_core, b'Y3hTdGF0ZQ=='), r, key) core.board.map_probe(probe, p)
def set_axons(self, board, nxsdk_board, spike_input): """Initialize the axon map for this object. Parameters ---------- board : Board The nengo_loihi object representing the Loihi board. nxsdk_board : NxsdkBoard The nxsdk object representing the Loihi board. spike_input : SpikeInput The SpikeInput containing information about which axons are to be targeted. """ assert len(self.axon_map) == 0 input_idxs = np.arange(spike_input.n_neurons) for axon in spike_input.axons: synapse = axon.target atom_bits_extra = synapse.atom_bits_extra() tchip_idx, tcore_idx, taxon_ids = board.find_synapse(synapse) tchip = d_get(nxsdk_board, b"bjJDaGlwcw==")[tchip_idx] tcore = d_get(tchip, b"bjJDb3Jlcw==")[tcore_idx] spikes = axon.map_spikes(input_idxs) for input_idx, spike in zip(input_idxs, spikes): if spike is None: # This should not happen, because input slices happen when # connecting into the spike input. If it does, we just skip it. continue # pragma: no cover self.axon_map.setdefault(input_idx, []) taxon_id = taxon_ids[spike.axon_idx] if taxon_id is None: continue # this goes to a dummy axon, so do not connect self.axon_map[input_idx].append( np.array( ( -1, axon.pop_type, tchip.id, tcore.id, taxon_id, spike.atom, atom_bits_extra, ), dtype=self.spike_dtype, ))
def build_block(nxsdk_core, core, block, compartment_idxs, ax_range): assert block.compartment.scale_u is False assert block.compartment.scale_v is False logger.debug("Building %s on core.id=%d", block, nxsdk_core.id) for i, bias in enumerate(block.compartment.bias): bman, bexp = bias_to_manexp(bias) icomp = core.compartment_cfg_idxs[block][i] ivth = core.vth_cfg_idxs[block][i] ii = compartment_idxs[i] d_func(d_get(nxsdk_core, b'Y3hDZmc=')[ii], b'Y29uZmlndXJl', kwargs={ b'Ymlhcw==': bman, b'Ymlhc0V4cA==': bexp, b'dnRoUHJvZmlsZQ==': ivth, b'Y3hQcm9maWxl': icomp, }) phasex = d(b'cGhhc2UlZA==') % (ii % 4, ) d_get( d_get(nxsdk_core, b'Y3hNZXRhU3RhdGU=')[ii // 4], b'Y29uZmlndXJl')(**{ phasex: 2 }) logger.debug("- Building %d synapses", len(block.synapses)) for synapse in block.synapses: build_synapse(nxsdk_core, core, block, synapse, compartment_idxs) logger.debug("- Building %d axons", len(block.axons)) pop_id_map = {} for axon in block.axons: build_axons(nxsdk_core, core, block, axon, compartment_idxs, pop_id_map) logger.debug("- Building %d probes", len(block.probes)) for probe in block.probes: build_probe(nxsdk_core, core, block, probe, compartment_idxs)
def get_probe_output(self, probe): assert isinstance(probe, Probe) if probe.use_snip: data = self._snip_probe_data[probe] else: nxsdk_probe = self.board.probe_map[probe] data = np.column_stack([ d_get(p, b'dGltZVNlcmllcw==', b'ZGF0YQ==') for p in nxsdk_probe ]) data = (data if probe.weights is None else np.dot( data, probe.weights)) return self._filter_probe(probe, data)
def connect(self, nxsdk_board): # pause to allow host snip to start and listen for connection time.sleep(0.1) host_address = d_get( nxsdk_board, b"ZXhlY3V0b3I==", b"X2hvc3RfY29vcmRpbmF0b3I==", b"aG9zdEFkZHI=", ) logger.info("Connecting to host socket at (%s, %s)", host_address, self.port) self.socket.connect((host_address, self.port)) self.connected = True
def test_d_get_set(): class TestClass: pass obj = TestClass() obj.attr0 = TestClass() obj.attr0.attr1 = "test" assert d_get(obj, obfuscate("attr0"), obfuscate("attr1")) == "test" # error if trying to set a new attribute with pytest.raises(AssertionError): d_set(obj, obfuscate("attr0"), obfuscate("attr2"), val="test2") obj.attr0.attr2 = None d_set(obj, obfuscate("attr0"), obfuscate("attr2"), val="test2") assert obj.attr0.attr2 == "test2"
def get_probe_output(self, probe): assert isinstance(probe, LoihiProbe) if self.use_snips: data = self.snips.probe_data[probe] else: nxsdk_probes = self.board.probe_map[probe] outputs = [ np.column_stack( [d_get(p, b"dGltZVNlcmllcw==", b"ZGF0YQ==") for p in nxsdk_probe] ) for nxsdk_probe in nxsdk_probes ] data = probe.weight_outputs(outputs) # --- Filter probed data dt = self.model.dt shape = data[0].shape i = self._probe_filter_pos.get(probe, 0) if i == 0: synapse = probe.synapse rng = None step = ( make_process_step(synapse, shape, shape, dt, rng, dtype=np.float32) if synapse is not None else None ) self._probe_filters[probe] = step else: step = self._probe_filters[probe] if step is None: self._probe_filter_pos[probe] = i + len(data) return data else: filt_data = np.zeros((len(data),) + shape, dtype=np.float32) for k, x in enumerate(data): filt_data[k] = step((i + k) * dt, x) self._probe_filter_pos[probe] = i + k return filt_data
class SnipMaker(d_get(snip_maker, b"R3JhcGg=")): """Patch of the snip process manager that is multiprocess safe.""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # We need to store references to the temporary directories so # that they don't get cleaned up self.nengo_tmp_dirs = [] def createProcess(self, name, cFilePath, includeDir, *args, **kwargs): # Copy the c file to a temporary directory (so that multiple # simulations can use the same snip files without running into # problems) tmp = tempfile.TemporaryDirectory() self.nengo_tmp_dirs.append(tmp) os.mkdir(os.path.join(tmp.name, name)) tmp_path = os.path.join(tmp.name, name, os.path.basename(cFilePath)) shutil.copyfile(cFilePath, tmp_path) with open(cFilePath) as f0, open(tmp_path) as f1: src = f0.read() dst = f1.read() if src != dst: print("=== SOURCE: %s" % (cFilePath, )) print(src) print("\n=== DEST: %s" % (tmp_path, )) print(dst) raise ValueError("Snip file not copied correctly") # Also copy all the include files include_path = os.path.join(tmp.name, name, "include") shutil.copytree(includeDir, include_path) assert os.path.isdir(include_path), "Copy failed %s" % include_path return super().createProcess(name, tmp_path, include_path, *args, **kwargs)
def build_input(nxsdk_core, core, spike_input, compartment_idxs): assert len(spike_input.axons) > 0 nxsdk_board = d_get(nxsdk_core, b'cGFyZW50', b'cGFyZW50') assert isinstance(spike_input, SpikeInput) loihi_input = LoihiSpikeInput() loihi_input.set_axons(core.board, nxsdk_board, spike_input) assert spike_input not in nxsdk_board.spike_inputs nxsdk_board.spike_inputs[spike_input] = loihi_input # add any pre-existing spikes to spikegen for t in spike_input.spike_times(): spikes = spike_input.spike_idxs(t) for spike in loihi_input.spikes_to_loihi(t, spikes): assert spike.axon.atom == 0, ( "Cannot send population spikes through spike generator") d_func(nxsdk_board.global_spike_generator, b'YWRkU3Bpa2U=', kwargs={ b'dGltZQ==': spike.time, b'Y2hpcElk': spike.axon.chip_id, b'Y29yZUlk': spike.axon.core_id, b'YXhvbklk': spike.axon.axon_id, })
def create(self, nxsdk_board, max_spikes_per_step): self.chip_id = d_get(d_get(nxsdk_board, b"bjJDaGlwcw==")[self.idx], b"aWQ=") chip_buffer_size = roundup( max( self.n_outputs, # currently, buffer needs to hold all outputs Snips.channel_packet_elements + max(SpikePacker.size, Snips.obfs["error_info_size"]), ), Snips.channel_packet_elements, ) # --- create IO snip c_path = os.path.join(self.tmp_snip_dir, "nengo_io_chip_%d.c" % self.idx) h_filename = "nengo_io_chip_%d.h" % self.idx logger.debug( "Creating %s with %d outputs, %d error, %d cores, %d probes", c_path, self.n_outputs, self.n_errors, len(self.cores), len(self.probes), ) Snips.render_template( "nengo_io.c", c_path, header_file=h_filename, n_outputs=self.n_outputs, n_output_packets=self.n_output_packets, n_errors=self.n_errors, buffer_size=chip_buffer_size, packet_elements=Snips.channel_packet_elements, input_channel=self.input_channel_name, output_channel=self.output_channel_name, cores=self.cores, probes=self.probes, ) # write header file using template Snips.render_template("nengo_io.h", os.path.join(self.tmp_snip_dir, h_filename)) # create SNIP process logger.debug("Creating nengo_io chip %d process", self.idx) self.io_snip = d_func( nxsdk_board, b"Y3JlYXRlU25pcA==", kwargs={ b"bmFtZQ==": "nengo_io_chip" + str(self.chip_id), b"Y0ZpbGVQYXRo": c_path, b"aW5jbHVkZURpcg==": self.tmp_snip_dir, b"ZnVuY05hbWU=": "nengo_io", b"Z3VhcmROYW1l": "guard_io", b"cGhhc2U=": d_get(SnipPhase, b"RU1CRURERURfTUdNVA=="), b"Y2hpcElk": self.chip_id, }, ) # --- create learning snip h_filename = "nengo_learn_chip_%d.h" % self.idx c_path = os.path.join(self.tmp_snip_dir, "nengo_learn_chip_%d.c" % self.idx) # write c file using template Snips.render_template( "nengo_learn.c", c_path, header_file=h_filename, ) # write header file using template Snips.render_template( "nengo_learn.h", os.path.join(self.tmp_snip_dir, h_filename) ) # create SNIP process logger.debug("Creating nengo_learn chip %d process", self.idx) self.learn_snip = d_func( nxsdk_board, b"Y3JlYXRlU25pcA==", kwargs={ b"bmFtZQ==": "nengo_learn", b"Y0ZpbGVQYXRo": c_path, b"aW5jbHVkZURpcg==": self.tmp_snip_dir, b"ZnVuY05hbWU=": "nengo_learn", b"Z3VhcmROYW1l": "guard_learn", b"cGhhc2U=": d_get(SnipPhase, b"RU1CRURERURfUFJFTEVBUk5fTUdNVA=="), b"Y2hpcElk": self.chip_id, }, ) # --- create channels input_channel_size = ( self.output_header_len # first int stores number of spikes + max_spikes_per_step * SpikePacker.size + self.total_error_len ) logger.debug( "Creating %s channel (%d)", self.input_channel_name, input_channel_size ) self.input_channel = d_get(nxsdk_board, b"Y3JlYXRlQ2hhbm5lbA==")( self.input_channel_name.encode(), **{ # channel size (in elements) d(b"bnVtRWxlbWVudHM="): input_channel_size, # size of one packet (in bytes) d(b"bWVzc2FnZVNpemU="): Snips.packet_bytes, # size of send/receive buffer on chip/host (in packets) d(b"c2xhY2s="): 16, }, ) logger.debug( "Creating %s channel (%d)", self.output_channel_name, self.n_outputs ) self.output_channel = d_get(nxsdk_board, b"Y3JlYXRlQ2hhbm5lbA==")( self.output_channel_name.encode(), **{ # channel size (in elements) d(b"bnVtRWxlbWVudHM="): self.n_outputs, # size of one packet (in bytes) d(b"bWVzc2FnZVNpemU="): Snips.packet_bytes, # size of send/receive buffer on chip/host (in packets) d(b"c2xhY2s="): 16, }, )
def build_axons(nxsdk_core, core, block, axon, compartment_ids, pop_id_map): synapse = axon.target tchip_idx, tcore_idx, taxon_ids = core.board.find_synapse(synapse) nxsdk_board = d_get(nxsdk_core, b"cGFyZW50", b"cGFyZW50") tchip_id = d_get(d_get(nxsdk_board, b"bjJDaGlwcw==")[tchip_idx], b"aWQ=") tcore_id = d_get( d_get(d_get(nxsdk_board, b"bjJDaGlwcw==")[tchip_idx], b"bjJDb3Jlc0FzTGlzdA==")[ tcore_idx ], b"aWQ=", ) compartment_idxs = np.arange(len(compartment_ids)) spikes = axon.map_spikes(compartment_idxs) for compartment_id, spike in zip(compartment_ids, spikes): if spike is None: continue # this compartment does not route through these axons taxon_idx = spike.axon_idx taxon_id = taxon_ids[taxon_idx] atom = int(spike.atom) n_atoms = synapse.axon_populations(taxon_idx) if taxon_id is None: continue # this connects to a dummy axon, so do not build if synapse.pop_type == 0: # discrete assert atom == 0 assert n_atoms == 1 d_func( nxsdk_core, b"Y3JlYXRlRGlzY3JldGVBeG9u", kwargs={ b"c3JjQ3hJZA==": compartment_id, b"ZHN0Q2hpcElk": tchip_id, b"ZHN0Q29yZUlk": tcore_id, b"ZHN0U3luTWFwSWQ=": taxon_id, }, ) elif synapse.pop_type in (16, 32): n_blocks = len(core.blocks) assert n_blocks == 0 or (n_blocks == 1 and block is core.blocks[0]) # pop_id is a unique index for the population. Must be the same for # all axons going to the same target synmap (with different atoms # of course), but otherwise different for all axons. Also, each # compartment can only have axons belonging to one population. if compartment_id not in pop_id_map: # If there's already an axon going to this synmap, use that # pop_id. Otherwise, make a new pop_id pop_key = (tchip_id, tcore_id, taxon_id) if pop_key not in pop_id_map: pop_id = max(pop_id_map.values()) + 1 if len(pop_id_map) > 0 else 0 pop_id_map[pop_key] = pop_id pop_id_map[compartment_id] = pop_id_map[pop_key] pop_id = pop_id_map[compartment_id] kwargs = { b"cG9wSWQ=": pop_id, b"c3JjQ3hJZA==": compartment_id, b"c3JjUmVsQ3hJZA==": atom, b"ZHN0Q2hpcElk": tchip_id, b"ZHN0Q29yZUlk": tcore_id, b"ZHN0U3luTWFwSWQ=": taxon_id, } if synapse.pop_type == 16: d_func(nxsdk_core, b"Y3JlYXRlUG9wMTZBeG9u", kwargs=kwargs) else: d_func(nxsdk_core, b"Y3JlYXRlUG9wMzJBeG9u", kwargs=kwargs) else: raise BuildError("Axon: unrecognized pop_type: %s" % (synapse.pop_type,))
def build_synapse(nxsdk_core, core, block, synapse, compartment_idxs): # noqa C901 # pre-decode some things for speed nxsdk_synapses = d_get(nxsdk_core, b"c3luYXBzZXM=") d_set_synapse = d(b"Y29uZmlndXJl") d_compartment_idx = d(b"Q0lkeA==") d_weight = d(b"V2d0") d_synapse_cfg_idx = d(b"c3luRm10SWQ=") d_is_learning = d(b"THJuRW4=") nxsdk_synapse_map = d_get(nxsdk_core, b"c3luYXBzZU1hcA==") d_synapse_ptr = d(b"c3luYXBzZVB0cg==") d_synapse_len = d(b"c3luYXBzZUxlbg==") d_pop_size = d(b"cG9wU2l6ZQ==") max_compartment_offset = d(b"MjU2", int) d_discrete_map = d(b"ZGlzY3JldGVNYXBFbnRyeQ==") d_pop16_map = d(b"cG9wdWxhdGlvbjE2TWFwRW50cnk=") d_pop32_map = d(b"cG9wdWxhdGlvbjMyTWFwRW50cnk=") d_set_map = d(b"Y29uZmlndXJl") d_compartment_offset = d(b"Y3hCYXNl") d_atom_bits_extra = d(b"YXRvbUJpdHM=") axon_ids = core.synapse_axons[synapse] synapse_cfg_idx = core.synapse_cfg_idxs[synapse] stdp_pre_cfg_idx = core.stdp_pre_cfg_idxs[synapse] atom_bits = synapse.atom_bits() axon_bits = synapse.axon_bits() atom_bits_extra = synapse.atom_bits_extra() target_compartments = set() synapse_map = {} # map weight_idx to (ptr, pop_size, len) total_synapse_ptr = int(core.synapse_entries[synapse][0]) for axon_idx, axon_id in enumerate(axon_ids): assert axon_id is None or axon_id <= 2 ** axon_bits weight_idx = synapse.axon_weight_idx(axon_idx) base = synapse.axon_compartment_base(axon_idx) if weight_idx not in synapse_map: weights = synapse.weights[weight_idx] indices = synapse.indices[weight_idx] weights = weights // synapse.synapse_cfg.scale assert weights.ndim == 2 assert weights.shape == indices.shape assert np.all(weights <= 255) and np.all(weights >= -256), str(weights) n_atoms, n_compartments = weights.shape synapse_map[weight_idx] = (total_synapse_ptr, n_atoms, n_compartments) for p in range(n_atoms): for q in range(n_compartments): compartment_idx = compartment_idxs[indices[p, q]] getattr(nxsdk_synapses[total_synapse_ptr], d_set_synapse)( **{ d_compartment_idx: compartment_idx, d_weight: weights[p, q], d_synapse_cfg_idx: synapse_cfg_idx, d_is_learning: int(synapse.learning), } ) target_compartments.add(compartment_idx) total_synapse_ptr += 1 synapse_ptr, n_atoms, n_compartments = synapse_map[weight_idx] assert n_atoms <= 2 ** atom_bits if axon_id is None: # pragma: no cover # This is a dummy axon with no base or no weights, so skip it assert base is None or n_compartments == 0 continue # base = int(base) assert base <= max_compartment_offset, "Currently limited by hardware" setattr(nxsdk_synapse_map[axon_id], d_synapse_ptr, synapse_ptr) setattr(nxsdk_synapse_map[axon_id], d_synapse_len, n_compartments) if synapse.pop_type == 0: # discrete assert n_atoms == 1 getattr(getattr(nxsdk_synapse_map[axon_id], d_discrete_map), d_set_map)( **{d_compartment_offset: base} ) elif synapse.pop_type == 16: # pop16 setattr(nxsdk_synapse_map[axon_id], d_pop_size, n_atoms) assert base % 4 == 0 getattr(getattr(nxsdk_synapse_map[axon_id], d_pop16_map), d_set_map)( **{d_compartment_offset: base // 4, d_atom_bits_extra: atom_bits_extra}, ) elif synapse.pop_type == 32: # pop32 setattr(nxsdk_synapse_map[axon_id], d_pop_size, n_atoms) getattr(getattr(nxsdk_synapse_map[axon_id], d_pop32_map), d_set_map)( **{d_compartment_offset: base} ) else: raise BuildError("Synapse: unrecognized pop_type: %s" % (synapse.pop_type,)) if synapse.learning: assert core.stdp_pre_cfg_idx is not None assert stdp_pre_cfg_idx is not None d_func( nxsdk_synapse_map[axon_id + 1], b"c2luZ2xlVHJhY2VFbnRyeQ==", b"Y29uZmlndXJl", kwargs={ b"cHJlUHJvZmlsZQ==": core.stdp_pre_cfg_idx, b"dGNz": stdp_pre_cfg_idx, }, ) assert ( total_synapse_ptr == core.synapse_entries[synapse][1] ), "Synapse pointer did not align with precomputed synapse length" if synapse.learning: assert core.stdp_cfg_idx is not None for compartment in target_compartments: # TODO: check that no compartment configured by multiple synapses d_func( d_get(nxsdk_core, b"c3RkcFBvc3RTdGF0ZQ==")[compartment], b"Y29uZmlndXJl", kwargs={ b"c3RkcFByb2ZpbGU=": core.stdp_cfg_idx, b"dHJhY2VQcm9maWxl": 3, # TODO: why this value }, )
def build_synapse( # noqa C901 nxsdk_core, core, block, synapse, compartment_idxs): axon_ids = core.synapse_axons[synapse] synapse_cfg_idx = core.synapse_cfg_idxs[synapse] stdp_pre_cfg_idx = core.stdp_pre_cfg_idxs[synapse] atom_bits = synapse.atom_bits() axon_bits = synapse.axon_bits() atom_bits_extra = synapse.atom_bits_extra() target_compartments = set() synapse_map = {} # map weight_idx to (ptr, pop_size, len) total_synapse_ptr = int(core.synapse_entries[synapse][0]) for axon_idx, axon_id in enumerate(axon_ids): assert axon_id <= 2**axon_bits weight_idx = int(synapse.axon_weight_idx(axon_idx)) base = synapse.axon_compartment_base(axon_idx) if weight_idx not in synapse_map: weights = synapse.weights[weight_idx] indices = synapse.indices[weight_idx] weights = weights // synapse.synapse_cfg.scale assert weights.ndim == 2 assert weights.shape == indices.shape assert np.all(weights <= 255) and np.all( weights >= -256), str(weights) n_atoms, n_compartments = weights.shape synapse_map[weight_idx] = (total_synapse_ptr, n_atoms, n_compartments) for p in range(n_atoms): for q in range(n_compartments): compartment_idx = compartment_idxs[indices[p, q]] d_func(d_get(nxsdk_core, b'c3luYXBzZXM=')[total_synapse_ptr], b'Y29uZmlndXJl', kwargs={ b'Q0lkeA==': compartment_idx, b'V2d0': weights[p, q], b'c3luRm10SWQ=': synapse_cfg_idx, b'THJuRW4=': int(synapse.learning), }) target_compartments.add(compartment_idx) total_synapse_ptr += 1 synapse_ptr, n_atoms, n_compartments = synapse_map[weight_idx] assert n_atoms <= 2**atom_bits if base is None: # this is a dummy axon with no weights, so set n_compartments to 0 synapse_ptr = 0 n_compartments = 0 base = 0 else: base = int(base) assert base <= d(b'MjU2', int), "Currently limited by hardware" d_set(d_get(nxsdk_core, b'c3luYXBzZU1hcA==')[axon_id], b'c3luYXBzZVB0cg==', val=synapse_ptr) d_set(d_get(nxsdk_core, b'c3luYXBzZU1hcA==')[axon_id], b'c3luYXBzZUxlbg==', val=n_compartments) if synapse.pop_type == 0: # discrete assert n_atoms == 1 d_func(d_get(nxsdk_core, b'c3luYXBzZU1hcA==')[axon_id], b'ZGlzY3JldGVNYXBFbnRyeQ==', b'Y29uZmlndXJl', kwargs={b'Y3hCYXNl': base}) elif synapse.pop_type == 16: # pop16 d_set(d_get(nxsdk_core, b'c3luYXBzZU1hcA==')[axon_id], b'cG9wU2l6ZQ==', val=n_atoms) assert base % 4 == 0 d_func(d_get(nxsdk_core, b'c3luYXBzZU1hcA==')[axon_id], b'cG9wdWxhdGlvbjE2TWFwRW50cnk=', b'Y29uZmlndXJl', kwargs={ b'Y3hCYXNl': base // 4, b'YXRvbUJpdHM=': atom_bits_extra, }) elif synapse.pop_type == 32: # pop32 d_set(d_get(nxsdk_core, b'c3luYXBzZU1hcA==')[axon_id], b'cG9wU2l6ZQ==', val=n_atoms) d_func(d_get(nxsdk_core, b'c3luYXBzZU1hcA==')[axon_id], b'cG9wdWxhdGlvbjMyTWFwRW50cnk=', b'Y29uZmlndXJl', kwargs={b'Y3hCYXNl': base}) else: raise BuildError("Synapse: unrecognized pop_type: %s" % (synapse.pop_type, )) if synapse.learning: assert core.stdp_pre_cfg_idx is not None assert stdp_pre_cfg_idx is not None d_func(d_get(nxsdk_core, b'c3luYXBzZU1hcA==')[axon_id + 1], b'c2luZ2xlVHJhY2VFbnRyeQ==', b'Y29uZmlndXJl', kwargs={ b'cHJlUHJvZmlsZQ==': core.stdp_pre_cfg_idx, b'dGNz': stdp_pre_cfg_idx, }) assert total_synapse_ptr == core.synapse_entries[synapse][1], ( "Synapse pointer did not align with precomputed synapse length") if synapse.learning: assert core.stdp_cfg_idx is not None for compartment in target_compartments: # TODO: check that no compartment configured by multiple synapses d_func( d_get(nxsdk_core, b'c3RkcFBvc3RTdGF0ZQ==')[compartment], b'Y29uZmlndXJl', kwargs={ b'c3RkcFByb2ZpbGU=': core.stdp_cfg_idx, b'dHJhY2VQcm9maWxl': 3 # TODO: why this value })
def build_core(nxsdk_core, core, seed=None): # noqa: C901 assert len(core.compartment_cfgs) < MAX_COMPARTMENT_CFGS assert len(core.vth_cfgs) < MAX_VTH_CFGS logger.debug("- Configuring compartments") for i, cfg in enumerate(core.compartment_cfgs): d_func( d_get(nxsdk_core, b"Y3hQcm9maWxlQ2Zn")[i], b"Y29uZmlndXJl", kwargs={ b"ZGVjYXlW": cfg.decay_v, b"ZGVjYXlV": cfg.decay_u, b"cmVmcmFjdERlbGF5": cfg.refract_delay, b"ZW5hYmxlTm9pc2U=": cfg.enable_noise, b"YmFwQWN0aW9u": 1, }, ) logger.debug("- Configuring vth_cfgs") for i, cfg in enumerate(core.vth_cfgs): d_func( d_get(nxsdk_core, b"dnRoUHJvZmlsZUNmZw==")[i], b"c3RhdGljQ2Zn", b"Y29uZmlndXJl", kwargs={b"dnRo": cfg.vth}, ) logger.debug("- Configuring synapse_cfgs") for i, cfg in enumerate(core.synapse_cfgs): if cfg is None: continue obj = d_get(nxsdk_core, b"c3luYXBzZUZtdA==")[i] d_set(obj, b"d2d0TGltaXRNYW50", val=cfg.weight_limit_mant) d_set(obj, b"d2d0TGltaXRFeHA=", val=cfg.weight_limit_exp) d_set(obj, b"d2d0RXhw", val=cfg.weight_exp) d_set(obj, b"ZGlzY01heFdndA==", val=cfg.disc_max_weight) d_set(obj, b"bGVhcm5pbmdDZmc=", val=cfg.learning_cfg) d_set(obj, b"dGFnQml0cw==", val=cfg.tag_bits) d_set(obj, b"ZGx5Qml0cw==", val=cfg.delay_bits) d_set(obj, b"d2d0Qml0cw==", val=cfg.weight_bits) d_set(obj, b"cmV1c2VTeW5EYXRh", val=cfg.reuse_synapse_data) d_set(obj, b"bnVtU3luYXBzZXM=", val=cfg.n_synapses) d_set(obj, b"Y0lkeE9mZnNldA==", val=cfg.idx_offset) d_set(obj, b"Y0lkeE11bHQ=", val=cfg.idx_mult) d_set(obj, b"c2tpcEJpdHM=", val=cfg.skip_bits) d_set(obj, b"aWR4Qml0cw==", val=cfg.idx_bits) d_set(obj, b"c3luVHlwZQ==", val=cfg.synapse_type) d_set(obj, b"ZmFub3V0VHlwZQ==", val=cfg.fanout_type) d_set(obj, b"Y29tcHJlc3Npb24=", val=cfg.compression) d_set(obj, b"c3RkcFByb2ZpbGU=", val=cfg.stdp_cfg) d_set(obj, b"aWdub3JlRGx5", val=cfg.ignore_delay) logger.debug("- Configuring stdp_pre_cfgs") for i, trace_cfg in enumerate(core.stdp_pre_cfgs): tcg = TraceConfigGenerator() tc = d_func( tcg, b"Z2VuVHJhY2VDZmc=", kwargs={ b"dGF1": trace_cfg.tau, b"c3Bpa2VMZXZlbEludA==": trace_cfg.spike_int, b"c3Bpa2VMZXZlbEZyYWM=": trace_cfg.spike_frac, }, ) d_get(tc, b"d3JpdGVUb1JlZ2lzdGVy")(d_get(nxsdk_core, b"c3RkcFByZUNmZw==")[i]) # --- seed randomness def seed_trace(trace_random, rng): trace_random.random0 = rng.randint(2 ** 32) trace_random.random1 = rng.randint(2 ** 32) trace_random.random2 = rng.randint(2 ** 32) rng = np.random.RandomState(seed) # neuron noise # TODO: how to set neuron noise? # d_set (nxsdk_core, b'ZGVuZHJpdGVSYW5kb20=', b'd29yZA==', # val=rng.randint(2 ** 32)) # pre trace rounding seed_trace(d_get(nxsdk_core, b"c3RkcFByZVJhbmRvbQ=="), rng) # post trace rounding seed_trace(d_get(nxsdk_core, b"c3RkcFBvc3RSYW5kb20="), rng) # soma activity trace rounding seed_trace(d_get(nxsdk_core, b"c29tYVJhbmRvbQ=="), rng) # synaptic rounding d_set( nxsdk_core, b"c3luYXBzZVJlcGFja1JhbmRvbQ==", b"d29yZA==", val=rng.randint(2 ** 32), ) # --- learning first_learning_index = None for synapse in core.iterate_synapses(): if synapse.learning and first_learning_index is None: first_learning_index = core.synapse_axons[synapse][0] core.learning_coreid = d_get(nxsdk_core, b"aWQ=") break num_stdp = 0 if first_learning_index is not None: for synapse in core.iterate_synapses(): assert ( synapse.learning ), "Currently, all synapses on core are learning or none are" axons = np.array(core.synapse_axons[synapse]) if synapse.learning: num_stdp += len(axons) assert np.all(axons >= first_learning_index) if num_stdp > 0: logger.debug("- Configuring PES learning") # add configurations tailored to PES learning d_func( nxsdk_core, b"c3RkcENmZw==", b"Y29uZmlndXJl", kwargs={ b"Zmlyc3RMZWFybmluZ0luZGV4": first_learning_index, b"bnVtUmV3YXJkQXhvbnM=": 0, }, ) assert core.stdp_pre_cfg_idx is None assert core.stdp_cfg_idx is None core.stdp_pre_cfg_idx = 0 # hard-code for now core.stdp_cfg_idx = 0 # hard-code for now (also in synapse_cfg) d_func( d_get(nxsdk_core, b"c3RkcFByZVByb2ZpbGVDZmc=")[0], b"Y29uZmlndXJl", kwargs={ b"dXBkYXRlQWx3YXlz": 1, b"bnVtVHJhY2Vz": 0, b"bnVtVHJhY2VIaXN0": 0, b"c3RkcFByb2ZpbGU=": 0, }, ) # stdp config for positive error d_func( d_get(nxsdk_core, b"c3RkcFByb2ZpbGVDZmc=")[0], b"Y29uZmlndXJl", kwargs={ b"dUNvZGVQdHI=": 0, b"ZGVjaW1hdGVFeHA=": 0, b"bnVtUHJvZHVjdHM=": 1, b"cmVxdWlyZVk=": 1, b"dXNlc1hlcG9jaA==": 1, }, ) # Microcode for the learning rule. `u1` evaluates the learning rule # every 2**1 timesteps, `x1` is the pre-trace, `y1` is the post-trace, # and 2^-7 is the learning rate. ucode = d_get(micro_gen, b"cnVsZVRvVUNvZGU=")( [d(b"ZHcgPSB1MSp4MSp5MSooMl4tNyk=")], **{d(b"ZG9PcHRpbWl6ZQ=="): False} ) assert d_get(ucode, b"bnVtVUNvZGVz") == 1 d_set( d_get(nxsdk_core, b"c3RkcFVjb2RlTWVt")[0], b"d29yZA==", val=d_get(ucode, b"dUNvZGVz")[0], ) # stdp config for negative error d_func( d_get(nxsdk_core, b"c3RkcFByb2ZpbGVDZmc=")[1], b"Y29uZmlndXJl", kwargs={ b"dUNvZGVQdHI=": 1, b"ZGVjaW1hdGVFeHA=": 0, b"bnVtUHJvZHVjdHM=": 1, b"cmVxdWlyZVk=": 1, b"dXNlc1hlcG9jaA==": 1, }, ) # use negative version of above microcode rule ucode = d_get(micro_gen, b"cnVsZVRvVUNvZGU=")( [d(b"ZHcgPSAtdTEqeDEqeTEqKDJeLTcp")], **{d(b"ZG9PcHRpbWl6ZQ=="): False} ) assert d_get(ucode, b"bnVtVUNvZGVz") == 1 d_set( d_get(nxsdk_core, b"c3RkcFVjb2RlTWVt")[1], b"d29yZA==", val=d_get(ucode, b"dUNvZGVz")[0], ) tcg = TraceConfigGenerator() tc = d_func( tcg, b"Z2VuVHJhY2VDZmc=", kwargs={b"dGF1": 0, b"c3Bpa2VMZXZlbEludA==": 0, b"c3Bpa2VMZXZlbEZyYWM=": 0}, ) d_get(tc, b"d3JpdGVUb1JlZ2lzdGVy")(d_get(nxsdk_core, b"c3RkcFBvc3RDZmc=")[0]) # TODO: allocator should be checking that vmin, vmax are the same # for all blocks on a core n_compartments = 0 if len(core.blocks) > 0: block0 = core.blocks[0] vmin, vmax = block0.compartment.vmin, block0.compartment.vmax assert all(block.compartment.vmin == vmin for block in core.blocks) assert all(block.compartment.vmax == vmax for block in core.blocks) neg_limit = np.log2(-vmin + 1) pos_limit = (np.log2(vmax + 1) - 9) * 0.5 assert int(neg_limit) == neg_limit assert int(pos_limit) == pos_limit noise_exp = block0.compartment.noise_exp noise_offset = block0.compartment.noise_offset noise_at_membrane = block0.compartment.noise_at_membrane assert all(block.compartment.noise_exp == noise_exp for block in core.blocks) assert all( block.compartment.noise_offset == noise_offset for block in core.blocks ) assert all( block.compartment.noise_at_membrane == noise_at_membrane for block in core.blocks ) if noise_exp < d(b"Nw==", int): # unexpected shifting: exp less than threshold acts as exp + 1 noise_exp = noise_exp - 1 d_func( nxsdk_core, b"ZGVuZHJpdGVTaGFyZWRDZmc=", b"Y29uZmlndXJl", kwargs={ b"cG9zVm1MaW1pdA==": int(pos_limit), b"bmVnVm1MaW1pdA==": int(neg_limit), b"bm9pc2VFeHAw": noise_exp, b"bm9pc2VNYW50T2Zmc2V0MA==": noise_offset, b"bm9pc2VBdERlbmRPclZt": noise_at_membrane, }, ) d_func( nxsdk_core, b"ZGVuZHJpdGVBY2N1bUNmZw==", b"Y29uZmlndXJl", kwargs={b"ZGVsYXlCaXRz": 3}, ) for block, compartment_idxs, ax_range in core.iterate_blocks(): build_block(nxsdk_core, core, block, compartment_idxs, ax_range) n_compartments = max(max(compartment_idxs) + 1, n_compartments) logger.debug("- Configuring n_updates=%d", ceil_div(n_compartments, 4)) d_func( nxsdk_core, b"bnVtVXBkYXRlcw==", b"Y29uZmlndXJl", kwargs={ b"bnVtVXBkYXRlcw==": ceil_div(n_compartments, 4), b"bnVtU3RkcA==": num_stdp, }, ) d_set(d_get(nxsdk_core, b"ZGVuZHJpdGVUaW1lU3RhdGU=")[0], b"dGVwb2No", val=2) d_set(d_get(nxsdk_core, b"dGltZVN0YXRl")[0], b"dGVwb2No", val=2)
def create_io_snip(self): # snips must be created before connecting assert not self.is_connected(), "still connected" snips_dir = os.path.join(os.path.dirname(__file__), "snips") env = jinja2.Environment(trim_blocks=True, loader=jinja2.FileSystemLoader(snips_dir), keep_trailing_newline=True) # --- generate custom code # Determine which cores have learning n_errors = 0 total_error_len = 0 max_error_len = 0 for core in self.board.chips[0].cores: # TODO: don't assume 1 chip if core.learning_coreid: error_len = core.blocks[0].n_neurons // 2 max_error_len = max(error_len, max_error_len) n_errors += 1 total_error_len += 2 + error_len n_outputs = 1 probes = [] cores = set() # TODO: should snip_range be stored on the probe? snip_range = {} for block in self.model.blocks: for probe in block.probes: if probe.use_snip: info = probe.snip_info assert info['key'] in ('u', 'v', 'spike') # For spike probes, we record V and determine if the neuron # spiked in Simulator. cores.add(info["core_id"]) snip_range[probe] = slice( n_outputs - 1, n_outputs + len(info["compartment_idxs"]) - 1) for compartment in info["compartment_idxs"]: probes.append((n_outputs, info["core_id"], compartment, info['key'])) n_outputs += 1 # obfuscated strings used in templates obfs = dict( core_class=d(b'TmV1cm9uQ29yZQ=='), id_class=d(b'Q29yZUlk'), get_channel=d(b'Z2V0Q2hhbm5lbElE'), int_type=d(b'aW50MzJfdA=='), spike_size=d(b'Mg=='), error_info_size=d(b'Mg=='), step=d(b'dGltZV9zdGVw'), read=d(b'cmVhZENoYW5uZWw='), write=d(b'd3JpdGVDaGFubmVs'), spike_shift=d(b'MTY='), spike_mask=d(b'MHgwMDAwRkZGRg=='), axon_type_0=d(b'MA=='), do_axon_type_0=d(b'bnhfc2VuZF9kaXNjcmV0ZV9zcGlrZQ=='), axon_type_1=d(b'MzI='), do_axon_type_1=d(b'bnhfc2VuZF9wb3AzMl9zcGlrZQ=='), data=d(b'dXNlckRhdGE='), state=d(b'Y3hfc3RhdGU='), neuron=d(b'TkVVUk9OX1BUUg=='), pos_pes_cfg= d(b'bmV1cm9uLT5zdGRwX3Bvc3Rfc3RhdGVbY29tcGFydG1lbnRfaWR4XSA9ICAgICAgICAgICAgICAgICAgICAgKFBvc3RUcmFjZUVudHJ5KSB7CiAgICAgICAgICAgICAgICAgICAgICAgIC5Zc3Bpa2UwICAgICAgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAuWXNwaWtlMSAgICAgID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgLllzcGlrZTIgICAgICA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgIC5ZZXBvY2gwICAgICAgPSBhYnMoZXJyb3IpLAogICAgICAgICAgICAgICAgICAgICAgICAuWWVwb2NoMSAgICAgID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgLlllcG9jaDIgICAgICA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgIC5Uc3Bpa2UgICAgICAgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAuVHJhY2VQcm9maWxlID0gMywKICAgICAgICAgICAgICAgICAgICAgICAgLlN0ZHBQcm9maWxlICA9IDEKICAgICAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgICAgbmV1cm9uLT5zdGRwX3Bvc3Rfc3RhdGVbY29tcGFydG1lbnRfaWR4K25fdmFsc10gPSAgICAgICAgICAgICAgICAgICAgIChQb3N0VHJhY2VFbnRyeSkgewogICAgICAgICAgICAgICAgICAgICAgICAuWXNwaWtlMCAgICAgID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgLllzcGlrZTEgICAgICA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgIC5Zc3Bpa2UyICAgICAgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAuWWVwb2NoMCAgICAgID0gYWJzKGVycm9yKSwKICAgICAgICAgICAgICAgICAgICAgICAgLlllcG9jaDEgICAgICA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgIC5ZZXBvY2gyICAgICAgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAuVHNwaWtlICAgICAgID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgLlRyYWNlUHJvZmlsZSA9IDMsCiAgICAgICAgICAgICAgICAgICAgICAgIC5TdGRwUHJvZmlsZSAgPSAwCiAgICAgICAgICAgICAgICAgICAgfTs=' ), # pylint: disable=line-too-long neg_pes_cfg= d(b'bmV1cm9uLT5zdGRwX3Bvc3Rfc3RhdGVbY29tcGFydG1lbnRfaWR4XSA9ICAgICAgICAgICAgICAgICAgICAgKFBvc3RUcmFjZUVudHJ5KSB7CiAgICAgICAgICAgICAgICAgICAgICAgIC5Zc3Bpa2UwICAgICAgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAuWXNwaWtlMSAgICAgID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgLllzcGlrZTIgICAgICA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgIC5ZZXBvY2gwICAgICAgPSBhYnMoZXJyb3IpLAogICAgICAgICAgICAgICAgICAgICAgICAuWWVwb2NoMSAgICAgID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgLlllcG9jaDIgICAgICA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgIC5Uc3Bpa2UgICAgICAgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAuVHJhY2VQcm9maWxlID0gMywKICAgICAgICAgICAgICAgICAgICAgICAgLlN0ZHBQcm9maWxlICA9IDAKICAgICAgICAgICAgICAgICAgICB9OwogICAgICAgICAgICAgICAgbmV1cm9uLT5zdGRwX3Bvc3Rfc3RhdGVbY29tcGFydG1lbnRfaWR4K25fdmFsc10gPSAgICAgICAgICAgICAgICAgICAgIChQb3N0VHJhY2VFbnRyeSkgewogICAgICAgICAgICAgICAgICAgICAgICAuWXNwaWtlMCAgICAgID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgLllzcGlrZTEgICAgICA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgIC5Zc3Bpa2UyICAgICAgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAuWWVwb2NoMCAgICAgID0gYWJzKGVycm9yKSwKICAgICAgICAgICAgICAgICAgICAgICAgLlllcG9jaDEgICAgICA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgIC5ZZXBvY2gyICAgICAgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAuVHNwaWtlICAgICAgID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgLlRyYWNlUHJvZmlsZSA9IDMsCiAgICAgICAgICAgICAgICAgICAgICAgIC5TdGRwUHJvZmlsZSAgPSAxCiAgICAgICAgICAgICAgICAgICAgfTs=' ), # pylint: disable=line-too-long ) # --- write c file using template template = env.get_template("nengo_io.c.template") self.tmp_snip_dir = tempfile.TemporaryDirectory() c_path = os.path.join(self.tmp_snip_dir.name, "nengo_io.c") logger.debug( "Creating %s with %d outputs, %d error, %d cores, %d probes", c_path, n_outputs, n_errors, len(cores), len(probes)) code = template.render( n_outputs=n_outputs, n_errors=n_errors, max_error_len=max_error_len, cores=cores, probes=probes, obfs=obfs, ) with open(c_path, 'w') as f: f.write(code) template = env.get_template("nengo_learn.c.template") code = template.render(obfs=obfs, ) with open(os.path.join(snips_dir, "nengo_learn.c"), "w") as f: f.write(code) # --- create SNIP process and channels logger.debug("Creating nengo_io snip process") nengo_io = d_func(self.nxsdk_board, b'Y3JlYXRlUHJvY2Vzcw==', kwargs={ b'bmFtZQ==': "nengo_io", b'Y0ZpbGVQYXRo': c_path, b'aW5jbHVkZURpcg==': snips_dir, b'ZnVuY05hbWU=': "nengo_io", b'Z3VhcmROYW1l': "guard_io", b'cGhhc2U=': d(b'bWdtdA=='), }) logger.debug("Creating nengo_learn snip process") c_path = os.path.join(self.tmp_snip_dir.name, "nengo_learn.c") shutil.copyfile(os.path.join(snips_dir, "nengo_learn.c"), c_path) d_func(self.nxsdk_board, b'Y3JlYXRlUHJvY2Vzcw==', kwargs={ b'bmFtZQ==': "nengo_learn", b'Y0ZpbGVQYXRo': os.path.join(snips_dir, "nengo_learn.c"), b'aW5jbHVkZURpcg==': snips_dir, b'ZnVuY05hbWU=': "nengo_learn", b'Z3VhcmROYW1l': "guard_learn", b'cGhhc2U=': d(b'cHJlTGVhcm5NZ210'), }) size = ( 1 # first int stores number of spikes + self.snip_max_spikes_per_step * SpikePacker.size() + total_error_len) logger.debug("Creating nengo_io_h2c channel (%d)" % size) self.nengo_io_h2c = d_get(self.nxsdk_board, b'Y3JlYXRlQ2hhbm5lbA==')(b'nengo_io_h2c', "int", size) logger.debug("Creating nengo_io_c2h channel (%d)" % n_outputs) self.nengo_io_c2h = d_get(self.nxsdk_board, b'Y3JlYXRlQ2hhbm5lbA==')(b'nengo_io_c2h', "int", n_outputs) d_get(self.nengo_io_h2c, b'Y29ubmVjdA==')(None, nengo_io) d_get(self.nengo_io_c2h, b'Y29ubmVjdA==')(nengo_io, None) self.nengo_io_h2c_errors = n_errors self.nengo_io_c2h_count = n_outputs self.nengo_io_snip_range = snip_range
def build_axons(nxsdk_core, core, block, axon, compartment_ids, pop_id_map): synapse = axon.target tchip_idx, tcore_idx, tsyn_idxs = core.board.find_synapse(synapse) nxsdk_board = d_get(nxsdk_core, b'cGFyZW50', b'cGFyZW50') tchip_id = d_get(d_get(nxsdk_board, b'bjJDaGlwcw==')[tchip_idx], b'aWQ=') tcore_id = d_get( d_get(d_get(nxsdk_board, b'bjJDaGlwcw==')[tchip_idx], b'bjJDb3Jlcw==')[tcore_idx], b'aWQ=') compartment_idxs = np.arange(len(compartment_ids)) spikes = axon.map_spikes(compartment_idxs) for compartment_id, spike in zip(compartment_ids, spikes): if spike is None: continue # this compartment does not route through these axons taxon_idx = int(spike.axon_id) taxon_id = int(tsyn_idxs[taxon_idx]) atom = int(spike.atom) n_atoms = synapse.axon_populations(taxon_idx) if synapse.pop_type == 0: # discrete assert atom == 0 assert n_atoms == 1 d_func(nxsdk_core, b'Y3JlYXRlRGlzY3JldGVBeG9u', kwargs={ b'c3JjQ3hJZA==': compartment_id, b'ZHN0Q2hpcElk': tchip_id, b'ZHN0Q29yZUlk': tcore_id, b'ZHN0U3luTWFwSWQ=': taxon_id, }) elif synapse.pop_type in (16, 32): n_blocks = len(core.blocks) assert (n_blocks == 0 or (n_blocks == 1 and block is core.blocks[0])) assert len(block.probes) == 0, ( "Probing a block with population axons mixes population and " "discrete axons for compartments, which is not supported.") # pop_id is a unique index for the population. Must be the same for # all axons going to the same target synmap (with different atoms # of course), but otherwise different for all axons. Also, each # compartment can only have axons belonging to one population. if compartment_id not in pop_id_map: # If there's already an axon going to this synmap, use that # pop_id. Otherwise, make a new pop_id pop_key = (tchip_id, tcore_id, taxon_id) if pop_key not in pop_id_map: pop_id = (max(pop_id_map.values()) + 1 if len(pop_id_map) > 0 else 0) pop_id_map[pop_key] = pop_id pop_id_map[compartment_id] = pop_id_map[pop_key] pop_id = pop_id_map[compartment_id] kwargs = { b'cG9wSWQ=': pop_id, b'c3JjQ3hJZA==': compartment_id, b'c3JjUmVsQ3hJZA==': atom, b'ZHN0Q2hpcElk': tchip_id, b'ZHN0Q29yZUlk': tcore_id, b'ZHN0U3luTWFwSWQ=': taxon_id, } if synapse.pop_type == 16: d_func(nxsdk_core, b'Y3JlYXRlUG9wMTZBeG9u', kwargs=kwargs) else: d_func(nxsdk_core, b'Y3JlYXRlUG9wMzJBeG9u', kwargs=kwargs) else: raise BuildError("Axon: unrecognized pop_type: %s" % (synapse.pop_type, ))