def test_sliced_probe(allclose, probe_slice, Simulator): n_neurons = 16 # The bias should be the same for each block, but different within the block # to see some variety. This gives bias 0, 1, 2, 3 to the four neurons in the # 2 by 2 block. bias = np.tile(np.arange(4).reshape((2, 2)), (2, 2)).flatten() with nengo.Network() as net: e = nengo.Ensemble(n_neurons, 1, gain=np.zeros(n_neurons), bias=bias) p = nengo.Probe(e.neurons[probe_slice], "voltage", synapse=0.002) with Simulator(net) as ref_sim: ref_sim.run(0.01) ref_voltages = ref_sim.data[p] with net: nengo_loihi.add_params(net) net.config[e].block_shape = nengo_loihi.BlockShape((2, 2), (n_neurons // 4, 4)) with Simulator(net) as split_sim: split_sim.run(ref_sim.time) split_voltages = split_sim.data[p] assert np.all(ref_sim.data[e].gain == split_sim.data[e].gain) assert np.all(ref_sim.data[e].bias == split_sim.data[e].bias) assert allclose(split_voltages, ref_voltages)
def test_split_ensembles(Simulator, seed, rng, plt, allclose): b_fn = lambda x: x**2 with nengo.Network(seed=seed) as net: nengo_loihi.add_params(net) u = nengo.Node(lambda t: np.sin(4 * np.pi * t)) up = nengo.Probe(u, synapse=0.03) # test auto-splitting large block a = nengo.Ensemble(1100, 1, label="a") nengo.Connection(u, a, synapse=None) ap = nengo.Probe(a, synapse=0.03) # test connection between two split blocks b = nengo.Ensemble(400, 1, label="b", seed=seed + 1) nengo.Connection(a, b, function=b_fn, seed=seed + 2) net.config[b].block_shape = nengo_loihi.BlockShape((134,), (400,)) bp = nengo.Probe(b, synapse=0.03) bp10 = nengo.Probe(b[:10], synapse=0.03) # have one block not be split c = nengo.Ensemble(400, 1, label="c", seed=seed + 1) nengo.Connection(a, c, function=b_fn, seed=seed + 2) cp = nengo.Probe(c, synapse=0.03) # TODO: uncomment when we allow connections to neuron slices # ensemble with input to not all blocks, to check synapse splitting, # specifically the `if len(axon_ids) == 0: continue` in `split_syanpse`. # However we currently don't allow connections to neuron slices, so ignore. # d_enc = nengo.dists.UniformHypersphere(surface=True).sample(400, d=1, rng=rng) # d = nengo.Ensemble(400, 1, label="d", encoders=d_enc) # net.config[d].block_shape = nengo_loihi.BlockShape((134,), (400,)) # nengo.Connection(a, d.neurons[:200], transform=d_enc[:200]) # nengo.Connection(a, d.neurons[200:], transform=d_enc[200:]) with Simulator(net) as sim: sim.run(0.5) assert len(sim.model.objs[a]["out"]) == 2 assert len(sim.model.objs[b]["out"]) == 3 assert len(sim.model.objs[c]["out"]) == 1 y = b_fn(nengo.synapses.Lowpass(0.01).filt(sim.data[up], dt=sim.dt)) plt.plot(sim.trange(), sim.data[up], "k", label="Ideal x") plt.plot(sim.trange(), sim.data[ap], label="x") plt.plot(sim.trange(), y, "k", label="Ideal x ** 2") plt.plot(sim.trange(), sim.data[bp], label="x ** 2, two blocks") plt.plot(sim.trange(), sim.data[cp], label="x ** 2, one block") plt.legend() assert allclose(sim.data[ap], sim.data[up], atol=0.15) assert allclose(sim.data[bp10], sim.data[bp][:, :10]) # b and c have same seeds, so should be very similar. However, since one # is split and one is not, discretizing the blocks after splitting means # that there will be slight numerical differences. assert allclose(sim.data[cp], sim.data[bp], atol=0.02) assert allclose(sim.data[bp], y, atol=0.2)
nengo_sim.freeze_params(net) with net: nengo_input.output = nengo.processes.PresentInput( test_data, presentation_time=pres_time) # set off-chip layer with net: nengo_loihi.add_params(net) net.config[nengo_converter.layers[to_spikes].ensemble].on_chip = False # set on-chip layers with net: L1_shape = L1_layer.output_shape[1:] net.config[nengo_converter.layers[L1]. ensemble].block_shape = nengo_loihi.BlockShape((50, ), L1_shape) L2_shape = L2_layer.output_shape[1:] net.config[nengo_converter.layers[L2]. ensemble].block_shape = nengo_loihi.BlockShape((50, ), L2_shape) L3_shape = L3_layer.output_shape[1:] net.config[nengo_converter.layers[L3]. ensemble].block_shape = nengo_loihi.BlockShape((50, ), L3_shape) print_neurons_type(nengo_converter) # build Nengo Loihi Simulator and run network with nengo_loihi.Simulator(net) as loihi_sim: loihi_sim.run(n_test * pres_time)
def test_conv_deepnet( channels_last, pop_type, precompute, Simulator, request, rng, seed, plt, allclose, ): """Run a convolutional network with two layers on the chip. Checks that network with block splitting on the target matches one without on the emulator. """ # TODO: This case fails in NxSDK 0.9.0 but will be fixed in the next version. # Remove this check once the next version is released. if pop_type == 32: pytest.skip("Pop32 multichip test requires latest NxSDK") def set_partition(partition): os.environ["PARTITION"] = partition request.addfinalizer(lambda: set_partition("")) # multichip pop_type = 16 works only on nahuku32 board currently if pop_type == 16: set_partition("nahuku32") def conv_layer(x, input_shape, array_init=None, label=None, conn_args=None, **conv_args): conn_args = {} if conn_args is None else conn_args if array_init is not None: assert all(a not in conv_args for a in ("init", "kernel_size", "n_filters")) assert array_init.ndim == 4 conv_args["init"] = array_init conv_args["kernel_size"] = array_init.shape[:2] assert array_init.shape[2] == input_shape.n_channels conv_args["n_filters"] = array_init.shape[3] conv = nengo.Convolution(input_shape=input_shape, **conv_args) # add an ensemble to implement the activation function layer = nengo.Ensemble(conv.output_shape.size, 1, label=label) # connect up the input object to the new layer conn = nengo.Connection(x, layer.neurons, transform=conv) return layer, conv, conn channels = 1 n_filters0 = 1 n_filters1 = 4 n_filters2 = 4 # 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) # range (0, 1) input_shape = make_channel_shape(test_x.shape, channels, channels_last) filters0 = np.ones((1, 1, channels, n_filters0)) # use Gabor filters for first layer filters1 = Gabor(freq=Uniform(0.5, 1), sigma_x=Choice([0.9]), sigma_y=Choice([0.9])).generate(n_filters1, (7, 7), rng=rng) assert n_filters0 == 1 filters1 = filters1[None, :, :, :] # single channel filters1 = np.transpose(filters1, (2, 3, 0, 1)) # rows, cols, in_chan, out_chan # use random combinations of first-layer channels in 1x1 convolution filters2 = rng.uniform(-0.2, 1, size=(n_filters1, n_filters2)).clip(0, None) filters2 *= 2 / filters2.sum(axis=0, keepdims=True) # each filter sums to 2 filters2 = filters2[None, None, :, :] # rows, cols, in_chan, out_chan tau_s = 0.001 max_rate = 100 amp = 1 / max_rate f_split = 2 if pop_type == 32 else 4 # use Loihi neuron type so Nengo sim mimics Loihi neuron effects neuron_type = LoihiSpikingRectifiedLinear(amplitude=amp) pres_time = 0.2 with nengo.Network(seed=seed) as net: nengo_loihi.add_params(net) net.config[nengo.Ensemble].neuron_type = neuron_type net.config[nengo.Ensemble].max_rates = Choice([max_rate]) net.config[nengo.Ensemble].intercepts = Choice([0]) net.config[nengo.Connection].synapse = tau_s u = nengo.Node(test_x.ravel(), label="u") layer0, conv0, conn0 = conv_layer( u, input_shape=input_shape, array_init=filters0, strides=(1, 1), channels_last=channels_last, label="layer0", conn_args=dict(synapse=None), ) net.config[layer0].on_chip = False layer1, conv1, conn1 = conv_layer( layer0.neurons, input_shape=conv0.output_shape, array_init=filters1, strides=(2, 2), channels_last=channels_last, label="layer1", ) net.config[layer1].block_shape = nengo_loihi.BlockShape( make_shape((4, 4), f_split, channels_last), conv1) net.config[conn1].pop_type = pop_type layer2, conv2, conn2 = conv_layer( layer1.neurons, input_shape=conv1.output_shape, array_init=filters2, strides=(1, 1), channels_last=channels_last, label="layer2", ) net.config[layer2].block_shape = nengo_loihi.BlockShape( make_shape((4, 4), f_split, channels_last), conv2) net.config[conn2].pop_type = pop_type output_p = nengo.Probe(layer2.neurons) output_shape = conv2.output_shape with nengo.Simulator(net, optimize=False) as sim_nengo: sim_nengo.run(pres_time) ref_out = (sim_nengo.data[output_p] > 0).sum(axis=0).reshape( output_shape.shape) with Simulator(net, target="sim") as sim_emu: sim_emu.run(pres_time) emu_out = (sim_emu.data[output_p] > 0).sum(axis=0).reshape( output_shape.shape) # TODO: Remove the if condition when configurable timeout parameter # is available in nxsdk if (pop_type == 32 or os.popen("sinfo -h --partition=nahuku32").read().find("idle") > 0): with Simulator( net, precompute=precompute, hardware_options={ "allocator": RoundRobin(), "snip_max_spikes_per_step": 800, }, ) as sim_loihi: sim_loihi.run(pres_time) sim_out = ((sim_loihi.data[output_p] > 0).sum(axis=0).reshape( output_shape.shape)) elif nengo_loihi.version.dev is None: pytest.fail( "Pop16 multichip test failed since Nahuku32 is unavailable") else: pytest.skip( "Pop16 multichip test skipped since Nahuku32 is unavailable") out_max = ref_out.max() ref_out = ref_out / out_max emu_out = emu_out / out_max sim_out = sim_out / out_max if channels_last: # channels first, to display channels in separate plots ref_out = np.transpose(ref_out, (2, 0, 1)) emu_out = np.transpose(emu_out, (2, 0, 1)) sim_out = np.transpose(sim_out, (2, 0, 1)) # --- plot results rows = 2 cols = 3 ax = plt.subplot(rows, cols, 1) imshow(test_x, vmin=0, vmax=1, ax=ax) ax = plt.subplot(rows, cols, 2) tile(np.transpose(filters1, (2, 3, 0, 1))[0], rows=2, cols=2, grid=True, ax=ax) ax = plt.subplot(rows, cols, 3) plt.hist((ref_out.ravel(), emu_out.ravel(), sim_out.ravel()), bins=21) ax = plt.subplot(rows, cols, 4) tile(ref_out, rows=2, cols=2, grid=True, ax=ax) ax = plt.subplot(rows, cols, 5) tile(emu_out, rows=2, cols=2, grid=True, ax=ax) ax = plt.subplot(rows, cols, 6) tile(sim_out, rows=2, cols=2, grid=True, ax=ax) assert allclose(sim_out, ref_out, atol=0.15, rtol=1e-3) assert allclose(sim_out, emu_out, atol=1e-3, rtol=1e-3)
with nengo_dl.Simulator(net) as nengo_sim: nengo_sim.load_params("keras_to_loihi_loihineuron_params") nengo_sim.freeze_params(net) with net: nengo_input.output = nengo.processes.PresentInput( test_images, presentation_time=pres_time) with net: nengo_loihi.add_params(net) # allow on_chip to be set net.config[nengo_converter.layers[to_spikes].ensemble].on_chip = False with net: conv0_shape = conv0_layer.output_shape[1:] net.config[nengo_converter.layers[conv0]. ensemble].block_shape = nengo_loihi.BlockShape((16, 16, 4), conv0_shape) conv1_shape = conv1_layer.output_shape[1:] net.config[nengo_converter.layers[conv1]. ensemble].block_shape = nengo_loihi.BlockShape((8, 8, 16), conv1_shape) dense0_shape = dense0_layer.output_shape[1:] net.config[nengo_converter.layers[dense0]. ensemble].block_shape = nengo_loihi.BlockShape((50, ), dense0_shape) # build Nengo Loihi Simulator and run network with nengo_loihi.Simulator(net) as loihi_sim: loihi_sim.run(n_test * pres_time)
nengo_sim.freeze_params(net) with net: nengo_input.output = nengo.processes.PresentInput( test_data, presentation_time=pres_time) # set off-chip layer with net: nengo_loihi.add_params(net) net.config[nengo_converter.layers[to_spikes].ensemble].on_chip = False # set on-chip layers with net: L1_shape = L1_layer.output_shape[1:] net.config[nengo_converter.layers[L1]. ensemble].block_shape = nengo_loihi.BlockShape((16, 16, 4), L1_shape) L2_shape = L2_layer.output_shape[1:] net.config[nengo_converter.layers[L2]. ensemble].block_shape = nengo_loihi.BlockShape((8, 8, 16), L2_shape) L3_shape = L3_layer.output_shape[1:] net.config[nengo_converter.layers[L3]. ensemble].block_shape = nengo_loihi.BlockShape((4, 4, 32), L3_shape) L4_shape = L4_layer.output_shape[1:] net.config[nengo_converter.layers[L4]. ensemble].block_shape = nengo_loihi.BlockShape((2, 2, 64), L4_shape)