Пример #1
0
def test_node_neurons(decode_neurons, tolerance, Simulator, seed, plt):
    sim_time = 0.2

    stim_fn = lambda t: 0.9 * np.sin(2 * np.pi * t / sim_time)
    out_synapse = nengo.Alpha(0.03)
    stim_synapse = out_synapse.combine(nengo.Alpha(0.005))

    with nengo.Network(seed=seed) as model:
        stim = nengo.Node(stim_fn)
        a = nengo.Ensemble(n_neurons=100, dimensions=1)
        nengo.Connection(stim, a)

        p_stim = nengo.Probe(stim, synapse=stim_synapse)
        p_a = nengo.Probe(a, synapse=out_synapse)

    build_model = Model()
    build_model.node_neurons = decode_neurons

    with Simulator(model, model=build_model) as sim:
        sim.run(sim_time)

    t = sim.trange()
    target = sim.data[p_stim]
    error = np.abs(sim.data[p_a] - target).mean()

    plt.plot(t, target)
    plt.plot(t, sim.data[p_a])
    plt.ylim([-1.1, 1.1])
    plt.title("error = %0.2e" % error)

    assert error < tolerance
Пример #2
0
def test_bad_gain_error(Simulator):
    with nengo.Network() as net:
        nengo.Ensemble(5, 1, intercepts=nengo.dists.Choice([2.0]))

    model = Model()
    model.intercept_limit = 10.0
    with pytest.raises(BuildError, match="negative.*gain"):
        with Simulator(net, model=model):
            pass
Пример #3
0
def test_add_inputs(decode_neurons, tolerance, Simulator, seed, plt):
    sim_time = 2.0
    pres_time = sim_time / 4
    eval_time = sim_time / 8

    stim_values = [[0.5, 0.5], [0.5, -0.9], [-0.7, -0.3], [-0.3, 1.0]]
    stim_times = np.arange(0, sim_time, pres_time)
    stim_fn_a = nengo.processes.Piecewise(
        {t: stim_values[i][0]
         for i, t in enumerate(stim_times)})
    stim_fn_b = nengo.processes.Piecewise(
        {t: stim_values[i][1]
         for i, t in enumerate(stim_times)})

    with nengo.Network(seed=seed) as model:
        stim_a = nengo.Node(stim_fn_a)
        stim_b = nengo.Node(stim_fn_b)

        a = nengo.Ensemble(n_neurons=100, dimensions=1)
        b = nengo.Ensemble(n_neurons=100, dimensions=1)

        nengo.Connection(stim_a, a)
        nengo.Connection(stim_b, b)

        c = nengo.Ensemble(n_neurons=100, dimensions=1)
        nengo.Connection(a, c)
        nengo.Connection(b, c)

        out_synapse = nengo.Alpha(0.03)
        stim_synapse = out_synapse.combine(nengo.Alpha(0.005)).combine(
            nengo.Alpha(0.005))
        p_stim_a = nengo.Probe(stim_a, synapse=stim_synapse)
        p_stim_b = nengo.Probe(stim_b, synapse=stim_synapse)
        p_c = nengo.Probe(c, synapse=out_synapse)

    build_model = Model()
    build_model.decode_neurons = decode_neurons

    with Simulator(model, model=build_model) as sim:
        sim.run(sim_time)

    t = sim.trange()
    tmask = np.zeros(t.shape, dtype=bool)
    for pres_t in np.arange(0, sim_time, pres_time):
        t0 = pres_t + pres_time - eval_time
        t1 = pres_t + pres_time
        tmask |= (t >= t0) & (t <= t1)

    target = sim.data[p_stim_a] + sim.data[p_stim_b]
    error = np.abs(sim.data[p_c][tmask] - target[tmask]).mean()

    plt.plot(t, target)
    plt.plot(t, sim.data[p_c])
    plt.ylim([-1.1, 1.1])
    plt.title("error = %0.2e" % error)

    assert error < tolerance
Пример #4
0
def test_pes_overflow(plt, seed, Simulator):
    dims = 3
    n_per_dim = 300
    tau = 0.01
    simtime = 0.6
    model, probes = pes_network(
        n_per_dim,
        dims,
        seed,
        learn_synapse=tau,
        input_scale=np.linspace(1, 0.7, dims),
        learning_rule_type=nengo.PES(learning_rate=1e-2),
        period=simtime,
    )

    loihi_model = Model()
    # set learning_wgt_exp low to create overflow in weight values
    loihi_model.pes_wgt_exp = -2

    with Simulator(
            model,
            model=loihi_model,
            hardware_options={"allocator": RoundRobin()},
    ) as loihi_sim:
        loihi_sim.run(simtime)

    t = loihi_sim.trange()
    post_tmask = t > simtime - 0.1

    dec_tau = loihi_sim.model.decode_tau
    y = loihi_sim.data[probes["stim"]]
    y_dpre = nengo.Lowpass(dec_tau).filt(y)
    y_dpost = nengo.Lowpass(tau).combine(nengo.Lowpass(dec_tau)).filt(y_dpre)
    y_loihi = loihi_sim.data[probes["post"]]

    plt.plot(t, y_dpost, "k", label="target")
    plt.plot(t, y_loihi, "g", label="loihi")

    # --- fit output to scaled version of target output
    z_ref0 = y_dpost[post_tmask][:, 0]
    z_loihi = y_loihi[post_tmask]
    scale = np.linspace(0, 1, 50)
    E = np.abs(z_loihi - scale[:, None, None] * z_ref0[:, None])
    errors = E.mean(axis=1)  # average over time (errors is: scales x dims)
    for j in range(dims):
        errors_j = errors[:, j]
        i = np.argmin(errors_j)
        assert errors_j[i] < 0.1, ("Learning output for dim %d did not match "
                                   "any scaled version of the target output" %
                                   j)
        assert scale[i] > 0.25, "Learning output for dim %d is too small" % j
        assert scale[i] < 0.9, (
            "Learning output for dim %d is too large "
            "(weights or traces not clipping as expected)" % j)
Пример #5
0
def _basic_model():
    model = Model()

    block0 = LoihiBlock(1)
    block0.compartment.configure_lif()
    model.add_block(block0)

    block1 = LoihiBlock(1)
    block1.compartment.configure_lif()
    model.add_block(block1)

    axon1 = Axon(1)
    block0.add_axon(axon1)

    synapse1 = Synapse(1)
    synapse1.set_full_weights([[1]])
    axon1.target = synapse1
    block1.add_synapse(synapse1)

    axon0 = Axon(1)
    input = LoihiInput()
    input.add_axon(axon0)
    model.add_input(input)

    synapse0 = Synapse(1)
    synapse0.set_full_weights([[1]])
    axon0.target = synapse0
    block0.add_synapse(synapse0)

    discretize_model(model)

    return model
Пример #6
0
def test_intercept_limit(passed_intercepts, rng):
    model = Model()
    assert model.intercept_limit == 0.95

    ens = nengo.Ensemble(10000, 1, intercepts=passed_intercepts, add_to_container=False)
    with pytest.warns(UserWarning):
        _, _, _, intercepts = get_gain_bias(ens, rng, model.intercept_limit)
    assert np.all(intercepts <= model.intercept_limit)
Пример #7
0
def test_builder_poptype_errors():
    pytest.importorskip("nxsdk")

    # Test error in build_synapse
    model = Model()
    block = LoihiBlock(1)
    block.compartment.configure_lif()
    model.add_block(block)

    synapse = Synapse(1)
    synapse.set_weights([[1]])
    synapse.pop_type = 8
    block.add_synapse(synapse)

    discretize_model(model)

    allocator = Greedy()  # one core per ensemble
    board = allocator(model, n_chips=1)

    with pytest.raises(ValueError, match="[Ss]ynapse.*[Uu]nrec.*pop.*type"):
        build_board(board)

    # Test error in collect_axons
    model = Model()
    block0 = LoihiBlock(1)
    block0.compartment.configure_lif()
    model.add_block(block0)
    block1 = LoihiBlock(1)
    block1.compartment.configure_lif()
    model.add_block(block1)

    axon = Axon(1)
    block0.add_axon(axon)

    synapse = Synapse(1)
    synapse.set_weights([[1]])
    synapse.pop_type = 8
    axon.target = synapse
    block1.add_synapse(synapse)

    discretize_model(model)

    board = allocator(model, n_chips=1)

    with pytest.raises(ValueError, match="[Aa]xon.*[Uu]nrec.*pop.*type"):
        build_board(board)
Пример #8
0
def test_strict_mode(strict, monkeypatch):
    # Tests should be run in strict mode
    assert EmulatorInterface.strict

    model = Model()
    model.add_block(LoihiBlock(1))

    monkeypatch.setattr(EmulatorInterface, "strict", strict)
    emu = EmulatorInterface(model)
    assert emu.strict == strict

    if strict:
        check = pytest.raises(SimulationError, match="Error in emulator")
    else:
        check = pytest.warns(UserWarning)

    with check:
        emu.compartment.error("Error in emulator")
Пример #9
0
def test_build_callback(Simulator):
    with nengo.Network() as net:
        a = nengo.Ensemble(3, 1)
        b = nengo.Ensemble(3, 1)
        c = nengo.Connection(a, b)

    objs = []

    def build_callback(obj):
        objs.append(obj)

    model = Model()
    model.build_callback = build_callback
    with Simulator(net, model=model):
        pass

    for obj in (a, b, c):
        assert obj in objs, "%s not in objs" % obj
Пример #10
0
def test_utilization():
    comp_fracs = [0.9, 0.2, 0.35]

    model = Model()

    for comp_frac in comp_fracs:
        n_compartments = int(round(comp_frac * MAX_COMPARTMENTS))
        block = LoihiBlock(n_compartments)
        block.compartment.configure_relu()
        model.add_block(block)

        util = block.utilization()
        assert np.allclose(
            util["compartments"], (n_compartments, MAX_COMPARTMENTS), rtol=0, atol=0.001
        )

    lines = model.utilization_summary()
    assert len(lines) == len(comp_fracs) + 1
    assert lines[-1].startswith("Average")
Пример #11
0
def _basic_model(n_blocks=2):
    model = Model()

    blocks = []
    for _ in range(n_blocks):
        block = LoihiBlock(1)
        block.compartment.configure_lif()
        model.add_block(block)
        blocks.append(block)

    for i in range(n_blocks - 1):
        axon = Axon(1)
        blocks[i].add_axon(axon)

        synapse = Synapse(1)
        synapse.set_weights([[1]])
        axon.target = synapse
        blocks[i + 1].add_synapse(synapse)

    axon0 = Axon(1)
    input = LoihiInput()
    input.add_axon(axon0)
    model.add_input(input)

    synapse0 = Synapse(1)
    synapse0.set_weights([[1]])
    axon0.target = synapse0
    blocks[0].add_synapse(synapse0)

    discretize_model(model)

    return model
Пример #12
0
def test_negative_base(request, seed):
    n_axons = 3

    model = Model()

    input = SpikeInput(n_axons)
    input.add_spikes(1, list(range(n_axons)), permanent=True)
    model.add_input(input)

    axon = Axon(n_axons)
    input.add_axon(axon)

    block = LoihiBlock(3)
    block.compartment.configure_relu()
    model.add_block(block)

    synapse = Synapse(n_axons)
    weights = [0.1, 0.1, 0.1]
    indices = [0, 1, 2]
    axon_to_weight_map = list(range(n_axons))
    bases = [0, 1, -1]
    synapse.set_population_weights(
        weights, indices, axon_to_weight_map, bases, pop_type=32
    )
    axon.target = synapse
    block.add_synapse(synapse)

    probe = LoihiProbe(target=block, key="voltage")
    model.add_probe(probe)

    discretize_model(model)

    n_steps = 2
    if request.config.getoption("--target") == "loihi":
        with HardwareInterface(model, use_snips=False, seed=seed) as sim:
            sim.run_steps(n_steps)
            y = sim.collect_probe_output(probe)
    else:
        with EmulatorInterface(model, seed=seed) as sim:
            sim.run_steps(n_steps)
            y = sim.collect_probe_output(probe)

    # Compartments 0 and 2 should change from axons 0 and 1.
    # Axon 2 should have no effect, and not change compartment 1 (the sum of
    # its base and index), or other compartments (e.g. 2 if base ignored)
    assert np.allclose(y[1, 1], 0), "Third axon not ignored"
    assert np.allclose(y[1, 0], y[1, 2]), "Third axon targeting another"
    assert not np.allclose(y[1], y[0]), "Voltage not changing"
