/
state.py
122 lines (108 loc) · 4.62 KB
/
state.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import nengo
from nengo.exceptions import ValidationError
from nengo.networks.ensemblearray import EnsembleArray
from nengo.params import BoolParam, Default, IntParam, NumberParam
from nengo_spa.network import Network
from nengo_spa.networks import IdentityEnsembleArray
from nengo_spa.vocabulary import VocabularyOrDimParam
class State(Network):
"""
Represents a single vector, with optional memory.
This is a minimal SPA network, useful for passing data along (for example,
visual input).
Parameters
----------
vocab : Vocabulary or int
The vocabulary to use to interpret the vector. If an integer is given,
the default vocabulary of that dimensionality will be used.
subdimensions : int, optional (Default: 16)
The dimension of the individual ensembles making up the vector.
Must divide *dimensions* evenly. The number of sub-ensembles
will be ``dimensions // subdimensions``.
neurons_per_dimension : int, optional (Default: 50)
Number of neurons per dimension. Each ensemble will have
``neurons_per_dimension * subdimensions`` neurons, for a total of
``neurons_per_dimension * dimensions`` neurons.
feedback : float, optional (Default: 0.0)
Gain of feedback connection. Set to 1.0 for perfect memory,
or 0.0 for no memory. Values in between will create a decaying memory.
represent_cc_identity : bool, optional
Whether to use optimizations to better represent the circular
convolution identity vector. If activated, the `.IdentityEnsembleArray`
will be used internally, otherwise a normal
`nengo.networks.EnsembleArray` split up regularly according to
*subdimensions*.
feedback_synapse : float, optional (Default: 0.1)
The synapse on the feedback connection.
**kwargs : dict
Keyword arguments passed through to `nengo_spa.Network`.
Attributes
----------
input : nengo.Node
Input.
output : nengo.Node
Output.
"""
vocab = VocabularyOrDimParam("vocab", default=None, readonly=True)
subdimensions = IntParam("subdimensions", default=16, low=1, readonly=True)
neurons_per_dimension = IntParam(
"neurons_per_dimension", default=50, low=1, readonly=True
)
feedback = NumberParam("feedback", default=0.0, readonly=True)
feedback_synapse = NumberParam("feedback_synapse", default=0.1, readonly=True)
represent_cc_identity = BoolParam(
"represent_cc_identity", default=True, readonly=True
)
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(
f"Dimensions ({dimensions}) must be divisible by "
f"subdimensions ({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)