I have a neural ensemble and I want to access the decoder in order to manually convert from neural spiking to the representational dimension. I see there’s an encoders attribute on ensembles, but is there a way to access the decoder? I thought the decoder is a matrix but now I’m not sure since it seems like the encoders are a probability distribution (UniformHypersphere) that is sampled from rather than a deterministic matrix? Thanks!
You are correct in the understanding that the encoders and decoders of an ensemble are matrices. In Nengo, however, there is a distinction between the model definition, and the model being used in the simulation.
Nengo Model Descriptions and Built Models
When you define a Nengo model like so:
with nengo.Network() as model: ...
You are only creating a description of that Nengo model, and most of the model’s parameters (e.g. encoders and decoders) are not defined until Nengo actually goes to build the model. Rather, Nengo typically defines these parameters with placeholders (like Nengo distributions) that inform the model builder on how to generate values for these objects when the times comes.
The Nengo model is not constructed until the
nengo.Simulator call is made, like so:
with nengo.Simulator(model) as sim: ...
Once this call is made, the Nengo builder goes through the process of generating and solving for the model parameters.
A note about the decoders - since the decoders are “defined” by the desired “output” function (you can have multiple sets of decoders coming from one ensemble, each implementing their own function), in Nengo, the decoders are not part of the ensemble. Rather they are part of the connection object that defines the function to be computed.
Now, let’s apply this to an example. Suppose you had a Nengo model defined like so:
with nengo.Network() as model: ens = nengo.Ensemble(10, 2) node = nengo.Node(size_in=2) # Have something to connect to so that we can see the decoders conn = nengo.Connection(ens, node, synapse=None)
To get at the ensemble’s encoders, we’ll need to build the model first. Since we aren’t actually running the model simulation, we aren’t using the
with context here (but it will be the same in the
sim = nengo.Simulator(model)
The ensemble encoders can then be retrieved like so:
encoders = sim.model.params[ens].encoders
Getting at the decoders is a little more complicated, and there are two ways to do it. The simplest method is to simply do this:
weights = sim.model.params[conn].weights
However, it should be noted that these
weights are a combination of the connection’s
transform and the connection’s
decoders. So, if you have defined a
transform value that is not
1 (or the default value), another method will be needed to get the decoders.
To save memory, Nengo doesn’t store the decoders separately from the connection weights. Thus, to get the decoders, one will need to manually compute the decoders by using the
decoders = nengo.builder.connection.build_decoders(sim.model, conn, np.random.RandomState())
build_decoders function returns a tuple of items, and the decoders are the second of them.