Пример #13
0
def test_noise_amplitude_warnings(Simulator, seed):
    with nengo.Network(seed=seed) as net:
        a = nengo.Ensemble(5, 1)
        b = nengo.Ensemble(5, 1)
        nengo.Connection(a, b)

    model = Model()
    model.decode_neurons = NoisyDecodeNeurons(10, noise_exp=5)
    with pytest.warns(UserWarning, match="[Nn]oise.*exceeds.*upper"):
        with Simulator(net, model=model):
            pass

    model = Model()
    model.decode_neurons = NoisyDecodeNeurons(10, noise_exp=-7)
    with pytest.warns(UserWarning, match="[Nn]oise.*below.*lower"):
        with Simulator(net, model=model):
            pass
Пример #14
0
class Simulator(object):
    """Nengo Loihi simulator for Loihi hardware and emulator.

    The simulator takes a `nengo.Network` and builds internal data structures
    to run the model defined by that network on Loihi emulator or hardware.
    Run the simulator with the `.Simulator.run` method, and access probed data
    through the ``data`` attribute.

    Building and running the simulation allocates resources. To properly free
    these resources, call the `.Simulator.close` method. Alternatively,
    `.Simulator.close` will automatically be called if you use
    ``with`` syntax::

        with nengo_loihi.Simulator(my_network) as sim:
            sim.run(0.1)
        print(sim.data[my_probe])

    Note that the ``data`` attribute is still accessible even when a simulator
    has been closed. Running the simulator, however, will raise an error.

    Parameters
    ----------
    network : Network or None
        A network object to be built and then simulated. If None,
        then the *model* parameter must be provided instead.
    dt : float, optional (Default: 0.001)
        The length of a simulator timestep, in seconds.
    seed : int, optional (Default: None)
        A seed for all stochastic operators used in this simulator.
        Will be set to ``network.seed + 1`` if not given.
    model : Model, optional (Default: None)
        A `.Model` that contains build artifacts to be simulated.
        Usually the simulator will build this model for you; however, if you
        want to build the network manually, or you want to inject build
        artifacts in the model before building the network, then you can
        pass in a `.Model` instance.
    precompute : bool, optional (Default: True)
        Whether model inputs should be precomputed to speed up simulation.
        When *precompute* is False, the simulator will be run one step
        at a time in order to use model outputs as inputs in other parts
        of the model.
    target : str, optional (Default: None)
        Whether the simulator should target the emulator (``'sim'``) or
        Loihi hardware (``'loihi'``). If None, *target* will default to
        ``'loihi'`` if NxSDK is installed, and the emulator if it is not.

    Attributes
    ----------
    closed : bool
        Whether the simulator has been closed.
        Once closed, it cannot be reopened.
    data : ProbeDict
        The dictionary mapping from Nengo objects to the data associated
        with those objects. In particular, each `nengo.Probe` maps to
        the data probed while running the simulation.
    model : Model
        The `.Model` containing the data structures necessary for
        simulating the network.
    precompute : bool
        Whether model inputs should be precomputed to speed up simulation.
        When *precompute* is False, the simulator will be run one step
        at a time in order to use model outputs as inputs in other parts
        of the model.

    """

    # 'unsupported' defines features unsupported by a simulator.
    # The format is a list of tuples of the form `(test, reason)` with `test`
    # being a string with wildcards (*, ?, [abc], [!abc]) matched against Nengo
    # test paths and names, and `reason` is a string describing why the feature
    # is not supported by the backend. For example:
    #     unsupported = [('test_pes*', 'PES rule not implemented')]
    # would skip all tests whose names start with 'test_pes'.
    unsupported = [
        # no ensembles on chip
        ('test_circularconv.py:*', "no ensembles onchip"),
        ('test_product.py:test_direct_mode_with_single_neuron',
         "no ensembles onchip"),
        ('test_connection.py:test_neuron_slicing', "no ensembles onchip"),
        ('test_connection.py:test_boolean_indexing', "no ensembles onchip"),
        ('test_learning_rules.py:test_pes_synapse*', "no ensembles onchip"),
        ('test_learning_rules.py:test_pes_recurrent_slice*',
         "no ensembles onchip"),
        ('test_neurons.py:test_amplitude[[]LIFRate[]]', "no ensembles onchip"),
        ('test_neurons.py:test_amplitude[[]RectifiedLinear[]]',
         "no ensembles onchip"),
        ('test_neurons.py:test_alif_rate', "no ensembles onchip"),
        ('test_neurons.py:test_izhikevich', "no ensembles onchip"),
        ('test_neurons.py:test_sigmoid_response_curves*',
         "no ensembles onchip"),
        ('test_node.py:test_[!i]*', "no ensembles onchip"),
        ('test_probe.py:test_multirun', "no ensembles onchip"),
        ('test_probe.py:test_dts', "no ensembles onchip"),
        ('test_probe.py:test_large', "no ensembles onchip"),
        ('test_probe.py:test_conn_output', "no ensembles onchip"),
        ('test_processes.py:test_time', "no ensembles onchip"),
        ('test_processes.py:test_brownnoise', "no ensembles onchip"),
        ('test_processes.py:test_gaussian_white*', "no ensembles onchip"),
        ('test_processes.py:test_whitesignal*', "no ensembles onchip"),
        ('test_processes.py:test_reset', "no ensembles onchip"),
        ('test_processes.py:test_seed', "no ensembles onchip"),
        ('test_processes.py:test_present_input', "no ensembles onchip"),
        ('test_processes.py:TestPiecewise*', "no ensembles onchip"),
        ('test_simulator.py:test_steps', "no ensembles onchip"),
        ('test_simulator.py:test_time_absolute', "no ensembles onchip"),
        ('test_simulator.py:test_trange*', "no ensembles onchip"),
        ('test_simulator.py:test_probe_cache', "no ensembles onchip"),
        ('test_simulator.py:test_invalid_run_time', "no ensembles onchip"),
        ('test_simulator.py:test_sample_every*', "no ensembles onchip"),
        ('test_synapses.py:test_lowpass', "no ensembles onchip"),
        ('test_synapses.py:test_alpha', "no ensembles onchip"),
        ('test_synapses.py:test_triangle', "no ensembles onchip"),
        ('test_synapses.py:test_linearfilter', "no ensembles onchip"),
        ('utils/*test_ensemble.py:test_*_curves_direct_mode*',
         "no ensembles onchip"),
        ('utils/*test_network.py:*direct_mode_learning[learning_rule[123]*',
         "no ensembles onchip"),
        ('utils/*test_neurons.py:test_rates_*', "no ensembles onchip"),

        # accuracy
        ('test_actionselection.py:test_basic', "inaccurate"),
        ('test_am_[!s]*', "integrator instability"),
        ('test_ensemblearray.py:test_matrix_mul', "inaccurate"),
        ('test_product.py:test_sine_waves', "inaccurate"),
        ('test_workingmemory.py:test_inputgatedmemory', "inaccurate"),
        ('test_cortical.py:test_convolution', "inaccurate"),
        ('test_thalamus.py:test_routing', "inaccurate"),
        ('test_thalamus.py:test_nondefault_routing', "inaccurate"),
        ('test_connection.py:test_node_to_ensemble*', "inaccurate"),
        ('test_connection.py:test_neurons_to_node*', "inaccurate"),
        ('test_connection.py:test_function_and_transform', "inaccurate"),
        ('test_connection.py:test_weights*', "inaccurate"),
        ('test_connection.py:test_vector*', "inaccurate"),
        ('test_connection.py:test_slicing*', "inaccurate"),
        ('test_connection.py:test_function_output_size', "inaccurate"),
        ('test_connection.py:test_function_points', "inaccurate"),
        ('test_ensemble.py:test_scalar*', "inaccurate"),
        ('test_ensemble.py:test_vector*', "inaccurate"),
        ('test_learning_rules.py:test_pes_transform', "inaccurate"),
        ('test_learning_rules.py:test_slicing', "inaccurate"),
        ('test_neurons.py:test_alif', "inaccurate"),
        ('test_neurons.py:test_amplitude[[]LIF[]]', "inaccurate"),
        ('test_neurons.py:test_amplitude[[]SpikingRectifiedLinear[]]',
         "inaccurate"),
        ('test_presets.py:test_thresholding_preset', "inaccurate"),
        ('test_synapses.py:test_decoders', "inaccurate"),
        ('test_actionselection.py:test_basic', "inaccurate"),
        ('test_actionselection.py:test_thalamus', "inaccurate"),

        # builder inconsistencies
        ('test_connection.py:test_neurons_to_ensemble*',
         "transform shape not implemented"),
        ('test_connection.py:test_transform_probe',
         "transform shape not implemented"),
        ('test_connection.py:test_list_indexing*', "indexing bug?"),
        ('test_connection.py:test_prepost_errors', "learning bug?"),
        ('test_ensemble.py:test_gain_bias_warning', "warning not raised"),
        ('test_ensemble.py:*invalid_intercepts*', "BuildError not raised"),
        ('test_learning_rules.py:test_pes_ens_*', "learning bug?"),
        ('test_learning_rules.py:test_pes_weight_solver', "learning bug?"),
        ('test_learning_rules.py:test_pes_neuron_*', "learning bug?"),
        ('test_learning_rules.py:test_pes_multidim_error',
         "dict of learning rules not handled"),
        ('test_learning_rules.py:test_reset*', "learning bug?"),
        ('test_neurons.py:test_lif_min_voltage*', "lif.min_voltage ignored"),
        ('test_neurons.py:test_lif_zero_tau_ref', "lif.tau_ref ignored"),
        ('test_probe.py:test_input_probe', "shape mismatch"),
        ('test_probe.py:test_slice', "ObjView not handled properly"),
        ('test_probe.py:test_update_timing', "probe bug?"),
        ('test_solvers.py:test_nosolver*', "NoSolver bug"),

        # reset bugs
        ('test_neurons.py:test_reset*', "sim.reset not working correctly"),

        # non-PES learning rules
        ('test_learning_rules.py:test_unsupervised*',
         "non-PES learning rules not implemented"),
        ('test_learning_rules.py:test_dt_dependence*',
         "non-PES learning rules not implemented"),
        ('*voja*', "voja not implemented"),
        ('test_learning_rules.py:test_custom_type',
         "non-PES learning rules not implemented"),

        # Nengo bug
        ('test_simulator.py:test_entry_point',
         "logic should be more flexible"),

        # ensemble noise
        ('test_ensemble.py:test_noise*', "ensemble.noise not implemented"),

        # probe types
        ('test_connection.py:test_dist_transform',
         "probe type not implemented"),
        ('test_connection.py:test_decoder_probe',
         "probe type not implemented"),
        ('test_probe.py:test_defaults', "probe type not implemented"),
        ('test_probe.py:test_ensemble_encoders', "probe type not implemented"),

        # probe.sample_every
        ('test_integrator.py:test_integrator',
         "probe.sample_every not implemented"),
        ('test_oscillator.py:test_oscillator',
         "probe.sample_every not implemented"),
        ('test_ensemble.py:test_product*',
         "probe.sample_every not implemented"),
        ('test_neurons.py:test_dt_dependence*',
         "probe.sample_every not implemented"),
        ('test_probe.py:test_multiple_probes',
         "probe.sample_every not implemented"),

        # needs better place and route
        ('test_ensemble.py:test_eval_points_heuristic*',
         "max number of compartments exceeded"),
        ('test_neurons.py:test_lif*', "idxBits out of range"),
        ('test_basalganglia.py:test_basal_ganglia',
         "output_axons exceedecd max"),
        ('test_cortical.py:test_connect', "total synapse bits exceeded max"),
        ('test_cortical.py:test_transform', "total synapse bits exceeded max"),
        ('test_cortical.py:test_translate', "total synapse bits exceeded max"),
        ('test_memory.py:test_run', "total synapse bits exceeded max"),
        ('test_memory.py:test_run_decay', "total synapse bits exceeded max"),
        ('test_state.py:test_memory_run', "total synapse bits exceeded max"),
        ('test_state.py:test_memory_run_decay',
         "total synapse bits exceeded max"),
        ('test_bind.py:test_run', "exceeded max cores per chip on loihi"),

        # serialization / deserialization
        ('test_cache.py:*', "model pickling not implemented"),
        ('test_copy.py:test_pickle_model', "model pickling not implemented"),
        ('test_simulator.py:test_signal_init_values',
         "nengo.builder.Model instances not handled"),

        # progress bars
        ('test_simulator.py:test_simulator_progress_bars',
         "progress bars not implemented"),

        # utils.connection.target_function (deprecated)
        ('utils/tests/test_connection.py*',
         "target_function (deprecated) not working"),

        # removing passthroughs changes test behaviour
        ('test_connection.py:test_zero_activities_error',
         "decoded connection optimized away"),
        ('test_connection.py:test_function_returns_none_error',
         "decoded connection optimized away"),
    ]

    def __init__(  # noqa: C901
            self,
            network,
            dt=0.001,
            seed=None,
            model=None,
            precompute=False,
            target=None,
            progress_bar=None,
            remove_passthrough=True
    ):
        self.closed = True  # Start closed in case constructor raises exception
        if progress_bar is not None:
            raise NotImplementedError("progress bars not implemented")

        if model is None:
            # Call the builder to make a model
            self.model = Model(dt=float(dt), label="%s, dt=%f" % (network, dt))
        else:
            assert isinstance(model, Model), (
                "model is not type 'nengo_loihi.builder.Model'")
            self.model = model
            assert self.model.dt == dt

        max_rate = self.model.inter_rate * self.model.inter_n
        rtol = 1e-8  # allow for floating point inaccuracies
        if max_rate > (1. / self.dt) * (1 + rtol):
            raise BuildError("Simulator `dt` must be <= %s (got %s)"
                             % (1. / max_rate, self.dt))
        self.precompute = precompute
        self.networks = None
        self.sims = OrderedDict()
        self._run_steps = None

        if network is not None:
            nengo.rc.set("decoder_cache", "enabled", "False")
            config.add_params(network)

            # split the host into one, two or three networks
            self.networks = split(
                network,
                precompute,
                max_rate,
                self.model.inter_tau,
                remove_passthrough=remove_passthrough,
            )
            network = self.networks.chip

            self.model.chip2host_params = self.networks.chip2host_params

            self.chip = self.networks.chip
            self.host = self.networks.host
            self.host_pre = self.networks.host_pre

            if len(self.host_pre.all_objects) > 0:
                self.sims["host_pre"] = nengo.Simulator(self.host_pre,
                                                        dt=self.dt,
                                                        progress_bar=False,
                                                        optimize=False)

            if len(self.host.all_objects) > 0:
                self.sims["host"] = nengo.Simulator(
                    self.host, dt=self.dt, progress_bar=False, optimize=False)
            elif not precompute:
                # If there is no host and precompute=False, then all objects
                # must be on the chip, which is precomputable in the sense that
                # no communication has to happen with the host.
                # We could warn about this, but we want to avoid people having
                # to specify `precompute` unless they absolutely have to.
                self.precompute = True

            # Build the network into the model
            self.model.build(network)

        self._probe_outputs = self.model.params
        self.data = ProbeDict(self._probe_outputs)
        for sim in self.sims.values():
            self.data.add_fallback(sim.data)

        if seed is None:
            if network is not None and network.seed is not None:
                seed = network.seed + 1
            else:
                seed = np.random.randint(npext.maxint)

        if target is None:
            try:
                import nxsdk
                target = 'loihi'
            except ImportError:
                target = 'sim'
        self.target = target

        logger.info("Simulator target is %r", target)
        logger.info("Simulator precompute is %r", self.precompute)

        if target != "simreal":
            self.model.discretize()

        if target in ("simreal", "sim"):
            self.sims["emulator"] = CxSimulator(self.model, seed=seed)
        elif target == 'loihi':
            self.sims["loihi"] = LoihiSimulator(
                self.model, use_snips=not self.precompute, seed=seed)
        else:
            raise ValidationError("Must be 'simreal', 'sim', or 'loihi'",
                                  attr="target")

        assert "emulator" in self.sims or "loihi" in self.sims

        self.closed = False
        self.reset(seed=seed)

    def __del__(self):
        """Raise a ResourceWarning if we are deallocated while open."""
        if not self.closed:
            warnings.warn(
                "Simulator with model=%s was deallocated while open. Please "
                "close simulators manually to ensure resources are properly "
                "freed." % self.model, ResourceWarning)

    def __enter__(self):
        for sim in self.sims.values():
            sim.__enter__()
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        for sim in self.sims.values():
            sim.__exit__(exc_type, exc_value, traceback)
        self.close()

    @property
    def dt(self):
        """(float) The step time of the simulator."""
        return self.model.dt

    @dt.setter
    def dt(self, dummy):
        raise ReadonlyError(attr='dt', obj=self)

    @property
    def n_steps(self):
        """(int) The current time step of the simulator."""
        return self._n_steps

    @property
    def time(self):
        """(float) The current time of the simulator."""
        return self._time

    def close(self):
        """Closes the simulator.

        Any call to `.Simulator.run`, `.Simulator.run_steps`,
        `.Simulator.step`, and `.Simulator.reset` on a closed simulator raises
        a ``SimulatorClosed`` exception.
        """

        for sim in self.sims.values():
            if not sim.closed:
                sim.close()
        self.closed = True

    def _probe(self):
        """Copy all probed signals to buffers."""
        self._probe_step_time()

        for probe in self.model.probes:
            if probe in self.networks.chip2host_params:
                continue
            assert probe.sample_every is None, (
                "probe.sample_every not implemented")
            assert ("loihi" not in self.sims
                    or "emulator" not in self.sims)
            cx_probe = self.model.objs[probe]['out']
            if "loihi" in self.sims:
                data = self.sims["loihi"].get_probe_output(cx_probe)
            elif "emulator" in self.sims:
                data = self.sims["emulator"].get_probe_output(cx_probe)
            # TODO: stop recomputing this all the time
            del self._probe_outputs[probe][:]
            self._probe_outputs[probe].extend(data)
            assert len(self._probe_outputs[probe]) == self.n_steps, (
                len(self._probe_outputs[probe]), self.n_steps)

    def _probe_step_time(self):
        self._time = self._n_steps * self.dt

    def reset(self, seed=None):
        """Reset the simulator state.

        Parameters
        ----------
        seed : int, optional
            A seed for all stochastic operators used in the simulator.
            This will change the random sequences generated for noise
            or inputs (e.g. from processes), but not the built objects
            (e.g. ensembles, connections).
        """
        if self.closed:
            raise SimulatorClosed("Cannot reset closed Simulator.")

        if seed is not None:
            self.seed = seed

        self._n_steps = 0
        self._time = 0

        # clear probe data
        for probe in self.model.probes:
            self._probe_outputs[probe] = []
        self.data.reset()

    def run(self, time_in_seconds):
        """Simulate for the given length of time.

        If the given length of time is not a multiple of ``dt``,
        it will be rounded to the nearest ``dt``. For example, if ``dt``
        is 0.001 and ``run`` is called with ``time_in_seconds=0.0006``,
        the simulator will advance one timestep, resulting in the actual
        simulator time being 0.001.

        The given length of time must be positive. The simulator cannot
        be run backwards.

        Parameters
        ----------
        time_in_seconds : float
            Amount of time to run the simulation for. Must be positive.
        """
        if time_in_seconds < 0:
            raise ValidationError("Must be positive (got %g)"
                                  % (time_in_seconds,), attr="time_in_seconds")

        steps = int(np.round(float(time_in_seconds) / self.dt))

        if steps == 0:
            warnings.warn("%g results in running for 0 timesteps. Simulator "
                          "still at time %g." % (time_in_seconds, self.time))
        else:
            logger.info("Running %s for %f seconds, or %d steps",
                        self.model.label, time_in_seconds, steps)
            self.run_steps(steps)

    def step(self):
        """Advance the simulator by 1 step (``dt`` seconds)."""
        self.run_steps(1)

    def _collect_receiver_info(self):
        spikes = []
        errors = {}
        for sender, receiver in self.networks.host2chip_senders.items():
            receiver.clear()
            for t, x in sender.queue:
                receiver.receive(t, x)
            del sender.queue[:]

            if hasattr(receiver, 'collect_spikes'):
                for cx_spike_input, t, spike_idxs in receiver.collect_spikes():
                    ti = round(t / self.model.dt)
                    spikes.append((cx_spike_input, ti, spike_idxs))
            if hasattr(receiver, 'collect_errors'):
                for probe, t, e in receiver.collect_errors():
                    conn = self.model.probe_conns[probe]
                    synapses = self.model.objs[conn]['decoders']
                    assert synapses.tracing
                    ti = round(t / self.model.dt)
                    errors_ti = errors.setdefault(ti, {})
                    if synapses in errors_ti:
                        errors_ti[synapses] += e
                    else:
                        errors_ti[synapses] = e.copy()

        errors = [(synapses, ti, e) for ti, ee in errors.items()
                  for synapses, e in ee.items()]
        return spikes, errors

    def _host2chip(self, sim):
        spikes, errors = self._collect_receiver_info()
        sim.host2chip(spikes, errors)

    def _chip2host(self, sim):
        probes_receivers = {  # map cx_probes to receivers
            self.model.objs[probe]['out']: receiver
            for probe, receiver in self.networks.chip2host_receivers.items()}
        sim.chip2host(probes_receivers)

    def _make_run_steps(self):
        if self._run_steps is not None:
            return
        assert "emulator" not in self.sims or "loihi" not in self.sims
        if "emulator" in self.sims:
            self._make_emu_run_steps()
        else:
            self._make_loihi_run_steps()

    def _make_emu_run_steps(self):
        host_pre = self.sims.get("host_pre", None)
        emulator = self.sims["emulator"]
        host = self.sims.get("host", None)

        if self.precompute:
            if host_pre is not None and host is not None:

                def emu_precomputed_host_pre_and_host(steps):
                    host_pre.run_steps(steps)
                    self._host2chip(emulator)
                    emulator.run_steps(steps)
                    self._chip2host(emulator)
                    host.run_steps(steps)
                self._run_steps = emu_precomputed_host_pre_and_host

            elif host_pre is not None:

                def emu_precomputed_host_pre_only(steps):
                    host_pre.run_steps(steps)
                    self._host2chip(emulator)
                    emulator.run_steps(steps)
                self._run_steps = emu_precomputed_host_pre_only

            elif host is not None:

                def emu_precomputed_host_only(steps):
                    emulator.run_steps(steps)
                    self._chip2host(emulator)
                    host.run_steps(steps)
                self._run_steps = emu_precomputed_host_only

            else:
                self._run_steps = emulator.run_steps

        else:
            assert host is not None, "Model is precomputable"

            def emu_bidirectional_with_host(steps):
                for _ in range(steps):
                    host.step()
                    self._host2chip(emulator)
                    emulator.step()
                    self._chip2host(emulator)
            self._run_steps = emu_bidirectional_with_host

    def _make_loihi_run_steps(self):
        host_pre = self.sims.get("host_pre", None)
        loihi = self.sims["loihi"]
        host = self.sims.get("host", None)

        if self.precompute:
            if host_pre is not None and host is not None:

                def loihi_precomputed_host_pre_and_host(steps):
                    host_pre.run_steps(steps)
                    self._host2chip(loihi)
                    loihi.run_steps(steps, blocking=True)
                    self._chip2host(loihi)
                    host.run_steps(steps)
                self._run_steps = loihi_precomputed_host_pre_and_host

            elif host_pre is not None:

                def loihi_precomputed_host_pre_only(steps):
                    host_pre.run_steps(steps)
                    self._host2chip(loihi)
                    loihi.run_steps(steps, blocking=True)
                self._run_steps = loihi_precomputed_host_pre_only

            elif host is not None:

                def loihi_precomputed_host_only(steps):
                    loihi.run_steps(steps, blocking=True)
                    self._chip2host(loihi)
                    host.run_steps(steps)
                self._run_steps = loihi_precomputed_host_only

            else:
                self._run_steps = loihi.run_steps

        else:
            assert host is not None, "Model is precomputable"

            def loihi_bidirectional_with_host(steps):
                loihi.run_steps(steps, blocking=False)
                for _ in range(steps):
                    host.step()
                    self._host2chip(loihi)
                    self._chip2host(loihi)
                logger.info("Waiting for run_steps to complete...")
                loihi.wait_for_completion()
                logger.info("run_steps completed")
            self._run_steps = loihi_bidirectional_with_host

    def run_steps(self, steps):
        """Simulate for the given number of ``dt`` steps.

        Parameters
        ----------
        steps : int
            Number of steps to run the simulation for.
        """
        if self.closed:
            raise SimulatorClosed("Simulator cannot run because it is closed.")
        if self._run_steps is None:
            self._make_run_steps()
        try:
            self._run_steps(steps)
        except Exception:
            if "loihi" in self.sims and self.sims["loihi"].use_snips:
                # Need to write to board, otherwise it will wait indefinitely
                h2c = self.sims["loihi"].nengo_io_h2c
                c2h = self.sims["loihi"].nengo_io_c2h

                print(traceback.format_exc())
                print("\nAttempting to end simulation...")

                for _ in range(steps):
                    h2c.write(h2c.numElements, [0] * h2c.numElements)
                    c2h.read(c2h.numElements)
                self.sims["loihi"].wait_for_completion()
                self.sims["loihi"].n2board.nxDriver.stopExecution()
                self.sims["loihi"].n2board.nxDriver.stopDriver()
            raise

        self._n_steps += steps
        logger.info("Finished running for %d steps", steps)
        self._probe()

    def trange(self, sample_every=None, dt=None):
        """Create a vector of times matching probed data.

        Note that the range does not start at 0 as one might expect, but at
        the first timestep (i.e., ``dt``).

        Parameters
        ----------
        sample_every : float, optional (Default: None)
            The sampling period of the probe to create a range for.
            If None, a time value for every ``dt`` will be produced.
        """
        period = 1 if sample_every is None else sample_every / self.dt
        steps = np.arange(1, self.n_steps + 1)
        return self.dt * steps[steps % period < 1]
