def test_nnls_repr(): pytest.importorskip("scipy.optimize") check_init_args(Nnls, ["weights"]) check_repr(Nnls(weights=True)) assert repr(Nnls(weights=True)) == "Nnls(weights=True)" check_init_args(NnlsL2, ["weights", "reg"]) check_repr(NnlsL2(weights=True, reg=0.2)) assert repr(NnlsL2(weights=True, reg=0.2)) == "NnlsL2(weights=True, reg=0.2)" check_init_args(NnlsL2nz, ["weights", "reg"]) check_repr(NnlsL2nz(weights=True, reg=0.2)) assert repr(NnlsL2nz(weights=True, reg=0.2)) == "NnlsL2nz(weights=True, reg=0.2)"
def __init__(self, dimensions, n_neurons_per_ensemble=100, output_weight=-3.0, input_bias=0.0, ampa_config=None, gaba_config=None, **kwargs): if "net" in kwargs: raise ObsoleteError("The 'net' argument is no longer supported.") kwargs.setdefault("label", "Basal Ganglia") super().__init__(**kwargs) ampa_config, override_ampa = config_with_default_synapse( ampa_config, nengo.Lowpass(0.002)) gaba_config, override_gaba = config_with_default_synapse( gaba_config, nengo.Lowpass(0.008)) # Affects all ensembles / connections in the BG # unless they've been overridden on `self.config` config = nengo.Config(nengo.Ensemble, nengo.Connection) config[nengo.Ensemble].radius = 1.5 config[nengo.Ensemble].encoders = Choice([[1]]) try: # Best, if we have SciPy config[nengo.Connection].solver = NnlsL2nz() except ImportError: # Warn if we can't use the better decoder solver. warnings.warn("SciPy is not installed, so BasalGanglia will " "use the default decoder solver. Installing SciPy " "may improve BasalGanglia performance.") ea_params = { "n_neurons": n_neurons_per_ensemble, "n_ensembles": dimensions } with self, config: self.strD1 = EnsembleArray( label="Striatal D1 neurons", intercepts=Uniform(Weights.e, 1), **ea_params, ) self.strD2 = EnsembleArray( label="Striatal D2 neurons", intercepts=Uniform(Weights.e, 1), **ea_params, ) self.stn = EnsembleArray( label="Subthalamic nucleus", intercepts=Uniform(Weights.ep, 1), **ea_params, ) self.gpi = EnsembleArray( label="Globus pallidus internus", intercepts=Uniform(Weights.eg, 1), **ea_params, ) self.gpe = EnsembleArray( label="Globus pallidus externus", intercepts=Uniform(Weights.ee, 1), **ea_params, ) self.input = nengo.Node(label="input", size_in=dimensions) self.output = nengo.Node(label="output", size_in=dimensions) # add bias input (BG performs best in the range 0.5--1.5) if abs(input_bias) > 0.0: self.bias_input = nengo.Node(np.ones(dimensions) * input_bias, label="basal ganglia bias") nengo.Connection(self.bias_input, self.input) # spread the input to StrD1, StrD2, and STN nengo.Connection( self.input, self.strD1.input, synapse=None, transform=Weights.ws * (1 + Weights.lg), ) nengo.Connection( self.input, self.strD2.input, synapse=None, transform=Weights.ws * (1 - Weights.le), ) nengo.Connection(self.input, self.stn.input, synapse=None, transform=Weights.wt) # connect the striatum to the GPi and GPe (inhibitory) strD1_output = self.strD1.add_output("func_str", Weights.str_func) strD2_output = self.strD2.add_output("func_str", Weights.str_func) with gaba_config: nengo.Connection(strD1_output, self.gpi.input, transform=-Weights.wm) nengo.Connection(strD2_output, self.gpe.input, transform=-Weights.wm) # connect the STN to GPi and GPe (broad and excitatory) tr = Weights.wp * np.ones((dimensions, dimensions)) stn_output = self.stn.add_output("func_stn", Weights.stn_func) with ampa_config: nengo.Connection(stn_output, self.gpi.input, transform=tr) nengo.Connection(stn_output, self.gpe.input, transform=tr) # connect the GPe to GPi and STN (inhibitory) gpe_output = self.gpe.add_output("func_gpe", Weights.gpe_func) with gaba_config: nengo.Connection(gpe_output, self.gpi.input, transform=-Weights.we) nengo.Connection(gpe_output, self.stn.input, transform=-Weights.wg) # connect GPi to output (inhibitory) gpi_output = self.gpi.add_output("func_gpi", Weights.gpi_func) nengo.Connection(gpi_output, self.output, synapse=None, transform=output_weight) # Return ampa_config and gaba_config to previous states, if changed if override_ampa: del ampa_config[nengo.Connection].synapse if override_gaba: del gaba_config[nengo.Connection].synapse
def BasalGanglia(dimensions, n_neurons_per_ensemble=100, output_weight=-3., input_bias=0., ampa_config=None, gaba_config=None, net=None): """Winner take all network, typically used for action selection. The basal ganglia network outputs approximately 0 at the dimension with the largest value, and is negative elsewhere. While the basal ganglia is primarily defined by its winner-take-all function, it is also organized to match the organization of the human basal ganglia. It consists of five ensembles: * Striatal D1 dopamine-receptor neurons (``strD1``) * Striatal D2 dopamine-receptor neurons (``strD2``) * Subthalamic nucleus (``stn``) * Globus pallidus internus / substantia nigra reticulata (``gpi``) * Globus pallidus externus (``gpe``) Interconnections between these areas are also based on known neuroanatomical connections. See [1]_ for more details, and [2]_ for the original non-spiking basal ganglia model by Gurney, Prescott & Redgrave that this model is based on. .. note:: The default `.Solver` for the basal ganglia is `.NnlsL2nz`, which requires SciPy. If SciPy is not installed, the global default solver will be used instead. Parameters ---------- dimensions : int Number of dimensions (i.e., actions). n_neurons_per_ensemble : int, optional (Default: 100) Number of neurons in each ensemble in the network. output_weight : float, optional (Default: -3.) A scaling factor on the output of the basal ganglia (specifically on the connection out of the GPi). input_bias : float, optional (Default: 0.) An amount by which to bias all dimensions of the input node. Biasing the input node is important for ensuring that all input dimensions are positive and easily comparable. ampa_config : config, optional (Default: None) Configuration for connections corresponding to biological connections to AMPA receptors (i.e., connections from STN to to GPi and GPe). If None, a default configuration using a 2 ms lowpass synapse will be used. gaba_config : config, optional (Default: None) Configuration for connections corresponding to biological connections to GABA receptors (i.e., connections from StrD1 to GPi, StrD2 to GPe, and GPe to GPi and STN). If None, a default configuration using an 8 ms lowpass synapse will be used. net : Network, optional (Default: None) A network in which the network components will be built. This is typically used to provide a custom set of Nengo object defaults through modifying ``net.config``. Returns ------- net : Network The newly built basal ganglia network, or the provided ``net``. Attributes ---------- net.bias_input : Node or None If ``input_bias`` is non-zero, this node will be created to bias all of the dimensions of the input signal. net.gpe : EnsembleArray Globus pallidus externus ensembles. net.gpi : EnsembleArray Globus pallidus internus ensembles. net.input : Node Accepts the input signal. net.output : Node Provides the output signal. net.stn : EnsembleArray Subthalamic nucleus ensembles. net.strD1 : EnsembleArray Striatal D1 ensembles. net.strD2 : EnsembleArray Striatal D2 ensembles. References ---------- .. [1] Stewart, T. C., Choo, X., & Eliasmith, C. (2010). Dynamic behaviour of a spiking model of action selection in the basal ganglia. In Proceedings of the 10th international conference on cognitive modeling (pp. 235-40). .. [2] Gurney, K., Prescott, T., & Redgrave, P. (2001). A computational model of action selection in the basal ganglia. Biological Cybernetics 84, 401-423. """ if net is None: net = nengo.Network("Basal Ganglia") ampa_config, override_ampa = config_with_default_synapse( ampa_config, nengo.Lowpass(0.002)) gaba_config, override_gaba = config_with_default_synapse( gaba_config, nengo.Lowpass(0.008)) # Affects all ensembles / connections in the BG # unless they've been overridden on `net.config` config = nengo.Config(nengo.Ensemble, nengo.Connection) config[nengo.Ensemble].radius = 1.5 config[nengo.Ensemble].encoders = Choice([[1]]) try: # Best, if we have SciPy config[nengo.Connection].solver = NnlsL2nz() except ImportError: # Warn if we can't use the better decoder solver. warnings.warn("SciPy is not installed, so BasalGanglia will " "use the default decoder solver. Installing SciPy " "may improve BasalGanglia performance.") ea_params = { 'n_neurons': n_neurons_per_ensemble, 'n_ensembles': dimensions } with config, net: net.strD1 = EnsembleArray(label="Striatal D1 neurons", intercepts=Uniform(Weights.e, 1), **ea_params) net.strD2 = EnsembleArray(label="Striatal D2 neurons", intercepts=Uniform(Weights.e, 1), **ea_params) net.stn = EnsembleArray(label="Subthalamic nucleus", intercepts=Uniform(Weights.ep, 1), **ea_params) net.gpi = EnsembleArray(label="Globus pallidus internus", intercepts=Uniform(Weights.eg, 1), **ea_params) net.gpe = EnsembleArray(label="Globus pallidus externus", intercepts=Uniform(Weights.ee, 1), **ea_params) net.input = nengo.Node(label="input", size_in=dimensions) net.output = nengo.Node(label="output", size_in=dimensions) # add bias input (BG performs best in the range 0.5--1.5) if abs(input_bias) > 0.0: net.bias_input = nengo.Node(np.ones(dimensions) * input_bias, label="basal ganglia bias") nengo.Connection(net.bias_input, net.input) # spread the input to StrD1, StrD2, and STN nengo.Connection(net.input, net.strD1.input, synapse=None, transform=Weights.ws * (1 + Weights.lg)) nengo.Connection(net.input, net.strD2.input, synapse=None, transform=Weights.ws * (1 - Weights.le)) nengo.Connection(net.input, net.stn.input, synapse=None, transform=Weights.wt) # connect the striatum to the GPi and GPe (inhibitory) strD1_output = net.strD1.add_output('func_str', Weights.str_func) strD2_output = net.strD2.add_output('func_str', Weights.str_func) with gaba_config: nengo.Connection(strD1_output, net.gpi.input, transform=-Weights.wm) nengo.Connection(strD2_output, net.gpe.input, transform=-Weights.wm) # connect the STN to GPi and GPe (broad and excitatory) tr = Weights.wp * np.ones((dimensions, dimensions)) stn_output = net.stn.add_output('func_stn', Weights.stn_func) with ampa_config: nengo.Connection(stn_output, net.gpi.input, transform=tr) nengo.Connection(stn_output, net.gpe.input, transform=tr) # connect the GPe to GPi and STN (inhibitory) gpe_output = net.gpe.add_output('func_gpe', Weights.gpe_func) with gaba_config: nengo.Connection(gpe_output, net.gpi.input, transform=-Weights.we) nengo.Connection(gpe_output, net.stn.input, transform=-Weights.wg) # connect GPi to output (inhibitory) gpi_output = net.gpi.add_output('func_gpi', Weights.gpi_func) nengo.Connection(gpi_output, net.output, synapse=None, transform=output_weight) # Return ampa_config and gaba_config to previous states, if changed if override_ampa: del ampa_config[nengo.Connection].synapse if override_gaba: del gaba_config[nengo.Connection].synapse return net
def BasalGanglia(dimensions, n_neurons_per_ensemble=100, output_weight=-3, input_bias=0.0, ampa_config=None, gaba_config=None, net=None): """Winner takes all; outputs 0 at max dimension, negative elsewhere.""" if net is None: net = nengo.Network("Basal Ganglia") ampa_config, override_ampa = config_with_default_synapse( ampa_config, nengo.Lowpass(0.002)) gaba_config, override_gaba = config_with_default_synapse( gaba_config, nengo.Lowpass(0.008)) # Affects all ensembles / connections in the BG # unless they've been overridden on `net.config` config = nengo.Config(nengo.Ensemble, nengo.Connection) config[nengo.Ensemble].radius = 1.5 config[nengo.Ensemble].encoders = Choice([[1]]) try: # Best, if we have SciPy config[nengo.Connection].solver = NnlsL2nz() except ImportError: # Warn if we can't use the better decoder solver. warnings.warn("SciPy is not installed, so BasalGanglia will " "use the default decoder solver. Installing SciPy " "may improve BasalGanglia performance.") ea_params = { 'n_neurons': n_neurons_per_ensemble, 'n_ensembles': dimensions } with config, net: net.strD1 = EnsembleArray(label="Striatal D1 neurons", intercepts=Uniform(Weights.e, 1), **ea_params) net.strD2 = EnsembleArray(label="Striatal D2 neurons", intercepts=Uniform(Weights.e, 1), **ea_params) net.stn = EnsembleArray(label="Subthalamic nucleus", intercepts=Uniform(Weights.ep, 1), **ea_params) net.gpi = EnsembleArray(label="Globus pallidus internus", intercepts=Uniform(Weights.eg, 1), **ea_params) net.gpe = EnsembleArray(label="Globus pallidus externus", intercepts=Uniform(Weights.ee, 1), **ea_params) net.input = nengo.Node(label="input", size_in=dimensions) net.output = nengo.Node(label="output", size_in=dimensions) # add bias input (BG performs best in the range 0.5--1.5) if abs(input_bias) > 0.0: net.bias_input = nengo.Node(np.ones(dimensions) * input_bias, label="basal ganglia bias") nengo.Connection(net.bias_input, net.input) # spread the input to StrD1, StrD2, and STN nengo.Connection(net.input, net.strD1.input, synapse=None, transform=Weights.ws * (1 + Weights.lg)) nengo.Connection(net.input, net.strD2.input, synapse=None, transform=Weights.ws * (1 - Weights.le)) nengo.Connection(net.input, net.stn.input, synapse=None, transform=Weights.wt) # connect the striatum to the GPi and GPe (inhibitory) strD1_output = net.strD1.add_output('func_str', Weights.str_func) strD2_output = net.strD2.add_output('func_str', Weights.str_func) with gaba_config: nengo.Connection(strD1_output, net.gpi.input, transform=-Weights.wm) nengo.Connection(strD2_output, net.gpe.input, transform=-Weights.wm) # connect the STN to GPi and GPe (broad and excitatory) tr = Weights.wp * np.ones((dimensions, dimensions)) stn_output = net.stn.add_output('func_stn', Weights.stn_func) with ampa_config: nengo.Connection(stn_output, net.gpi.input, transform=tr) nengo.Connection(stn_output, net.gpe.input, transform=tr) # connect the GPe to GPi and STN (inhibitory) gpe_output = net.gpe.add_output('func_gpe', Weights.gpe_func) with gaba_config: nengo.Connection(gpe_output, net.gpi.input, transform=-Weights.we) nengo.Connection(gpe_output, net.stn.input, transform=-Weights.wg) # connect GPi to output (inhibitory) gpi_output = net.gpi.add_output('func_gpi', Weights.gpi_func) nengo.Connection(gpi_output, net.output, synapse=None, transform=output_weight) # Return ampa_config and gaba_config to previous states, if changed if override_ampa: del ampa_config[nengo.Connection].synapse if override_gaba: del gaba_config[nengo.Connection].synapse return net
def __init__(self, dimensions, n_neurons_per_ensemble=100, radius=1.5, tau_ampa=0.002, tau_gaba=0.008, output_weight=-3, input_bias=0.0, solver=None): if solver is None: try: # Best, if we have SciPy solver = NnlsL2nz() except ImportError: # If not, use default warnings.warn("SciPy is not installed, so BasalGanglia will " "use default decoder solver. Installing SciPy " "may improve BasalGanglia performance.") solver = nengo.Default encoders = np.ones((n_neurons_per_ensemble, 1)) ea_params = { 'n_neurons': n_neurons_per_ensemble, 'n_ensembles': dimensions, 'radius': radius, 'encoders': encoders, } self.strD1 = EnsembleArray(label="Striatal D1 neurons", intercepts=Uniform(self.e, 1), **ea_params) self.strD2 = EnsembleArray(label="Striatal D2 neurons", intercepts=Uniform(self.e, 1), **ea_params) self.stn = EnsembleArray(label="Subthalamic nucleus", intercepts=Uniform(self.ep, 1), **ea_params) self.gpi = EnsembleArray(label="Globus pallidus internus", intercepts=Uniform(self.eg, 1), **ea_params) self.gpe = EnsembleArray(label="Globus pallidus externus", intercepts=Uniform(self.ee, 1), **ea_params) self.input = nengo.Node(label="input", size_in=dimensions) self.output = nengo.Node(label="output", size_in=dimensions) # add bias input (BG performs best in the range 0.5--1.5) if abs(input_bias) > 0.0: self.bias_input = nengo.Node([input_bias] * dimensions) nengo.Connection(self.bias_input, self.input) # spread the input to StrD1, StrD2, and STN nengo.Connection(self.input, self.strD1.input, synapse=None, transform=self.ws * (1 + self.lg)) nengo.Connection(self.input, self.strD2.input, synapse=None, transform=self.ws * (1 - self.le)) nengo.Connection(self.input, self.stn.input, synapse=None, transform=self.wt) # connect the striatum to the GPi and GPe (inhibitory) strD1_output = self.strD1.add_output('func_str', self.str_func, solver=solver) nengo.Connection(strD1_output, self.gpi.input, synapse=tau_gaba, transform=-np.eye(dimensions) * self.wm) strD2_output = self.strD2.add_output('func_str', self.str_func, solver=solver) nengo.Connection(strD2_output, self.gpe.input, synapse=tau_gaba, transform=-np.eye(dimensions) * self.wm) # connect the STN to GPi and GPe (broad and excitatory) tr = self.wp * np.ones((dimensions, dimensions)) stn_output = self.stn.add_output('func_stn', self.stn_func, solver=solver) nengo.Connection(stn_output, self.gpi.input, transform=tr, synapse=tau_ampa) nengo.Connection(stn_output, self.gpe.input, transform=tr, synapse=tau_ampa) # connect the GPe to GPi and STN (inhibitory) gpe_output = self.gpe.add_output('func_gpe', self.gpe_func, solver=solver) nengo.Connection(gpe_output, self.gpi.input, synapse=tau_gaba, transform=-self.we) nengo.Connection(gpe_output, self.stn.input, synapse=tau_gaba, transform=-self.wg) # connect GPi to output (inhibitory) gpi_output = self.gpi.add_output('func_gpi', self.gpi_func, solver=solver) nengo.Connection(gpi_output, self.output, synapse=None, transform=output_weight)