Dynamicly scaling a semantic pointer in nengo_spa


#1

Hello,

I am using nengo_spa to form semantic pointers that can vary dynamically in scale. Implementing this bring up the error: NotImplementedError: Dynamic scaling of the semantic pointer not implemented. using the code below:

import nengo
import nengo_spa as spa

spa_dim = 32
vocab = spa.Vocabulary(dimensions=spa_dim)
vocab.populate('HELLO; WORLD')

model = spa.Network()
with model:
    spa_input = spa.Transcode('HELLO', output_vocab=vocab, label='spa_input')
    spa_output = spa.State(vocab, label='spa_output')
    scale_node = nengo.Node([0.5])

    # dynamically scale SP
    scale_node * spa_input >> spa_output

    # statically scale SP
    #0.8 * spa_input >> spa_output

Is there an alternative way going about this?

Thanks!


#2

So this is the work around I’ve come up with at the moment. I’m not sure how ideal the setup is.

import nengo
import nengo_spa as spa

spa_dim = 32
vocab = spa.Vocabulary(dimensions=spa_dim)
vocab.populate('HELLO; WORLD')

model = spa.Network()
with model:
    spa_input = spa.Transcode('HELLO', output_vocab=vocab, label='spa_input')
    spa_output = spa.State(vocab, label='spa_output')
    scale_node = nengo.Node([0.5])

    scaled_spa = nengo.Ensemble(n_neurons=1, dimensions=spa_dim+1, neuron_type=nengo.Direct())
    nengo.Connection(spa_input.output, scaled_spa[:spa_dim])
    nengo.Connection(scale_node, scaled_spa[spa_dim])
    
    nengo.Connection(scaled_spa, spa_output.input, function=lambda x: x[spa_dim] * x[:spa_dim])

#3

Note that you are using direct mode in your solution which means that the scaling is not computed in neurons. Depending on your use case this might be fine or it might not be (e.g. if you want to argue that your model is biological plausible).

Similar to your solution, but maybe a bit clearer is this approach that uses a Node:

scaled_spa = nengo.Node(lambda t, x: x[:spa_dim] * x[spa_dim], size_in=spa_dim + 1)
nengo.Connection(spa_input.output, scaled_spa[:spa_dim])
nengo.Connection(scale_node, scale_spa[spa_dim])
nengo.Connection(scaled_spa, spa_output.input)

To do the scaling in actual neurons, you can use the Product network:

scaled_spa = nengo.networks.Product(n_neurons=50, dimensions=spa_dim)
nengo.Connection(spa_input.output, scale.input_a)
nengo.Connection(scale_node, scaled_spa.input_b, transform=np.ones((spa_dim, 1)))
nengo.Connection(scaled_spa.output, spa_output.input)

The disadvantage of this approach is that the scaling factor gets replicated or each vector dimension. This is also the main reason this is not implemented in nengo_spa. This replication (and amount of required neural resources) might be surprising and thus it might be better to require the user to be explicit about this. But there is no technical reason and I could be persuaded with a good argument to include this functionality.