Пример #15
0
    def __init__(  # noqa: C901
            self,
            network,
            dt=0.001,
            seed=None,
            model=None,
            precompute=False,
            target=None,
            progress_bar=None,
            remove_passthrough=True
    ):
        self.closed = True  # Start closed in case constructor raises exception
        if progress_bar is not None:
            raise NotImplementedError("progress bars not implemented")

        if model is None:
            # Call the builder to make a model
            self.model = Model(dt=float(dt), label="%s, dt=%f" % (network, dt))
        else:
            assert isinstance(model, Model), (
                "model is not type 'nengo_loihi.builder.Model'")
            self.model = model
            assert self.model.dt == dt

        max_rate = self.model.inter_rate * self.model.inter_n
        rtol = 1e-8  # allow for floating point inaccuracies
        if max_rate > (1. / self.dt) * (1 + rtol):
            raise BuildError("Simulator `dt` must be <= %s (got %s)"
                             % (1. / max_rate, self.dt))
        self.precompute = precompute
        self.networks = None
        self.sims = OrderedDict()
        self._run_steps = None

        if network is not None:
            nengo.rc.set("decoder_cache", "enabled", "False")
            config.add_params(network)

            # split the host into one, two or three networks
            self.networks = split(
                network,
                precompute,
                max_rate,
                self.model.inter_tau,
                remove_passthrough=remove_passthrough,
            )
            network = self.networks.chip

            self.model.chip2host_params = self.networks.chip2host_params

            self.chip = self.networks.chip
            self.host = self.networks.host
            self.host_pre = self.networks.host_pre

            if len(self.host_pre.all_objects) > 0:
                self.sims["host_pre"] = nengo.Simulator(self.host_pre,
                                                        dt=self.dt,
                                                        progress_bar=False,
                                                        optimize=False)

            if len(self.host.all_objects) > 0:
                self.sims["host"] = nengo.Simulator(
                    self.host, dt=self.dt, progress_bar=False, optimize=False)
            elif not precompute:
                # If there is no host and precompute=False, then all objects
                # must be on the chip, which is precomputable in the sense that
                # no communication has to happen with the host.
                # We could warn about this, but we want to avoid people having
                # to specify `precompute` unless they absolutely have to.
                self.precompute = True

            # Build the network into the model
            self.model.build(network)

        self._probe_outputs = self.model.params
        self.data = ProbeDict(self._probe_outputs)
        for sim in self.sims.values():
            self.data.add_fallback(sim.data)

        if seed is None:
            if network is not None and network.seed is not None:
                seed = network.seed + 1
            else:
                seed = np.random.randint(npext.maxint)

        if target is None:
            try:
                import nxsdk
                target = 'loihi'
            except ImportError:
                target = 'sim'
        self.target = target

        logger.info("Simulator target is %r", target)
        logger.info("Simulator precompute is %r", self.precompute)

        if target != "simreal":
            self.model.discretize()

        if target in ("simreal", "sim"):
            self.sims["emulator"] = CxSimulator(self.model, seed=seed)
        elif target == 'loihi':
            self.sims["loihi"] = LoihiSimulator(
                self.model, use_snips=not self.precompute, seed=seed)
        else:
            raise ValidationError("Must be 'simreal', 'sim', or 'loihi'",
                                  attr="target")

        assert "emulator" in self.sims or "loihi" in self.sims

        self.closed = False
        self.reset(seed=seed)
