def test_repeat_config_warning(): """tests a warning is run on repeat config""" with nengo.Network(): test_am = AssociativeMemory([0]) test_am.add_threshold_to_outputs() with pytest.warns(UserWarning, match="already configured with thresholded outputs"): test_am.add_threshold_to_outputs() test_am.add_wta_network() with pytest.warns(UserWarning, match="already configured with a WTA network"): test_am.add_wta_network()
def test_am_wta(Simulator, plt, seed, rng): """Test the winner-take-all ability of the associative memory.""" D = 64 vocab = make_vocab(4, D, rng) def input_func(t): if t < 0.2: return vocab[0, :] + 0.8 * vocab[1, :] elif t < 0.3: return np.zeros(D) else: return 0.8 * vocab[0, :] + vocab[1, :] with nengo.Network('model', seed=seed) as m: am = AssociativeMemory(vocab) am.add_wta_network() in_node = nengo.Node(output=input_func, label='input') nengo.Connection(in_node, am.input) in_p = nengo.Probe(in_node) out_p = nengo.Probe(am.output, synapse=0.03) utils_p = nengo.Probe(am.utilities, synapse=0.03) sim = Simulator(m) sim.run(0.5) t = sim.trange() more_a = (t > 0.15) & (t < 0.2) more_b = t > 0.45 plt.subplot(2, 1, 1) plt.plot(t, np.dot(sim.data[in_p], vocab.T)) plt.ylabel("Input") plt.ylim(top=1.1) plt.subplot(2, 1, 2) plt.plot(t, np.dot(sim.data[out_p], vocab.T)) plt.plot(t[more_a], np.ones(t.shape)[more_a] * 0.9, c='g', lw=2) plt.plot(t[more_b], np.ones(t.shape)[more_b] * 0.9, c='g', lw=2) plt.ylabel("Output") assert similarity(sim.data[out_p][more_a], vocab[0, :]) > 0.79 assert similarity(sim.data[out_p][more_a], vocab[1, :]) < 0.1 assert similarity(sim.data[out_p][more_b], vocab[1, :]) > 0.79 assert similarity(sim.data[out_p][more_b], vocab[0, :]) < 0.1 assert similarity(sim.data[utils_p][more_a], np.array([1, 0, 0, 0])) > 0.95 assert similarity(sim.data[utils_p][more_a], np.array([0, 1, 1, 1])) < 0.001 assert similarity(sim.data[utils_p][more_b], np.array([0, 1, 0, 0])) > 0.95 assert similarity(sim.data[utils_p][more_b], np.array([1, 0, 1, 1])) < 0.001
def test_am_wta(Simulator, plt, seed, rng): """Test the winner-take-all ability of the associative memory.""" D = 64 vocab = make_vocab(4, D, rng) def input_func(t): if t < 0.2: return vocab[0, :] + 0.8 * vocab[1, :] elif t < 0.3: return np.zeros(D) else: return 0.8 * vocab[0, :] + vocab[1, :] with nengo.Network("model", seed=seed) as m: am = AssociativeMemory(vocab) am.add_wta_network() in_node = nengo.Node(output=input_func, label="input") nengo.Connection(in_node, am.input) in_p = nengo.Probe(in_node) out_p = nengo.Probe(am.output, synapse=0.03) utils_p = nengo.Probe(am.utilities, synapse=0.03) with Simulator(m) as sim: sim.run(0.5) t = sim.trange() more_a = (t > 0.15) & (t < 0.2) more_b = t > 0.45 plt.subplot(2, 1, 1) plt.plot(t, np.dot(sim.data[in_p], vocab.T)) plt.ylabel("Input") plt.ylim(top=1.1) plt.subplot(2, 1, 2) plt.plot(t, np.dot(sim.data[out_p], vocab.T)) plt.plot(t[more_a], np.ones(t.shape)[more_a] * 0.9, c="g", lw=2) plt.plot(t[more_b], np.ones(t.shape)[more_b] * 0.9, c="g", lw=2) plt.ylabel("Output") assert similarity(sim.data[out_p][more_a], vocab[0, :]) > 0.79 assert similarity(sim.data[out_p][more_a], vocab[1, :]) < 0.1 assert similarity(sim.data[out_p][more_b], vocab[1, :]) > 0.79 assert similarity(sim.data[out_p][more_b], vocab[0, :]) < 0.1 assert similarity(sim.data[utils_p][more_a], np.array([1, 0, 0, 0])) > 0.95 assert similarity(sim.data[utils_p][more_a], np.array([0, 1, 1, 1 ])) < 0.001 assert similarity(sim.data[utils_p][more_b], np.array([0, 1, 0, 0])) > 0.95 assert similarity(sim.data[utils_p][more_b], np.array([1, 0, 1, 1 ])) < 0.001
class AssociativeMemory(Module): """Associative memory module. See :doc:`examples/associative_memory` for an introduction and examples. Parameters ---------- input_vocab: list or Vocabulary The vocabulary (or list of vectors) to match. output_vocab: list or Vocabulary, optional (Default: None) The vocabulary (or list of vectors) to be produced for each match. If None, the associative memory will act like an autoassociative memory (cleanup memory). input_keys : list, optional (Default: None) A list of strings that correspond to the input vectors. output_keys : list, optional (Default: None) A list of strings that correspond to the output vectors. default_output_key: str, optional (Default: None) The semantic pointer string to be produced if the input value matches none of vectors in the input vector list. threshold: float, optional (Default: 0.3) The association activation threshold. inhibitable: bool, optional (Default: False) Flag to indicate if the entire associative memory module is inhibitable (i.e., the entire module can be inhibited). wta_output: bool, optional (Default: False) Flag to indicate if output of the associative memory should contain more than one vector. If True, only one vector's output will be produced; i.e. produce a winner-take-all (WTA) output. If False, combinations of vectors will be produced. wta_inhibit_scale: float, optional (Default: 3.0) Scaling factor on the winner-take-all (WTA) inhibitory connections. wta_synapse: float, optional (Default: 0.005) Synapse to use for the winner-take-all (wta) inhibitory connections. threshold_output: bool, optional (Default: False) Adds a threholded output if True. label : str, optional (Default: None) A name for the ensemble. Used for debugging and visualization. seed : int, optional (Default: None) The seed used for random number generation. add_to_container : bool, optional (Default: None) Determines if this Network will be added to the current container. If None, will be true if currently within a Network. """ def __init__( self, input_vocab, output_vocab=None, # noqa: C901 input_keys=None, output_keys=None, default_output_key=None, threshold=0.3, inhibitable=False, wta_output=False, wta_inhibit_scale=3.0, wta_synapse=0.005, threshold_output=False, label=None, seed=None, add_to_container=None): super(AssociativeMemory, self).__init__(label, seed, add_to_container) if input_keys is None: input_keys = input_vocab.keys input_vectors = input_vocab.vectors else: input_vectors = input_vocab.create_subset(input_keys).vectors # If output vocabulary is not specified, use input vocabulary # (i.e autoassociative memory) if output_vocab is None: output_vocab = input_vocab output_vectors = input_vectors else: if output_keys is None: output_keys = input_keys output_vectors = output_vocab.create_subset(output_keys).vectors if default_output_key is None: default_output_vector = None else: default_output_vector = output_vocab.parse(default_output_key).v # Create nengo network with self: self.am = AssocMem(input_vectors=input_vectors, output_vectors=output_vectors, threshold=threshold, inhibitable=inhibitable, label=label, seed=seed, add_to_container=add_to_container) if default_output_vector is not None: self.am.add_default_output_vector(default_output_vector) if wta_output: self.am.add_wta_network(wta_inhibit_scale, wta_synapse) if threshold_output: self.am.add_threshold_to_outputs() self.input = self.am.input self.output = self.am.output if inhibitable: self.inhibit = self.am.inhibit self.utilities = self.am.utilities if threshold_output: self.thresholded_utilities = self.am.thresholded_utilities self.inputs = dict(default=(self.input, input_vocab)) 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). input_keys: list of strings, optional List of keys (ordered) from the input vocabulary to use as the input semantic pointers for the associative memory. output_keys: list of strings, optional List of keys (ordered) from the output vocabulary to use as the output semantic pointers for the associative 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. inhibitable: boolean, optional Flag to indicate if the entire associative memory module is inhibitable (entire thing can be shut off). 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. cleanup_output: boolean, optional Create the associative memory with cleaned outputs as well as the standard outputs. replace_output_with_cleaned_output: boolean, optional Set to true to use the cleaned outputs as the default output of the associative memory module. label : str, optional A name to assign this AssociativeMemory. Used for visualization and debugging. Also used as a label prefix for each of the internal ensembles in the AssociativeMemory network. Additional network parameters are passed to the Network constructor through **module_kwargs """ def __init__(self, input_vocab, output_vocab=None, # noqa: C901 input_keys=None, output_keys=None, default_output_key=None, threshold=0.3, inhibitable=False, wta_output=False, wta_inhibit_scale=3.0, wta_synapse=0.005, cleanup_output=False, replace_output_with_cleaned_output=True, label=None, **module_kwargs): super(AssociativeMemory, self).__init__(label=label, **module_kwargs) if input_keys is None: input_keys = input_vocab.keys input_vectors = input_vocab.vectors else: input_vectors = input_vocab.create_subset(input_keys).vectors # If output vocabulary is not specified, use input vocabulary # (i.e autoassociative memory) if output_vocab is None: output_vocab = input_vocab output_vectors = input_vectors else: if output_keys is None: output_keys = input_keys output_vectors = output_vocab.create_subset(output_keys).vectors if default_output_key is None: default_output_vector = None else: default_output_vector = output_vocab.parse(default_output_key).v # Create nengo network with self: self.am = AssocMem(input_vectors=input_vectors, output_vectors=output_vectors, threshold=threshold, inhibitable=inhibitable, label=label, **module_kwargs) if default_output_vector is not None: self.am.add_default_output_vector(default_output_vector) if wta_output: self.am.add_wta_network(wta_inhibit_scale, wta_synapse) if cleanup_output: self.am.add_cleanup_output( replace_output=replace_output_with_cleaned_output) self.input = self.am.input self.output = self.am.output if cleanup_output and not replace_output_with_cleaned_output: self.cleaned_output = self.am.cleaned_output if inhibitable: self.inhibit = self.am.inhibit self.utilities = self.am.output_utilities if cleanup_output: self.cleaned_utilities = self.am.cleaned_output_utilities self.inputs = dict(default=(self.input, input_vocab)) self.outputs = dict(default=(self.output, output_vocab))
class AssociativeMemory(Module): """Associative memory module. See :doc:`examples/associative_memory` for an introduction and examples. Parameters ---------- input_vocab: list or Vocabulary The vocabulary (or list of vectors) to match. output_vocab: list or Vocabulary, optional (Default: None) The vocabulary (or list of vectors) to be produced for each match. If None, the associative memory will act like an autoassociative memory (cleanup memory). input_keys : list, optional (Default: None) A list of strings that correspond to the input vectors. output_keys : list, optional (Default: None) A list of strings that correspond to the output vectors. default_output_key: str, optional (Default: None) The semantic pointer string to be produced if the input value matches none of vectors in the input vector list. threshold: float, optional (Default: 0.3) The association activation threshold. inhibitable: bool, optional (Default: False) Flag to indicate if the entire associative memory module is inhibitable (i.e., the entire module can be inhibited). wta_output: bool, optional (Default: False) Flag to indicate if output of the associative memory should contain more than one vector. If True, only one vector's output will be produced; i.e. produce a winner-take-all (WTA) output. If False, combinations of vectors will be produced. wta_inhibit_scale: float, optional (Default: 3.0) Scaling factor on the winner-take-all (WTA) inhibitory connections. wta_synapse: float, optional (Default: 0.005) Synapse to use for the winner-take-all (wta) inhibitory connections. threshold_output: bool, optional (Default: False) Adds a threholded output if True. label : str, optional (Default: None) A name for the ensemble. Used for debugging and visualization. seed : int, optional (Default: None) The seed used for random number generation. add_to_container : bool, optional (Default: None) Determines if this Network will be added to the current container. If None, will be true if currently within a Network. """ def __init__(self, input_vocab, output_vocab=None, # noqa: C901 input_keys=None, output_keys=None, default_output_key=None, threshold=0.3, inhibitable=False, wta_output=False, wta_inhibit_scale=3.0, wta_synapse=0.005, threshold_output=False, label=None, seed=None, add_to_container=None): super(AssociativeMemory, self).__init__(label, seed, add_to_container) if input_keys is None: input_keys = input_vocab.keys input_vectors = input_vocab.vectors else: input_vectors = input_vocab.create_subset(input_keys).vectors # If output vocabulary is not specified, use input vocabulary # (i.e autoassociative memory) if output_vocab is None: output_vocab = input_vocab output_vectors = input_vectors else: if output_keys is None: output_keys = input_keys output_vectors = output_vocab.create_subset(output_keys).vectors if default_output_key is None: default_output_vector = None else: default_output_vector = output_vocab.parse(default_output_key).v # Create nengo network with self: self.am = AssocMem(input_vectors=input_vectors, output_vectors=output_vectors, threshold=threshold, inhibitable=inhibitable, label=label, seed=seed, add_to_container=add_to_container) if default_output_vector is not None: self.am.add_default_output_vector(default_output_vector) if wta_output: self.am.add_wta_network(wta_inhibit_scale, wta_synapse) if threshold_output: self.am.add_threshold_to_outputs() self.input = self.am.input self.output = self.am.output if inhibitable: self.inhibit = self.am.inhibit self.utilities = self.am.utilities if threshold_output: self.thresholded_utilities = self.am.thresholded_utilities self.inputs = dict(default=(self.input, input_vocab)) 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 input_keys=None, output_keys=None, default_output_key=None, threshold=0.3, inhibitable=False, wta_output=False, wta_inhibit_scale=3.0, wta_synapse=0.005, threshold_output=False, label=None, seed=None, add_to_container=None): super(AssociativeMemory, self).__init__(label, seed, add_to_container) if input_keys is None: input_keys = input_vocab.keys input_vectors = input_vocab.vectors else: input_vectors = input_vocab.create_subset(input_keys).vectors # If output vocabulary is not specified, use input vocabulary # (i.e autoassociative memory) if output_vocab is None: output_vocab = input_vocab output_vectors = input_vectors else: if output_keys is None: output_keys = input_keys output_vectors = output_vocab.create_subset(output_keys).vectors if default_output_key is None: default_output_vector = None else: default_output_vector = output_vocab.parse(default_output_key).v # Create nengo network with self: self.am = AssocMem(input_vectors=input_vectors, output_vectors=output_vectors, threshold=threshold, inhibitable=inhibitable, label=label, seed=seed, add_to_container=add_to_container) if default_output_vector is not None: self.am.add_default_output_vector(default_output_vector) if wta_output: self.am.add_wta_network(wta_inhibit_scale, wta_synapse) if threshold_output: self.am.add_threshold_to_outputs() self.input = self.am.input self.output = self.am.output if inhibitable: self.inhibit = self.am.inhibit self.utilities = self.am.utilities if threshold_output: self.thresholded_utilities = self.am.thresholded_utilities self.inputs = dict(default=(self.input, input_vocab)) 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). input_keys: list of strings, optional List of keys (ordered) from the input vocabulary to use as the input semantic pointers for the associative memory. output_keys: list of strings, optional List of keys (ordered) from the output vocabulary to use as the output semantic pointers for the associative 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. inhibitable: boolean, optional Flag to indicate if the entire associative memory module is inhibitable (entire thing can be shut off). 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. cleanup_output: boolean, optional Create the associative memory with cleaned outputs as well as the standard outputs. replace_output_with_cleaned_output: boolean, optional Set to true to use the cleaned outputs as the default output of the associative memory module. label : str, optional A name to assign this AssociativeMemory. Used for visualization and debugging. Also used as a label prefix for each of the internal ensembles in the AssociativeMemory network. Additional network parameters are passed to the Network constructor through **module_kwargs """ def __init__( self, input_vocab, output_vocab=None, # noqa: C901 input_keys=None, output_keys=None, default_output_key=None, threshold=0.3, inhibitable=False, wta_output=False, wta_inhibit_scale=3.0, wta_synapse=0.005, cleanup_output=False, replace_output_with_cleaned_output=True, label=None, **module_kwargs): super(AssociativeMemory, self).__init__(label=label, **module_kwargs) if input_keys is None: input_keys = input_vocab.keys input_vectors = input_vocab.vectors else: input_vectors = input_vocab.create_subset(input_keys).vectors # If output vocabulary is not specified, use input vocabulary # (i.e autoassociative memory) if output_vocab is None: output_vocab = input_vocab output_vectors = input_vectors else: if output_keys is None: output_keys = input_keys output_vectors = output_vocab.create_subset(output_keys).vectors if default_output_key is None: default_output_vector = None else: default_output_vector = output_vocab.parse(default_output_key).v # Create nengo network with self: self.am = AssocMem(input_vectors=input_vectors, output_vectors=output_vectors, threshold=threshold, inhibitable=inhibitable, label=label, **module_kwargs) if default_output_vector is not None: self.am.add_default_output_vector(default_output_vector) if wta_output: self.am.add_wta_network(wta_inhibit_scale, wta_synapse) if cleanup_output: self.am.add_cleanup_output( replace_output=replace_output_with_cleaned_output) self.input = self.am.input self.output = self.am.output if cleanup_output and not replace_output_with_cleaned_output: self.cleaned_output = self.am.cleaned_output if inhibitable: self.inhibit = self.am.inhibit self.utilities = self.am.output_utilities if cleanup_output: self.cleaned_utilities = self.am.cleaned_output_utilities self.inputs = dict(default=(self.input, input_vocab)) self.outputs = dict(default=(self.output, output_vocab))