spa-question-answering-memory
A spiking SPA model that binds colour × shape into a bound pair, stores it in a recurrent working memory, and answers questions about the stored pair after the original inputs have gone quiet.
Description
This is example 4 of chapter 5 of How to Build a Brain (Eliasmith, 2013), distributed with nengo-gui as 4-spa_question-memory.py. It extends the spa-question-answering model by adding a recurrent spa.State(dim, feedback=1) named memory and rewiring the cortical actions so the bound pair persists after stimulus offset.
The cortical actions are:
D = A * B # bind colour (A) to shape (B)
memory = D # write the bound pair into recurrent memory
E = memory * ~C # answer cue questions from memory
Stimulation is sequential rather than alternating:
t ∈ [0, 0.25)—A=RED,B=CIRCLEt ∈ [0.25, 0.5)—A=BLUE,B=SQUAREt ≥ 0.5— inputs zero; cues start cycling and memory must answer
By the end of the input phase, memory holds (approximately) RED * CIRCLE + BLUE * SQUARE. After that, asking C = SQUARE returns something most similar to BLUE; asking C = BLUE returns SQUARE; and so on.
The model uses 32-dimensional semantic pointers — small enough for fast CI builds while still keeping vocabulary similarities clean.
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 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_memory.py
Or just at the command line:
python spa_question_answering_memory.py
How it works
The trick is the feedback=1 argument to spa.State: the state gets a recurrent connection from its own output back to its input with unit gain, which approximates a perfect integrator. Inputs from the cortical action memory = D accumulate; once those inputs go to zero, the state holds the most recent value (up to neural drift). The cue is then used to project back out a single attribute via the inverse-binding action E = memory * ~C, just as in the no-memory version.
spa.Cortical compiles each action string into the equivalent set of always-on nengo.Connections — no action selection, no gating, the bindings and memory writes are continuous.
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
2 seconds of the SPA question-answering-with-memory network, produced by running spa_question_answering_memory.py directly.
The first 0.5 s presents two colour×shape bindings to the network with no cue; the bindings accumulate in the memory. After 0.5 s the colour and shape inputs go silent and only the cue varies. The network must use memory to recover the answers.
A — colour input. RED (0 – 0.25 s) then BLUE (0.25 – 0.5 s), then ZERO for the rest of the run.
B — shape input. CIRCLE then SQUARE on the same schedule, then ZERO.
C — cue. Stays at ZERO for the first 0.5 s while the bindings are presented, then cycles through ZERO, CIRCLE, RED, ZERO, SQUARE, BLUE.
memory — bound-pair contents. RED * CIRCLE builds up during 0 – 0.25 s and persists; BLUE * SQUARE builds up during 0.25 – 0.5 s and persists. Both pairs remain in memory throughout the question phase thanks to the State's recurrent connection.
E — recovered answer. Computed as memory * ~cue. When the cue is CIRCLE the network recovers a mixture peaked on RED; when the cue is RED it recovers CIRCLE; and so on. The mixture is "fuzzier" than in the cortical-only variant because both bound pairs are in the memory at once.