Пример #16
0
def test_pop_tiny(pop_type, channels_last, nc, request, plt, seed, allclose):
    tau_rc = 0.02
    tau_ref = 0.001
    tau_s = 0.0
    dt = 0.001

    neuron_bias = 1.

    pres_time = 0.4

    sti, stj = 1, 1

    if nc == 1:
        filters = np.array([[-0.5, 2., -0.25], [-0.75, 2., -1.0],
                            [-0.5, 3., -0.5], [-1.0, 6.,
                                               -0.25]]).reshape(1, 4, 1, 3)

        inp_biases = np.array([[1, 5, 1], [2, 1, 2]])
        inp_biases = inp_biases[:, :, None]
    elif nc == 2:
        filters = np.array([[[-0.5, 2., -0.2], [-0.7, 2., -1.0],
                             [-0.5, 3., -0.5], [-1.0, 6., -0.2]],
                            [[-1.0, 2., -1.0], [-0.5, 2., -0.5],
                             [-0.8, 3., -0.2], [-1.0, 4.,
                                                -0.2]]]).reshape(2, 4, 1, 3)

        inp_biases = np.array([[[1, 5, 1], [2, 1, 2]], [[0, 3, 1], [4, 2, 1]]])
        inp_biases = np.transpose(inp_biases, (1, 2, 0))

    # rearrange to (kernel_rows, kernel_cols, in_channels, out_channels)
    filters = np.transpose(filters, (2, 3, 0, 1))

    inp_biases = inp_biases / (inp_biases.max() + 0.001)

    # --- compute nengo_loihi outputs
    ni, nj, nk = inp_biases.shape
    si, sj, nc, nf = filters.shape
    nij = ni * nj
    nyi = 1 + (ni - si) // sti
    nyj = 1 + (nj - sj) // stj
    out_size = nyi * nyj * nf
    assert out_size <= 1024

    model = Model()

    # input block
    inp = LoihiBlock(ni * nj * nk, label='inp')
    assert inp.n_neurons <= 1024
    inp.compartment.configure_relu()
    inp.compartment.bias[:] = inp_biases.ravel()

    inp_ax = Axon(nij, label='inp_ax')

    # we always compute the pixel/channel idxs with channels_last=True
    # (not sure why?), and then set it to the correct value afterwards
    inp_shape = nengo_transforms.ChannelShape((ni, nj, nk), channels_last=True)
    inp_ax.set_compartment_axon_map(target_axons=conv.pixel_idxs(inp_shape),
                                    atoms=conv.channel_idxs(inp_shape))
    inp_shape.shape = (ni, nj, nk) if channels_last else (nk, ni, nj)
    inp_shape.channels_last = channels_last

    inp.add_axon(inp_ax)

    model.add_block(inp)

    # conv block
    neurons = LoihiBlock(out_size, label='neurons')
    assert neurons.n_neurons <= 1024
    neurons.compartment.configure_lif(tau_rc=tau_rc, tau_ref=tau_ref, dt=dt)
    neurons.compartment.configure_filter(tau_s, dt=dt)
    neurons.compartment.bias[:] = neuron_bias

    synapse = Synapse(np.prod(inp_shape.spatial_shape), label='synapse')
    conv2d_transform = nengo_transforms.Convolution(
        nf,
        inp_shape,
        strides=(sti, stj),
        channels_last=channels_last,
        init=filters,
        kernel_size=(1, 3))
    weights, indices, axon_to_weight_map, bases = conv.conv2d_loihi_weights(
        conv2d_transform)
    synapse.set_population_weights(weights,
                                   indices,
                                   axon_to_weight_map,
                                   bases,
                                   pop_type=pop_type)
    neurons.add_synapse(synapse)

    out_probe = Probe(target=neurons, key='spiked')
    neurons.add_probe(out_probe)

    inp_ax.target = synapse
    model.add_block(neurons)

    # simulation
    discretize_model(model)

    n_steps = int(pres_time / dt)
    target = request.config.getoption("--target")
    if target == 'loihi':
        with HardwareInterface(model, use_snips=False, seed=seed) as sim:
            sim.run_steps(n_steps)
            sim_out = sim.get_probe_output(out_probe)
    else:
        with EmulatorInterface(model, seed=seed) as sim:
            sim.run_steps(n_steps)
            sim_out = sim.get_probe_output(out_probe)

    sim_out = np.sum(sim_out, axis=0) * (dt / pres_time)
    if channels_last:
        sim_out.shape = (nyi, nyj, nf)
        sim_out = np.transpose(sim_out, (2, 0, 1))
    else:
        sim_out.shape = (nf, nyi, nyj)

    out_max = sim_out.max()

    # --- plot results
    rows = 1
    cols = 2

    ax = plt.subplot(rows, cols, 1)
    plt.hist(sim_out.ravel(), bins=11)

    ax = plt.subplot(rows, cols, 2)
    tile(sim_out, vmin=0, vmax=out_max, grid=True, ax=ax)

    # ref_out determined by emulator running code known to work
    if nc == 1:
        ref_out = np.array([[0.06, 0.02], [0.055, 0.], [0.0825, 0.0225],
                            [0.125, 0.04]])
    elif nc == 2:
        ref_out = np.array([[0.0975, 0.02], [0.0825, 0.02], [0.125, 0.055],
                            [0.2475, 0.0825]])
    assert allclose(sim_out[:, :, 0], ref_out, rtol=0, atol=1e-7)
