예제 #1
0
    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,
                        ))
예제 #2
0
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
예제 #3
0
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)
예제 #4
0
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
예제 #5
0
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)
예제 #6
0
    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)
예제 #7
0
    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
        })
예제 #8
0
    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
        )
예제 #9
0
    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
예제 #10
0
    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
예제 #11
0
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)
예제 #12
0
    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,
                    ))
예제 #13
0
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)
예제 #14
0
 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)
예제 #15
0
    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
예제 #16
0
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"
예제 #17
0
    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
예제 #18
0
    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)
예제 #19
0
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,
                   })
예제 #20
0
    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,
            },
        )
예제 #21
0
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,))
예제 #22
0
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
                },
            )
예제 #23
0
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
                })
예제 #24
0
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)
예제 #25
0
    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
예제 #26
0
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, ))