spa-question-answering-control
A spiking SPA model that decides — using a basal-ganglia/thalamus action-selection loop — whether an incoming visual input is something to remember (a STATEMENT) or something to answer (a QUESTION), and acts accordingly.
Description
This is example 6 of chapter 5 of How to Build a Brain (Eliasmith, 2013), distributed with nengo-gui as 6-spa_question-control.py. It's the most elaborate of the chapter's question-answering models: instead of always-on cortical bindings, the right thing to do is selected dynamically based on the structure of the visual input.
There are three states:
visual— receives the current input, e.g.STATEMENT+RED*CIRCLEorQUESTION+BLUEmemory— recurrent SPA state, holds the sum of seen bound pairsmotor— read-out used to "answer" questions
And two competing actions, picked by spa.BasalGanglia / spa.Thalamus:
dot(visual, STATEMENT) --> memory = visual # store the statement
dot(visual, QUESTION) --> motor = memory * ~visual # answer the question
The utility of each action is the dot product of visual with one of the role pointers (STATEMENT, QUESTION). Whichever role is present wins, the basal ganglia inhibits the loser, the thalamus releases the winner, and the corresponding routing happens. Statements load memory; questions read it out.
A toy schedule of inputs runs:
0.1 – 0.3 s:STATEMENT + RED*CIRCLE0.35 – 0.5 s:STATEMENT + BLUE*SQUARE0.55 – 0.7 s:QUESTION + BLUE→ motor should read outSQUARE0.75 – 0.9 s:QUESTION + CIRCLE→ motor should read outRED
This example is sensitive to dimensionality: 32 dimensions is small enough that you may need a couple of runs (or to bump dim higher) to see clean answers in motor. The tutorial keeps it at 32 to stay fast in the GUI.
A note on nengo.spa vs nengo_spa
This script uses the legacy nengo.spa module that still ships inside core Nengo. The newer, separately maintained nengo_spa package has a redesigned action-selection API. Both run today, but new submissions are generally encouraged to prefer nengo_spa; this submission preserves the original tutorial verbatim.
Run it
In NengoGUI (the intended way to view it):
pip install nengo-gui
nengo spa_question_answering_control.py
Or just at the command line:
python spa_question_answering_control.py
How it works
spa.BasalGanglia builds a spiking neural model of the direct/indirect striatal pathway: a population per action whose firing rate scales with the action's utility (here, dot(visual, STATEMENT) or dot(visual, QUESTION)). The pathway competitively inhibits all but the highest-utility action's GPi output. spa.Thalamus reads GPi, gates the corresponding routing connection (here, either "copy visual into memory" or "compute memory * ~visual into motor"), and lets the winning action execute.
The result is a closed-loop control system: stimuli arrive in visual, the BG/thalamus pick which routing to enable based on the role pointer present, and memory/motor update accordingly. No clock, no explicit gating signals from outside — selection emerges from the dynamics of the action utilities.
memory uses feedback=1, feedback_synapse=0.1 to integrate inputs over a 100 ms timescale, giving the statement enough time to be written in cleanly without smearing into the subsequent question.
Citation
@book{eliasmith2013htb,
author = {Eliasmith, Chris},
title = {How to Build a Brain: A Neural Architecture for Biological Cognition},
publisher = {Oxford University Press},
year = {2013}
}
License
GPLv2 (see LICENSE).
Figures
1 second of the SPA question-answering-with-control network, produced by running spa_question_answering_control.py directly.
The basal-ganglia / thalamus loop selects one of two cortical actions on each timestep based on what's currently in visual: when visual is similar to STATEMENT + …, the bound pair is written into memory; when visual is similar to QUESTION + …, the memory is unbound by the cue and routed to motor.
Top — visual input. Each subnet receives one of four scripted inputs:
STATEMENT + RED * CIRCLE (0.1 – 0.3 s), STATEMENT + BLUE * SQUARE (0.35 – 0.5 s), QUESTION + BLUE (0.55 – 0.7 s), QUESTION + CIRCLE (0.75 – 0.9 s). Similarities to the six atomic vocab terms are plotted.
Middle — memory contents. Plotted against the two bound pairs the network is shown. RED * CIRCLE rises during the first statement, then BLUE * SQUARE accumulates during the second; both persist into the question phase thanks to the memory's recurrent connection.
Bottom — motor output. Stays near zero during the statement phase (the BG selects the "store" action, not the "answer" action). When the first question (QUESTION + BLUE) arrives, SQUARE rises sharply — the network has recalled the answer to "blue is what shape?". When the second question (QUESTION + CIRCLE) arrives, RED rises — "circle is what colour?".