Пример #17
0
class Simulator:
    """Nengo Loihi simulator for Loihi hardware and emulator.

    The simulator takes a `nengo.Network` and builds internal data structures
    to run the model defined by that network on Loihi emulator or hardware.
    Run the simulator with the `.Simulator.run` method, and access probed data
    through the ``data`` attribute.

    Building and running the simulation allocates resources. To properly free
    these resources, call the `.Simulator.close` method. Alternatively,
    `.Simulator.close` will automatically be called if you use
    ``with`` syntax::

        with nengo_loihi.Simulator(my_network) as sim:
            sim.run(0.1)
        print(sim.data[my_probe])

    Note that the ``data`` attribute is still accessible even when a simulator
    has been closed. Running the simulator, however, will raise an error.

    Parameters
    ----------
    network : Network or None
        A network object to be built and then simulated. If None,
        then the *model* parameter must be provided instead.
    dt : float, optional (Default: 0.001)
        The length of a simulator timestep, in seconds.
    seed : int, optional (Default: None)
        A seed for all stochastic operators used in this simulator.
        Will be set to ``network.seed + 1`` if not given.
    model : Model, optional (Default: None)
        A `.Model` that contains build artifacts to be simulated.
        Usually the simulator will build this model for you; however, if you
        want to build the network manually, or you want to inject build
        artifacts in the model before building the network, then you can
        pass in a `.Model` instance.
    precompute : bool, optional (Default: True)
        Whether model inputs should be precomputed to speed up simulation.
        When *precompute* is False, the simulator will be run one step
        at a time in order to use model outputs as inputs in other parts
        of the model.
    target : str, optional (Default: None)
        Whether the simulator should target the emulator (``'sim'``) or
        Loihi hardware (``'loihi'``). If None, *target* will default to
        ``'loihi'`` if NxSDK is installed, and the emulator if it is not.
    hardware_options : dict, optional (Default: {})
        Dictionary of additional configuration for the hardware.
        See `.hardware.HardwareInterface` for possible parameters.

    Attributes
    ----------
    closed : bool
        Whether the simulator has been closed.
        Once closed, it cannot be reopened.
    data : ProbeDict
        The dictionary mapping from Nengo objects to the data associated
        with those objects. In particular, each `nengo.Probe` maps to
        the data probed while running the simulation.
    model : Model
        The `.Model` containing the data structures necessary for
        simulating the network.
    precompute : bool
        Whether model inputs should be precomputed to speed up simulation.
        When *precompute* is False, the simulator will be run one step
        at a time in order to use model outputs as inputs in other parts
        of the model.

    """

    def __init__(  # noqa: C901
            self,
            network,
            dt=0.001,
            seed=None,
            model=None,
            precompute=False,
            target=None,
            progress_bar=None,
            remove_passthrough=True,
            hardware_options=None,
    ):
        # initialize values used in __del__ and close() first
        self.closed = True
        self.precompute = precompute
        self.networks = None
        self.sims = OrderedDict()
        self._run_steps = None

        hardware_options = {} if hardware_options is None else hardware_options

        if progress_bar:
            warnings.warn("nengo-loihi does not support progress bars")

        if HAS_DL:
            install_dl_builders()

        if model is None:
            # Call the builder to make a model
            self.model = Model(dt=float(dt), label="%s, dt=%f" % (network, dt))
        else:
            assert isinstance(model, Model), (
                "model is not type 'nengo_loihi.builder.Model'")
            self.model = model
            assert self.model.dt == dt

        if network is not None:
            nengo.rc.set("decoder_cache", "enabled", "False")
            config.add_params(network)

            # ensure seeds are identical to nengo
            seed_network(network, seeds=self.model.seeds,
                         seeded=self.model.seeded)

            # split the host into one, two or three networks
            self.networks = split(
                network,
                precompute=precompute,
                node_neurons=self.model.node_neurons,
                node_tau=self.model.decode_tau,
                remove_passthrough=remove_passthrough,
            )
            network = self.networks.chip

            self.model.chip2host_params = self.networks.chip2host_params

            self.chip = self.networks.chip
            self.host = self.networks.host
            self.host_pre = self.networks.host_pre

            if len(self.host_pre.all_objects) > 0:
                host_pre_model = self._get_host_model(
                    self.host_pre, dt=dt, seeds=self.model.seeds,
                    seeded=self.model.seeded)
                self.sims["host_pre"] = nengo.Simulator(self.host_pre,
                                                        dt=self.dt,
                                                        model=host_pre_model,
                                                        progress_bar=False,
                                                        optimize=False)

            if len(self.host.all_objects) > 0:
                host_model = self._get_host_model(
                    self.host, dt=dt, seeds=self.model.seeds,
                    seeded=self.model.seeded)
                self.sims["host"] = nengo.Simulator(
                    self.host,
                    dt=self.dt,
                    model=host_model,
                    progress_bar=False,
                    optimize=False)
            elif not precompute:
                # If there is no host and precompute=False, then all objects
                # must be on the chip, which is precomputable in the sense that
                # no communication has to happen with the host.
                # We could warn about this, but we want to avoid people having
                # to specify `precompute` unless they absolutely have to.
                self.precompute = True

            # Build the network into the model
            self.model.build(network)

        self._probe_outputs = self.model.params
        self.data = ProbeDict(self._probe_outputs)
        for sim in self.sims.values():
            self.data.add_fallback(sim.data)

        if seed is None:
            if network is not None and network.seed is not None:
                seed = network.seed + 1
            else:
                seed = np.random.randint(npext.maxint)

        if target is None:
            target = 'loihi' if HAS_NXSDK else 'sim'
        self.target = target

        logger.info("Simulator target is %r", target)
        logger.info("Simulator precompute is %r", self.precompute)

        if target != "simreal":
            discretize_model(self.model)

        if target in ("simreal", "sim"):
            self.sims["emulator"] = EmulatorInterface(self.model, seed=seed)
        elif target == 'loihi':
            assert HAS_NXSDK, "Must have NxSDK installed to use Loihi hardware"
            self.sims["loihi"] = HardwareInterface(
                self.model, use_snips=not self.precompute, seed=seed,
                **hardware_options)
        else:
            raise ValidationError("Must be 'simreal', 'sim', or 'loihi'",
                                  attr="target")

        assert "emulator" in self.sims or "loihi" in self.sims

        self.closed = False
        self.reset(seed=seed)

    @staticmethod
    def _get_host_model(network, dt, seeds, seeded):
        model = nengo.builder.Model(
            dt=float(dt),
            label="%s, dt=%f" % (network, dt),
            decoder_cache=get_default_decoder_cache())
        model.seeds.update(seeds)
        model.seeded.update(seeded)
        return model

    def __del__(self):
        """Raise a ResourceWarning if we are deallocated while open."""
        if not self.closed:
            warnings.warn(
                "Simulator with model=%s was deallocated while open. Please "
                "close simulators manually to ensure resources are properly "
                "freed." % self.model, ResourceWarning)

    def __enter__(self):
        for sim in self.sims.values():
            sim.__enter__()
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        for sim in self.sims.values():
            sim.__exit__(exc_type, exc_value, traceback)
        self.close()

    @property
    def dt(self):
        """(float) The step time of the simulator."""
        return self.model.dt

    @dt.setter
    def dt(self, dummy):
        raise ReadonlyError(attr='dt', obj=self)

    @property
    def n_steps(self):
        """(int) The current time step of the simulator."""
        return self._n_steps

    @property
    def time(self):
        """(float) The current time of the simulator."""
        return self._time

    def close(self):
        """Closes the simulator.

        Any call to `.Simulator.run`, `.Simulator.run_steps`,
        `.Simulator.step`, and `.Simulator.reset` on a closed simulator raises
        a ``SimulatorClosed`` exception.
        """

        for sim in self.sims.values():
            if not sim.closed:
                sim.close()
        self.closed = True

    def _probe(self):
        """Copy all probed signals to buffers."""
        self._probe_step_time()

        for probe in self.model.probes:
            if probe in self.networks.chip2host_params:
                continue
            assert probe.sample_every is None, (
                "probe.sample_every not implemented")
            assert ("loihi" not in self.sims
                    or "emulator" not in self.sims)
            loihi_probe = self.model.objs[probe]['out']
            if "loihi" in self.sims:
                data = self.sims["loihi"].get_probe_output(loihi_probe)
            elif "emulator" in self.sims:
                data = self.sims["emulator"].get_probe_output(loihi_probe)
            # TODO: stop recomputing this all the time
            del self._probe_outputs[probe][:]
            self._probe_outputs[probe].extend(data)
            assert len(self._probe_outputs[probe]) == self.n_steps, (
                len(self._probe_outputs[probe]), self.n_steps)

    def _probe_step_time(self):
        self._time = self._n_steps * self.dt

    def reset(self, seed=None):
        """Reset the simulator state.

        Parameters
        ----------
        seed : int, optional
            A seed for all stochastic operators used in the simulator.
            This will change the random sequences generated for noise
            or inputs (e.g. from processes), but not the built objects
            (e.g. ensembles, connections).
        """
        if self.closed:
            raise SimulatorClosed("Cannot reset closed Simulator.")

        if seed is not None:
            self.seed = seed

        self._n_steps = 0
        self._time = 0

        # clear probe data
        for probe in self.model.probes:
            self._probe_outputs[probe] = []
        self.data.reset()

    def run(self, time_in_seconds):
        """Simulate for the given length of time.

        If the given length of time is not a multiple of ``dt``,
        it will be rounded to the nearest ``dt``. For example, if ``dt``
        is 0.001 and ``run`` is called with ``time_in_seconds=0.0006``,
        the simulator will advance one timestep, resulting in the actual
        simulator time being 0.001.

        The given length of time must be positive. The simulator cannot
        be run backwards.

        Parameters
        ----------
        time_in_seconds : float
            Amount of time to run the simulation for. Must be positive.
        """
        if time_in_seconds < 0:
            raise ValidationError("Must be positive (got %g)"
                                  % (time_in_seconds,), attr="time_in_seconds")

        steps = int(np.round(float(time_in_seconds) / self.dt))

        if steps == 0:
            warnings.warn("%g results in running for 0 timesteps. Simulator "
                          "still at time %g." % (time_in_seconds, self.time))
        else:
            logger.info("Running %s for %f seconds, or %d steps",
                        self.model.label, time_in_seconds, steps)
            self.run_steps(steps)

    def step(self):
        """Advance the simulator by 1 step (``dt`` seconds)."""
        self.run_steps(1)

    def _collect_receiver_info(self):
        spikes = []
        errors = OrderedDict()
        for sender, receiver in self.networks.host2chip_senders.items():
            receiver.clear()
            for t, x in sender.queue:
                receiver.receive(t, x)
            del sender.queue[:]

            if hasattr(receiver, 'collect_spikes'):
                for spike_input, t, spike_idxs in receiver.collect_spikes():
                    ti = round(t / self.model.dt)
                    spikes.append((spike_input, ti, spike_idxs))
            if hasattr(receiver, 'collect_errors'):
                for probe, t, e in receiver.collect_errors():
                    conn = self.model.probe_conns[probe]
                    synapse = self.model.objs[conn]['decoders']
                    assert synapse.learning
                    ti = round(t / self.model.dt)
                    errors_ti = errors.setdefault(ti, OrderedDict())
                    if synapse in errors_ti:
                        errors_ti[synapse] += e
                    else:
                        errors_ti[synapse] = e.copy()

        errors = [(synapse, ti, e) for ti, ee in errors.items()
                  for synapse, e in ee.items()]
        return spikes, errors

    def _host2chip(self, sim):
        spikes, errors = self._collect_receiver_info()
        sim.host2chip(spikes, errors)

    def _chip2host(self, sim):
        probes_receivers = OrderedDict(  # map probes to receivers
            (self.model.objs[probe]['out'], receiver)
            for probe, receiver in self.networks.chip2host_receivers.items())
        sim.chip2host(probes_receivers)

    def _make_run_steps(self):
        if self._run_steps is not None:
            return

        assert "emulator" not in self.sims or "loihi" not in self.sims
        if "emulator" in self.sims:
            self._make_emu_run_steps()
        else:
            self._make_loihi_run_steps()

    def _make_emu_run_steps(self):
        host_pre = self.sims.get("host_pre", None)
        emulator = self.sims["emulator"]
        host = self.sims.get("host", None)

        if self.precompute:
            if host_pre is not None and host is not None:

                def emu_precomputed_host_pre_and_host(steps):
                    host_pre.run_steps(steps)
                    self._host2chip(emulator)
                    emulator.run_steps(steps)
                    self._chip2host(emulator)
                    host.run_steps(steps)
                self._run_steps = emu_precomputed_host_pre_and_host

            elif host_pre is not None:

                def emu_precomputed_host_pre_only(steps):
                    host_pre.run_steps(steps)
                    self._host2chip(emulator)
                    emulator.run_steps(steps)
                self._run_steps = emu_precomputed_host_pre_only

            elif host is not None:

                def emu_precomputed_host_only(steps):
                    emulator.run_steps(steps)
                    self._chip2host(emulator)
                    host.run_steps(steps)
                self._run_steps = emu_precomputed_host_only

            else:
                self._run_steps = emulator.run_steps

        else:
            assert host is not None, "Model is precomputable"

            def emu_bidirectional_with_host(steps):
                for _ in range(steps):
                    host.step()
                    self._host2chip(emulator)
                    emulator.step()
                    self._chip2host(emulator)
            self._run_steps = emu_bidirectional_with_host

    def _make_loihi_run_steps(self):
        host_pre = self.sims.get("host_pre", None)
        loihi = self.sims["loihi"]
        host = self.sims.get("host", None)

        if self.precompute:
            if host_pre is not None and host is not None:

                def loihi_precomputed_host_pre_and_host(steps):
                    host_pre.run_steps(steps)
                    self._host2chip(loihi)
                    loihi.run_steps(steps, blocking=True)
                    self._chip2host(loihi)
                    host.run_steps(steps)
                self._run_steps = loihi_precomputed_host_pre_and_host

            elif host_pre is not None:

                def loihi_precomputed_host_pre_only(steps):
                    host_pre.run_steps(steps)
                    self._host2chip(loihi)
                    loihi.run_steps(steps, blocking=True)
                self._run_steps = loihi_precomputed_host_pre_only

            elif host is not None:

                def loihi_precomputed_host_only(steps):
                    loihi.run_steps(steps, blocking=True)
                    self._chip2host(loihi)
                    host.run_steps(steps)
                self._run_steps = loihi_precomputed_host_only

            else:
                self._run_steps = loihi.run_steps

        else:
            assert host is not None, "Model is precomputable"

            def loihi_bidirectional_with_host(steps):
                loihi.run_steps(steps, blocking=False)
                for _ in range(steps):
                    host.step()
                    self._host2chip(loihi)
                    self._chip2host(loihi)
                logger.info("Waiting for run_steps to complete...")
                loihi.wait_for_completion()
                logger.info("run_steps completed")
            self._run_steps = loihi_bidirectional_with_host

    def run_steps(self, steps):
        """Simulate for the given number of ``dt`` steps.

        Parameters
        ----------
        steps : int
            Number of steps to run the simulation for.
        """
        if self.closed:
            raise SimulatorClosed("Simulator cannot run because it is closed.")

        self._make_run_steps()
        try:
            self._run_steps(steps)
        except Exception:
            if "loihi" in self.sims and self.sims["loihi"].use_snips:
                # Need to write to board, otherwise it will wait indefinitely
                h2c = self.sims["loihi"].nengo_io_h2c
                c2h = self.sims["loihi"].nengo_io_c2h

                print(traceback.format_exc())
                print("\nAttempting to end simulation...")

                for _ in range(steps):
                    h2c.write(h2c.numElements, [0] * h2c.numElements)
                    c2h.read(c2h.numElements)
                self.sims["loihi"].wait_for_completion()
                self.sims["loihi"].n2board.nxDriver.stopExecution()
                self.sims["loihi"].n2board.nxDriver.stopDriver()
            raise

        self._n_steps += steps
        logger.info("Finished running for %d steps", steps)
        self._probe()

    def trange(self, sample_every=None, dt=None):
        """Create a vector of times matching probed data.

        Note that the range does not start at 0 as one might expect, but at
        the first timestep (i.e., ``dt``).

        Parameters
        ----------
        sample_every : float, optional (Default: None)
            The sampling period of the probe to create a range for.
            If None, a time value for every ``dt`` will be produced.
        """
        period = 1 if sample_every is None else sample_every / self.dt
        steps = np.arange(1, self.n_steps + 1)
        return self.dt * steps[steps % period < 1]
