def __init__(self, network, precompute=False, remove_passthrough=True): self.network = network # subset of network: only nodes and ensembles; # probes are handled dynamically self._seen_objects = set() # subset of seen, marking which are run on the hardware; # those running on the host are "seen - chip" self._chip_objects = set() # Step 1. Place nodes on host self._seen_objects.update(network.all_nodes) # Step 2. Place all possible ensembles on chip # Note: assumes add_params already called by the simulator for ens in network.all_ensembles: if (network.config[ens].on_chip in (None, True) and not isinstance(ens.neuron_type, Direct)): self._chip_objects.add(ens) self._seen_objects.add(ens) # Step 3. Move learning ensembles (post and error) to host for conn in network.all_connections: pre = base_obj(conn.pre) post = base_obj(conn.post) if (conn.learning_rule_type is not None and isinstance(post, Ensemble) and post in self._chip_objects): if network.config[post].on_chip: raise BuildError("Post ensemble (%r) of learned " "connection (%r) must not be configured " "as on_chip." % (post, conn)) self._chip_objects.remove(post) elif (isinstance(post, LearningRule) and isinstance(pre, Ensemble) and pre in self._chip_objects): if network.config[pre].on_chip: raise BuildError("Pre ensemble (%r) of error " "connection (%r) must not be configured " "as on_chip." % (pre, conn)) self._chip_objects.remove(pre) # Step 4. Mark passthrough nodes for removal if remove_passthrough: passthroughs = set( obj for obj in network.all_nodes if is_passthrough(obj)) ignore = self._seen_objects - self._chip_objects - passthroughs self.passthrough = PassthroughSplit(network, ignore) else: self.passthrough = PassthroughSplit(None) # Step 5. Split precomputable parts of host # This is a subset of host, marking which are precomputable if precompute: self._host_precomputable_objects = self._preclosure() else: self._host_precomputable_objects = set()
def test_passthrough_placement(): with nengo.Network() as model: stim = nengo.Node(0) a = nengo.Node(None, size_in=1) # should be off-chip b = nengo.Ensemble(10, 1) c = nengo.Node(None, size_in=1) # should be removed d = nengo.Node(None, size_in=1) # should be removed e = nengo.Node(None, size_in=1) # should be removed f = nengo.Ensemble(10, 1) g = nengo.Node(None, size_in=1) # should be off-chip nengo.Connection(stim, a) nengo.Connection(a, b) conn_bc = nengo.Connection(b, c) conn_cd = nengo.Connection(c, d) conn_de = nengo.Connection(d, e) conn_ef = nengo.Connection(e, f) nengo.Connection(f, g) nengo.Probe(g) split = PassthroughSplit(model, ignore={stim}) assert split.to_remove == {c, d, e, conn_bc, conn_cd, conn_de, conn_ef} assert len(split.to_add) == 1 conn = next(iter(split.to_add)) assert conn.pre is b assert conn.post is f
def __init__(self, network, precompute=None, remove_passthrough=True): self.network = network # Place objects on host or chip self.hostchip = HostChipSplit(network) # Determine how passthrough nodes will be handled if remove_passthrough: self.passthrough = PassthroughSplit(self.network, self.hostchip) else: self.passthrough = PassthroughSplit(None, None) # Determine which host objects are precomputable self._precomputable = PrecomputableSplit( network, self.hostchip, self.passthrough, strict=precompute is True ) self.precompute = precompute if self.precompute is None: self.precompute = self.precomputable()
def test_full_array(n_ensembles, ens_dimensions): with nengo.Network() as model: a = nengo.networks.EnsembleArray(10, n_ensembles, ens_dimensions) b = nengo.networks.EnsembleArray(10, n_ensembles, ens_dimensions) D = n_ensembles * ens_dimensions nengo.Connection(a.output, b.input, transform=np.ones((D, D))) split = PassthroughSplit(model) assert len(split.to_add) == n_ensembles**2 pairs = set() for conn in split.to_add: assert conn.pre in a.all_ensembles assert conn.post in b.all_ensembles assert np.allclose(transform_array(conn.transform), np.ones((ens_dimensions, ens_dimensions))) pairs.add((conn.pre, conn.post)) assert len(pairs) == n_ensembles**2
def test_transform_merging(d1, d2, d3): with nengo.Network() as model: a = nengo.Ensemble(10, d1) b = nengo.Node(None, size_in=d2) c = nengo.Ensemble(10, d3) t1 = np.random.uniform(-1, 1, (d2, d1)) t2 = np.random.uniform(-1, 1, (d3, d2)) conn_ab = nengo.Connection(a, b, transform=t1) conn_bc = nengo.Connection(b, c, transform=t2) split = PassthroughSplit(model) assert split.to_remove == {b, conn_ab, conn_bc} assert len(split.to_add) == 1 conn = next(iter(split.to_add)) assert np.allclose(transform_array(conn.transform), np.dot(t2, t1))
def test_identity_array(n_ensembles, ens_dimensions): with nengo.Network() as net: a = nengo.networks.EnsembleArray(10, n_ensembles, ens_dimensions) b = nengo.networks.EnsembleArray(10, n_ensembles, ens_dimensions) nengo.Connection(a.output, b.input) split = PassthroughSplit(net, HostChipSplit(net)) assert len(split.to_add) == n_ensembles pre = set() post = set() for conn in split.to_add: assert conn.pre in a.all_ensembles or conn.pre_obj is a.input assert conn.post in b.all_ensembles assert np.allclose(conn.transform.init, np.eye(ens_dimensions)) pre.add(conn.pre) post.add(conn.post) assert len(pre) == n_ensembles assert len(post) == n_ensembles
def test_synapse_merging(Simulator, seed): with nengo.Network(seed=seed) as model: a = nengo.networks.EnsembleArray(10, n_ensembles=2) b = nengo.Node(None, size_in=2) c = nengo.networks.EnsembleArray(10, n_ensembles=2) nengo.Connection(a.output[0], b[0], synapse=None) nengo.Connection(a.output[1], b[1], synapse=0.1) nengo.Connection(b[0], c.input[0], synapse=None) nengo.Connection(b[0], c.input[1], synapse=0.2) nengo.Connection(b[1], c.input[0], synapse=None) nengo.Connection(b[1], c.input[1], synapse=0.2) split = PassthroughSplit(model) assert len(split.to_add) == 4 desired_filters = { ('0', '0'): None, ('0', '1'): 0.2, ('1', '0'): 0.1, ('1', '1'): 0.3, } for conn in split.to_add: if desired_filters[(conn.pre.label, conn.post.label)] is None: assert conn.synapse is None else: assert isinstance(conn.synapse, nengo.Lowpass) assert np.allclose( conn.synapse.tau, desired_filters[(conn.pre.label, conn.post.label)]) # check that model builds/runs, and issues the warning with pytest.warns(UserWarning) as record: with Simulator(model, remove_passthrough=True) as sim: sim.step() assert any("Combining two Lowpass synapses" in r.message.args[0] for r in record)