def test_stateful(Simulator, sim_stateful, func_stateful, func): with Network() as net: config.configure_settings(stateful=sim_stateful) Ensemble(30, 1) with Simulator(net) as sim: kwargs = dict(n_steps=5, stateful=func_stateful) with pytest.warns(None) as recwarns: getattr(sim, func)(**kwargs) assert sim.n_steps == (5 if func_stateful and sim_stateful else 0) if func == "predict" and func_stateful and not sim_stateful: # note: we do not get warnings for predict_on_batch/run_steps because # they automatically set func_stateful=sim_stateful assert (len([ w for w in recwarns if "Ignoring stateful=True" in str(w.message) ]) > 0) else: assert len(recwarns) == 0 getattr(sim, func)(**kwargs) assert sim.n_steps == (10 if func_stateful and sim_stateful else 0)
def tensor_layer(input, layer_func, shape_in=None, synapse=None, transform=1, **layer_args): """A utility function to construct TensorNodes that apply some function to their input (analogous to the ``tf.layers`` syntax). Parameters ---------- input : :class:`~nengo:nengo.base.NengoObject` object providing input to the layer layer_func : callable or :class:`~nengo:nengo.neurons.NeuronType` a function that takes the value from ``input`` (represented as a ``tf.Tensor``) and maps it to some output value. or a Nengo neuron type, defining a nonlinearity that will be applied to ``input`` shape_in : tuple of int, optional if not None, reshape the input to the given shape synapse : float or :class:`~nengo:nengo.synapses.Synapse`, optional synapse to apply on connection from ``input`` to this layer transform : :class:`~numpy:numpy.ndarray`, optional transform matrix to apply on connection from ``input`` to this layer layer_args : dict, optional these arguments will be passed to ``layer_func`` if it is callable, or :class:`~nengo:nengo.Ensemble` if ``layer_func`` is a :class:`~nengo:nengo.neurons.NeuronType` Returns ------- :class:`.TensorNode` or :class:`~nengo:nengo.ensemble.Neurons` a TensorNode that implements the given layer function (if ``layer_func`` was a callable), or a Neuron object with the given neuron type, connected to ``input`` """ if isinstance(layer_func, NeuronType): node = Ensemble(input.size_out, 1, neuron_type=layer_func, **layer_args).neurons else: # add (ignored) time input and pass kwargs def node_func(_, x): return layer_func(x, **layer_args) # reshape input if necessary if shape_in is not None: node_func = reshaped(shape_in)(node_func) node = TensorNode(node_func, size_in=input.size_out) Connection(input, node, synapse=synapse, transform=transform) return node
def test_keep_history(Simulator, seed): with Network(seed=seed) as net: config.configure_settings(keep_history=True) a = Ensemble(30, 1) p = Probe(a.neurons, synapse=0.1) with Simulator(net) as sim: sim.run_steps(10) with net: net.config[p].keep_history = False with Simulator(net) as sim2: sim2.run_steps(10) assert sim.data[p].shape == (10, 30) assert sim2.data[p].shape == (1, 30) assert np.allclose(sim.data[p][[-1]], sim2.data[p])
def test_keep_history(Simulator, use_loop, seed): with Network(seed=seed) as net: config.configure_settings(keep_history=True, use_loop=use_loop) a = Ensemble(30, 1) p = Probe(a.neurons, synapse=0.1) kwargs = dict() if use_loop else dict(unroll_simulation=10) with Simulator(net, **kwargs) as sim: sim.run_steps(10) with net: net.config[p].keep_history = False with Simulator(net, **kwargs) as sim2: sim2.run_steps(10) assert sim.data[p].shape == (10, 30) assert sim2.data[p].shape == (1, 30) assert np.allclose(sim.data[p][[-1]], sim2.data[p])
def get_ensemble(self, dim, add_to_container=True): if self.is_input and self.pairs_per_dim != 1: # To support this, we need to figure out how to deal with the # `post_inds` that map neurons to axons. Either we can do this # on the host, in which case we'd have inputs going to the chip # where we can have multiple spikes per axon per timestep, or we # need to do it on the chip with one input axon per neuron. raise NotImplementedError( "Input neurons with more than one neuron per dimension") n_neurons = 2 * dim * self.pairs_per_dim encoders = np.vstack([np.eye(dim), -np.eye(dim)] * self.pairs_per_dim) return Ensemble( n_neurons, dim, neuron_type=SpikingRectifiedLinear(), encoders=encoders, gain=self.gain.repeat(dim), bias=self.bias.repeat(dim), add_to_container=add_to_container, )
def __call__( self, input, transform=default_transform, shape_in=None, synapse=None, return_conn=False, **layer_args ): """ Apply the TensorNode layer to the given input object. Parameters ---------- input : ``NengoObject`` Object providing input to the layer. transform : `~numpy.ndarray` Transform matrix to apply on connection from ``input`` to this layer. shape_in : tuple of int If not None, reshape the input to the given shape. synapse : float or `~nengo.synapses.Synapse` Synapse to apply on connection from ``input`` to this layer. return_conn : bool If True, also return the connection linking this layer to ``input``. layer_args : dict These arguments will be passed to `.TensorNode` if ``layer_func`` is a callable or Keras Layer, or `~nengo.Ensemble` if ``layer_func`` is a `~nengo.neurons.NeuronType`. Returns ------- obj : `.TensorNode` or `~nengo.ensemble.Neurons` A TensorNode that implements the given layer function (if ``layer_func`` was a callable/Keras layer), or a Neuron object with the given neuron type, connected to ``input``. conn : `~nengo.Connection` If ``return_conn`` is True, also returns the connection object linking ``input`` and ``obj``. Notes ----- The input connection created for the new TensorNode will be marked as non-trainable by default. """ if shape_in is not None and all(x is not None for x in shape_in): size_in = np.prod(shape_in) elif isinstance(transform, np.ndarray) and transform.ndim == 2: size_in = transform.shape[0] else: size_in = input.size_out if isinstance(self.layer_func, NeuronType): obj = Ensemble( size_in, 1, neuron_type=self.layer_func, **layer_args ).neurons else: obj = TensorNode( self.layer_func, shape_in=(size_in,) if shape_in is None else shape_in, pass_time=False, **layer_args, ) conn = Connection(input, obj, synapse=synapse, transform=transform) # set connection to non-trainable cfg = Config.context[0][conn] if not hasattr(cfg, "trainable"): configure_settings(trainable=None) cfg.trainable = False return (obj, conn) if return_conn else obj
from matplotlib.pyplot import plot, show from nengo import Connection, Ensemble, Network, Node, Probe # from nengo.utils.simulator import operator_dependency_graph from nengo_dl import Simulator from numpy import sin # define the model with Network() as model: stim = Node(sin) a = Ensemble(100, 1) b = Ensemble(100, 1) Connection(stim, a) Connection(a, b, function=lambda x: x**2) probe_a = Probe(a, synapse=0.01) probe_b = Probe(b, synapse=0.01) # build and run the model with Simulator(model) as sim: sim.run(10) # plot the results plot(sim.trange(), sim.data[probe_a]) plot(sim.trange(), sim.data[probe_b]) show()
def tensor_layer(input, layer_func, shape_in=None, synapse=None, transform=1, return_conn=False, **layer_args): """A utility function to construct TensorNodes that apply some function to their input (analogous to the ``tf.layers`` syntax). Parameters ---------- input : ``NengoObject`` Object providing input to the layer layer_func : callable or `~nengo.neurons.NeuronType` A function that takes the value from ``input`` (represented as a ``tf.Tensor``) and maps it to some output value, or a Nengo neuron type, defining a nonlinearity that will be applied to ``input``. shape_in : tuple of int If not None, reshape the input to the given shape synapse : float or `~nengo.synapses.Synapse` Synapse to apply on connection from ``input`` to this layer transform : `~numpy.ndarray` Transform matrix to apply on connection from ``input`` to this layer return_conn : bool If True, also return the connection linking this layer to ``input`` layer_args : dict These arguments will be passed to ``layer_func`` if it is callable, or `~nengo.Ensemble` if ``layer_func`` is a `~nengo.neurons.NeuronType` Returns ------- node : `.TensorNode` or `~nengo.ensemble.Neurons` A TensorNode that implements the given layer function (if ``layer_func`` was a callable), or a Neuron object with the given neuron type, connected to ``input`` conn : `~nengo.Connection` If ``return_conn`` is True, also returns the connection object linking ``input`` and ``node``. """ if isinstance(transform, np.ndarray) and transform.ndim == 2: size_in = transform.shape[0] elif shape_in is not None: size_in = np.prod(shape_in) else: size_in = input.size_out if isinstance(layer_func, NeuronType): node = Ensemble(size_in, 1, neuron_type=layer_func, **layer_args).neurons else: # add (ignored) time input and pass kwargs def node_func(_, x): return layer_func(x, **layer_args) # reshape input if necessary if shape_in is not None: node_func = reshaped(shape_in)(node_func) node = TensorNode(node_func, size_in=size_in) conn = Connection(input, node, synapse=synapse, transform=transform) return (node, conn) if return_conn else node