Пример #18
0
def test_add_inputs(decode_neurons, tolerance, Simulator, seed, plt):
    """Test the addition of two inputs with DecodeNeurons.

    This test forms the basis for the scale factors for Preset5DecodeNeurons
    and Preset10DecodeNeurons. It is unclear exactly why these scale factors help.
    The best values depend on the exact inputs below, as well as the seed used for
    this test. More testing is needed to find optimal scale factors, or (ideally)
    get rid of them completely if we can better understand the underlying mechanics.
    """

    sim_time = 2.0
    pres_time = sim_time / 4
    eval_time = sim_time / 8

    stim_values = [[0.5, 0.5], [0.5, -0.9], [-0.7, -0.3], [-0.3, 1.0]]
    stim_times = np.arange(0, sim_time, pres_time)
    stim_fn_a = nengo.processes.Piecewise(
        {t: stim_values[i][0]
         for i, t in enumerate(stim_times)})
    stim_fn_b = nengo.processes.Piecewise(
        {t: stim_values[i][1]
         for i, t in enumerate(stim_times)})

    probe_solver = nengo.solvers.LstsqL2nz(reg=0.01)

    with nengo.Network(seed=seed) as model:
        stim_a = nengo.Node(stim_fn_a)
        stim_b = nengo.Node(stim_fn_b)

        a = nengo.Ensemble(n_neurons=100, dimensions=1)
        b = nengo.Ensemble(n_neurons=100, dimensions=1)

        nengo.Connection(stim_a, a)
        nengo.Connection(stim_b, b)

        c = nengo.Ensemble(n_neurons=100, dimensions=1)
        nengo.Connection(a, c)
        nengo.Connection(b, c)

        out_synapse = nengo.Alpha(0.03)
        stim_synapse = out_synapse.combine(nengo.Alpha(0.005)).combine(
            nengo.Alpha(0.005))
        p_stim_a = nengo.Probe(stim_a,
                               synapse=stim_synapse,
                               solver=probe_solver)
        p_stim_b = nengo.Probe(stim_b,
                               synapse=stim_synapse,
                               solver=probe_solver)
        p_c = nengo.Probe(c, synapse=out_synapse, solver=probe_solver)

    build_model = Model()
    build_model.decode_neurons = decode_neurons

    with Simulator(model, model=build_model) as sim:
        sim.run(sim_time)

    t = sim.trange()
    tmask = np.zeros(t.shape, dtype=bool)
    for pres_t in np.arange(0, sim_time, pres_time):
        t0 = pres_t + pres_time - eval_time
        t1 = pres_t + pres_time
        tmask |= (t >= t0) & (t <= t1)

    target = sim.data[p_stim_a] + sim.data[p_stim_b]
    error = np.abs(sim.data[p_c][tmask] - target[tmask]).mean()

    plt.plot(t, target)
    plt.plot(t, sim.data[p_c])
    plt.ylim([-1.1, 1.1])
    plt.title("error = %0.2e" % error)

    assert error < tolerance
Пример #19
0
def test_one_to_one_allocator_big_block_error():
    model = Model()
    model.add_block(LoihiBlock(1050))

    with pytest.raises(ValidationError, match="Segment does not fit"):
        OneToOne()(model)
Пример #20
0
    def __init__(  # noqa: C901
        self,
        network,
        dt=0.001,
        seed=None,
        model=None,
        precompute=None,
        target=None,
        progress_bar=None,
        remove_passthrough=True,
        hardware_options=None,
    ):
        # initialize values used in __del__ and close() first
        self.closed = True
        self.network = network
        self.sims = OrderedDict()
        self.timers = Timers()
        self.timers.start("build")
        self.seed = seed
        self._n_steps = 0
        self._time = 0

        hardware_options = {} if hardware_options is None else hardware_options

        if progress_bar:
            warnings.warn("nengo-loihi does not support progress bars")

        if model is None:
            self.model = Model(dt=float(dt), label="%s, dt=%f" % (network, dt))
        else:
            assert isinstance(
                model, Model), "model is not type 'nengo_loihi.builder.Model'"
            self.model = model
            assert self.model.dt == dt

        if network is None:
            raise ValidationError("network parameter must not be None",
                                  attr="network")

        if target is None:
            target = "loihi" if HAS_NXSDK else "sim"
        self.target = target
        logger.info("Simulator target is %r", target)

        # Build the network into the model
        self.model.build(
            network,
            precompute=precompute,
            remove_passthrough=remove_passthrough,
            discretize=target != "simreal",
        )

        # Create host_pre and host simulators if necessary
        self.precompute = self.model.split.precompute
        logger.info("Simulator precompute is %r", self.precompute)
        assert precompute is None or precompute == self.precompute
        if self.model.split.precomputable() and not self.precompute:
            warnings.warn(
                "Model is precomputable. Setting precompute=False may slow execution."
            )

        if len(self.model.host_pre.params) > 0:
            assert self.precompute
            self.sims["host_pre"] = nengo.Simulator(
                network=None,
                dt=self.dt,
                model=self.model.host_pre,
                progress_bar=False,
                optimize=False,
            )

        if len(self.model.host.params) > 0:
            self.sims["host"] = nengo.Simulator(
                network=None,
                dt=self.dt,
                model=self.model.host,
                progress_bar=False,
                optimize=False,
            )

        self._probe_outputs = self.model.params
        self.data = SimulationData(self._probe_outputs)
        for sim in self.sims.values():
            self.data.add_fallback(sim.data)

        if seed is None:
            if network is not None and network.seed is not None:
                seed = network.seed + 1
            else:
                seed = np.random.randint(npext.maxint)

        if target in ("simreal", "sim"):
            self.sims["emulator"] = EmulatorInterface(self.model, seed=seed)
        elif target == "loihi":
            assert HAS_NXSDK, "Must have NxSDK installed to use Loihi hardware"
            use_snips = not self.precompute and self.sims.get("host",
                                                              None) is not None
            self.sims["loihi"] = HardwareInterface(self.model,
                                                   use_snips=use_snips,
                                                   seed=seed,
                                                   **hardware_options)
        else:
            raise ValidationError("Must be 'simreal', 'sim', or 'loihi'",
                                  attr="target")

        assert "emulator" in self.sims or "loihi" in self.sims

        self._runner = StepRunner(self.model, self.sims, self.precompute,
                                  self.timers)
        self.closed = False
        self.timers.stop("build")
