Readings: Stewart et al.
Lots of contemporary neural models are quite simple
What happens when our models get more complex?
One group of neurons to represent the state $s$
One group of neurons for each action's utility $Q(s, a_i)$
What should the output be?
The second option seems easier if we consider that we have to do action execution next...
State $s$ is 2-dimensional (x,y plane)
Four actions (A, B, C, D)
Do action A if $s$ is near [1,0], B if near [-1,0], C if near [0,1], D if near [0,-1]
REMINDER: COURSE EVALUATION STUFF!
%pylab inline
import nengo
model = nengo.Network('Selection')
with model:
stim = nengo.Node(lambda t: [np.sin(t), np.cos(t)])
s = nengo.Ensemble(200, dimensions=2)
Q_A = nengo.Ensemble(50, dimensions=1)
Q_B = nengo.Ensemble(50, dimensions=1)
Q_C = nengo.Ensemble(50, dimensions=1)
Q_D = nengo.Ensemble(50, dimensions=1)
nengo.Connection(s, Q_A, transform=[[1,0]])
nengo.Connection(s, Q_B, transform=[[-1,0]])
nengo.Connection(s, Q_C, transform=[[0,1]])
nengo.Connection(s, Q_D, transform=[[0,-1]])
nengo.Connection(stim, s)
model.config[nengo.Probe].synapse = nengo.Lowpass(0.01)
qa_p = nengo.Probe(Q_A)
qb_p = nengo.Probe(Q_B)
qc_p = nengo.Probe(Q_C)
qd_p = nengo.Probe(Q_D)
s_p = nengo.Probe(s)
sim = nengo.Simulator(model)
sim.run(3.)
Populating the interactive namespace from numpy and matplotlib
//anaconda/envs/python3/lib/python3.6/site-packages/IPython/core/magics/pylab.py:160: UserWarning: pylab import has clobbered these variables: ['e', 'positive'] `%matplotlib` prevents importing * from pylab and numpy "\n`%matplotlib` prevents importing * from pylab and numpy"
t = sim.trange()
plot(t, sim.data[s_p], label="state")
legend()
figure(figsize=(8,8))
plot(t, sim.data[qa_p], label='Q_A')
plot(t, sim.data[qb_p], label='Q_B')
plot(t, sim.data[qc_p], label='Q_C')
plot(t, sim.data[qd_p], label='Q_D')
legend(loc='best');
That behavior makes a lot of sense
It's annoying to have all those separate $Q$ neurons
Perfect opportunity to use the EnsembleArray again (see last lecture)
import nengo
model = nengo.Network('Selection')
with model:
stim = nengo.Node(lambda t: [np.sin(t), np.cos(t)])
s = nengo.Ensemble(200, dimensions=2)
Qs = nengo.networks.EnsembleArray(50, n_ensembles=4)
nengo.Connection(s, Qs.input, transform=[[1,0],[-1,0],[0,1],[0,-1]])
nengo.Connection(stim, s)
model.config[nengo.Probe].synapse = nengo.Lowpass(0.01)
qs_p = nengo.Probe(Qs.output)
s_p = nengo.Probe(s)
sim = nengo.Simulator(model)
sim.run(3.)
t = sim.trange()
plot(t, sim.data[s_p], label="state")
legend()
figure(figsize=(8,8))
plot(t, sim.data[qs_p], label='Qs')
legend(loc='best');
Yay, Network Arrays make shorter code!
Back to the model: How do we implement the $max$ function?
Well, it's just a function, so let's implement it
import nengo
def maximum(x):
result = [0,0,0,0]
result[np.argmax(x)] = 1
return result
model = nengo.Network('Selection')
with model:
stim = nengo.Node(lambda t: [np.sin(t), np.cos(t)])
s = nengo.Ensemble(200, dimensions=2)
Qs = nengo.networks.EnsembleArray(50, n_ensembles=4)
Qall = nengo.Ensemble(400, dimensions=4)
Action = nengo.Ensemble(200, dimensions=4)
nengo.Connection(s, Qs.input, transform=[[1,0],[-1,0],[0,1],[0,-1]])
nengo.Connection(Qs.output, Qall)
nengo.Connection(Qall, Action, function=maximum)
nengo.Connection(stim, s)
model.config[nengo.Probe].synapse = nengo.Lowpass(0.01)
qs_p = nengo.Probe(Qs.output)
action_p = nengo.Probe(Action)
s_p = nengo.Probe(s)
sim = nengo.Simulator(model)
sim.run(3.)
t = sim.trange()
plot(t, sim.data[s_p], label="state")
legend()
figure()
plot(t, sim.data[qs_p], label='Qs')
legend(loc='best')
figure()
plot(t, sim.data[action_p], label='Action')
legend(loc='best');
import nengo
model = nengo.Network('Selection')
with model:
stim = nengo.Node(lambda t: [.5,.4] if t <1. else [0,0] )
s = nengo.Ensemble(200, dimensions=2)
Qs = nengo.networks.EnsembleArray(50, n_ensembles=4)
nengo.Connection(s, Qs.input, transform=[[1,0],[-1,0],[0,1],[0,-1]])
e = 0.1
i = -1
recur = [[e, i, i, i], [i, e, i, i], [i, i, e, i], [i, i, i, e]]
nengo.Connection(Qs.output, Qs.input, transform=recur)
nengo.Connection(stim, s)
model.config[nengo.Probe].synapse = nengo.Lowpass(0.01)
qs_p = nengo.Probe(Qs.output)
s_p = nengo.Probe(s)
sim = nengo.Simulator(model)
sim.run(1.)
t = sim.trange()
plot(t, sim.data[s_p], label="state")
legend()
figure()
plot(t, sim.data[qs_p], label='Qs')
legend(loc='best');
import nengo
model = nengo.Network('Selection')
with model:
stim = nengo.Node(lambda t: [.5,.4] if t <1. else [0,0] )
s = nengo.Ensemble(200, dimensions=2)
Qs = nengo.networks.EnsembleArray(50, n_ensembles=4)
Action = nengo.networks.EnsembleArray(50, n_ensembles=4)
nengo.Connection(s, Qs.input, transform=[[1,0],[-1,0],[0,1],[0,-1]])
nengo.Connection(Qs.output, Action.input)
e = 0.1
i = -1
recur = [[e, i, i, i], [i, e, i, i], [i, i, e, i], [i, i, i, e]]
# Let's force the feedback connection to only consider positive values
def positive(x):
if x[0]<0: return [0]
else: return x
pos = Action.add_output('positive', positive)
nengo.Connection(pos, Action.input, transform=recur)
nengo.Connection(stim, s)
model.config[nengo.Probe].synapse = nengo.Lowpass(0.01)
qs_p = nengo.Probe(Qs.output)
action_p = nengo.Probe(Action.output)
s_p = nengo.Probe(s)
sim = nengo.Simulator(model)
sim.run(1.)
t = sim.trange()
plot(t, sim.data[s_p], label="state")
legend(loc='best')
figure()
plot(t, sim.data[qs_p], label='Qs')
legend(loc='best')
figure()
plot(t, sim.data[action_p], label='Action')
legend(loc='best');
e
?%pylab inline
import nengo
def stimulus(t):
if t<.3:
return [.5,.4]
elif .3<t<.5:
return [.4,.5]
else:
return [0,0]
model = nengo.Network('Selection')
with model:
stim = nengo.Node(stimulus)
s = nengo.Ensemble(200, dimensions=2)
Qs = nengo.networks.EnsembleArray(50, n_ensembles=4)
Action = nengo.networks.EnsembleArray(50, n_ensembles=4)
nengo.Connection(s, Qs.input, transform=[[1,0],[-1,0],[0,1],[0,-1]])
nengo.Connection(Qs.output, Action.input)
e = .5
i = -1
recur = [[e, i, i, i], [i, e, i, i], [i, i, e, i], [i, i, i, e]]
# Let's force the feedback connection to only consider positive values
def positive(x):
if x[0]<0: return [0]
else: return x
pos = Action.add_output('positive', positive)
nengo.Connection(pos, Action.input, transform=recur)
nengo.Connection(stim, s)
model.config[nengo.Probe].synapse = nengo.Lowpass(0.01)
qs_p = nengo.Probe(Qs.output)
action_p = nengo.Probe(Action.output)
s_p = nengo.Probe(s)
Populating the interactive namespace from numpy and matplotlib
//anaconda/envs/python3/lib/python3.6/site-packages/IPython/core/magics/pylab.py:160: UserWarning: pylab import has clobbered these variables: ['e', 'maximum', 'positive'] `%matplotlib` prevents importing * from pylab and numpy "\n`%matplotlib` prevents importing * from pylab and numpy"
from nengo_gui.ipython import IPythonViz
IPythonViz(model, "configs/action_selection.py.cfg")
sim = nengo.Simulator(model)
sim.run(1.)
t = sim.trange()
plot(t, sim.data[s_p], label="state")
legend(loc='best')
figure()
plot(t, sim.data[qs_p], label='Qs')
legend(loc='best')
figure()
plot(t, sim.data[action_p], label='Action')
legend(loc='best');
e
too much?%pylab inline
import nengo
def stimulus(t):
if t<.3:
return [.5,.4]
elif .3<t<.5:
return [.3,.5]
else:
return [0,0]
model = nengo.Network('Selection')
with model:
stim = nengo.Node(stimulus)
s = nengo.Ensemble(200, dimensions=2)
Qs = nengo.networks.EnsembleArray(50, n_ensembles=4)
Action = nengo.networks.EnsembleArray(50, n_ensembles=4)
nengo.Connection(s, Qs.input, transform=[[1,0],[-1,0],[0,1],[0,-1]])
nengo.Connection(Qs.output, Action.input)
e = 0.2
i = -1
recur = [[e, i, i, i], [i, e, i, i], [i, i, e, i], [i, i, i, e]]
def positive(x):
if x[0]<0: return [0]
else: return x
pos = Action.add_output('positive', positive)
nengo.Connection(pos, Action.input, transform=recur)
def select(x):
if x[0]>=0: return [1]
else: return [0]
sel = Action.add_output('select', select)
aValues = nengo.networks.EnsembleArray(50, n_ensembles=4)
nengo.Connection(sel, aValues.input)
nengo.Connection(stim, s)
model.config[nengo.Probe].synapse = nengo.Lowpass(0.01)
qs_p = nengo.Probe(Qs.output)
action_p = nengo.Probe(Action.output)
aValues_p = nengo.Probe(aValues.output)
s_p = nengo.Probe(s)
Populating the interactive namespace from numpy and matplotlib
//anaconda/envs/python3/lib/python3.6/site-packages/IPython/core/magics/pylab.py:160: UserWarning: pylab import has clobbered these variables: ['e', 'positive'] `%matplotlib` prevents importing * from pylab and numpy "\n`%matplotlib` prevents importing * from pylab and numpy"
from nengo_gui.ipython import IPythonViz
IPythonViz(model, "configs/action_selection2.py.cfg")
sim = nengo.Simulator(model)
sim.run(1.)
t = sim.trange()
plot(t, sim.data[s_p], label="state")
legend(loc='best')
figure()
plot(t, sim.data[qs_p], label='Qs')
legend(loc='best')
figure()
plot(t, sim.data[action_p], label='Action')
legend(loc='best')
figure()
plot(t, sim.data[aValues_p], label='Action Values')
legend(loc='best');
e
%pylab inline
import nengo
def stimulus(t):
if t<.3:
return [.5,.4]
elif .3<t<.5:
return [.3,.5]
else:
return [0,0]
model = nengo.Network('Selection')
with model:
stim = nengo.Node(stimulus)
s = nengo.Ensemble(200, dimensions=2)
Qs = nengo.networks.EnsembleArray(50, n_ensembles=4)
Action = nengo.networks.EnsembleArray(50, n_ensembles=4)
nengo.Connection(s, Qs.input, transform=[[1,0],[-1,0],[0,1],[0,-1]])
nengo.Connection(Qs.output, Action.input)
e = 0.1
i = -1
recur = [[e, i, i, i], [i, e, i, i], [i, i, e, i], [i, i, i, e]]
def positive(x):
if x[0]<0: return [0]
else: return x
pos = Action.add_output('positive', positive)
nengo.Connection(pos, Action.input, transform=recur)
def select(x):
if x[0]>=0: return [1]
else: return [0]
sel = Action.add_output('select', select)
aValues = nengo.networks.EnsembleArray(50, n_ensembles=4)
nengo.Connection(sel, aValues.input)
nengo.Connection(stim, s)
model.config[nengo.Probe].synapse = nengo.Lowpass(0.01)
qs_p = nengo.Probe(Qs.output)
action_p = nengo.Probe(Action.output)
aValues_p = nengo.Probe(aValues.output)
s_p = nengo.Probe(s)
#sim = nengo.Simulator(model)
#sim.run(1.)
Populating the interactive namespace from numpy and matplotlib
//anaconda/envs/python3/lib/python3.6/site-packages/IPython/core/magics/pylab.py:160: UserWarning: pylab import has clobbered these variables: ['e', 'positive', 'select'] `%matplotlib` prevents importing * from pylab and numpy "\n`%matplotlib` prevents importing * from pylab and numpy"
from nengo_gui.ipython import IPythonViz
IPythonViz(model, "configs/bg_simple1.py.cfg")
And this gets harder to balance as the number of actions increases
But this is still a pretty standard approach
They tend to use a "kWTA" (k-Winners Take All) approach in their models
Any other options?
Activity in the GPi (output)
Leabra approach
Seems to match onto the biology okay
Maybe the weird structure of the basal ganglia is an attempt to do action selection without doing mutual inhibition
Needs to select from a large number of actions
Needs to do so quickly, and without the memory effects
%pylab inline
mm=1
mp=1
me=1
mg=1
#connection strengths from original model
ws=1
wt=1
wm=1
wg=1
wp=0.9
we=0.3
#neuron lower thresholds for various populations
e=0.2
ep=-0.25
ee=-0.2
eg=-0.2
le=0.2
lg=0.2
D = 10
tau_ampa=0.002
tau_gaba=0.008
N = 50
radius = 1.5
import nengo
from nengo.dists import Uniform
model = nengo.Network('Basal Ganglia', seed=4)
with model:
stim = nengo.Node([0]*D)
StrD1 = nengo.networks.EnsembleArray(N, n_ensembles=D, intercepts=Uniform(e,1),
encoders=Uniform(1,1), radius=radius)
StrD2 = nengo.networks.EnsembleArray(N, n_ensembles=D, intercepts=Uniform(e,1),
encoders=Uniform(1,1), radius=radius)
STN = nengo.networks.EnsembleArray(N, n_ensembles=D, intercepts=Uniform(ep,1),
encoders=Uniform(1,1), radius=radius)
GPi = nengo.networks.EnsembleArray(N, n_ensembles=D, intercepts=Uniform(eg,1),
encoders=Uniform(1,1), radius=radius)
GPe = nengo.networks.EnsembleArray(N, n_ensembles=D, intercepts=Uniform(ee,1),
encoders=Uniform(1,1), radius=radius)
nengo.Connection(stim, StrD1.input, transform=ws*(1+lg), synapse=tau_ampa)
nengo.Connection(stim, StrD2.input, transform=ws*(1-le), synapse=tau_ampa)
nengo.Connection(stim, STN.input, transform=wt, synapse=tau_ampa)
def func_str(x): #relu-like function
if x[0]<e: return 0
return mm*(x[0]-e)
strd1_out = StrD1.add_output('func_str', func_str)
strd2_out = StrD2.add_output('func_str', func_str)
nengo.Connection(strd1_out, GPi.input, transform=-wm, synapse=tau_gaba)
nengo.Connection(strd2_out, GPe.input, transform=-wm, synapse=tau_gaba)
def func_stn(x):
if x[0]<ep: return 0
return mp*(x[0]-ep)
stn_out = STN.add_output('func_stn', func_stn)
tr=[[wp]*D for i in range(D)]
nengo.Connection(stn_out, GPi.input, transform=tr, synapse=tau_ampa)
nengo.Connection(stn_out, GPe.input, transform=tr, synapse=tau_ampa)
def func_gpe(x):
if x[0]<ee: return 0
return me*(x[0]-ee)
gpe_out = GPe.add_output('func_gpe', func_gpe)
nengo.Connection(gpe_out, GPi.input, transform=-we, synapse=tau_gaba)
nengo.Connection(gpe_out, STN.input, transform=-wg, synapse=tau_gaba)
Action = nengo.networks.EnsembleArray(N, n_ensembles=D, intercepts=Uniform(0.2,1),
encoders=Uniform(1,1))
bias = nengo.Node([1]*D)
nengo.Connection(bias, Action.input)
nengo.Connection(Action.output, Action.input, transform=(np.eye(D)-1), synapse=tau_gaba)
def func_gpi(x):
if x[0]<eg: return 0
return mg*(x[0]-eg)
gpi_out = GPi.add_output('func_gpi', func_gpi)
nengo.Connection(gpi_out, Action.input, transform=-3, synapse=tau_gaba)
WARNING: pylab import has clobbered these variables: ['negative'] `%matplotlib` prevents importing * from pylab and numpy
from nengo_gui.ipython import IPythonViz
IPythonViz(model, "configs/bg_good2.py.cfg")
Notice that we are also flipping the output from [1, 1, 0, 1] to [0, 0, 1, 0]
Works pretty well
Scales up to many actions
Selects quickly
Dynamic Behaviour of a Spiking Model of Action Selection in the Basal Ganglia
Let's make sure this works with our original system
To make it easy to use the basal ganglia, there is a special network constructor
%pylab inline
import nengo
from nengo.dists import Uniform
model = nengo.Network(label='Selection')
D=4
with model:
stim = nengo.Node([0,0])
s = nengo.Ensemble(200, dimensions=2)
Qs = nengo.networks.EnsembleArray(50, n_ensembles=D)
nengo.Connection(stim, s)
nengo.Connection(s, Qs.input, transform=[[1,0],[-1,0],[0,1],[0,-1]])
Action = nengo.networks.EnsembleArray(50, n_ensembles=D, intercepts=Uniform(0.2,1),
encoders=Uniform(1,1))
bias = nengo.Node([1]*D)
nengo.Connection(bias, Action.input)
nengo.Connection(Action.output, Action.input, transform=(np.eye(D)-1), synapse=0.008)
basal_ganglia = nengo.networks.BasalGanglia(dimensions=D)
nengo.Connection(Qs.output, basal_ganglia.input, synapse=None)
nengo.Connection(basal_ganglia.output, Action.input)
Populating the interactive namespace from numpy and matplotlib
//anaconda/envs/python3/lib/python3.6/site-packages/IPython/core/magics/pylab.py:160: UserWarning: pylab import has clobbered these variables: ['e', 'positive', 'select'] `%matplotlib` prevents importing * from pylab and numpy "\n`%matplotlib` prevents importing * from pylab and numpy"
from nengo_gui.ipython import IPythonViz
IPythonViz(model, "configs/bg_good1.py.cfg")
%pylab inline
import nengo
from nengo.dists import Uniform
model = nengo.Network(label='Selection')
D=4
with model:
stim = nengo.Node([0,0])
s = nengo.Ensemble(200, dimensions=2)
Qs = nengo.networks.EnsembleArray(50, n_ensembles=4)
nengo.Connection(stim, s)
nengo.Connection(s, Qs.input, transform=[[1,0],[-1,0],[0,1],[0,-1]])
Action = nengo.networks.EnsembleArray(50, n_ensembles=D, intercepts=Uniform(0.2,1),
encoders=Uniform(1,1))
bias = nengo.Node([1]*D)
nengo.Connection(bias, Action.input)
nengo.Connection(Action.output, Action.input, transform=(np.eye(D)-1), synapse=0.008)
basal_ganglia = nengo.networks.BasalGanglia(dimensions=D)
nengo.Connection(Qs.output, basal_ganglia.input, synapse=None)
nengo.Connection(basal_ganglia.output, Action.input)
motor = nengo.Ensemble(100, dimensions=2)
nengo.Connection(Action.output[0], motor, transform=[[1],[0]])
nengo.Connection(Action.output[1], motor, transform=[[-1],[0]])
nengo.Connection(Action.output[2], motor, transform=[[0],[1]])
nengo.Connection(Action.output[3], motor, transform=[[0],[-1]])
from nengo_gui.ipython import IPythonViz
IPythonViz(model, "configs/bg_good3.py.cfg")
%pylab inline
import nengo
from nengo.dists import Uniform
model = nengo.Network('Creature')
with model:
stim = nengo.Node([0,0], label='stim')
command = nengo.Ensemble(100, dimensions=2, label='command')
motor = nengo.Ensemble(100, dimensions=2, label='motor')
position = nengo.Ensemble(1000, dimensions=2, label='position')
scared_direction = nengo.Ensemble(100, dimensions=2, label='scared direction')
def negative(x):
return -x[0], -x[1]
nengo.Connection(position, scared_direction, function=negative)
nengo.Connection(position, position, synapse=.05)
def rescale(x):
return x[0]*0.1, x[1]*0.1
nengo.Connection(motor, position, function=rescale)
nengo.Connection(stim, command)
D=4
Q_input = nengo.Node([0,0,0,0], label='select')
Qs = nengo.networks.EnsembleArray(50, n_ensembles=4)
nengo.Connection(Q_input, Qs.input)
Action = nengo.networks.EnsembleArray(50, n_ensembles=D, intercepts=Uniform(0.2,1),
encoders=Uniform(1,1))
bias = nengo.Node([1]*D)
nengo.Connection(bias, Action.input)
nengo.Connection(Action.output, Action.input, transform=(np.eye(D)-1), synapse=0.008)
basal_ganglia = nengo.networks.BasalGanglia(dimensions=D)
nengo.Connection(Qs.output, basal_ganglia.input, synapse=None)
nengo.Connection(basal_ganglia.output, Action.input)
do_command = nengo.Ensemble(300, dimensions=3, label='do command')
nengo.Connection(command, do_command[0:2])
nengo.Connection(Action.output[0], do_command[2])
def apply_command(x):
return x[2]*x[0], x[2]*x[1]
nengo.Connection(do_command, motor, function=apply_command)
do_scared = nengo.Ensemble(300, dimensions=3, label='do scared')
nengo.Connection(scared_direction, do_scared[0:2])
nengo.Connection(Action.output[1], do_scared[2])
nengo.Connection(do_scared, motor, function=apply_command)
//anaconda/envs/python3/lib/python3.6/site-packages/IPython/core/magics/pylab.py:161: UserWarning: pylab import has clobbered these variables: ['negative'] `%matplotlib` prevents importing * from pylab and numpy "\n`%matplotlib` prevents importing * from pylab and numpy"
from nengo_gui.ipython import IPythonViz
IPythonViz(model, "configs/bg_creature.py.cfg")
#first dimensions activates do_command, i.e. go in the indicated direciton
#second dimension activates do_scared, i.e. return 'home' (0,0)
#creature tracks the position it goes to (by integrating)
#creature inverts direction to position via scared direction/do_scared and puts that into motor
%pylab inline
import nengo
from nengo.dists import Uniform
model = nengo.Network('Creature')
with model:
stim = nengo.Node([0,0], label='stim')
command = nengo.Ensemble(100, dimensions=2, label='command')
motor = nengo.Ensemble(100, dimensions=2, label='motor')
position = nengo.Ensemble(1000, dimensions=2, label='position')
scared_direction = nengo.Ensemble(100, dimensions=2, label='scared direction')
def negative(x):
return -x[0], -x[1]
nengo.Connection(position, scared_direction, function=negative)
nengo.Connection(position, position, synapse=.05)
def rescale(x):
return x[0]*0.1, x[1]*0.1
nengo.Connection(motor, position, function=rescale)
nengo.Connection(stim, command)
D=4
Q_input = nengo.Node([0,0,0,0], label='select')
Qs = nengo.networks.EnsembleArray(50, n_ensembles=4)
nengo.Connection(Q_input, Qs.input)
Action = nengo.networks.EnsembleArray(50, n_ensembles=D, intercepts=Uniform(0.2,1),
encoders=Uniform(1,1))
bias = nengo.Node([1]*D)
nengo.Connection(bias, Action.input)
nengo.Connection(Action.output, Action.input, transform=(np.eye(D)-1), synapse=0.008)
basal_ganglia = nengo.networks.BasalGanglia(dimensions=D)
nengo.Connection(Qs.output, basal_ganglia.input, synapse=None)
nengo.Connection(basal_ganglia.output, Action.input)
do_command = nengo.Ensemble(300, dimensions=2, label='do command')
nengo.Connection(command, do_command)
nengo.Connection(Action.output[1], do_command.neurons, transform=-np.ones([300,1]))
nengo.Connection(do_command, motor)
do_scared = nengo.Ensemble(300, dimensions=2, label='do scared')
nengo.Connection(scared_direction, do_scared)
nengo.Connection(Action.output[0], do_scared.neurons, transform=-np.ones([300,1]))
nengo.Connection(do_scared, motor)
//anaconda/envs/python3/lib/python3.6/site-packages/IPython/core/magics/pylab.py:161: UserWarning: pylab import has clobbered these variables: ['negative'] `%matplotlib` prevents importing * from pylab and numpy "\n`%matplotlib` prevents importing * from pylab and numpy"
from nengo_gui.ipython import IPythonViz
IPythonViz(model, "configs/bg_creature2.py.cfg")
We build systems in cortex that give some input-output functionality
Example
%pylab inline
import nengo
from nengo import spa
D = 16
def start(t):
if t < 0.05:
return 'A'
else:
return '0'
model = spa.SPA(label='Sequence_Module', seed=5)
with model:
model.cortex = spa.Buffer(dimensions=D, label='cortex')
model.input = spa.Input(cortex=start, label='input')
actions = spa.Actions(
'dot(cortex, A) --> cortex = B',
'dot(cortex, B) --> cortex = C',
'dot(cortex, C) --> cortex = D',
'dot(cortex, D) --> cortex = E',
'dot(cortex, E) --> cortex = A'
)
model.bg = spa.BasalGanglia(actions=actions)
model.thal = spa.Thalamus(model.bg)
cortex = nengo.Probe(model.cortex.state.output, synapse=0.01)
actions = nengo.Probe(model.thal.actions.output, synapse=0.01)
utility = nengo.Probe(model.bg.input, synapse=0.01)
sim = nengo.Simulator(model)
sim.run(0.5)
WARNING: pylab import has clobbered these variables: ['negative'] `%matplotlib` prevents importing * from pylab and numpy
from nengo_gui.ipython import IPythonViz
IPythonViz(model, "configs/bg_alphabet.py.cfg")
fig = figure(figsize=(12,8))
p1 = fig.add_subplot(3,1,1)
p1.plot(sim.trange(), model.similarity(sim.data, cortex))
p1.legend(model.get_output_vocab('cortex').keys, fontsize='x-small')
p1.set_ylabel('State')
p2 = fig.add_subplot(3,1,2)
p2.plot(sim.trange(), sim.data[actions])
p2_legend_txt = [a.effect for a in model.bg.actions.actions]
p2.legend(p2_legend_txt, fontsize='x-small')
p2.set_ylabel('Action')
p3 = fig.add_subplot(3,1,3)
p3.plot(sim.trange(), sim.data[utility])
p3_legend_txt = [a.condition for a in model.bg.actions.actions]
p3.legend(p3_legend_txt, fontsize='x-small')
p3.set_ylabel('Utility')
fig.subplots_adjust(hspace=0.2)
Is there any evidence that this is the way it works in brains?
What about behavioural evidence?
A few sources of support
Timing data
from IPython.display import YouTubeVideo
YouTubeVideo('sUvHCs5y0o8', width=640, height=390, loop=1, autoplay=0)
What do the actions look like?
State:
goal
: what disk am I trying to move (D0, D1, D2)focus
: what disk am I looking at (D0, D1, D2)goal_peg
: where is the disk I am trying to move (A, B, C)focus_peg
: where is the disk I am looking at (A, B, C)target_peg
: where am I trying to move a disk to (A, B, C)goal_final
: what is the overall final desired location of the disk I'm trying to move (A, B, C)Note: we're not yet modelling all the sensory and memory stuff (e.g. loading) here, so we manually set things like goal_final
.
Action effects: when an action is selected, it could do the following
focus
goal
goal_peg
move
and move_peg
Is this sufficient to implement the algorithm described above?
focus
=NONE then focus
=D2, goal
=D2, goal_peg
=goal_final
focus
$\cdot$ NONEfocus
=D2 and goal
=D2 and goal_peg
!=target_peg
then focus
=D1focus
$\cdot$ D2 + goal
$\cdot$ D2 - goal_peg
$\cdot$ target_peg
focus
=D2 and goal
=D2 and goal_peg
==target_peg
then focus
=D1, goal
=D1, goal_peg
=goal_final
focus
=D1 and goal
=D1 and goal_peg
!=target_peg
then focus
=D0focus
=D1 and goal
=D1 and goal_peg
==target_peg
then focus
=D0, goal
=D0, goal_peg
=goal_final
focus
=D0 and goal_peg
==target_peg
then focus
=NONEfocus
=D0 and goal
=D0 and goal_peg
!=target_peg
then focus
=NONE, move
=D0, move_peg
=target_peg
focus
!=goal
and focus_peg
==goal_peg
and target_peg!=focus_peg
then goal
=focus
, goal_peg
=A+B+C-target_peg
-focus_peg
focus
!=goal
and focus_peg
!=goal_peg
and target_peg==focus_peg
then goal
=focus
, goal_peg
=A+B+C-target_peg
-goal_peg
focus
=D0 and goal
!=D0 and target_peg
!=focus_peg
and target_peg
!=goal_peg
and focus_peg
!=goal_peg
then move
=goal
, move_peg
=target_peg
focus
=D1 and goal
!=D1 and target_peg
!=focus_peg
and target_peg
!=goal_peg
and focus_peg
!=goal_peg
then focus
=D0Do science
Timing: