def __init__(self, n_neurons, dimensions, radius=1.0, encoders=nengo.Default, **ens_kwargs): super(Product, self).__init__(self) with self: self.config[nengo.Ensemble].update(ens_kwargs) self.A = nengo.Node(size_in=dimensions, label="A") self.B = nengo.Node(size_in=dimensions, label="B") self.dimensions = dimensions if encoders is nengo.Default: encoders = Choice([[1, 1], [1, -1], [-1, 1], [-1, -1]]) optimizer = SubvectorRadiusOptimizer(n_neurons, 2, ens_kwargs=ens_kwargs) scaled_r = radius * optimizer.find_optimal_radius(dimensions, 1) self.product = EnsembleArray(n_neurons, n_ensembles=dimensions, ens_dimensions=2, radius=scaled_r, encoders=encoders, **ens_kwargs) nengo.Connection(self.A, self.product.input[::2], synapse=None) nengo.Connection(self.B, self.product.input[1::2], synapse=None) self.output = self.product.add_output('product', lambda x: x[0] * x[1])
def __init__(self, n_neurons, dimensions, radius=1, encoders=nengo.Default, **ens_kwargs): self.config[nengo.Ensemble].update(ens_kwargs) self.A = nengo.Node(size_in=dimensions, label="A") self.B = nengo.Node(size_in=dimensions, label="B") self.output = nengo.Node(size_in=dimensions, label="output") self.dimensions = dimensions if encoders is nengo.Default: encoders = np.tile( [[1, 1], [1, -1], [-1, 1], [-1, -1]], ((n_neurons // 4) + 1, 1))[:n_neurons] self.product = EnsembleArray( n_neurons, n_ensembles=dimensions, ens_dimensions=2, encoders=encoders, radius=np.sqrt(2) * radius) nengo.Connection( self.A, self.product.input[::2], synapse=None) nengo.Connection( self.B, self.product.input[1::2], synapse=None) nengo.Connection( self.product.add_output('product', lambda x: x[0] * x[1]), self.output, synapse=None)
def __init__(self, neurons, dimensions, radius=1, encoders=None, **ens_kwargs): self.A = nengo.Node(size_in=dimensions, label="A") self.B = nengo.Node(size_in=dimensions, label="B") self.output = nengo.Node(size_in=dimensions, label="output") self.dimensions = dimensions if encoders is None and not isinstance(neurons, nengo.Direct): encoders = np.tile( [[1, 1], [1, -1], [-1, 1], [-1, -1]], ((neurons.n_neurons / 4) + 1, 1))[:neurons.n_neurons] else: encoders = None self.product = EnsembleArray(neurons, n_ensembles=dimensions, ens_dimensions=2, encoders=encoders, radius=np.sqrt(2) * radius, **ens_kwargs) nengo.Connection(self.A, self.product.input[::2], synapse=None) nengo.Connection(self.B, self.product.input[1::2], synapse=None) nengo.Connection(self.product.add_output('product', lambda x: x[0] * x[1]), self.output, synapse=None)
def __init__(self, n_neurons, dimensions, input_magnitude=1.0, **kwargs): if "net" in kwargs: raise ObsoleteError("The 'net' argument is no longer supported.") kwargs.setdefault("label", "Product") super().__init__(**kwargs) with self: self.input_a = nengo.Node(size_in=dimensions, label="input_a") self.input_b = nengo.Node(size_in=dimensions, label="input_b") self.output = nengo.Node(size_in=dimensions, label="output") self.sq1 = EnsembleArray( max(1, n_neurons // 2), n_ensembles=dimensions, ens_dimensions=1, radius=input_magnitude * np.sqrt(2), ) self.sq2 = EnsembleArray( max(1, n_neurons // 2), n_ensembles=dimensions, ens_dimensions=1, radius=input_magnitude * np.sqrt(2), ) tr = 1.0 / np.sqrt(2.0) nengo.Connection(self.input_a, self.sq1.input, transform=tr, synapse=None) nengo.Connection(self.input_b, self.sq1.input, transform=tr, synapse=None) nengo.Connection(self.input_a, self.sq2.input, transform=tr, synapse=None) nengo.Connection(self.input_b, self.sq2.input, transform=-tr, synapse=None) sq1_out = self.sq1.add_output("square", np.square) nengo.Connection(sq1_out, self.output, transform=0.5, synapse=None) sq2_out = self.sq2.add_output("square", np.square) nengo.Connection(sq2_out, self.output, transform=-0.5, synapse=None)
def Thalamus(dimensions, n_neurons_per_ensemble=50, mutual_inhib=1, threshold=0, net=None): """Inhibits non-selected actions. Converts basal ganglia output into a signal with (approximately) 1 for the selected action and 0 elsewhere. """ if net is None: net = nengo.Network("Thalamus") with net: net.actions = EnsembleArray(n_neurons_per_ensemble, dimensions, intercepts=Uniform(threshold, 1), encoders=Choice([[1.0]]), label="actions") nengo.Connection(net.actions.output, net.actions.input, transform=(np.eye(dimensions) - 1) * mutual_inhib) net.bias = nengo.Node([1], label="thalamus bias") nengo.Connection(net.bias, net.actions.input, transform=np.ones((dimensions, 1))) net.input = net.actions.input net.output = net.actions.output return net
def __init__( self, n_neurons, dimensions, radius=1.0, encoders=nengo.Default, **ens_kwargs): super(Product, self).__init__(self) with self: self.config[nengo.Ensemble].update(ens_kwargs) self.A = nengo.Node(size_in=dimensions, label="A") self.B = nengo.Node(size_in=dimensions, label="B") self.dimensions = dimensions if encoders is nengo.Default: encoders = Choice([[1, 1], [1, -1], [-1, 1], [-1, -1]]) optimizer = SubvectorRadiusOptimizer( n_neurons, 2, ens_kwargs=ens_kwargs) scaled_r = radius * optimizer.find_optimal_radius(dimensions, 1) self.product = EnsembleArray( n_neurons, n_ensembles=dimensions, ens_dimensions=2, radius=scaled_r, encoders=encoders, **ens_kwargs) nengo.Connection( self.A, self.product.input[::2], synapse=None) nengo.Connection( self.B, self.product.input[1::2], synapse=None) self.output = self.product.add_output( 'product', lambda x: x[0] * x[1])
class Product(nengo.Network): """Computes the element-wise product of two equally sized vectors.""" def __init__(self, n_neurons, dimensions, radius=1, encoders=nengo.Default, **ens_kwargs): self.config[nengo.Ensemble].update(ens_kwargs) self.A = nengo.Node(size_in=dimensions, label="A") self.B = nengo.Node(size_in=dimensions, label="B") self.dimensions = dimensions if encoders is nengo.Default: encoders = Choice([[1, 1], [1, -1], [-1, 1], [-1, -1]]) self.product = EnsembleArray( n_neurons, n_ensembles=dimensions, ens_dimensions=2, encoders=encoders, radius=np.sqrt(2) * radius) nengo.Connection( self.A, self.product.input[0::2], synapse=None) nengo.Connection( self.B, self.product.input[1::2], synapse=None) self.output = self.product.add_output('product', lambda x: x[0] * x[1]) def dot_product_transform(self, scale=1.0): """Returns a transform for output to compute the scaled dot product.""" return scale*np.ones((1, self.dimensions))
def __init__(self, dimensions, n_neurons_per_ensemble=50, mutual_inhib=1.0, threshold=0.0, **kwargs): if "net" in kwargs: raise ObsoleteError("The 'net' argument is no longer supported.") kwargs.setdefault("label", "Thalamus") super().__init__(**kwargs) with self: self.actions = EnsembleArray( n_neurons_per_ensemble, dimensions, intercepts=Uniform(threshold, 1), encoders=Choice([[1.0]]), label="actions", ) nengo.Connection( self.actions.output, self.actions.input, transform=(np.eye(dimensions) - 1) * mutual_inhib, ) self.bias = nengo.Node([1], label="thalamus bias") nengo.Connection(self.bias, self.actions.input, transform=np.ones((dimensions, 1))) self.input = self.actions.input self.output = self.actions.output
class Product(nengo.Network): """Computes the element-wise product of two equally sized vectors.""" def __init__(self, n_neurons, dimensions, radius=1, encoders=nengo.Default, **ens_kwargs): self.config[nengo.Ensemble].update(ens_kwargs) self.A = nengo.Node(size_in=dimensions, label="A") self.B = nengo.Node(size_in=dimensions, label="B") self.output = nengo.Node(size_in=dimensions, label="output") self.dimensions = dimensions if encoders is nengo.Default: encoders = np.tile( [[1, 1], [1, -1], [-1, 1], [-1, -1]], ((n_neurons // 4) + 1, 1))[:n_neurons] self.product = EnsembleArray( n_neurons, n_ensembles=dimensions, ens_dimensions=2, encoders=encoders, radius=np.sqrt(2) * radius) nengo.Connection( self.A, self.product.input[::2], synapse=None) nengo.Connection( self.B, self.product.input[1::2], synapse=None) nengo.Connection( self.product.add_output('product', lambda x: x[0] * x[1]), self.output, synapse=None) def dot_product_transform(self, scale=1.0): """Returns a transform for output to compute the scaled dot product.""" return scale*np.ones((1, self.dimensions))
def Product_2D_ens(n_neurons, dimensions, input_magnitude=1, config=None, net=None): """Computes the element-wise product of two equally sized vectors.""" if net is None: net = nengo.Network(label="Product") if config is None: config = nengo.Config(nengo.Ensemble) config[nengo.Ensemble].encoders = Choice([[1, 1], [1, -1], [-1, 1], [-1, -1]]) with net, config: net.A = nengo.Node(size_in=dimensions, label="A") net.B = nengo.Node(size_in=dimensions, label="B") net.output = nengo.Node(size_in=dimensions, label="output") net.product = EnsembleArray(n_neurons, n_ensembles=dimensions, ens_dimensions=2, radius=input_magnitude * np.sqrt(2)) nengo.Connection(net.A, net.product.input[::2], synapse=None) nengo.Connection(net.B, net.product.input[1::2], synapse=None) net.output = net.product.add_output('product', lambda x: x[0] * x[1]) return net
def __init__(self, neurons, dimensions, radius=1, encoders=None, **ens_kwargs): self.A = nengo.Node(size_in=dimensions, label="A") self.B = nengo.Node(size_in=dimensions, label="B") self.output = nengo.Node(size_in=dimensions, label="output") self.dimensions = dimensions if encoders is None and not isinstance(neurons, nengo.Direct): encoders = np.tile( [[1, 1], [1, -1], [-1, 1], [-1, -1]], ((neurons.n_neurons / 4) + 1, 1))[:neurons.n_neurons] else: encoders = None self.product = EnsembleArray( neurons, n_ensembles=dimensions, ens_dimensions=2, encoders=encoders, radius=np.sqrt(2) * radius, **ens_kwargs) nengo.Connection( self.A, self.product.input[::2], synapse=None) nengo.Connection( self.B, self.product.input[1::2], synapse=None) nengo.Connection( self.product.add_output('product', lambda x: x[0] * x[1]), self.output, synapse=None)
class Product(nengo.Network): """Computes the element-wise product of two equally sized vectors.""" def __init__(self, neurons, dimensions, radius=1, encoders=None, **ens_kwargs): self.A = nengo.Node(size_in=dimensions, label="A") self.B = nengo.Node(size_in=dimensions, label="B") self.output = nengo.Node(size_in=dimensions, label="output") self.dimensions = dimensions if encoders is None and not isinstance(neurons, nengo.Direct): encoders = np.tile( [[1, 1], [1, -1], [-1, 1], [-1, -1]], ((neurons.n_neurons / 4) + 1, 1))[:neurons.n_neurons] else: encoders = None self.product = EnsembleArray( neurons, n_ensembles=dimensions, ens_dimensions=2, encoders=encoders, radius=np.sqrt(2) * radius, **ens_kwargs) nengo.Connection( self.A, self.product.input[::2], synapse=None) nengo.Connection( self.B, self.product.input[1::2], synapse=None) nengo.Connection( self.product.add_output('product', lambda x: x[0] * x[1]), self.output, synapse=None) def dot_product_transform(self, scale=1.0): """Returns a transform for output to compute the scaled dot product.""" return scale*np.ones((1, self.dimensions))
class Product(nengo.Network): """Computes the element-wise product of two (scaled) unit vectors. Requires Scipy. """ # def __init__(self, n_neurons, dimensions, radius=1.0, # n_eval_points=nengo.Default, eval_points=nengo.Default, # encoders=nengo.Default, **ens_kwargs): def __init__(self, n_neurons, dimensions, radius=np.sqrt(2.0), encoders=nengo.Default, **ens_kwargs): self.A = nengo.Node(size_in=dimensions, label="A") self.B = nengo.Node(size_in=dimensions, label="B") self.dimensions = dimensions if encoders is nengo.Default: encoders = Choice([[1, 1], [1, -1], [-1, 1], [-1, -1]]) self.product = EnsembleArray( n_neurons, n_ensembles=dimensions, ens_dimensions=2, encoders=encoders, radius=np.sqrt(2) * radius, **ens_kwargs ) nengo.Connection(self.A, self.product.input[0::2], synapse=None) nengo.Connection(self.B, self.product.input[1::2], synapse=None) self.output = self.product.add_output("product", lambda x: x[0] * x[1])
def make(self, neurons, dimensions, radius=1, invert_a=False, invert_b=False): self.transformA = self._input_transform( dimensions, first=True, invert=invert_a) self.transformB = self._input_transform( dimensions, first=False, invert=invert_b) self.transformC = self._output_transform(dimensions) self.A = nengo.Node(size_in=dimensions, label='A') self.B = nengo.Node(size_in=dimensions, label='B') self.ensemble = EnsembleArray(neurons, self.transformC.shape[1], dimensions=2, radius=radius, label='conv') self.output = nengo.Node(size_in=dimensions, label='output') for ens in self.ensemble.ensembles: if not isinstance(neurons, nengo.Direct): ens.encoders = np.tile( [[1, 1], [-1, 1], [1, -1], [-1, -1]], (ens.n_neurons // 4, 1)) nengo.Connection( self.A, self.ensemble.input, transform=self.transformA, filter=None) nengo.Connection( self.B, self.ensemble.input, transform=self.transformB, filter=None) nengo.Connection(self.ensemble.add_output('product', self.product), self.output, filter=None, transform=self.transformC)
def __init__(self, neurons, dimensions, kernel=None, input_transform=None): self.kernel = kernel if kernel is not None else self.product self.dimensions = dimensions self.A = nengo.Node(size_in=dimensions, label='A') self.B = nengo.Node(size_in=dimensions, label='B') self.ensemble = EnsembleArray(neurons, n_ensembles=dimensions, dimensions=2, radius=1, label='elementwise_operation') self.output = nengo.Node(size_in=dimensions, label='output') if input_transform is None: self.input_transform = self.elementwise_comparator_transform else: self.input_transform = input_transform for ens in self.ensemble.ensembles: if not isinstance(neurons, nengo.Direct): ens.encoders = corners(ens.n_neurons) nengo.Connection(self.A, self.ensemble.input, synapse=None, transform=self.input_transform) nengo.Connection(self.B, self.ensemble.input, synapse=None, transform=self.input_transform) nengo.Connection(self.ensemble.add_output('result', self.kernel), self.output)
def __init__( self, vocab=Default, subdimensions=Default, neurons_per_dimension=Default, feedback=Default, represent_cc_identity=Default, feedback_synapse=Default, **kwargs ): super(State, self).__init__(**kwargs) self.vocab = vocab self.subdimensions = subdimensions self.neurons_per_dimension = neurons_per_dimension self.feedback = feedback self.feedback_synapse = feedback_synapse self.represent_cc_identity = represent_cc_identity dimensions = self.vocab.dimensions if dimensions % self.subdimensions != 0: raise ValidationError( "Dimensions (%d) must be divisible by subdimensions (%d)" % (dimensions, self.subdimensions), attr="dimensions", obj=self, ) with self: if self.represent_cc_identity: self.state_ensembles = IdentityEnsembleArray( self.neurons_per_dimension, dimensions, self.subdimensions, label="state", ) else: self.state_ensembles = EnsembleArray( self.neurons_per_dimension * self.subdimensions, dimensions // self.subdimensions, ens_dimensions=self.subdimensions, eval_points=nengo.dists.CosineSimilarity(dimensions + 2), intercepts=nengo.dists.CosineSimilarity(dimensions + 2), label="state", ) if self.feedback is not None and self.feedback != 0.0: nengo.Connection( self.state_ensembles.output, self.state_ensembles.input, transform=self.feedback, synapse=self.feedback_synapse, ) self.input = self.state_ensembles.input self.output = self.state_ensembles.output self.declare_input(self.input, self.vocab) self.declare_output(self.output, self.vocab)
def __init__( self, dimensions, subdimensions=16, neurons_per_dimension=50, feedback=0.0, feedback_synapse=0.1, vocab=None, label=None, seed=None, add_to_container=None, ): super().__init__(label, seed, add_to_container) if vocab is None: # use the default one for this dimensionality vocab = dimensions elif vocab.dimensions != dimensions: raise ValidationError( "Dimensionality of given vocabulary (%d) does not " "match dimensionality of buffer (%d)" % (vocab.dimensions, dimensions), attr="dimensions", obj=self, ) # Subdimensions should be at most the number of dimensions subdimensions = min(dimensions, subdimensions) if dimensions % subdimensions != 0: raise ValidationError( "Dimensions (%d) must be divisible by subdimensions (%d)" % (dimensions, subdimensions), attr="dimensions", obj=self, ) with self: self.state_ensembles = EnsembleArray( neurons_per_dimension * subdimensions, dimensions // subdimensions, ens_dimensions=subdimensions, radius=np.sqrt(float(subdimensions) / dimensions), label="state", ) self.input = self.state_ensembles.input self.output = self.state_ensembles.output self.inputs = dict(default=(self.input, vocab)) self.outputs = dict(default=(self.output, vocab)) with self: if feedback is not None and feedback != 0.0: nengo.Connection( self.output, self.input, transform=feedback, synapse=feedback_synapse, )
def Product(n_neurons, dimensions, input_magnitude=1, config=None, net=None): """Computes the element-wise product of two equally sized vectors. The network used to calculate the product is described in `Precise multiplications with the NEF <http://nbviewer.ipython.org/github/ctn-archive/technical-reports/blob/master/Precise-multiplications-with-the-NEF.ipynb#An-alternative-network>`_. A simpler version of this network can be found in the `Multiplication example <http://pythonhosted.org/nengo/examples/multiplication.html>`_. """ if net is None: net = nengo.Network(label="Product") if config is None: config = nengo.Config(nengo.Ensemble) with nested(net, config): net.A = nengo.Node(size_in=dimensions, label="A") net.B = nengo.Node(size_in=dimensions, label="B") net.output = nengo.Node(size_in=dimensions, label="output") net.sq1 = EnsembleArray(max(1, n_neurons // 2), n_ensembles=dimensions, ens_dimensions=1, radius=input_magnitude * np.sqrt(2)) net.sq2 = EnsembleArray(max(1, n_neurons // 2), n_ensembles=dimensions, ens_dimensions=1, radius=input_magnitude * np.sqrt(2)) tr = 1. / np.sqrt(2.) nengo.Connection(net.A, net.sq1.input, transform=tr, synapse=None) nengo.Connection(net.B, net.sq1.input, transform=tr, synapse=None) nengo.Connection(net.A, net.sq2.input, transform=tr, synapse=None) nengo.Connection(net.B, net.sq2.input, transform=-tr, synapse=None) sq1_out = net.sq1.add_output('square', np.square) nengo.Connection(sq1_out, net.output, transform=.5) sq2_out = net.sq2.add_output('square', np.square) nengo.Connection(sq2_out, net.output, transform=-.5) return net
def __init__(self, n_neurons, dimensions, input_magnitude=1., **kwargs): if 'net' in kwargs: raise ObsoleteError("The 'net' argument is no longer supported.") kwargs.setdefault('label', "Product") super().__init__(**kwargs) with self: self.input_a = nengo.Node(size_in=dimensions, label="input_a") self.input_b = nengo.Node(size_in=dimensions, label="input_b") self.output = nengo.Node(size_in=dimensions, label="output") self.sq1 = EnsembleArray( max(1, n_neurons // 2), n_ensembles=dimensions, ens_dimensions=1, radius=input_magnitude * np.sqrt(2), ) self.sq2 = EnsembleArray( max(1, n_neurons // 2), n_ensembles=dimensions, ens_dimensions=1, radius=input_magnitude * np.sqrt(2), ) tr = 1. / np.sqrt(2.) nengo.Connection( self.input_a, self.sq1.input, transform=tr, synapse=None) nengo.Connection( self.input_b, self.sq1.input, transform=tr, synapse=None) nengo.Connection( self.input_a, self.sq2.input, transform=tr, synapse=None) nengo.Connection( self.input_b, self.sq2.input, transform=-tr, synapse=None) sq1_out = self.sq1.add_output('square', np.square) nengo.Connection(sq1_out, self.output, transform=.5, synapse=None) sq2_out = self.sq2.add_output('square', np.square) nengo.Connection(sq2_out, self.output, transform=-.5, synapse=None)
class Product(nengo.Network): """Computes the element-wise product of two (scaled) unit vectors. Requires Scipy. """ def __init__(self, n_neurons, dimensions, radius=1.0, encoders=nengo.Default, **ens_kwargs): super(Product, self).__init__(self) with self: self.config[nengo.Ensemble].update(ens_kwargs) self.A = nengo.Node(size_in=dimensions, label="A") self.B = nengo.Node(size_in=dimensions, label="B") self.dimensions = dimensions if encoders is nengo.Default: encoders = Choice([[1, 1], [1, -1], [-1, 1], [-1, -1]]) optimizer = SubvectorRadiusOptimizer(n_neurons, 2, ens_kwargs=ens_kwargs) scaled_r = radius * optimizer.find_optimal_radius(dimensions, 1) self.product = EnsembleArray(n_neurons, n_ensembles=dimensions, ens_dimensions=2, radius=scaled_r, encoders=encoders, **ens_kwargs) nengo.Connection(self.A, self.product.input[::2], synapse=None) nengo.Connection(self.B, self.product.input[1::2], synapse=None) self.output = self.product.add_output('product', lambda x: x[0] * x[1]) def dot_product_transform(self, scale=1.0): """Returns a transform for output to compute the scaled dot product.""" return scale * np.ones((1, self.dimensions))
class BinaryElementwiseOperation(nengo.Network): '''Handles splitting high-dimensions stuff into ensemble arrays which each handle one 'dimension' or 'element'. the x.output object is of the same dimensions as the inputs''' def __init__(self, neurons, dimensions, kernel=None, input_transform=None): self.kernel = kernel if kernel is not None else self.product self.dimensions = dimensions self.A = nengo.Node(size_in=dimensions, label='A') self.B = nengo.Node(size_in=dimensions, label='B') self.ensemble = EnsembleArray(neurons, n_ensembles=dimensions, dimensions=2, radius=1, label='elementwise_operation') self.output = nengo.Node(size_in=dimensions, label='output') if input_transform is None: self.input_transform = self.elementwise_comparator_transform else: self.input_transform = input_transform for ens in self.ensemble.ensembles: if not isinstance(neurons, nengo.Direct): ens.encoders = corners(ens.n_neurons) nengo.Connection(self.A, self.ensemble.input, synapse=None, transform=self.input_transform) nengo.Connection(self.B, self.ensemble.input, synapse=None, transform=self.input_transform) nengo.Connection(self.ensemble.add_output('result', self.kernel), self.output) @property def elementwise_comparator_transform(self): I = np.eye(self.dimensions) return np.vstack((I, I)) @staticmethod def product(x): return x[0] * x[1]
def __init__(self, n_neurons, dimensions, radius=np.sqrt(2.0), encoders=nengo.Default, **ens_kwargs): self.A = nengo.Node(size_in=dimensions, label="A") self.B = nengo.Node(size_in=dimensions, label="B") self.dimensions = dimensions if encoders is nengo.Default: encoders = Choice([[1, 1], [1, -1], [-1, 1], [-1, -1]]) self.product = EnsembleArray( n_neurons, n_ensembles=dimensions, ens_dimensions=2, encoders=encoders, radius=np.sqrt(2) * radius, **ens_kwargs ) nengo.Connection(self.A, self.product.input[0::2], synapse=None) nengo.Connection(self.B, self.product.input[1::2], synapse=None) self.output = self.product.add_output("product", lambda x: x[0] * x[1])
class Product(nengo.Network): """Computes the element-wise product of two (scaled) unit vectors. Requires Scipy. """ def __init__( self, n_neurons, dimensions, radius=1.0, encoders=nengo.Default, **ens_kwargs): super(Product, self).__init__(self) with self: self.config[nengo.Ensemble].update(ens_kwargs) self.A = nengo.Node(size_in=dimensions, label="A") self.B = nengo.Node(size_in=dimensions, label="B") self.dimensions = dimensions if encoders is nengo.Default: encoders = Choice([[1, 1], [1, -1], [-1, 1], [-1, -1]]) optimizer = SubvectorRadiusOptimizer( n_neurons, 2, ens_kwargs=ens_kwargs) scaled_r = radius * optimizer.find_optimal_radius(dimensions, 1) self.product = EnsembleArray( n_neurons, n_ensembles=dimensions, ens_dimensions=2, radius=scaled_r, encoders=encoders, **ens_kwargs) nengo.Connection( self.A, self.product.input[::2], synapse=None) nengo.Connection( self.B, self.product.input[1::2], synapse=None) self.output = self.product.add_output( 'product', lambda x: x[0] * x[1]) def dot_product_transform(self, scale=1.0): """Returns a transform for output to compute the scaled dot product.""" return scale * np.ones((1, self.dimensions))
def __init__(self, dimensions, n_neurons_per_ensemble=50, mutual_inhib=1, threshold=0): self.actions = EnsembleArray(n_neurons_per_ensemble, dimensions, intercepts=Uniform(threshold, 1), encoders=[[1]] * n_neurons_per_ensemble, label="actions") self.input = self.actions.input self.output = self.actions.output nengo.Connection(self.actions.output, self.actions.input, transform=(np.eye(dimensions) - 1) * mutual_inhib) self.bias = nengo.Node([1]) nengo.Connection(self.bias, self.actions.input, transform=[[1]] * dimensions)
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)
def __init__(self, action_count, n_neurons_per_ensemble=Default, output_weight=Default, input_bias=Default, ampa_synapse=Default, gaba_synapse=Default, sBCBG_params=None, **kwargs): kwargs.setdefault('label', "Basal ganglia") super(BasalGanglia, self).__init__(**kwargs) self.action_count = action_count self.input_connections = {} self.input_bias = input_bias if BasalGanglia.sBCBG: # parameters filter_tau = .01 if output_weight == Default: self.output_weight = -0.001 import sBCBG if sBCBG_params == None: sBCBG_params = {} sBCBG.nengo_instantiate( self.action_count, self, sBCBG_params if sBCBG_params != None else {}) with self: # connect input to CSN self.input = nengo.Node(label="input", size_in=self.action_count) scale = nengo.Ensemble(100, self.input.size_out) nengo.Connection(self.input, scale) for d in range(self.action_count): nengo.Connection(scale[d], self.pops['CSN'][d], function=lambda x: 10 * x, synapse=.01, label='CSN input') # add bias input (BG performs best in the range 0.5--1.5) if abs(self.input_bias) > 0.0: self.bias_input = nengo.Node(np.ones(self.action_count) * input_bias, label="basal ganglia bias") nengo.Connection(self.bias_input, self.input) # connect GPi to output (inhibitory) decoding_weight = 1 # scaling of decoding GPi->out self.output = nengo.Node(label="output", size_in=self.action_count) for d in range(self.action_count): GPi_ens = self.pops["GPi"][d] decoder_values = np.ones( (GPi_ens.n_neurons, 1)) * decoding_weight nengo.Connection( GPi_ens, self.output[d], synapse=nengo.synapses.Lowpass(filter_tau), transform=self.output_weight, #eval_points=eval_points) solver=nengo.solvers.NoSolver(decoder_values)) else: self.n_neurons_per_ensemble = n_neurons_per_ensemble self.ampa_synapse = ampa_synapse self.gaba_synapse = gaba_synapse self.output_weight = output_weight # Affects all ensembles / connections in the BG # unless overwritten with general_config config = nengo.Config(nengo.Ensemble, nengo.Connection) config[nengo.Ensemble].radius = 1.5 config[nengo.Ensemble].encoders = nengo.dists.Choice([[1]]) try: # Best, if we have SciPy config[nengo.Connection].solver = nengo.solvers.NnlsL2nz() except ImportError: warnings.warn("SciPy is not installed, so BasalGanglia will " "use the default decoder solver. Installing " "SciPy may improve BasalGanglia performance.") ea_params = { 'n_neurons': self.n_neurons_per_ensemble, 'n_ensembles': self.action_count } with self, config: self.strD1 = EnsembleArray(label="Striatal D1 neurons", intercepts=nengo.dists.Uniform( Weights.e, 1), **ea_params) self.strD2 = EnsembleArray(label="Striatal D2 neurons", intercepts=nengo.dists.Uniform( Weights.e, 1), **ea_params) self.stn = EnsembleArray(label="Subthalamic nucleus", intercepts=nengo.dists.Uniform( Weights.ep, 1), **ea_params) self.gpi = EnsembleArray(label="Globus pallidus internus", intercepts=nengo.dists.Uniform( Weights.eg, 1), **ea_params) self.gpe = EnsembleArray(label="Globus pallidus externus", intercepts=nengo.dists.Uniform( Weights.ee, 1), **ea_params) self.input = nengo.Node(label="input", size_in=self.action_count) self.output = nengo.Node(label="output", size_in=self.action_count) # add bias input (BG performs best in the range 0.5--1.5) if abs(self.input_bias) > 0.0: self.bias_input = nengo.Node(np.ones(self.action_count) * self.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) self.gaba = nengo.Network("GABAergic connections") self.gaba.config[nengo.Connection].synapse = self.gaba_synapse with self.gaba: 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( (self.action_count, self.action_count)) stn_output = self.stn.add_output('func_stn', Weights.stn_func) self.ampa = nengo.Network("AMPAergic connectiions") self.ampa.config[nengo.Connection].synapse = self.ampa_synapse with self.ampa: 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 self.gaba: 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=self.output_weight)
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)
def __init__( self, input_vocab, output_vocab=None, # noqa: C901 default_output_vector=None, threshold=0.3, input_scale=1.0, inhibitable=False, inhibit_scale=1.0, wta_output=False, wta_inhibit_scale=2.0, wta_synapse=0.005, precise=False, output_utilities=False, output_thresholded_utilities=False, neuron_type=nengo.LIF(), n_neurons_per_ensemble=10): super(AssociativeMemory, self).__init__() # If output vocabulary is not specified, use input vocabulary # (i.e autoassociative memory) if output_vocab is None: output_vocab = input_vocab # Handle different vocabulary types if isinstance(input_vocab, Vocabulary): input_vectors = input_vocab.vectors elif is_iterable(input_vocab): input_vectors = np.matrix(input_vocab) else: input_vectors = input_vocab if isinstance(output_vocab, Vocabulary): output_vectors = output_vocab.vectors elif is_iterable(output_vocab): output_vectors = np.matrix(output_vocab) else: output_vectors = output_vocab # Fail if number of input items and number of output items don't match if input_vectors.shape[0] != output_vectors.shape[0]: raise ValueError( 'number of input vectors does not match number of output ' 'vectors. %d != %d' % (input_vectors.shape[0], output_vectors.shape[0])) N = len(input_vectors) n_eval_points = 1500 eval_point_margin = 0.0001 if precise == True else 0.1 eval_points = Uniform( threshold + eval_point_margin, 1 + eval_point_margin).sample(n_eval_points).reshape(-1, 1) # Ensemble array parameters ea_params = { 'radius': 1.0, 'neuron_type': neuron_type, 'n_neurons': n_neurons_per_ensemble, 'n_ensembles': N, 'intercepts': Uniform(threshold, 1), 'max_rates': Uniform(80, 100) if precise == True else Uniform(100, 200), 'encoders': np.ones((n_neurons_per_ensemble, 1)), 'eval_points': eval_points } # Thresholding function def threshold_func(x): return x > threshold # Input and output nodes self.input = nengo.Node(size_in=input_vectors.shape[1], label="input") self.output = nengo.Node(size_in=output_vectors.shape[1], label="output") # Ensemble array to do the thresholding stuff self.thresholded_ens_array = EnsembleArray( label="thresholded ens array", **ea_params) # Connect input and output nodes nengo.Connection(self.input, self.thresholded_ens_array.input, synapse=None, transform=input_vectors * input_scale) nengo.Connection(self.thresholded_ens_array.add_output( 'thresholded_output', threshold_func), self.output, synapse=None, transform=output_vectors.T) # Configure associative memory to be inhibitable if inhibitable: # Input node for inhibitory gating signal (if enabled) self.inhibit = nengo.Node(size_in=1, label="inhibit") nengo.Connection(self.inhibit, self.thresholded_ens_array.input, synapse=None, transform=-np.ones((N, 1))) # Note: We can use decoded connection here because all the # encoding vectors are [1] # Configure associative memory to have mutually inhibited output if wta_output: nengo.Connection(self.thresholded_ens_array.output, self.thresholded_ens_array.input, synapse=wta_synapse, transform=(np.eye(N) - 1) * inhibit_scale) # Configure utilities output if output_utilities: self.utilities = nengo.Node(size_in=N, label="utilities") nengo.Connection(self.thresholded_ens_array.output, self.utilities, synapse=None) # Configure utilities output if output_thresholded_utilities: self.thresholded_utilities = nengo.Node( size_in=N, label="thresholded_utilities") nengo.Connection(self.thresholded_ens_array.thresholded_output, self.thresholded_utilities, synapse=None) # Configure default output vector if default_output_vector is not None: eval_points = Uniform(0.8, 1).sample(n_eval_points).reshape(-1, 1) bias = nengo.Node(output=[1]) default_vector_gate = nengo.Ensemble( n_neurons_per_ensemble, dimensions=1, encoders=np.ones((n_neurons_per_ensemble, 1)), intercepts=Uniform(0.5, 1), max_rates=ea_params['max_rates'], eval_points=eval_points, label="default vector gate") nengo.Connection(bias, default_vector_gate, synapse=None) nengo.Connection(self.thresholded_ens_array.thresholded_output, default_vector_gate, transform=-np.ones((1, N)), synapse=0.005) nengo.Connection(default_vector_gate, self.output, synapse=None, transform=np.matrix(default_output_vector).T) if inhibitable: nengo.Connection(self.inhibit, default_vector_gate, synapse=None, transform=[[-1]]) if isinstance(input_vocab, Vocabulary): self.inputs = dict(default=(self.input, input_vocab)) if isinstance(output_vocab, Vocabulary): self.outputs = dict(default=(self.output, output_vocab))
def Thalamus(dimensions, n_neurons_per_ensemble=50, mutual_inhib=1., threshold=0., net=None): """Inhibits non-selected actions. The thalamus is intended to work in tandem with a basal ganglia network. It converts basal ganglia output into a signal with (approximately) 1 for the selected action and 0 elsewhere. In order to suppress low responses and strengthen high responses, a constant bias is added to each dimension (i.e., action), and dimensions mutually inhibit each other. Additionally, the ensemble representing each dimension is created with positive encoders and can be assigned positive x-intercepts to threshold low responses. Parameters ---------- dimensions : int Number of dimensions (i.e., actions). n_neurons_per_ensemble : int, optional (Default: 50) Number of neurons in each ensemble in the network. mutual_inhib : float, optional (Default: 1.) Strength of the mutual inhibition between actions. threshold : float, optional (Default: 0.) The threshold below which values will not be represented. 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 thalamus network, or the provided ``net``. Attributes ---------- net.actions : EnsembleArray Each ensemble represents one dimension (action). net.bias : Node The constant bias injected in each ``actions`` ensemble. net.input : Node Input to the ``actions`` ensembles. net.output : Node Output from the ``actions`` ensembles. """ if net is None: net = nengo.Network("Thalamus") with net: net.actions = EnsembleArray(n_neurons_per_ensemble, dimensions, intercepts=Uniform(threshold, 1), encoders=Choice([[1.0]]), label="actions") nengo.Connection(net.actions.output, net.actions.input, transform=(np.eye(dimensions) - 1) * mutual_inhib) net.bias = nengo.Node([1], label="thalamus bias") nengo.Connection(net.bias, net.actions.input, transform=np.ones((dimensions, 1))) net.input = net.actions.input net.output = net.actions.output return net
def __init__(self, input_vocab, output_vocab=None, # noqa: C901 default_output_vector=None, threshold=0.3, input_scale=1.0, inhibitable=False, inhibit_scale=1.0, wta_output=False, wta_inhibit_scale=2.0, wta_synapse=0.005, output_utilities=False, output_thresholded_utilities=False, neuron_type=nengo.LIF(), n_neurons_per_ensemble=10): super(AssociativeMemory, self).__init__() # If output vocabulary is not specified, use input vocabulary # (i.e autoassociative memory) if output_vocab is None: output_vocab = input_vocab # Handle different vocabulary types if isinstance(input_vocab, Vocabulary): input_vectors = input_vocab.vectors elif is_iterable(input_vocab): input_vectors = np.matrix(input_vocab) else: input_vectors = input_vocab if isinstance(output_vocab, Vocabulary): output_vectors = output_vocab.vectors elif is_iterable(output_vocab): output_vectors = np.matrix(output_vocab) else: output_vectors = output_vocab # Fail if number of input items and number of output items don't match if input_vectors.shape[0] != output_vectors.shape[0]: raise ValueError( 'number of input vectors does not match number of output ' 'vectors. %d != %d' % (input_vectors.shape[0], output_vectors.shape[0])) N = len(input_vectors) n_eval_points = 500 eval_point_margin = 0.1 eval_points = Uniform( threshold + eval_point_margin, 1 + eval_point_margin) # Ensemble array parameters ea_params = {'radius': 1.0, 'neuron_type': neuron_type, 'n_neurons': n_neurons_per_ensemble, 'n_ensembles': N, 'intercepts': Uniform(threshold, 1), 'max_rates': Uniform(100, 200), 'encoders': Choice([[1]]), 'n_eval_points': n_eval_points, 'eval_points': eval_points} # Thresholding function def threshold_func(x): return x > threshold # Input and output nodes self.input = nengo.Node(size_in=input_vectors.shape[1], label="input") self.output = nengo.Node(size_in=output_vectors.shape[1], label="output") # Ensemble array to do the thresholding stuff self.thresholded_ens_array = EnsembleArray( label="thresholded ens array", **ea_params) # Connect input and output nodes nengo.Connection(self.input, self.thresholded_ens_array.input, synapse=None, transform=input_vectors * input_scale) nengo.Connection( self.thresholded_ens_array.add_output( 'thresholded_output', threshold_func), self.output, synapse=None, transform=output_vectors.T) # Configure associative memory to be inhibitable if inhibitable: # Input node for inhibitory gating signal (if enabled) self.inhibit = nengo.Node(size_in=1, label="inhibit") nengo.Connection(self.inhibit, self.thresholded_ens_array.input, synapse=None, transform=-np.ones((N, 1))) # Note: We can use decoded connection here because all the # encoding vectors are [1] # Configure associative memory to have mutually inhibited output if wta_output: nengo.Connection(self.thresholded_ens_array.output, self.thresholded_ens_array.input, synapse=wta_synapse, transform=(np.eye(N) - 1) * inhibit_scale) # Configure utilities output if output_utilities: self.utilities = nengo.Node(size_in=N, label="utilities") nengo.Connection(self.thresholded_ens_array.output, self.utilities, synapse=None) # Configure utilities output if output_thresholded_utilities: self.thresholded_utilities = nengo.Node( size_in=N, label="thresholded_utilities") nengo.Connection(self.thresholded_ens_array.thresholded_output, self.thresholded_utilities, synapse=None) # Configure default output vector if default_output_vector is not None: eval_points = Uniform(0.8, 1) bias = nengo.Node(output=[1]) default_vector_gate = nengo.Ensemble( n_neurons_per_ensemble, dimensions=1, encoders=Choice([[1]]), intercepts=Uniform(0.5, 1), max_rates=ea_params['max_rates'], n_eval_points=n_eval_points, eval_points=eval_points, label="default vector gate") nengo.Connection(bias, default_vector_gate, synapse=None) nengo.Connection(self.thresholded_ens_array.thresholded_output, default_vector_gate, transform=-np.ones((1, N)), synapse=0.005) nengo.Connection(default_vector_gate, self.output, synapse=None, transform=np.matrix(default_output_vector).T) if inhibitable: nengo.Connection(self.inhibit, default_vector_gate, synapse=None, transform=[[-1]]) if isinstance(input_vocab, Vocabulary): self.inputs = dict(default=(self.input, input_vocab)) if isinstance(output_vocab, Vocabulary): self.outputs = dict(default=(self.output, output_vocab))
class AssociativeMemory(Module): """Associative memory module. Parameters ---------- input_vocab: list of numpy.array, spa.Vocabulary The vocabulary (or list of vectors) to match. output_vocab: list of numpy.array, spa.Vocabulary, optional The vocabulary (or list of vectors) to be produced for each match. If not given, the associative memory will act like an auto-associative memory (cleanup memory). default_output_vector: numpy.array, spa.SemanticPointer, optional The vector to be produced if the input value matches none of vectors in the input vector list. threshold: float, optional The association activation threshold. input_scale: float, optional Scaling factor to apply on the input vectors. inhibitable: boolean, optional Flag to indicate if the entire associative memory module is inhibitable (entire thing can be shut off). inhibit_scale: float, optional Scaling factor on the gating connections (must have inhibitable = True). Setting a larger value will ensure that the cleanup memory output is inhibited at a faster rate, however, recovery of the network when inhibition is released will be slower. wta_output: boolean, optional Flag to indicate if output of the associative memory should contain more than one vectors. Set to True if only one vectors output is desired -- i.e. a winner-take-all (wta) output. Leave as default (False) if (possible) combinations of vectors is desired. wta_inhibit_scale: float, optional Scaling factor on the winner-take-all (wta) inhibitory connections. wta_synapse: float, optional Synapse to use for the winner-take-all (wta) inhibitory connections. output_utilities: boolean, optional Flag to indicate if the direct utilities (in addition to the vectors) are output as well. output_thresholded_utilities: boolean, optional Flag to indicate if the direct thresholded utilities (in addition to the vectors) are output as well. neuron_type: nengo.Neurons, optional Neuron type to use in the associative memory. Defaults to n_neurons_per_ensemble: int, optional Number of neurons per ensemble in the associative memory. There is one ensemble created per vector being compared. """ def __init__(self, input_vocab, output_vocab=None, # noqa: C901 default_output_vector=None, threshold=0.3, input_scale=1.0, inhibitable=False, inhibit_scale=1.0, wta_output=False, wta_inhibit_scale=2.0, wta_synapse=0.005, output_utilities=False, output_thresholded_utilities=False, neuron_type=nengo.LIF(), n_neurons_per_ensemble=10): super(AssociativeMemory, self).__init__() # If output vocabulary is not specified, use input vocabulary # (i.e autoassociative memory) if output_vocab is None: output_vocab = input_vocab # Handle different vocabulary types if isinstance(input_vocab, Vocabulary): input_vectors = input_vocab.vectors elif is_iterable(input_vocab): input_vectors = np.matrix(input_vocab) else: input_vectors = input_vocab if isinstance(output_vocab, Vocabulary): output_vectors = output_vocab.vectors elif is_iterable(output_vocab): output_vectors = np.matrix(output_vocab) else: output_vectors = output_vocab # Fail if number of input items and number of output items don't match if input_vectors.shape[0] != output_vectors.shape[0]: raise ValueError( 'number of input vectors does not match number of output ' 'vectors. %d != %d' % (input_vectors.shape[0], output_vectors.shape[0])) N = len(input_vectors) n_eval_points = 500 eval_point_margin = 0.1 eval_points = Uniform( threshold + eval_point_margin, 1 + eval_point_margin) # Ensemble array parameters ea_params = {'radius': 1.0, 'neuron_type': neuron_type, 'n_neurons': n_neurons_per_ensemble, 'n_ensembles': N, 'intercepts': Uniform(threshold, 1), 'max_rates': Uniform(100, 200), 'encoders': Choice([[1]]), 'n_eval_points': n_eval_points, 'eval_points': eval_points} # Thresholding function def threshold_func(x): return x > threshold # Input and output nodes self.input = nengo.Node(size_in=input_vectors.shape[1], label="input") self.output = nengo.Node(size_in=output_vectors.shape[1], label="output") # Ensemble array to do the thresholding stuff self.thresholded_ens_array = EnsembleArray( label="thresholded ens array", **ea_params) # Connect input and output nodes nengo.Connection(self.input, self.thresholded_ens_array.input, synapse=None, transform=input_vectors * input_scale) nengo.Connection( self.thresholded_ens_array.add_output( 'thresholded_output', threshold_func), self.output, synapse=None, transform=output_vectors.T) # Configure associative memory to be inhibitable if inhibitable: # Input node for inhibitory gating signal (if enabled) self.inhibit = nengo.Node(size_in=1, label="inhibit") nengo.Connection(self.inhibit, self.thresholded_ens_array.input, synapse=None, transform=-np.ones((N, 1))) # Note: We can use decoded connection here because all the # encoding vectors are [1] # Configure associative memory to have mutually inhibited output if wta_output: nengo.Connection(self.thresholded_ens_array.output, self.thresholded_ens_array.input, synapse=wta_synapse, transform=(np.eye(N) - 1) * inhibit_scale) # Configure utilities output if output_utilities: self.utilities = nengo.Node(size_in=N, label="utilities") nengo.Connection(self.thresholded_ens_array.output, self.utilities, synapse=None) # Configure utilities output if output_thresholded_utilities: self.thresholded_utilities = nengo.Node( size_in=N, label="thresholded_utilities") nengo.Connection(self.thresholded_ens_array.thresholded_output, self.thresholded_utilities, synapse=None) # Configure default output vector if default_output_vector is not None: eval_points = Uniform(0.8, 1) bias = nengo.Node(output=[1]) default_vector_gate = nengo.Ensemble( n_neurons_per_ensemble, dimensions=1, encoders=Choice([[1]]), intercepts=Uniform(0.5, 1), max_rates=ea_params['max_rates'], n_eval_points=n_eval_points, eval_points=eval_points, label="default vector gate") nengo.Connection(bias, default_vector_gate, synapse=None) nengo.Connection(self.thresholded_ens_array.thresholded_output, default_vector_gate, transform=-np.ones((1, N)), synapse=0.005) nengo.Connection(default_vector_gate, self.output, synapse=None, transform=np.matrix(default_output_vector).T) if inhibitable: nengo.Connection(self.inhibit, default_vector_gate, synapse=None, transform=[[-1]]) if isinstance(input_vocab, Vocabulary): self.inputs = dict(default=(self.input, input_vocab)) if isinstance(output_vocab, Vocabulary): self.outputs = dict(default=(self.output, output_vocab))
class Product(nengo.Network): """Computes the element-wise product of two equally sized vectors. The network used to calculate the product is described in `Gosmann, 2015`_. A simpler version of this network can be found in the :doc:`Multiplication example <examples/basic/multiplication>`. Note that this network is optimized under the assumption that both input values (or both values for each input dimensions of the input vectors) are uniformly and independently distributed. Visualized in a joint 2D space, this would give a square of equal probabilities for pairs of input values. This assumption is violated with non-uniform input value distributions (for example, if the input values follow a Gaussian or cosine similarity distribution). In that case, no square of equal probabilities is obtained, but a probability landscape with circular equi-probability lines. To obtain the optimal network accuracy, scale the *input_magnitude* by a factor of ``1 / sqrt(2)``. .. _Gosmann, 2015: https://nbviewer.jupyter.org/github/ctn-archive/technical-reports/blob/ master/Precise-multiplications-with-the-NEF.ipynb Parameters ---------- n_neurons : int Number of neurons per dimension in the vector. .. note:: These neurons will be distributed evenly across two ensembles. If an odd number of neurons is specified, the extra neuron will not be used. dimensions : int Number of dimensions in each of the vectors to be multiplied. input_magnitude : float, optional (Default: 1.) The expected magnitude of the vectors to be multiplied. This value is used to determine the radius of the ensembles computing the element-wise product. **kwargs Keyword arguments passed through to ``nengo.Network`` like 'label' and 'seed'. Attributes ---------- input_a : Node The first vector to be multiplied. input_b : Node The second vector to be multiplied. output : Node The resulting product. sq1 : EnsembleArray Represents the first squared term. See `Gosmann, 2015`_ for details. sq2 : EnsembleArray Represents the second squared term. See `Gosmann, 2015`_ for details. """ def __init__(self, n_neurons, dimensions, input_magnitude=1., **kwargs): if 'net' in kwargs: raise ObsoleteError("The 'net' argument is no longer supported.") kwargs.setdefault('label', "Product") super().__init__(**kwargs) with self: self.input_a = nengo.Node(size_in=dimensions, label="input_a") self.input_b = nengo.Node(size_in=dimensions, label="input_b") self.output = nengo.Node(size_in=dimensions, label="output") self.sq1 = EnsembleArray( max(1, n_neurons // 2), n_ensembles=dimensions, ens_dimensions=1, radius=input_magnitude * np.sqrt(2), ) self.sq2 = EnsembleArray( max(1, n_neurons // 2), n_ensembles=dimensions, ens_dimensions=1, radius=input_magnitude * np.sqrt(2), ) tr = 1. / np.sqrt(2.) nengo.Connection( self.input_a, self.sq1.input, transform=tr, synapse=None) nengo.Connection( self.input_b, self.sq1.input, transform=tr, synapse=None) nengo.Connection( self.input_a, self.sq2.input, transform=tr, synapse=None) nengo.Connection( self.input_b, self.sq2.input, transform=-tr, synapse=None) sq1_out = self.sq1.add_output('square', np.square) nengo.Connection(sq1_out, self.output, transform=.5, synapse=None) sq2_out = self.sq2.add_output('square', np.square) nengo.Connection(sq2_out, self.output, transform=-.5, synapse=None) @property def A(self): warnings.warn(DeprecationWarning("Use 'input_a' instead of 'A'.")) return self.input_a @property def B(self): warnings.warn(DeprecationWarning("Use 'input_b' instead of 'B'.")) return self.input_b
def __init__( self, phis, angles, encoder_rng=np.random, vocab=Default, # subdimensions=Default, neurons_per_dimension=Default, feedback=Default, represent_cc_identity=Default, feedback_synapse=Default, limit_low=-5, limit_high=-5, **kwargs): super(SSPState, self).__init__(**kwargs) self.vocab = vocab self.subdimensions = 6 self.neurons_per_dimension = neurons_per_dimension self.feedback = feedback self.feedback_synapse = feedback_synapse self.represent_cc_identity = represent_cc_identity dimensions = self.vocab.dimensions coord_rot_mat = get_coord_rot_mat(dimensions) inv_coord_rot_mat = np.linalg.pinv(coord_rot_mat) origin = np.zeros((dimensions, )) origin[0] = 1 rot_origin = origin @ coord_rot_mat.T origin_back = rot_origin @ inv_coord_rot_mat.T offset_vec = origin - origin_back # this offset only works for odd dimensions # offset_vec = np.ones((dimensions,)) * 1. / dimensions if ((dimensions - 1) % self.subdimensions != 0) and ( (dimensions - 2) % self.subdimensions != 0): raise ValidationError( "Dimensions (%d) must be divisible by subdimensions (%d)" % (dimensions, self.subdimensions), attr="dimensions", obj=self, ) with self: # if self.represent_cc_identity: # self.state_ensembles = IdentityEnsembleArray( # self.neurons_per_dimension, # dimensions, # self.subdimensions, # label="ssp state", # ) # else: # self.state_ensembles = EnsembleArray( # self.neurons_per_dimension * self.subdimensions, # dimensions // self.subdimensions, # ens_dimensions=self.subdimensions, # eval_points=nengo.dists.CosineSimilarity(dimensions + 2), # intercepts=nengo.dists.CosineSimilarity(dimensions + 2), # label="ssp state", # ) # the dimensionality with the constant(s) removed reduced_dim = coord_rot_mat.shape[0] n_toroids = len(phis) assert n_toroids == reduced_dim // self.subdimensions self.state_ensembles = EnsembleArray( self.neurons_per_dimension * self.subdimensions, n_toroids, ens_dimensions=self.subdimensions, # radius=2./dimensions, radius=1., # eval_points=nengo.dists.CosineSimilarity(dimensions + 2), # intercepts=nengo.dists.CosineSimilarity(dimensions + 2), label="ssp state", ) n_neurons = self.neurons_per_dimension * self.subdimensions # set the intercepts/encoders/eval points based on orientation and angle for k in range(n_toroids): preferred_locations = hilbert_2d(limit_low, limit_high, n_neurons, encoder_rng, p=8, N=2, normal_std=3) encoders_grid_cell = np.zeros((n_neurons, dimensions)) for n in range(n_neurons): encoders_grid_cell[n, :] = grid_cell_encoder( location=preferred_locations[n, :], dim=dimensions, phi=phis[k], angle=angles[k], toroid_index=k) # rotate, shift, and slice out relevant dimensions encoders_transformed = ( encoders_grid_cell @ coord_rot_mat.T)[:, k * 6:(k + 1) * 6].copy() self.state_ensembles.ea_ensembles[ k].intercepts = nengo.dists.Uniform(0, 1) self.state_ensembles.ea_ensembles[ k].encoders = encoders_transformed * (dimensions / 2.) # scaling eval points by the radius, so when they are rescaled later they are correct self.state_ensembles.ea_ensembles[ k].eval_points = encoders_transformed * (dimensions / 2.) # self.state_ensembles.ea_ensembles[k].normalize_encoders = False if self.feedback is not None and self.feedback != 0.0: nengo.Connection( self.state_ensembles.output, self.state_ensembles.input, transform=self.feedback, synapse=self.feedback_synapse, ) # Apply coordinate transform on the input and output self.input = nengo.Node(size_in=dimensions, label="input") self.output = nengo.Node(size_in=dimensions, label="output") # fixed offset to push the result back into the unitary space self.offset = nengo.Node(offset_vec) nengo.Connection(self.input, self.state_ensembles.input, transform=coord_rot_mat * (dimensions / 2.)) nengo.Connection(self.state_ensembles.output, self.output, transform=inv_coord_rot_mat / (dimensions / 2.)) nengo.Connection(self.offset, self.output) # self.input = self.state_ensembles.input # self.output = self.state_ensembles.output self.declare_input(self.input, self.vocab) self.declare_output(self.output, self.vocab)
class BasalGanglia(nengo.Network): """Winner takes all; outputs 0 at max dimension, negative elsewhere.""" # connection weights from (Gurney, Prescott, & Redgrave, 2001) mm = 1 mp = 1 me = 1 mg = 1 ws = 1 wt = 1 wm = 1 wg = 1 wp = 0.9 we = 0.3 e = 0.2 ep = -0.25 ee = -0.2 eg = -0.2 le = 0.2 lg = 0.2 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) @classmethod def str_func(cls, x): if x < cls.e: return 0 return cls.mm * (x - cls.e) @classmethod def stn_func(cls, x): if x < cls.ep: return 0 return cls.mp * (x - cls.ep) @classmethod def gpe_func(cls, x): if x < cls.ee: return 0 return cls.me * (x - cls.ee) @classmethod def gpi_func(cls, x): if x < cls.eg: return 0 return cls.mg * (x - cls.eg)
def __init__(self, action_count, n_neurons_per_ensemble=Default, output_weight=Default, input_bias=Default, ampa_synapse=Default, gaba_synapse=Default, **kwargs): super(BasalGanglia, self).__init__(**kwargs) self.action_count = action_count self.n_neurons_per_ensemble = n_neurons_per_ensemble self.output_weight = output_weight self.input_bias = input_bias self.ampa_synapse = ampa_synapse self.gaba_synapse = gaba_synapse self.input_connections = {} # Affects all ensembles / connections in the BG # unless overwritten with general_config config = nengo.Config(nengo.Ensemble, nengo.Connection) config[nengo.Ensemble].radius = 1.5 config[nengo.Ensemble].encoders = nengo.dists.Choice([[1]]) try: # Best, if we have SciPy config[nengo.Connection].solver = nengo.solvers.NnlsL2nz() except ImportError: warnings.warn("SciPy is not installed, so BasalGanglia will " "use the default decoder solver. Installing " "SciPy may improve BasalGanglia performance.") ea_params = { "n_neurons": self.n_neurons_per_ensemble, "n_ensembles": self.action_count, } with self, config: self.strD1 = EnsembleArray(label="Striatal D1 neurons", intercepts=nengo.dists.Uniform( Weights.e, 1), **ea_params) self.strD2 = EnsembleArray(label="Striatal D2 neurons", intercepts=nengo.dists.Uniform( Weights.e, 1), **ea_params) self.stn = EnsembleArray(label="Subthalamic nucleus", intercepts=nengo.dists.Uniform( Weights.ep, 1), **ea_params) self.gpi = EnsembleArray(label="Globus pallidus internus", intercepts=nengo.dists.Uniform( Weights.eg, 1), **ea_params) self.gpe = EnsembleArray(label="Globus pallidus externus", intercepts=nengo.dists.Uniform( Weights.ee, 1), **ea_params) self.input = nengo.Node(label="input", size_in=self.action_count) self.output = nengo.Node(label="output", size_in=self.action_count) # add bias input (BG performs best in the range 0.5--1.5) if abs(self.input_bias) > 0.0: self.bias_input = nengo.Node( np.ones(self.action_count) * self.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) self.gaba = nengo.Network("GABAergic connections") self.gaba.config[nengo.Connection].synapse = self.gaba_synapse with self.gaba: 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((self.action_count, self.action_count)) stn_output = self.stn.add_output("func_stn", Weights.stn_func) self.ampa = nengo.Network("AMPAergic connectiions") self.ampa.config[nengo.Connection].synapse = self.ampa_synapse with self.ampa: 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 self.gaba: 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=self.output_weight)
def __init__(self, dimensions, n_neurons_per_ensemble=100, output_weight=-3., input_bias=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
class CircularConvolution(nengo.Network): """CircularConvolution docs XXX""" def make(self, neurons, dimensions, radius=1, invert_a=False, invert_b=False): self.transformA = self._input_transform( dimensions, first=True, invert=invert_a) self.transformB = self._input_transform( dimensions, first=False, invert=invert_b) self.transformC = self._output_transform(dimensions) self.A = nengo.Node(size_in=dimensions, label='A') self.B = nengo.Node(size_in=dimensions, label='B') self.ensemble = EnsembleArray(neurons, self.transformC.shape[1], dimensions=2, radius=radius, label='conv') self.output = nengo.Node(size_in=dimensions, label='output') for ens in self.ensemble.ensembles: if not isinstance(neurons, nengo.Direct): ens.encoders = np.tile( [[1, 1], [-1, 1], [1, -1], [-1, -1]], (ens.n_neurons // 4, 1)) nengo.Connection( self.A, self.ensemble.input, transform=self.transformA, filter=None) nengo.Connection( self.B, self.ensemble.input, transform=self.transformB, filter=None) nengo.Connection(self.ensemble.add_output('product', self.product), self.output, filter=None, transform=self.transformC) @staticmethod def _input_transform(dims, first, invert=False): dims2 = 4 * (dims // 2 + 1) T = np.zeros((dims2, 2, dims)) dft = _dft_half_cached(dims) for i in range(dims2): row = dft[i // 4] if not invert else dft[i // 4].conj() if first: T[i, 0] = row.real if i % 2 == 0 else row.imag else: T[i, 1] = row.real if i % 4 == 0 or i % 4 == 3 else row.imag # --- Throw away rows that we don't need (b/c they're zero) i = np.arange(dims2) if dims % 2 == 0: T = T[(i == 0) | (i > 3) & (i < len(i) - 3)] else: T = T[(i == 0) | (i > 3)] return T.reshape((-1, dims)) @staticmethod def _output_transform(dims): dims2 = (dims // 2 + 1) T = np.zeros((dims2, 4, dims)) idft = _dft_half_cached(dims).conj() for i in range(dims2): row = idft[i] if i == 0 or 2*i == dims else 2*idft[i] T[i, 0] = row.real T[i, 1] = -row.real T[i, 2] = -row.imag T[i, 3] = -row.imag T = T.reshape(4*dims2, dims) # --- Throw away rows that we don't need (b/c they're zero) i = np.arange(4*dims2) if dims % 2 == 0: T = T[(i == 0) | (i > 3) & (i < len(i) - 3)] else: T = T[(i == 0) | (i > 3)] # scaling is needed since we have 1./sqrt(dims) in DFT T *= np.sqrt(dims) return T.T @staticmethod def product(x): return x[0] * x[1]
def Product(n_neurons, dimensions, input_magnitude=1., net=None, **kwargs): """Computes the element-wise product of two equally sized vectors. The network used to calculate the product is described in `Gosmann, 2015`_. A simpler version of this network can be found in the `Multiplication example <http://pythonhosted.org/nengo/examples/multiplication.html>`_. .. _Gosmann, 2015: http://nbviewer.jupyter.org/github/ctn-archive/technical-reports/blob/ master/Precise-multiplications-with-the-NEF.ipynb#An-alternative-network Parameters ---------- n_neurons : int Number of neurons per dimension in the vector. .. note:: These neurons will be distributed evenly across two ensembles. If an odd number of neurons is specified, the extra neuron will not be used. dimensions : int Number of dimensions in each of the vectors to be multiplied. input_magnitude : float, optional (Default: 1.) The expected magnitude of the vectors to be multiplied. This value is used to determine the radius of the ensembles computing the element-wise product. kwargs Keyword arguments passed through to ``nengo.Network``. Returns ------- net : Network The newly built product network, or the provided ``net``. Attributes ---------- net.input_a : Node The first vector to be multiplied. net.input_b : Node The second vector to be multiplied. net.output : Node The resulting product. net.sq1 : EnsembleArray Represents the first squared term. See `Gosmann, 2015`_ for details. net.sq2 : EnsembleArray Represents the second squared term. See `Gosmann, 2015`_ for details. """ if net is None: kwargs.setdefault('label', "Product") net = nengo.Network(**kwargs) else: warnings.warn("The 'net' argument is deprecated.", DeprecationWarning) with net: net.input_a = net.A = nengo.Node(size_in=dimensions, label="input_a") net.input_b = net.B = nengo.Node(size_in=dimensions, label="input_b") net.output = nengo.Node(size_in=dimensions, label="output") net.sq1 = EnsembleArray( max(1, n_neurons // 2), n_ensembles=dimensions, ens_dimensions=1, radius=input_magnitude * np.sqrt(2)) net.sq2 = EnsembleArray( max(1, n_neurons // 2), n_ensembles=dimensions, ens_dimensions=1, radius=input_magnitude * np.sqrt(2)) tr = 1. / np.sqrt(2.) nengo.Connection( net.input_a, net.sq1.input, transform=tr, synapse=None) nengo.Connection( net.input_b, net.sq1.input, transform=tr, synapse=None) nengo.Connection( net.input_a, net.sq2.input, transform=tr, synapse=None) nengo.Connection( net.input_b, net.sq2.input, transform=-tr, synapse=None) sq1_out = net.sq1.add_output('square', np.square) nengo.Connection(sq1_out, net.output, transform=.5, synapse=None) sq2_out = net.sq2.add_output('square', np.square) nengo.Connection(sq2_out, net.output, transform=-.5, synapse=None) 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, decoder_solver=nnls_L2nz): encoders = np.ones((n_neurons_per_ensemble, 1)) ea_params = { 'neurons': nengo.LIF(n_neurons_per_ensemble), 'n_ensembles': dimensions, 'radius': radius, 'encoders': encoders, } strD1 = EnsembleArray(label="Striatal D1 neurons", intercepts=Uniform(self.e, 1), **ea_params) strD2 = EnsembleArray(label="Striatal D2 neurons", intercepts=Uniform(self.e, 1), **ea_params) stn = EnsembleArray(label="Subthalamic nucleus", intercepts=Uniform(self.ep, 1), **ea_params) gpi = EnsembleArray(label="Globus pallidus internus", intercepts=Uniform(self.eg, 1), **ea_params) 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) # spread the input to StrD1, StrD2, and STN nengo.Connection(self.input, strD1.input, synapse=None, transform=self.ws * (1 + self.lg)) nengo.Connection(self.input, strD2.input, synapse=None, transform=self.ws * (1 - self.le)) nengo.Connection(self.input, stn.input, synapse=None, transform=self.wt) # connect the striatum to the GPi and GPe (inhibitory) strD1_output = strD1.add_output( 'func_str', self.str, decoder_solver=decoder_solver) nengo.Connection(strD1_output, gpi.input, synapse=tau_gaba, transform=-np.eye(dimensions) * self.wm) strD2_output = strD2.add_output( 'func_str', self.str, decoder_solver=decoder_solver) nengo.Connection(strD2_output, 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 = stn.add_output( 'func_stn', self.stn, decoder_solver=decoder_solver) nengo.Connection(stn_output, gpi.input, transform=tr, synapse=tau_ampa) nengo.Connection(stn_output, gpe.input, transform=tr, synapse=tau_ampa) # connect the GPe to GPi and STN (inhibitory) gpe_output = gpe.add_output( 'func_gpe', self.gpe, decoder_solver=decoder_solver) nengo.Connection(gpe_output, gpi.input, synapse=tau_gaba, transform=-self.we) nengo.Connection(gpe_output, stn.input, synapse=tau_gaba, transform=-self.wg) # connect GPi to output (inhibitory) gpi_output = gpi.add_output( 'func_gpi', self.gpi, decoder_solver=decoder_solver) nengo.Connection(gpi_output, self.output, synapse=None, transform=output_weight)
class AssociativeMemory(Module): """Associative memory module. Parameters ---------- input_vocab: list of numpy.array, spa.Vocabulary The vocabulary (or list of vectors) to match. output_vocab: list of numpy.array, spa.Vocabulary, optional The vocabulary (or list of vectors) to be produced for each match. If not given, the associative memory will act like an auto-associative memory (cleanup memory). default_output_vector: numpy.array, spa.SemanticPointer, optional The vector to be produced if the input value matches none of vectors in the input vector list. threshold: float, optional The association activation threshold. input_scale: float, optional Scaling factor to apply on the input vectors. inhibitable: boolean, optional Flag to indicate if the entire associative memory module is inhibitable (entire thing can be shut off). inhibit_scale: float, optional Scaling factor on the gating connections (must have inhibitable = True). Setting a larger value will ensure that the cleanup memory output is inhibited at a faster rate, however, recovery of the network when inhibition is released will be slower. wta_output: boolean, optional Flag to indicate if output of the associative memory should contain more than one vectors. Set to True if only one vectors output is desired -- i.e. a winner-take-all (wta) output. Leave as default (False) if (possible) combinations of vectors is desired. wta_inhibit_scale: float, optional Scaling factor on the winner-take-all (wta) inhibitory connections. wta_synapse: float, optional Synapse to use for the winner-take-all (wta) inhibitory connections. output_utilities: boolean, optional Flag to indicate if the direct utilities (in addition to the vectors) are output as well. output_thresholded_utilities: boolean, optional Flag to indicate if the direct thresholded utilities (in addition to the vectors) are output as well. neuron_type: nengo.Neurons, optional Neuron type to use in the associative memory. Defaults to n_neurons_per_ensemble: int, optional Number of neurons per ensemble in the associative memory. There is one ensemble created per vector being compared. """ def __init__( self, input_vocab, output_vocab=None, # noqa: C901 default_output_vector=None, threshold=0.3, input_scale=1.0, inhibitable=False, inhibit_scale=1.0, wta_output=False, wta_inhibit_scale=2.0, wta_synapse=0.005, precise=False, output_utilities=False, output_thresholded_utilities=False, neuron_type=nengo.LIF(), n_neurons_per_ensemble=10): super(AssociativeMemory, self).__init__() # If output vocabulary is not specified, use input vocabulary # (i.e autoassociative memory) if output_vocab is None: output_vocab = input_vocab # Handle different vocabulary types if isinstance(input_vocab, Vocabulary): input_vectors = input_vocab.vectors elif is_iterable(input_vocab): input_vectors = np.matrix(input_vocab) else: input_vectors = input_vocab if isinstance(output_vocab, Vocabulary): output_vectors = output_vocab.vectors elif is_iterable(output_vocab): output_vectors = np.matrix(output_vocab) else: output_vectors = output_vocab # Fail if number of input items and number of output items don't match if input_vectors.shape[0] != output_vectors.shape[0]: raise ValueError( 'number of input vectors does not match number of output ' 'vectors. %d != %d' % (input_vectors.shape[0], output_vectors.shape[0])) N = len(input_vectors) n_eval_points = 1500 eval_point_margin = 0.0001 if precise == True else 0.1 eval_points = Uniform( threshold + eval_point_margin, 1 + eval_point_margin).sample(n_eval_points).reshape(-1, 1) # Ensemble array parameters ea_params = { 'radius': 1.0, 'neuron_type': neuron_type, 'n_neurons': n_neurons_per_ensemble, 'n_ensembles': N, 'intercepts': Uniform(threshold, 1), 'max_rates': Uniform(80, 100) if precise == True else Uniform(100, 200), 'encoders': np.ones((n_neurons_per_ensemble, 1)), 'eval_points': eval_points } # Thresholding function def threshold_func(x): return x > threshold # Input and output nodes self.input = nengo.Node(size_in=input_vectors.shape[1], label="input") self.output = nengo.Node(size_in=output_vectors.shape[1], label="output") # Ensemble array to do the thresholding stuff self.thresholded_ens_array = EnsembleArray( label="thresholded ens array", **ea_params) # Connect input and output nodes nengo.Connection(self.input, self.thresholded_ens_array.input, synapse=None, transform=input_vectors * input_scale) nengo.Connection(self.thresholded_ens_array.add_output( 'thresholded_output', threshold_func), self.output, synapse=None, transform=output_vectors.T) # Configure associative memory to be inhibitable if inhibitable: # Input node for inhibitory gating signal (if enabled) self.inhibit = nengo.Node(size_in=1, label="inhibit") nengo.Connection(self.inhibit, self.thresholded_ens_array.input, synapse=None, transform=-np.ones((N, 1))) # Note: We can use decoded connection here because all the # encoding vectors are [1] # Configure associative memory to have mutually inhibited output if wta_output: nengo.Connection(self.thresholded_ens_array.output, self.thresholded_ens_array.input, synapse=wta_synapse, transform=(np.eye(N) - 1) * inhibit_scale) # Configure utilities output if output_utilities: self.utilities = nengo.Node(size_in=N, label="utilities") nengo.Connection(self.thresholded_ens_array.output, self.utilities, synapse=None) # Configure utilities output if output_thresholded_utilities: self.thresholded_utilities = nengo.Node( size_in=N, label="thresholded_utilities") nengo.Connection(self.thresholded_ens_array.thresholded_output, self.thresholded_utilities, synapse=None) # Configure default output vector if default_output_vector is not None: eval_points = Uniform(0.8, 1).sample(n_eval_points).reshape(-1, 1) bias = nengo.Node(output=[1]) default_vector_gate = nengo.Ensemble( n_neurons_per_ensemble, dimensions=1, encoders=np.ones((n_neurons_per_ensemble, 1)), intercepts=Uniform(0.5, 1), max_rates=ea_params['max_rates'], eval_points=eval_points, label="default vector gate") nengo.Connection(bias, default_vector_gate, synapse=None) nengo.Connection(self.thresholded_ens_array.thresholded_output, default_vector_gate, transform=-np.ones((1, N)), synapse=0.005) nengo.Connection(default_vector_gate, self.output, synapse=None, transform=np.matrix(default_output_vector).T) if inhibitable: nengo.Connection(self.inhibit, default_vector_gate, synapse=None, transform=[[-1]]) if isinstance(input_vocab, Vocabulary): self.inputs = dict(default=(self.input, input_vocab)) if isinstance(output_vocab, Vocabulary): self.outputs = dict(default=(self.output, output_vocab))
class BasalGanglia(nengo.Network): """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. **kwargs Keyword arguments passed through to ``nengo.Network`` like 'label' and 'seed'. Attributes ---------- 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. gpe : EnsembleArray Globus pallidus externus ensembles. gpi : EnsembleArray Globus pallidus internus ensembles. input : Node Accepts the input signal. output : Node Provides the output signal. stn : EnsembleArray Subthalamic nucleus ensembles. strD1 : EnsembleArray Striatal D1 ensembles. 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. """ def __init__(self, dimensions, n_neurons_per_ensemble=100, output_weight=-3., input_bias=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
class BasalGanglia(nengo.Network): """Winner takes all; outputs 0 at max dimension, negative elsewhere.""" # connection weights from (Gurney, Prescott, & Redgrave, 2001) mm = 1 mp = 1 me = 1 mg = 1 ws = 1 wt = 1 wm = 1 wg = 1 wp = 0.9 we = 0.3 e = 0.2 ep = -0.25 ee = -0.2 eg = -0.2 le = 0.2 lg = 0.2 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) @classmethod def str_func(cls, x): if x < cls.e: return 0 return cls.mm * (x - cls.e) @classmethod def stn_func(cls, x): if x < cls.ep: return 0 return cls.mp * (x - cls.ep) @classmethod def gpe_func(cls, x): if x < cls.ee: return 0 return cls.me * (x - cls.ee) @classmethod def gpi_func(cls, x): if x < cls.eg: return 0 return cls.mg * (x - cls.eg)
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, 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 Product(n_neurons, dimensions, input_magnitude=1., net=None, **kwargs): """Computes the element-wise product of two equally sized vectors. The network used to calculate the product is described in `Gosmann, 2015`_. A simpler version of this network can be found in the `Multiplication example <http://pythonhosted.org/nengo/examples/multiplication.html>`_. Note that this network is optimized under the assumption that both input values (or both values for each input dimensions of the input vectors) are uniformly and independently distributed. Visualized in a joint 2D space, this would give a square of equal probabilities for pairs of input values. This assumption is violated with non-uniform input value distributions (for example, if the input values follow a Gaussian or cosine similarity distribution). In that case, no square of equal probabilities is obtained, but a probability landscape with circular equi-probability lines. To obtain the optimal network accuracy, scale the *input_magnitude* by a factor of ``1 / sqrt(2)``. .. _Gosmann, 2015: http://nbviewer.jupyter.org/github/ctn-archive/technical-reports/blob/ master/Precise-multiplications-with-the-NEF.ipynb#An-alternative-network Parameters ---------- n_neurons : int Number of neurons per dimension in the vector. .. note:: These neurons will be distributed evenly across two ensembles. If an odd number of neurons is specified, the extra neuron will not be used. dimensions : int Number of dimensions in each of the vectors to be multiplied. input_magnitude : float, optional (Default: 1.) The expected magnitude of the vectors to be multiplied. This value is used to determine the radius of the ensembles computing the element-wise product. kwargs Keyword arguments passed through to ``nengo.Network``. Returns ------- net : Network The newly built product network, or the provided ``net``. Attributes ---------- net.input_a : Node The first vector to be multiplied. net.input_b : Node The second vector to be multiplied. net.output : Node The resulting product. net.sq1 : EnsembleArray Represents the first squared term. See `Gosmann, 2015`_ for details. net.sq2 : EnsembleArray Represents the second squared term. See `Gosmann, 2015`_ for details. """ if net is None: kwargs.setdefault('label', "Product") net = nengo.Network(**kwargs) else: warnings.warn("The 'net' argument is deprecated.", DeprecationWarning) with net: net.input_a = net.A = nengo.Node(size_in=dimensions, label="input_a") net.input_b = net.B = nengo.Node(size_in=dimensions, label="input_b") net.output = nengo.Node(size_in=dimensions, label="output") net.sq1 = EnsembleArray(max(1, n_neurons // 2), n_ensembles=dimensions, ens_dimensions=1, radius=input_magnitude * np.sqrt(2)) net.sq2 = EnsembleArray(max(1, n_neurons // 2), n_ensembles=dimensions, ens_dimensions=1, radius=input_magnitude * np.sqrt(2)) tr = 1. / np.sqrt(2.) nengo.Connection(net.input_a, net.sq1.input, transform=tr, synapse=None) nengo.Connection(net.input_b, net.sq1.input, transform=tr, synapse=None) nengo.Connection(net.input_a, net.sq2.input, transform=tr, synapse=None) nengo.Connection(net.input_b, net.sq2.input, transform=-tr, synapse=None) sq1_out = net.sq1.add_output('square', np.square) nengo.Connection(sq1_out, net.output, transform=.5, synapse=None) sq2_out = net.sq2.add_output('square', np.square) nengo.Connection(sq2_out, net.output, transform=-.5, synapse=None) return net
class BasalGanglia(nengo.Network): """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 Number of neurons in each ensemble in the network. output_weight : float, optional A scaling factor on the output of the basal ganglia (specifically on the connection out of the GPi). input_bias : float, optional 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 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 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. **kwargs Keyword arguments passed through to ``nengo.Network`` like 'label' and 'seed'. Attributes ---------- 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. gpe : EnsembleArray Globus pallidus externus ensembles. gpi : EnsembleArray Globus pallidus internus ensembles. input : Node Accepts the input signal. output : Node Provides the output signal. stn : EnsembleArray Subthalamic nucleus ensembles. strD1 : EnsembleArray Striatal D1 ensembles. 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. """ 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
class Product(nengo.Network): """Computes the element-wise product of two equally sized vectors. The network used to calculate the product is described in `Gosmann, 2015`_. A simpler version of this network can be found in the :doc:`Multiplication example <examples/basic/multiplication>`. Note that this network is optimized under the assumption that both input values (or both values for each input dimensions of the input vectors) are uniformly and independently distributed. Visualized in a joint 2D space, this would give a square of equal probabilities for pairs of input values. This assumption is violated with non-uniform input value distributions (for example, if the input values follow a Gaussian or cosine similarity distribution). In that case, no square of equal probabilities is obtained, but a probability landscape with circular equi-probability lines. To obtain the optimal network accuracy, scale the *input_magnitude* by a factor of ``1 / sqrt(2)``. .. _Gosmann, 2015: https://nbviewer.jupyter.org/github/ctn-archive/technical-reports/blob/ master/Precise-multiplications-with-the-NEF.ipynb Parameters ---------- n_neurons : int Number of neurons per dimension in the vector. .. note:: These neurons will be distributed evenly across two ensembles. If an odd number of neurons is specified, the extra neuron will not be used. dimensions : int Number of dimensions in each of the vectors to be multiplied. input_magnitude : float, optional (Default: 1.) The expected magnitude of the vectors to be multiplied. This value is used to determine the radius of the ensembles computing the element-wise product. **kwargs Keyword arguments passed through to ``nengo.Network`` like 'label' and 'seed'. Attributes ---------- input_a : Node The first vector to be multiplied. input_b : Node The second vector to be multiplied. output : Node The resulting product. sq1 : EnsembleArray Represents the first squared term. See `Gosmann, 2015`_ for details. sq2 : EnsembleArray Represents the second squared term. See `Gosmann, 2015`_ for details. """ def __init__(self, n_neurons, dimensions, input_magnitude=1., **kwargs): if 'net' in kwargs: raise ObsoleteError("The 'net' argument is no longer supported.") kwargs.setdefault('label', "Product") super().__init__(**kwargs) with self: self.input_a = nengo.Node(size_in=dimensions, label="input_a") self.input_b = nengo.Node(size_in=dimensions, label="input_b") self.output = nengo.Node(size_in=dimensions, label="output") self.sq1 = EnsembleArray( max(1, n_neurons // 2), n_ensembles=dimensions, ens_dimensions=1, radius=input_magnitude * np.sqrt(2), ) self.sq2 = EnsembleArray( max(1, n_neurons // 2), n_ensembles=dimensions, ens_dimensions=1, radius=input_magnitude * np.sqrt(2), ) tr = 1. / np.sqrt(2.) nengo.Connection(self.input_a, self.sq1.input, transform=tr, synapse=None) nengo.Connection(self.input_b, self.sq1.input, transform=tr, synapse=None) nengo.Connection(self.input_a, self.sq2.input, transform=tr, synapse=None) nengo.Connection(self.input_b, self.sq2.input, transform=-tr, synapse=None) sq1_out = self.sq1.add_output('square', np.square) nengo.Connection(sq1_out, self.output, transform=.5, synapse=None) sq2_out = self.sq2.add_output('square', np.square) nengo.Connection(sq2_out, self.output, transform=-.5, synapse=None) @property def A(self): warnings.warn(DeprecationWarning("Use 'input_a' instead of 'A'.")) return self.input_a @property def B(self): warnings.warn(DeprecationWarning("Use 'input_b' instead of 'B'.")) return self.input_b
class BasalGanglia(Network): """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 `nengo.solvers.Solver` for the basal ganglia is `nengo.solvers.NnlsL2nz`, which requires SciPy. If SciPy is not installed, the global default solver will be used instead. Parameters ---------- action_count : int Number of actions. n_neuron_per_ensemble : int, optional Number of neurons in each ensemble in the network. output_weight : float, optional A scaling factor on the output of the basal ganglia (specifically on the connection out of the GPi). input_bias : float, optional 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_synapse : Synapse, optional Synapse for connections corresponding to biological connections to AMPA receptors (i.e., connections from STN to to GPi and GPe). gaba_synapse : Synapse, optional Synapse 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). kwargs Passed through the `nengo_spa.Network`. Attributes ---------- bias_input : nengo.Node or None If *input_bias* is non-zero, this node will be created to bias all of the dimensions of the input signal. gpe : nengo.networks.EnsembleArray Globus pallidus externus ensembles. gpi : nengo.networks.EnsembleArray Globus pallidus internus ensembles. input : nengo.Node Accepts the input signal. output : nengo.Node Provides the output signal. stn : nengo.networks.EnsembleArray Subthalamic nucleus ensembles. strD1 : nengo.networks.EnsembleArray Striatal D1 ensembles. strD2 : nengo.networks.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. """ input_synapse = SynapseParam('input_synapse', default=Lowpass(0.002)) ampa_synapse = SynapseParam('ampa_synapse', default=Lowpass(0.002)) gaba_synapse = SynapseParam('gaba_synapse', default=Lowpass(0.008)) n_neurons_per_ensemble = IntParam('n_neurons_per_ensemble', default=100, low=1, readonly=True) output_weight = NumberParam('output_weight', default=-3., readonly=True) input_bias = NumberParam('input_bias', default=0., readonly=True) def __init__(self, action_count, n_neurons_per_ensemble=Default, output_weight=Default, input_bias=Default, ampa_synapse=Default, gaba_synapse=Default, sBCBG_params=None, **kwargs): kwargs.setdefault('label', "Basal ganglia") super(BasalGanglia, self).__init__(**kwargs) self.action_count = action_count self.input_connections = {} self.input_bias = input_bias if BasalGanglia.sBCBG: # parameters filter_tau = .01 if output_weight == Default: self.output_weight = -0.001 import sBCBG if sBCBG_params == None: sBCBG_params = {} sBCBG.nengo_instantiate( self.action_count, self, sBCBG_params if sBCBG_params != None else {}) with self: # connect input to CSN self.input = nengo.Node(label="input", size_in=self.action_count) scale = nengo.Ensemble(100, self.input.size_out) nengo.Connection(self.input, scale) for d in range(self.action_count): nengo.Connection(scale[d], self.pops['CSN'][d], function=lambda x: 10 * x, synapse=.01, label='CSN input') # add bias input (BG performs best in the range 0.5--1.5) if abs(self.input_bias) > 0.0: self.bias_input = nengo.Node(np.ones(self.action_count) * input_bias, label="basal ganglia bias") nengo.Connection(self.bias_input, self.input) # connect GPi to output (inhibitory) decoding_weight = 1 # scaling of decoding GPi->out self.output = nengo.Node(label="output", size_in=self.action_count) for d in range(self.action_count): GPi_ens = self.pops["GPi"][d] decoder_values = np.ones( (GPi_ens.n_neurons, 1)) * decoding_weight nengo.Connection( GPi_ens, self.output[d], synapse=nengo.synapses.Lowpass(filter_tau), transform=self.output_weight, #eval_points=eval_points) solver=nengo.solvers.NoSolver(decoder_values)) else: self.n_neurons_per_ensemble = n_neurons_per_ensemble self.ampa_synapse = ampa_synapse self.gaba_synapse = gaba_synapse self.output_weight = output_weight # Affects all ensembles / connections in the BG # unless overwritten with general_config config = nengo.Config(nengo.Ensemble, nengo.Connection) config[nengo.Ensemble].radius = 1.5 config[nengo.Ensemble].encoders = nengo.dists.Choice([[1]]) try: # Best, if we have SciPy config[nengo.Connection].solver = nengo.solvers.NnlsL2nz() except ImportError: warnings.warn("SciPy is not installed, so BasalGanglia will " "use the default decoder solver. Installing " "SciPy may improve BasalGanglia performance.") ea_params = { 'n_neurons': self.n_neurons_per_ensemble, 'n_ensembles': self.action_count } with self, config: self.strD1 = EnsembleArray(label="Striatal D1 neurons", intercepts=nengo.dists.Uniform( Weights.e, 1), **ea_params) self.strD2 = EnsembleArray(label="Striatal D2 neurons", intercepts=nengo.dists.Uniform( Weights.e, 1), **ea_params) self.stn = EnsembleArray(label="Subthalamic nucleus", intercepts=nengo.dists.Uniform( Weights.ep, 1), **ea_params) self.gpi = EnsembleArray(label="Globus pallidus internus", intercepts=nengo.dists.Uniform( Weights.eg, 1), **ea_params) self.gpe = EnsembleArray(label="Globus pallidus externus", intercepts=nengo.dists.Uniform( Weights.ee, 1), **ea_params) self.input = nengo.Node(label="input", size_in=self.action_count) self.output = nengo.Node(label="output", size_in=self.action_count) # add bias input (BG performs best in the range 0.5--1.5) if abs(self.input_bias) > 0.0: self.bias_input = nengo.Node(np.ones(self.action_count) * self.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) self.gaba = nengo.Network("GABAergic connections") self.gaba.config[nengo.Connection].synapse = self.gaba_synapse with self.gaba: 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( (self.action_count, self.action_count)) stn_output = self.stn.add_output('func_stn', Weights.stn_func) self.ampa = nengo.Network("AMPAergic connectiions") self.ampa.config[nengo.Connection].synapse = self.ampa_synapse with self.ampa: 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 self.gaba: 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=self.output_weight) def connect_input(self, source, transform=Default, index=None): self.input_connections[index] = nengo.Connection( source, self.input[index], transform=transform, synapse=self.input_synapse)
def __init__(self, input_vectors, output_vectors=None, # noqa: C901 default_output_vector=None, threshold=0.3, input_scale=1.0, inhibitable=False, inhibit_scale=1.5, wta_output=False, wta_inhibit_scale=3.0, wta_synapse=0.005, threshold_output=False, label=None, seed=None, add_to_container=None, **ens_args): super(AssociativeMemory, self).__init__(label, seed, add_to_container) label_prefix = "" if label is None else label + "_" n_neurons_per_ensemble = ens_args.get('n_neurons', 50) # If output vocabulary is not specified, use input vocabulary # (i.e autoassociative memory) if output_vectors is None: output_vectors = input_vectors # Handle different vocabulary types if is_iterable(input_vectors): input_vectors = np.matrix(input_vectors) if is_iterable(output_vectors): output_vectors = np.matrix(output_vectors) # Fail if number of input items and number of output items don't # match if input_vectors.shape[0] != output_vectors.shape[0]: raise ValueError( 'Number of input vectors does not match number of output ' 'vectors. %d != %d' % (input_vectors.shape[0], output_vectors.shape[0])) # Handle possible different threshold / input_scale values for each # element in the associative memory if not is_iterable(threshold): threshold = np.array([threshold] * input_vectors.shape[0]) else: threshold = np.array(threshold) if threshold.shape[0] != input_vectors.shape[0]: raise ValueError( 'Number of threshold values do not match number of input' 'vectors. Got: %d, expected %d.' % (threshold.shape[0], input_vectors.shape[0])) if not is_iterable(input_scale): input_scale = np.matrix([input_scale] * input_vectors.shape[0]) else: input_scale = np.matrix(input_scale) if input_scale.shape[1] != input_vectors.shape[0]: raise ValueError( 'Number of input_scale values do not match number of input' 'vectors. Got: %d, expected %d.' % (input_scale.shape[1], input_vectors.shape[0])) # Input and output nodes N = input_vectors.shape[0] self.num_items = N with self: bias_node = nengo.Node(output=1) self.input = nengo.Node(size_in=input_vectors.shape[1], label="input") self.output = nengo.Node(size_in=output_vectors.shape[1], label="output") self.elem_input = nengo.Node(size_in=N, label="element input") self.elem_output = nengo.Node(size_in=N, label="element output") self.threshold_output = threshold_output nengo.Connection(self.input, self.elem_input, synapse=None, transform=np.multiply(input_vectors, input_scale.T)) # Evaluation points parameters n_eval_points = 5000 # Make each ensemble self.am_ensembles = [] for i in range(N): # Ensemble array parameters ens_params = dict(ens_args) ens_params['radius'] = ens_args.get('radius', 1.0) ens_params['dimensions'] = 1 ens_params['n_neurons'] = n_neurons_per_ensemble ens_params['intercepts'] = Uniform(threshold[i], 1) ens_params['encoders'] = Choice([[1]]) ens_params['eval_points'] = Uniform(threshold[i], 1.2) ens_params['n_eval_points'] = n_eval_points ens_params['label'] = label_prefix + str(i) # Create ensemble e = nengo.Ensemble(**ens_params) self.am_ensembles.append(e) # Connect input and output nodes nengo.Connection(self.elem_input[i], e, synapse=None) nengo.Connection(e, self.elem_output[i], synapse=None) # Configure associative memory to be inhibitable if inhibitable: # Input node for inhibitory gating signal (if enabled) self.inhibit = nengo.Node(size_in=1, label="inhibit") nengo.Connection(self.inhibit, self.elem_input, transform=-np.ones((N, 1)) * inhibit_scale, synapse=None) # Note: We can use decoded connection here because all the # encoding vectors are [1] # Configure associative memory to have mutually inhibited output if wta_output: nengo.Connection(self.elem_output, self.elem_input, synapse=wta_synapse, transform=(np.eye(N) - 1) * wta_inhibit_scale) # Configure utilities output self.utilities = self.elem_output # Configure default output vector if default_output_vector is not None or threshold_output: default_threshold = min(1 - np.min(threshold), 0.9) ens_params = dict(ens_args) ens_params['radius'] = ens_args.get('radius', 1.0) ens_params['dimensions'] = 1 ens_params['n_neurons'] = n_neurons_per_ensemble ens_params['intercepts'] = Uniform(default_threshold, 1) ens_params['encoders'] = Choice([[1]]) ens_params['eval_points'] = Uniform(default_threshold, 1.1) ens_params['n_eval_points'] = n_eval_points ens_params['label'] = "default vector gate" default_vector_gate = nengo.Ensemble(**ens_params) nengo.Connection(bias_node, default_vector_gate, synapse=None) nengo.Connection(self.elem_output, default_vector_gate, transform=-2 * np.ones((1, N)), synapse=0.01) self.default_output_utility = default_vector_gate self.default_output_thresholded_utility = default_vector_gate if default_output_vector is not None: nengo.Connection( default_vector_gate, self.output, transform=np.matrix(default_output_vector).T, synapse=None) if inhibitable: nengo.Connection(self.inhibit, default_vector_gate, transform=[[-1]], synapse=None) # Set up thresholding ensembles if threshold_output: # Ensemble array parameters ens_params = dict(ens_args) ens_params['radius'] = ens_args.get('radius', 1.0) ens_params['n_neurons'] = n_neurons_per_ensemble ens_params['n_ensembles'] = N ens_params['intercepts'] = Uniform(0.5, 1) ens_params['encoders'] = Choice([[1]]) ens_params['eval_points'] = Uniform(0.5, 1.1) ens_params['n_eval_points'] = n_eval_points self.thresh_ens = EnsembleArray(**ens_params) self.thresholded_utilities = self.thresh_ens.output nengo.Connection(bias_node, self.thresh_ens.input, transform=np.ones((N, 1)), synapse=None) if wta_output: nengo.Connection(self.elem_output, self.thresh_ens.input, transform=10 * (np.eye(N) - 1), synapse=0.01) else: ens_params['intercepts'] = Uniform(0.25, 1) self.thresh_ens_int = EnsembleArray(**ens_params) nengo.Connection(bias_node, self.thresh_ens_int.input, transform=np.ones((N, 1)), synapse=None) nengo.Connection(self.elem_output, self.thresh_ens_int.input, transform=-10, synapse=0.005) nengo.Connection(self.thresh_ens_int.output, self.thresh_ens.input, transform=-10, synapse=0.005) nengo.Connection(self.thresh_ens.output, self.output, transform=output_vectors.T, synapse=None) nengo.Connection(default_vector_gate, self.thresh_ens.input, transform=-2 * np.ones((N, 1)), synapse=0.01) if inhibitable: nengo.Connection( self.inhibit, self.thresh_ens.input, transform=-np.ones((N, 1)) * inhibit_scale, synapse=None) else: nengo.Connection(self.elem_output, self.output, transform=output_vectors.T, synapse=None)