How to directly access and Modify the connection weight matrix for a nengo connection


#1

Apologies if this has been asked before (I can see an entry for my question at http://www.nengo.ca/faq ) but it is still not clear to me.

In nengo 1.4 it was possible to directly access and modify the connection weight matrix http://nengo.ca/docs/html/weights.html.

Is there a way to do this in nengo 2.3? Specifically, I need to set a certain number of connection weights to zero in a connection between two SPA modules.

Thanks in advance.


#2

The inhibitory gating example makes a direct neuron-to-neuron connection. We also discuss this in a bit more depth in this document.

Note that if you have an existing connection, you may not be able to access the connection weight matrix directly because not all connections have a full connection weight matrix (the document linked above discusses this in more depth). You can effectively zero out a decoded connection by setting its transform to 0, or setting its function to be lambda x: np.zeros(dimensions).


#3

Thanks for the quick reply It was really helpful. I went through both the links mentioned. Suppose I had two directly connected ensembles A and B and wanted to set wij = 0 for a neuron i in A and a neuron j in B. How would I do that without disturbing any other connection?

Setting the transform to 0 or changing the function to np.zeros(dimensions) would effectively disconnect all neurons in A from all neurons in B,if I understand correctly, which is something I do not want to do.

I am trying to damage a single synapse in an already existing connection without modifying anything else. Is there a way to do that ?

Thanks again


#4

Here is some code to get you started:

# First we build a network just containing the connection we want to modify.
# Note that we specify seeds to keep all randomly determined parameters constant.
# These have to be defined on the ensembles and connection because otherwise they
# can change when adding more things to the network.
# We alse set the `solver` on the connection to produce the full weight matrix
# (instead of the usual factorization into decoders and encoders).
with nengo.Network() as find_weights:
    ens1 = nengo.Ensemble(50, 1, seed=1)
    ens2 = nengo.Ensemble(50, 1, seed=2)
    conn = nengo.Connection(ens1, ens2, seed=3, solver=nengo.solvers.LstsqL2(weights=True))
    
with nengo.Simulator(find_weights) as sim:
    pass

# Then we can retrieve the neural connection weights.
# The gains of the post population will be included in the weights and they
# will also be included when doing a neuron to neuron connection. Thus, we
# have to cancel them out here.
weights = sim.data[conn].weights / sim.data[ens2].gain[:, None]

# Here you can modify the weight matrix. Set entries to 0 etc.

# Then you build the actual model with all components.
# Now that we know the weights, we do the connection from the pre neurons to the
# post neurons and set the transform to the weights. Note that these weights get
# multiplied with the gains of the post neurons (that we divided by above).
with nengo.Network() as model:
    ens1 = nengo.Ensemble(50, 1, seed=1)
    ens2 = nengo.Ensemble(50, 1, seed=2)
    conn = nengo.Connection(ens1.neurons, ens2.neurons, transform=weights)
    
# Run your simulation etc.

#5

Thank you so much. Exactly what I was looking for. Would there be a way to do something similar in a cortical connection between two SPA modules?


#6

Yes, but you have to insert the connections manually and be aware that each SPA module usually uses multiple ensembles. This can be adjusted with the subdimensions parameter. Set it to the full dimensionality to get things represented in a single ensemble, but comes with certain trade-offs (model will take longer and more memory to build, accuracy of the representation will be worse for the same number of neurons).

Example to create and get all the connections between the ensembles of two SPA states:

with spa.SPA() as find_weights:
    find_weights.state1 = spa.State(d, seed=1)
    find_weights.state2 = spa.State(d, seed=2)
    connections = [nengo.Connection(e1, e2, seed=seed, solver=nengo.solvers.LstsqL2(weights=True))
        for seed, (e1, e2) in enumerate(zip(
            find_weights.state1.state_ensembles.ensembles,
            find_weigths.state2.state_ensembles.ensembles))]

Usually you can do a cortical connection by just nengo.Connection(find_weights.state1.output, find_weights.state2.input), but the output and input objects are intermediary nodes that prevent you from getting the actual neuron to neuron connection weights.