Пример #21
0
class Simulator:
    """Nengo Loihi simulator for Loihi hardware and emulator.

    The simulator takes a `nengo.Network` and builds internal data structures
    to run the model defined by that network on Loihi emulator or hardware.
    Run the simulator with the `.Simulator.run` method, and access probed data
    through the ``data`` attribute.

    Building and running the simulation allocates resources. To properly free
    these resources, call the `.Simulator.close` method. Alternatively,
    `.Simulator.close` will automatically be called if you use
    ``with`` syntax::

        with nengo_loihi.Simulator(my_network) as sim:
            sim.run(0.1)
        print(sim.data[my_probe])

    Note that the ``data`` attribute is still accessible even when a simulator
    has been closed. Running the simulator, however, will raise an error.

    Parameters
    ----------
    network : Network
        A network object to be built and then simulated. If None,
        then the *model* parameter must be provided instead.
    dt : float, optional (Default: 0.001)
        The length of a simulator timestep, in seconds.
    seed : int, optional (Default: None)
        A seed for all stochastic operators used in this simulator.
        Will be set to ``network.seed + 1`` if not given.
    model : Model, optional (Default: None)
        A `.Model` that contains build artifacts to be simulated.
        Usually the simulator will build this model for you; however, if you
        want to build the network manually, or you want to inject build
        artifacts in the model before building the network, then you can
        pass in a `.Model` instance.
    precompute : bool, optional (Default: None)
        Whether model inputs should be precomputed to speed up simulation.
        When *precompute* is False, the simulator will be run one step
        at a time in order to use model outputs as inputs in other parts
        of the model. By default, the simulator will choose ``True`` if it
        works for your model, and ``False`` otherwise.
    target : str, optional (Default: None)
        Whether the simulator should target the emulator (``'sim'``) or
        Loihi hardware (``'loihi'``). If None, *target* will default to
        ``'loihi'`` if NxSDK is installed, and the emulator if it is not.
    hardware_options : dict, optional (Default: {})
        Dictionary of additional configuration for the hardware.
        See `.hardware.HardwareInterface` for possible parameters.

    Attributes
    ----------
    closed : bool
        Whether the simulator has been closed.
        Once closed, it cannot be reopened.
    data : ProbeDict
        The dictionary mapping from Nengo objects to the data associated
        with those objects. In particular, each `nengo.Probe` maps to
        the data probed while running the simulation.
    model : Model
        The `.Model` containing the data structures necessary for
        simulating the network.
    precompute : bool
        Whether model inputs should be precomputed to speed up simulation.
        When *precompute* is False, the simulator will be run one step
        at a time in order to use model outputs as inputs in other parts
        of the model.

    """
    def __init__(  # noqa: C901
        self,
        network,
        dt=0.001,
        seed=None,
        model=None,
        precompute=None,
        target=None,
        progress_bar=None,
        remove_passthrough=True,
        hardware_options=None,
    ):
        # initialize values used in __del__ and close() first
        self.closed = True
        self.network = network
        self.sims = OrderedDict()
        self.timers = Timers()
        self.timers.start("build")
        self.seed = seed
        self._n_steps = 0
        self._time = 0

        hardware_options = {} if hardware_options is None else hardware_options

        if progress_bar:
            warnings.warn("nengo-loihi does not support progress bars")

        if model is None:
            self.model = Model(dt=float(dt), label="%s, dt=%f" % (network, dt))
        else:
            assert isinstance(
                model, Model), "model is not type 'nengo_loihi.builder.Model'"
            self.model = model
            assert self.model.dt == dt

        if network is None:
            raise ValidationError("network parameter must not be None",
                                  attr="network")

        if target is None:
            target = "loihi" if HAS_NXSDK else "sim"
        self.target = target
        logger.info("Simulator target is %r", target)

        # Build the network into the model
        self.model.build(
            network,
            precompute=precompute,
            remove_passthrough=remove_passthrough,
            discretize=target != "simreal",
        )

        # Create host_pre and host simulators if necessary
        self.precompute = self.model.split.precompute
        logger.info("Simulator precompute is %r", self.precompute)
        assert precompute is None or precompute == self.precompute
        if self.model.split.precomputable() and not self.precompute:
            warnings.warn(
                "Model is precomputable. Setting precompute=False may slow execution."
            )

        if len(self.model.host_pre.params) > 0:
            assert self.precompute
            self.sims["host_pre"] = nengo.Simulator(
                network=None,
                dt=self.dt,
                model=self.model.host_pre,
                progress_bar=False,
                optimize=False,
            )

        if len(self.model.host.params) > 0:
            self.sims["host"] = nengo.Simulator(
                network=None,
                dt=self.dt,
                model=self.model.host,
                progress_bar=False,
                optimize=False,
            )

        self._probe_outputs = self.model.params
        self.data = SimulationData(self._probe_outputs)
        for sim in self.sims.values():
            self.data.add_fallback(sim.data)

        if seed is None:
            if network is not None and network.seed is not None:
                seed = network.seed + 1
            else:
                seed = np.random.randint(npext.maxint)

        if target in ("simreal", "sim"):
            self.sims["emulator"] = EmulatorInterface(self.model, seed=seed)
        elif target == "loihi":
            assert HAS_NXSDK, "Must have NxSDK installed to use Loihi hardware"
            use_snips = not self.precompute and self.sims.get("host",
                                                              None) is not None
            self.sims["loihi"] = HardwareInterface(self.model,
                                                   use_snips=use_snips,
                                                   seed=seed,
                                                   **hardware_options)
        else:
            raise ValidationError("Must be 'simreal', 'sim', or 'loihi'",
                                  attr="target")

        assert "emulator" in self.sims or "loihi" in self.sims

        self._runner = StepRunner(self.model, self.sims, self.precompute,
                                  self.timers)
        self.closed = False
        self.timers.stop("build")

    def __del__(self):
        """Raise a ResourceWarning if we are deallocated while open."""
        if not self.closed:
            warnings.warn(
                "Simulator with model=%s was deallocated while open. Please "
                "close simulators manually to ensure resources are properly "
                "freed." % self.model,
                ResourceWarning,
            )

    def __enter__(self):
        self.timers.start("connect")
        for sim in self.sims.values():
            sim.__enter__()
        self.timers.stop("connect")
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        for sim in self.sims.values():
            sim.__exit__(exc_type, exc_value, traceback)
        self.close()

    @property
    def dt(self):
        """(float) The step time of the simulator."""
        return self.model.dt

    @dt.setter
    def dt(self, dummy):
        raise ReadonlyError(attr="dt", obj=self)

    @property
    def n_steps(self):
        """(int) The current time step of the simulator."""
        return self._n_steps

    @property
    def time(self):
        """(float) The current time of the simulator."""
        return self._time

    def close(self):
        """Closes the simulator.

        Any call to `.Simulator.run`, `.Simulator.run_steps`,
        `.Simulator.step`, and `.Simulator.reset` on a closed simulator raises
        a ``SimulatorClosed`` exception.
        """

        for sim in self.sims.values():
            if not sim.closed:
                sim.close()
        self._runner = None
        self.closed = True

    def _probe(self):
        """Copy all probed signals to buffers."""
        self._probe_step_time()

        for probe in self.model.nengo_probes:
            if probe in self.model.chip2host_params:
                continue
            assert probe.sample_every is None, "probe.sample_every not implemented"
            assert "loihi" not in self.sims or "emulator" not in self.sims
            loihi_probe = self.model.objs[probe]["out"]
            if "loihi" in self.sims:
                data = self.sims["loihi"].get_probe_output(loihi_probe)
            elif "emulator" in self.sims:
                data = self.sims["emulator"].get_probe_output(loihi_probe)
            # TODO: stop recomputing this all the time
            del self._probe_outputs[probe][:]
            self._probe_outputs[probe].extend(data)
            assert len(self._probe_outputs[probe]) == self.n_steps, (
                len(self._probe_outputs[probe]),
                self.n_steps,
            )

    def _probe_step_time(self):
        self._time = self._n_steps * self.dt

    def reset(self, seed=None):
        """Reset the simulator state.

        Parameters
        ----------
        seed : int, optional
            A seed for all stochastic operators used in the simulator.
            This will change the random sequences generated for noise
            or inputs (e.g. from processes), but not the built objects
            (e.g. ensembles, connections).
        """
        if self.closed:
            raise SimulatorClosed("Cannot reset closed Simulator.")

        raise NotImplementedError()

    def run(self, time_in_seconds):
        """Simulate for the given length of time.

        If the given length of time is not a multiple of ``dt``,
        it will be rounded to the nearest ``dt``. For example, if ``dt``
        is 0.001 and ``run`` is called with ``time_in_seconds=0.0006``,
        the simulator will advance one timestep, resulting in the actual
        simulator time being 0.001.

        The given length of time must be positive. The simulator cannot
        be run backwards.

        Parameters
        ----------
        time_in_seconds : float
            Amount of time to run the simulation for. Must be positive.
        """
        if time_in_seconds < 0:
            raise ValidationError("Must be positive (got %g)" %
                                  (time_in_seconds, ),
                                  attr="time_in_seconds")

        steps = int(np.round(float(time_in_seconds) / self.dt))

        if steps == 0:
            warnings.warn("%g results in running for 0 timesteps. Simulator "
                          "still at time %g." % (time_in_seconds, self.time))
        else:
            logger.info(
                "Running %s for %f seconds, or %d steps",
                self.model.label,
                time_in_seconds,
                steps,
            )
            self.run_steps(steps)

    def run_steps(self, steps):
        """Simulate for the given number of ``dt`` steps.

        Parameters
        ----------
        steps : int
            Number of steps to run the simulation for.
        """
        if self.closed:
            raise SimulatorClosed("Simulator cannot run because it is closed.")

        self._runner.run_steps(steps)
        self._n_steps += steps
        logger.info("Finished running for %d steps", steps)
        self._probe()

    def step(self):
        """Advance the simulator by 1 step (``dt`` seconds)."""
        self.run_steps(1)

    def trange(self, sample_every=None, dt=None):
        """Create a vector of times matching probed data.

        Note that the range does not start at 0 as one might expect, but at
        the first timestep (i.e., ``dt``).

        Parameters
        ----------
        sample_every : float, optional (Default: None)
            The sampling period of the probe to create a range for.
            If None, a time value for every ``dt`` will be produced.
        """
        period = 1 if sample_every is None else sample_every / self.dt
        steps = np.arange(1, self.n_steps + 1)
        return self.dt * steps[steps % period < 1]
Пример #22
0
def test_uv_overflow(n_axons, plt, allclose, monkeypatch):
    # TODO: Currently this is not testing the V overflow, since it is higher
    #  and I haven't been able to figure out a way to make it overflow.
    nt = 15

    model = Model()

    # n_axons controls number of input spikes and thus amount of overflow
    input = SpikeInput(n_axons)
    for t in np.arange(1, nt + 1):
        # send spikes to all axons
        input.add_spikes(t, np.arange(n_axons), permanent=True)
    model.add_input(input)

    block = LoihiBlock(1)
    block.compartment.configure_relu()
    block.compartment.configure_filter(0.1)
    model.add_block(block)

    synapse = Synapse(n_axons)
    synapse.set_weights(np.ones((n_axons, 1)))
    block.add_synapse(synapse)

    axon = Axon(n_axons)
    axon.target = synapse
    input.add_axon(axon)

    probe_u = LoihiProbe(target=block, key="current")
    model.add_probe(probe_u)
    probe_v = LoihiProbe(target=block, key="voltage")
    model.add_probe(probe_v)
    probe_s = LoihiProbe(target=block, key="spiked")
    model.add_probe(probe_s)

    discretize_model(model)

    # must set these after `discretize` to specify discretized values
    block.compartment.vmin = -(2**22) + 1
    block.compartment.vth[:] = VTH_MAX

    assert EmulatorInterface.strict  # Tests should be run in strict mode
    monkeypatch.setattr(EmulatorInterface, "strict", False)
    overflow_var = "q0" if n_axons == 1000 else "current"
    with EmulatorInterface(model) as emu:
        with pytest.warns(UserWarning, match=f"Overflow in {overflow_var}"):
            emu.run_steps(nt)
        emu_u = emu.collect_probe_output(probe_u)
        emu_v = emu.collect_probe_output(probe_v)
        emu_s = emu.collect_probe_output(probe_s)

    with HardwareInterface(model, use_snips=False) as sim:
        sim.run_steps(nt)
        sim_u = sim.collect_probe_output(probe_u)
        sim_v = sim.collect_probe_output(probe_v)
        sim_s = sim.collect_probe_output(probe_s)
        sim_v[sim_s > 0] = 0  # since Loihi has placeholder voltage after spike

    plt.subplot(311)
    plt.plot(emu_u)
    plt.plot(sim_u)

    plt.subplot(312)
    plt.plot(emu_v)
    plt.plot(sim_v)

    plt.subplot(313)
    plt.plot(emu_s)
    plt.plot(sim_s)

    assert allclose(emu_u, sim_u)
    assert allclose(emu_v, sim_v)
Пример #23
0
def test_simulator_noise(exp, request, plt, seed, allclose):
    # TODO: test that the mean falls within a number of standard errors
    # of the expected mean, and that non-zero offsets work correctly.
    # Currently, there is an unexpected negative bias for small noise
    # exponents, apparently because there is a probability of generating
    # the shifted equivalent of -128, whereas with e.g. exp = 7 all the
    # generated numbers fall in [-127, 127].
    offset = 0

    target = request.config.getoption("--target")
    n_cx = 1000

    model = Model()
    block = LoihiBlock(n_cx)
    block.compartment.configure_relu()

    block.compartment.vmin = -1

    block.compartment.enableNoise[:] = 1
    block.compartment.noiseExp0 = exp
    block.compartment.noiseMantOffset0 = offset
    block.compartment.noiseAtDendOrVm = 1

    probe = Probe(target=block, key='voltage')
    block.add_probe(probe)
    model.add_block(block)

    discretize_model(model)
    exp2 = block.compartment.noiseExp0
    offset2 = block.compartment.noiseMantOffset0

    n_steps = 100
    if target == 'loihi':
        with HardwareInterface(model, use_snips=False, seed=seed) as sim:
            sim.run_steps(n_steps)
            y = sim.get_probe_output(probe)
    else:
        with EmulatorInterface(model, seed=seed) as sim:
            sim.run_steps(n_steps)
            y = sim.get_probe_output(probe)

    t = np.arange(1, n_steps + 1)
    bias = offset2 * 2.**(exp2 - 1)
    std = 2.**exp2 / np.sqrt(3)  # divide by sqrt(3) for std of uniform -1..1
    rmean = t * bias
    rstd = np.sqrt(t) * std
    rerr = rstd / np.sqrt(n_cx)
    ymean = y.mean(axis=1)
    ystd = y.std(axis=1)
    diffs = np.diff(np.vstack([np.zeros_like(y[0]), y]), axis=0)

    plt.subplot(311)
    plt.hist(diffs.ravel(), bins=256)

    plt.subplot(312)
    plt.plot(rmean, 'k')
    plt.plot(rmean + 3 * rerr, 'k--')
    plt.plot(rmean - 3 * rerr, 'k--')
    plt.plot(ymean)
    plt.title('mean')

    plt.subplot(313)
    plt.plot(rstd, 'k')
    plt.plot(ystd)
    plt.title('std')

    assert allclose(ystd, rstd, rtol=0.1, atol=1)
Пример #24
0
def test_big_block_error():
    model = Model()
    model.add_block(LoihiBlock(1050))

    with pytest.raises(ValidationError, match="Segment does not fit"):
        Greedy()(model, n_chips=1)
Пример #25
0
def test_builder_strings():
    model = Model(label="myModel")
    assert str(model) == "Model(myModel)"
Пример #26
0
def test_population_input(request, allclose):
    target = request.config.getoption("--target")
    dt = 0.001

    n_inputs = 3
    n_axons = 1
    n_cx = 2

    steps = 6
    spike_times_inds = [(1, [0]), (3, [1]), (5, [2])]

    model = Model()

    input = SpikeInput(n_inputs)
    model.add_input(input)
    spikes = [(input, ti, inds) for ti, inds in spike_times_inds]

    input_axon = Axon(n_axons)
    axon_map = np.zeros(n_inputs, dtype=int)
    atoms = np.arange(n_inputs)
    input_axon.set_axon_map(axon_map, atoms)
    input.add_axon(input_axon)

    block = LoihiBlock(n_cx)
    block.compartment.configure_lif(tau_rc=0., tau_ref=0., dt=dt)
    block.compartment.configure_filter(0, dt=dt)
    model.add_block(block)

    synapse = Synapse(n_axons)
    weights = 0.1 * np.array([[[1, 2], [2, 3], [4, 5]]], dtype=float)
    indices = np.array([[[0, 1], [0, 1], [0, 1]]], dtype=int)
    axon_to_weight_map = np.zeros(n_axons, dtype=int)
    cx_bases = np.zeros(n_axons, dtype=int)
    synapse.set_population_weights(weights,
                                   indices,
                                   axon_to_weight_map,
                                   cx_bases,
                                   pop_type=32)
    block.add_synapse(synapse)
    input_axon.target = synapse

    probe = Probe(target=block, key='voltage')
    block.add_probe(probe)

    discretize_model(model)

    if target == 'loihi':
        with HardwareInterface(model, use_snips=True) as sim:
            sim.run_steps(steps, blocking=False)
            for ti in range(1, steps + 1):
                spikes_i = [spike for spike in spikes if spike[1] == ti]
                sim.host2chip(spikes=spikes_i, errors=[])
                sim.chip2host(probes_receivers={})

            y = sim.get_probe_output(probe)
    else:
        for inp, ti, inds in spikes:
            inp.add_spikes(ti, inds)

        with EmulatorInterface(model) as sim:
            sim.run_steps(steps)
            y = sim.get_probe_output(probe)

    vth = block.compartment.vth[0]
    assert (block.compartment.vth == vth).all()
    z = y / vth
    assert allclose(z[[1, 3, 5]], weights[0], atol=4e-2, rtol=0)
