LCA - Toy Model#
A simple demo of LCA
reference: Usher, M., & McClelland, J. L. (2001). The time course of perceptual choice: the leaky, competing accumulator model. Psychological Review, 108(3), 550–592. Retrieved from https://www.ncbi.nlm.nih.gov/pubmed/11488378
adapted from: PrincetonUniversity/PsyNeuLink “””
Setup and Installation:
%%capture
%pip install psyneulink
%pip install seaborn
import numpy as np
from matplotlib import pyplot as plt
import seaborn as sns
import psyneulink as pnl
sns.set(style='white', context='poster', font_scale=.8, rc={"lines.linewidth": 2})
np.random.seed(0)
%matplotlib inline
%autosave 5
Autosaving every 5 seconds
# time step
time_step_size = .1
# network params
n_nodes = 3
sd = .2
leak = -1
# Weights
w_input = 1 # w_input (Input to decision layer)
w_cross = .1 # w_cross (Crosstalk input to decision layer)
w_inhib = 1 # w_inhib (Mutual inhibition among decision units)
w_self = 0 # w_self (Self recurrent conn. for each decision unit)
b_dec = 0 # b_dec (Bias input to decision units)
# Weight matrix from Input Layer --> Decision Layer
# Input weights are diagonals, cross weights are off diagonals
identity = np.matrix(np.eye(n_nodes))
mirror_identity = np.ones((n_nodes,n_nodes))
np.fill_diagonal(mirror_identity,0)
input_weights = identity * w_input + mirror_identity * w_cross
# initial states
initial_value = np.zeros((n_nodes,))
# initial_value = np.random.normal(size=(n_nodes,))
input_layer = pnl.TransferMechanism(
size=n_nodes, # Number of units in input layer
initial_value=np.zeros(n_nodes,), # Initial input values
name='INPUT LAYER'
)
decision_layer = pnl.LCAMechanism(
size=n_nodes, # Number of units in input layer
initial_value=initial_value, # Initial input values
time_step_size=time_step_size, # Integration step size
leak=leak, # Sets off diagonals to negative values
self_excitation=w_self, # Set diagonals to self excitate
competition=w_inhib, # Set off diagonals to inhibit
function=pnl.Logistic(x_0=b_dec),
noise=pnl.UniformToNormalDist(standard_deviation=sd).function,
integrator_mode=True,
name='DECISION LAYER'
)
# Set initial output values for decision layer to 0
# for output_state in decision_layer.output_states:
# output_state.value *= 0
decision_process = pnl.Process(
pathway=[input_layer, input_weights, decision_layer],
name='DECISION PROCESS'
)
model = pnl.System(
processes=[decision_process],
reinitialize_mechanisms_when=pnl.Never()
)
---------------------------------------------------------------------------
ComponentError Traceback (most recent call last)
Cell In[4], line 1
----> 1 input_layer = pnl.TransferMechanism(
2 size=n_nodes, # Number of units in input layer
3 initial_value=np.zeros(n_nodes,), # Initial input values
4 name='INPUT LAYER'
5 )
7 decision_layer = pnl.LCAMechanism(
8 size=n_nodes, # Number of units in input layer
9 initial_value=initial_value, # Initial input values
(...) 17 name='DECISION LAYER'
18 )
20 # Set initial output values for decision layer to 0
21 # for output_state in decision_layer.output_states:
22 # output_state.value *= 0
File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/psyneulink/core/globals/parameters.py:506, in check_user_specified.<locals>.check_user_specified_wrapper(self, *args, **kwargs)
503 self._prev_constructor = constructor
505 self._prev_kwargs = kwargs
--> 506 return func(self, *args, **orig_kwargs)
File <@beartype(psyneulink.core.components.mechanisms.processing.transfermechanism.TransferMechanism.__init__) at 0x7f447accf920>:176, in __init__(__beartype_object_139932095902992, __beartype_get_violation, __beartype_conf, __beartype_object_139932213316480, __beartype_object_139935450143936, __beartype_object_139936467789992, __beartype_object_139932094794288, __beartype_object_139936467790104, __beartype_object_139932094794352, __beartype_object_139932094794416, __beartype_object_139932094794480, __beartype_object_139932095724096, __beartype_object_139933100921472, __beartype_object_139932213272592, __beartype_object_139932213319984, __beartype_object_139932213320048, __beartype_object_139932213272672, __beartype_object_139932213320112, __beartype_object_139932213272752, __beartype_args_name_keywordable, __beartype_check_meta, __beartype_func, *args, **kwargs)
File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/psyneulink/core/components/mechanisms/processing/transfermechanism.py:1361, in TransferMechanism.__init__(self, default_variable, input_shapes, input_ports, function, noise, clip, integrator_mode, integrator_function, initial_value, integration_rate, on_resume_integrator_mode, termination_measure, termination_threshold, termination_comparison_op, output_ports, params, name, prefs, **kwargs)
1357 initial_value = self._parse_arg_initial_value(initial_value)
1359 self._current_variable_index = 0
-> 1361 super(TransferMechanism, self).__init__(
1362 default_variable=default_variable,
1363 input_shapes=input_shapes,
1364 input_ports=input_ports,
1365 output_ports=output_ports,
1366 initial_value=initial_value,
1367 noise=noise,
1368 integration_rate=integration_rate,
1369 integrator_mode=integrator_mode,
1370 clip=clip,
1371 termination_measure=termination_measure,
1372 termination_threshold=termination_threshold,
1373 termination_comparison_op=termination_comparison_op,
1374 integrator_function=integrator_function,
1375 on_resume_integrator_mode=on_resume_integrator_mode,
1376 function=function,
1377 params=params,
1378 name=name,
1379 prefs=prefs,
1380 **kwargs
1381 )
File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/psyneulink/core/globals/parameters.py:506, in check_user_specified.<locals>.check_user_specified_wrapper(self, *args, **kwargs)
503 self._prev_constructor = constructor
505 self._prev_kwargs = kwargs
--> 506 return func(self, *args, **orig_kwargs)
File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/psyneulink/core/components/mechanisms/processing/processingmechanism.py:293, in ProcessingMechanism_Base.__init__(self, default_variable, input_shapes, input_ports, function, output_ports, params, name, prefs, context, **kwargs)
270 @check_user_specified
271 def __init__(self,
272 default_variable=None,
(...) 281 **kwargs
282 ):
283 """Abstract class for processing mechanisms
284
285 :param variable: (value)
(...) 290 :param context: (str)
291 """
--> 293 super().__init__(default_variable=default_variable,
294 input_shapes=input_shapes,
295 input_ports=input_ports,
296 function=function,
297 output_ports=output_ports,
298 params=params,
299 name=name,
300 prefs=prefs,
301 context=context,
302 **kwargs
303 )
File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/psyneulink/core/globals/parameters.py:506, in check_user_specified.<locals>.check_user_specified_wrapper(self, *args, **kwargs)
503 self._prev_constructor = constructor
505 self._prev_kwargs = kwargs
--> 506 return func(self, *args, **orig_kwargs)
File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/psyneulink/core/components/mechanisms/mechanism.py:1762, in Mechanism_Base.__init__(self, default_variable, input_shapes, input_ports, input_labels, function, output_ports, output_labels, params, name, prefs, context, **kwargs)
1756 from psyneulink.core.components.ports.outputport import OutputPort
1757 register_category(entry=OutputPort,
1758 base_class=Port_Base,
1759 registry=self._portRegistry,
1760 )
-> 1762 super(Mechanism_Base, self).__init__(
1763 default_variable=default_variable,
1764 input_shapes=input_shapes,
1765 function=function,
1766 param_defaults=params,
1767 prefs=prefs,
1768 name=name,
1769 input_ports=input_ports,
1770 output_ports=output_ports,
1771 input_labels_dict=input_labels,
1772 output_labels_dict=output_labels,
1773 **kwargs
1774 )
1776 # FIX: 10/3/17 - IS THIS CORRECT? SHOULD IT BE INITIALIZED??
1777 self._status = INITIALIZING
File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/psyneulink/core/globals/parameters.py:506, in check_user_specified.<locals>.check_user_specified_wrapper(self, *args, **kwargs)
503 self._prev_constructor = constructor
505 self._prev_kwargs = kwargs
--> 506 return func(self, *args, **orig_kwargs)
File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/psyneulink/core/components/shellclasses.py:82, in Mechanism.__init__(self, default_variable, input_shapes, function, param_defaults, name, prefs, **kwargs)
73 @check_user_specified
74 def __init__(self,
75 default_variable=None,
(...) 80 prefs=None,
81 **kwargs):
---> 82 super().__init__(default_variable=default_variable,
83 input_shapes=input_shapes,
84 function=function,
85 param_defaults=param_defaults,
86 name=name,
87 prefs=prefs,
88 **kwargs)
File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/psyneulink/core/globals/parameters.py:506, in check_user_specified.<locals>.check_user_specified_wrapper(self, *args, **kwargs)
503 self._prev_constructor = constructor
505 self._prev_kwargs = kwargs
--> 506 return func(self, *args, **orig_kwargs)
File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/psyneulink/core/components/component.py:1146, in Component.__init__(self, default_variable, param_defaults, input_shapes, function, name, reset_stateful_function_when, prefs, function_params, **kwargs)
1143 else:
1144 self.reset_stateful_function_when = Never()
-> 1146 parameter_values, function_params = self._parse_arguments(
1147 default_variable, param_defaults, input_shapes, function, function_params, kwargs
1148 )
1150 self._initialize_parameters(
1151 context=context,
1152 **parameter_values
1153 )
1155 var = call_with_pruned_args(
1156 self._handle_default_variable,
1157 **parameter_values
1158 )
File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/psyneulink/core/components/component.py:2245, in Component._parse_arguments(self, default_variable, param_defaults, input_shapes, function, function_params, kwargs)
2240 function_params = {
2241 **kwargs,
2242 **function_params
2243 }
2244 else:
-> 2245 self._validate_arguments(parameter_values)
2247 # self.parameters here still references <class>.parameters, but
2248 # only unchanging attributes are needed here
2249 for p in self.parameters:
File /opt/hostedtoolcache/Python/3.11.11/x64/lib/python3.11/site-packages/psyneulink/core/components/component.py:2190, in Component._validate_arguments(self, parameter_values)
2188 # raise deprecated argument errors
2189 if len(deprecated_args) > 0:
-> 2190 raise create_illegal_argument_error([
2191 f"'{arg}' is deprecated. Use '{new_arg}' instead"
2192 for arg, new_arg in deprecated_args.items()
2193 ])
2195 # raise generic illegal argument error
2196 unknown_args = illegal_passed_args.difference(unused_constructor_args)
ComponentError: INPUT LAYER: Illegal argument in constructor (type: TransferMechanism):
'size' is deprecated. Use 'input_shapes' instead
model.show_graph(output_fmt = 'jupyter')
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[5], line 1
----> 1 model.show_graph(output_fmt = 'jupyter')
NameError: name 'model' is not defined
input_pattern_set = list(np.eye(n_nodes))
num_time_steps = 80
trials = 2
total_trial_length = trials * num_time_steps
stimuli = np.concatenate([
np.repeat(np.array([pattern_i]), num_time_steps, axis=0)
for pattern_i in input_pattern_set
])
# stimuli = np.concatenate([np.zeros((num_time_steps,n_nodes)) for _ in range(trials)])
# assign inputs to input_layer (Origin Mechanism) for each trial
stim_list_dict = {input_layer: stimuli}
# print out the inputs
print(input_pattern_set)
# run the system
r = model.run(inputs=stim_list_dict, num_trials=total_trial_length)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[6], line 14
6 stimuli = np.concatenate([
7 np.repeat(np.array([pattern_i]), num_time_steps, axis=0)
8 for pattern_i in input_pattern_set
9 ])
11 # stimuli = np.concatenate([np.zeros((num_time_steps,n_nodes)) for _ in range(trials)])
12
13 # assign inputs to input_layer (Origin Mechanism) for each trial
---> 14 stim_list_dict = {input_layer: stimuli}
16 # print out the inputs
17 print(input_pattern_set)
NameError: name 'input_layer' is not defined
sns.set_palette("colorblind")
# compute event bonds
bonds = np.arange(num_time_steps, total_trial_length, num_time_steps)
# fetch activities (n_time_points x n_neurons)
acts = np.squeeze(model.results)
# plot the dynamics
f, ax = plt.subplots(1,1, figsize = (12,5))
ax.plot(acts)
ax.set_title(f'Leaky, competitive dynamics across {n_nodes} units')
ax.set_xlabel('Time')
ax.set_ylabel('Activation')
f.legend([f'unit {i}' for i in range(n_nodes)], frameon=False, bbox_to_anchor=(1.1,.6))
for bond in bonds:
ax.axvline(bond, color='grey', alpha=.5, linestyle='--')
f.tight_layout()
sns.despine()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[7], line 6
3 bonds = np.arange(num_time_steps, total_trial_length, num_time_steps)
5 # fetch activities (n_time_points x n_neurons)
----> 6 acts = np.squeeze(model.results)
8 # plot the dynamics
9 f, ax = plt.subplots(1,1, figsize = (12,5))
NameError: name 'model' is not defined