Basal Ganglia input

Hello,
I have a question regarding tutorial 20 about Basal Ganglia and Action selection. I know that Basal Ganglia can receive multiple scalar inputs. In order to change the input to 2 action groups (to manipulate their activity), I created 2 nodes and connected to Basal Ganglia input node. However, the code is not working and I could not figure out why. I was wondering if you could explain it to me. You can see the code down below:

import nengo
import nengo.spa as spa

D = 32
model = spa.SPA()
   with model:
      model.mind = spa.State(D)
      model.action = spa.State(D)

actions = spa.Actions(
    "dot(mind,THOUGHT1) --> action=DO1",
    "dot(mind,THOUGHT2) --> action=DO2"
   )
model.bg = spa.BasalGanglia(actions)
node1 = nengo.Node([0])
node2 = nengo.Node([0])
nengo.Connection(node1[0], model.bg.input)
nengo.Connection(node2[0], model.bg.input)

model.thalamus = spa.Thalamus(model.bg)
1 Like

Hi @cansukucuksozen,

You didn’t specify but I assume that you are doing this from within the NengoGUI? If you are not using NengoGUI, there are some other things (apart from those I will be discussing below) that you will need to add to your code to get it to function.

Apart from that, I presume that what you are attempting to accomplish is to use the scalar inputs (from nodes) to affect the input values to the two actions you have defined? Let me know if my presumption is wrong.

Looking at your code, it is mostly correct. I’ll step through your code and explain what each part of it does, and if it need correction.


import nengo
import nengo.spa as spa

D = 32
model = spa.SPA()
with model:
    model.mind = spa.State(D)
    model.action = spa.State(D)

This part is pretty straight forward. You defined an SPA model, as well as two State modules, one called mind and the other called action.


    actions = spa.Actions(
        "dot(mind,THOUGHT1) --> action=DO1",
        "dot(mind,THOUGHT2) --> action=DO2"
    )
    model.bg = spa.BasalGanglia(actions)

In this part of the code two rules are defined as part of the BG actions. The first rule triggers if the value represented in the mind State is the THOUGHT1 semantic pointer. When this rule triggers, the value in the action State is set to the DO1 semantic pointer. The second rule triggers if the value represented in the mind State is the THOUGHT2 semantic pointer, and this will result in the semantic pointer DO2 being stored in the action State.

If you are using NengoGUI, you will need to modify the semantic pointer values of the mind State for these rules to have any effect. You do this by right clicking on the mind State on the network diagram, choosing the semantic pointer cloud and then using the set value option in the right-click menu of the semantic pointer cloud.

If you are not using NengoGUI, you’ll need to add a spa.Input module (the syntax is very much like a nengo.Node) to provide the mind State with some input. Otherwise, the value inside mind will not change as the simulation is running. You can see an example of how to do this on this documentation page. I should note that the documentation I’ve linked to is not the most recent version since the build-in nengo.spa library has been deprecated in favour of using the more fully featured NengoSPA package.


    node1 = nengo.Node([0])
    node2 = nengo.Node([0])

Here, you create two Nengo nodes. These nodes are (I assume) to be used to feed a scalar value offset to the BG inputs. They are currently defined with a starting output of [0] (which is just a scalar value of 0). If you are using the NengoGUI, you can set these values using the input slider for these nodes. If you are not using the GUI, you’ll need to modify this code to use a python function instead of a steady “0” as an output.


    nengo.Connection(node1[0], model.bg.input)
    nengo.Connection(node2[0], model.bg.input)

So here is where your issue is. I think what you are trying to do is to connect node1 to the first BG action, and node2 to the second BG action? If that was the case, what you’ll want to do is this:

    nengo.Connection(node1, model.bg.input[0])
    nengo.Connection(node2, model.bg.input[1])

In the corrected code, the output of each node is a scalar value, so it doesn’t need (or can’t) be index. For the connection’s destinations, we use the list index to tell Nengo which dimension of the BG input to connect to. Since node1 is to be connected to the first action, the index [0] is used here. Likewise, since node2 is to be connected to the second action, the index [1] is used.

And that should fix your code, assuming i’ve interpreted your intention properly.

1 Like

Thank you so much, this explanation was very helpful! I have two more questions about this tutorial:

  • I saw in the source code that mutual inhibition happens in thalamus but I could not understand why that is since what I read from Gurney et al. (2001) and “How to Build a Brain” book indicates that Basal Ganglia is the one that does the mutual inhibition through the competition of the direct and indirect pathways.
  • When I try to change my code in Nengo, first it gives an error and does not run the program. But when I save this change and shut down the program, when I reopen the same file (that has the new changes), it suddenly works and does not give an error. I could not understand why this happens. Could this be a type of bug?
1 Like

There are multiple mutual inhibition circuits within Nengo’s default implementation of the BG-Thalamus-Cortex loop. The mutual inhibition circuit in the Thalamus network is a “standard” mutual inhibition circuit. And while it can be used to do action selection, it can get “stuck” when the inputs are fairly close to each other. This can happen when the input switch with particular values(e.g., going from [0, 0.8] to [0.7, 0.8]). The structure of the BG network somewhat mitigates this, but, for the BG network, it is possible to have outputs that are not as “clean” as one would like (e.g., the output can be [-1, -0.2]). So, in Nengo, we default the Thalamus network to perform mutual inhibition on the outputs of the BG. This two-step process produces a “cleaner” output, which makes the action selection more robust. (Caveat: All of what I mentioned above is from prior experience playing around with the BG-Thalamus network, and is more a generalization than anything… i.e., don’t quote me! :laughing:)

Note that if you don’t want the Thalamus to have mutual inhibition, you can turn this off by doing this:

model.thal = spa.Thalamus(model.bg, mutual_inhibit=0)

Without knowing exactly what the error is, it’s a little hard to say exactly why this is happening to you. From experience, this typically happens when something trips up the code editor (maybe an exception, or misconfiguration of the network), which gets it stuck in an error loop. Unfortunately, the only way to solve this is to shut down and reopen Nengo.

The next time you encounter this error, post the error message here, and the steps you took to produce the problem. Then I can provide some suggestions on how to mitigate the issue.

1 Like