Пример #27
0
    def __init__(  # noqa: C901
            self,
            network,
            dt=0.001,
            seed=None,
            model=None,
            precompute=False,
            target=None,
            progress_bar=None,
            remove_passthrough=True,
            hardware_options=None,
    ):
        # initialize values used in __del__ and close() first
        self.closed = True
        self.precompute = precompute
        self.networks = None
        self.sims = OrderedDict()
        self._run_steps = None

        hardware_options = {} if hardware_options is None else hardware_options

        if progress_bar:
            warnings.warn("nengo-loihi does not support progress bars")

        if HAS_DL:
            install_dl_builders()

        if model is None:
            # Call the builder to make a model
            self.model = Model(dt=float(dt), label="%s, dt=%f" % (network, dt))
        else:
            assert isinstance(model, Model), (
                "model is not type 'nengo_loihi.builder.Model'")
            self.model = model
            assert self.model.dt == dt

        if network is not None:
            nengo.rc.set("decoder_cache", "enabled", "False")
            config.add_params(network)

            # ensure seeds are identical to nengo
            seed_network(network, seeds=self.model.seeds,
                         seeded=self.model.seeded)

            # split the host into one, two or three networks
            self.networks = split(
                network,
                precompute=precompute,
                node_neurons=self.model.node_neurons,
                node_tau=self.model.decode_tau,
                remove_passthrough=remove_passthrough,
            )
            network = self.networks.chip

            self.model.chip2host_params = self.networks.chip2host_params

            self.chip = self.networks.chip
            self.host = self.networks.host
            self.host_pre = self.networks.host_pre

            if len(self.host_pre.all_objects) > 0:
                host_pre_model = self._get_host_model(
                    self.host_pre, dt=dt, seeds=self.model.seeds,
                    seeded=self.model.seeded)
                self.sims["host_pre"] = nengo.Simulator(self.host_pre,
                                                        dt=self.dt,
                                                        model=host_pre_model,
                                                        progress_bar=False,
                                                        optimize=False)

            if len(self.host.all_objects) > 0:
                host_model = self._get_host_model(
                    self.host, dt=dt, seeds=self.model.seeds,
                    seeded=self.model.seeded)
                self.sims["host"] = nengo.Simulator(
                    self.host,
                    dt=self.dt,
                    model=host_model,
                    progress_bar=False,
                    optimize=False)
            elif not precompute:
                # If there is no host and precompute=False, then all objects
                # must be on the chip, which is precomputable in the sense that
                # no communication has to happen with the host.
                # We could warn about this, but we want to avoid people having
                # to specify `precompute` unless they absolutely have to.
                self.precompute = True

            # Build the network into the model
            self.model.build(network)

        self._probe_outputs = self.model.params
        self.data = ProbeDict(self._probe_outputs)
        for sim in self.sims.values():
            self.data.add_fallback(sim.data)

        if seed is None:
            if network is not None and network.seed is not None:
                seed = network.seed + 1
            else:
                seed = np.random.randint(npext.maxint)

        if target is None:
            target = 'loihi' if HAS_NXSDK else 'sim'
        self.target = target

        logger.info("Simulator target is %r", target)
        logger.info("Simulator precompute is %r", self.precompute)

        if target != "simreal":
            discretize_model(self.model)

        if target in ("simreal", "sim"):
            self.sims["emulator"] = EmulatorInterface(self.model, seed=seed)
        elif target == 'loihi':
            assert HAS_NXSDK, "Must have NxSDK installed to use Loihi hardware"
            self.sims["loihi"] = HardwareInterface(
                self.model, use_snips=not self.precompute, seed=seed,
                **hardware_options)
        else:
            raise ValidationError("Must be 'simreal', 'sim', or 'loihi'",
                                  attr="target")

        assert "emulator" in self.sims or "loihi" in self.sims

        self.closed = False
        self.reset(seed=seed)
Пример #28
0
def test_multiple_get_probe_output():
    n_steps = 15
    n_axons = 3

    model = Model()

    # n_axons controls number of input spikes and thus amount of overflow
    input = SpikeInput(n_axons)
    for t in np.arange(1, n_steps + 1):
        input.add_spikes(t, np.arange(n_axons))  # send spikes to all axons
    model.add_input(input)

    block = LoihiBlock(1)
    block.compartment.configure_relu()
    block.compartment.configure_filter(0.1)
    model.add_block(block)

    synapse = Synapse(n_axons)
    synapse.set_weights(np.ones((n_axons, 1)))
    block.add_synapse(synapse)

    axon = Axon(n_axons)
    axon.target = synapse
    input.add_axon(axon)

    probe_u = LoihiProbe(target=block, key="current", synapse=Lowpass(0.005))
    model.add_probe(probe_u)
    probe_v = LoihiProbe(target=block, key="voltage", synapse=Lowpass(0.005))
    model.add_probe(probe_v)
    probe_s = LoihiProbe(target=block, key="spiked", synapse=Lowpass(0.005))
    model.add_probe(probe_s)

    discretize_model(model)

    # must set these after `discretize` to specify discretized values
    block.compartment.vmin = -(2**22) + 1
    block.compartment.vth[:] = VTH_MAX

    with EmulatorInterface(model) as emu:
        emu.run_steps(n_steps)
        first_u = emu.get_probe_output(probe_u)
        first_v = emu.get_probe_output(probe_v)
        first_s = emu.get_probe_output(probe_s)
        second_u = emu.get_probe_output(probe_u)
        second_v = emu.get_probe_output(probe_v)
        second_s = emu.get_probe_output(probe_s)

    assert np.all(first_u == second_u)
    assert np.all(first_v == second_v)
    assert np.all(first_s == second_s)
Пример #29
0
def test_conv2d_weights(channels_last, hw_opts, request, plt, seed, rng,
                        allclose):
    def loihi_rates_n(neuron_type, x, gain, bias, dt):
        """Compute Loihi rates on higher dimensional inputs"""
        y = x.reshape(-1, x.shape[-1])
        gain = np.asarray(gain)
        bias = np.asarray(bias)
        if gain.ndim == 0:
            gain = gain * np.ones(x.shape[-1])
        if bias.ndim == 0:
            bias = bias * np.ones(x.shape[-1])
        rates = loihi_rates(neuron_type, y, gain, bias, dt)
        return rates.reshape(*x.shape)

    if channels_last:
        plt.saveas = None
        pytest.xfail("Blocked by CxBase cannot be > 256 bug")

    target = request.config.getoption("--target")
    if target != 'loihi' and len(hw_opts) > 0:
        pytest.skip("Hardware options only available on hardware")

    pop_type = 32

    # load data
    with open(os.path.join(test_dir, 'mnist10.pkl'), 'rb') as f:
        test10 = pickle.load(f)

    test_x = test10[0][0].reshape(28, 28)
    test_x = test_x[3:24, 3:24]
    test_x = 1.999 * test_x - 0.999

    filters = Gabor(freq=Uniform(0.5, 1)).generate(8, (7, 7), rng=rng)
    sti, stj = 2, 2
    tau_rc = 0.02
    tau_ref = 0.002
    tau_s = 0.005
    dt = 0.001

    encode_type = nengo.SpikingRectifiedLinear()
    encode_gain = 1. / dt
    encode_bias = 0.
    neuron_type = nengo.LIF(tau_rc=tau_rc, tau_ref=tau_ref)
    neuron_gain = 1.
    neuron_bias = 1.

    pres_time = 0.2

    # --- compute ideal outputs
    def conv_pm(x, kernel):
        y0 = scipy.signal.correlate2d(x[0], kernel, mode='valid')[::sti, ::stj]
        y1 = scipy.signal.correlate2d(x[1], kernel, mode='valid')[::sti, ::stj]
        return [y0, -y1]

    ref_out = np.array([test_x, -test_x])
    ref_out = loihi_rates_n(encode_type, ref_out, encode_gain, encode_bias, dt)
    ref_out = ref_out / encode_gain
    ref_out = np.array([conv_pm(ref_out, kernel) for kernel in filters])
    ref_out = ref_out.sum(axis=1)  # sum positive and negative parts
    ref_out = loihi_rates_n(neuron_type, ref_out, neuron_gain, neuron_bias, dt)

    # --- compute nengo_loihi outputs
    inp_biases = np.stack([test_x, -test_x], axis=-1 if channels_last else 0)
    inp_shape = nengo_transforms.ChannelShape(inp_biases.shape,
                                              channels_last=channels_last)

    kernel = np.array([filters, -filters])  # two channels, pos and neg
    kernel = np.transpose(kernel, (2, 3, 0, 1))
    conv2d_transform = nengo_transforms.Convolution(
        8,
        inp_shape,
        strides=(sti, stj),
        channels_last=channels_last,
        kernel_size=(7, 7),
        init=kernel)

    out_size = ref_out.size
    nf, nyi, nyj = ref_out.shape
    assert out_size <= 1024

    model = Model()

    # input block
    inp = LoihiBlock(inp_shape.size, label='inp')
    assert inp.n_neurons <= 1024
    inp.compartment.configure_relu()
    inp.compartment.bias[:] = inp_biases.ravel()

    inp_ax = Axon(np.prod(inp_shape.spatial_shape), label='inp_ax')
    inp_ax.set_compartment_axon_map(target_axons=conv.pixel_idxs(inp_shape),
                                    atoms=conv.channel_idxs(inp_shape))
    inp.add_axon(inp_ax)

    model.add_block(inp)

    # conv block
    neurons = LoihiBlock(out_size, label='neurons')
    assert neurons.n_neurons <= 1024
    neurons.compartment.configure_lif(tau_rc=tau_rc, tau_ref=tau_ref, dt=dt)
    neurons.compartment.configure_filter(tau_s, dt=dt)
    neurons.compartment.bias[:] = neuron_bias

    synapse = Synapse(np.prod(inp_shape.spatial_shape), label='synapse')
    weights, indices, axon_to_weight_map, bases = conv.conv2d_loihi_weights(
        conv2d_transform)
    synapse.set_population_weights(weights,
                                   indices,
                                   axon_to_weight_map,
                                   bases,
                                   pop_type=pop_type)

    neurons.add_synapse(synapse)

    out_probe = Probe(target=neurons, key='spiked')
    neurons.add_probe(out_probe)

    inp_ax.target = synapse
    model.add_block(neurons)

    # simulation
    discretize_model(model)

    n_steps = int(pres_time / dt)
    if target == 'loihi':
        with HardwareInterface(model, use_snips=False, seed=seed,
                               **hw_opts) as sim:
            sim.run_steps(n_steps)
            sim_out = sim.get_probe_output(out_probe)
    else:
        with EmulatorInterface(model, seed=seed) as sim:
            sim.run_steps(n_steps)
            sim_out = sim.get_probe_output(out_probe)

    sim_out = np.sum(sim_out, axis=0) / pres_time
    if channels_last:
        sim_out.shape = (nyi, nyj, nf)
        sim_out = np.transpose(sim_out, (2, 0, 1))
    else:
        sim_out.shape = (nf, nyi, nyj)

    out_max = max(ref_out.max(), sim_out.max())

    # --- plot results
    rows = 2
    cols = 2

    ax = plt.subplot(rows, cols, 1)
    tile(filters, cols=8, ax=ax)

    ax = plt.subplot(rows, cols, 2)
    tile(ref_out, vmin=0, vmax=out_max, cols=8, ax=ax)

    ax = plt.subplot(rows, cols, 3)
    plt.hist(ref_out.ravel(), bins=31)
    plt.hist(sim_out.ravel(), bins=31)

    ax = plt.subplot(rows, cols, 4)
    # tile(sim_out, vmin=0, vmax=1, cols=8, ax=ax)
    tile(sim_out, vmin=0, vmax=out_max, cols=8, ax=ax)

    assert allclose(sim_out, ref_out, atol=10, rtol=1e-3)
Пример #30
0
def test_one_to_one_allocator_big_block_error():
    model = Model()
    model.add_block(LoihiBlock(1050))

    with pytest.raises(ValidationError):
        OneToOne()(model)