1 """
2 LISSOM and related sheet classes.
3
4 $Id: lissom.py 8001 2008-02-18 15:15:10Z ceball $
5 """
6 __version__='$Revision: 8001 $'
7
8 import numpy.oldnumeric as Numeric
9 import numpy
10 from numpy import abs,zeros,ones
11 import topo
12
13 from topo.base.functionfamilies import OutputFn
14 from topo.base.cf import CFSheet, CFPOutputFn
15 from topo.base.parameterclasses import BooleanParameter, Number, Integer,\
16 ListParameter,ClassSelectorParameter
17 from topo.base.projection import Projection
18 from topo.base.parameterizedobject import ParameterizedObject
19 from topo.base.sheet import activity_type
20 from topo.misc.inlinec import optimized
21 from topo.misc.keyedlist import KeyedList
22 from topo.outputfns.basic import PiecewiseLinear
23
24
26 """
27 A type of CFSheet extended to support joint sum-based normalization.
28
29 For L1 normalization, joint normalization means normalizing the
30 sum of (the absolute values of) all weights in a set of
31 corresponding CFs in different Projections, rather than only
32 considering weights in the same CF.
33
34 This class makes it possible for a model to use joint
35 normalization, by providing a mechanism for grouping Projections
36 (see _port_match), plus a learn() function that computes the joint
37 sums. Joint normalization also requires having ConnectionField
38 store and return a norm_total for each neuron, and having an
39 OutputFn that will respect this norm_total rather than the strict
40 total of the ConnectionField's weights. At present,
41 CFPOF_DivisiveNormalizeL1 and CFPOF_DivisiveNormalizeL1_opt do use
42 norm_total; others can be extended to do something similar if
43 necessary.
44
45 To enable joint normalization, you can declare that all the
46 incoming connections that should be normalized together each
47 have a dest_port of:
48
49 dest_port=('Activity','JointNormalize', 'AfferentGroup1'),
50
51 Then all those that have this dest_port will be normalized
52 together, as long as an appropriate OutputFn is being used.
53 """
54
55
56
57
60
61
63 """
64 Compute norm_total for each CF in each projection from a group to be normalized jointly.
65 """
66
67
68 assert len(projlist)>=1
69 proj = projlist[0]
70 rows,cols = proj.cfs_shape
71
72 for r in range(rows):
73 for c in range(cols):
74 if(mask[r,c] != 0):
75 sums = [p.cf(r,c).norm_total for p in projlist]
76 joint_sum = Numeric.add.reduce(sums)
77 for p in projlist:
78 p.cf(r,c).norm_total=joint_sum
79
80
103
104
106 """
107 Call the learn() method on every Projection to the Sheet, and
108 call the output functions (jointly if necessary).
109 """
110
111 for proj in self.in_connections:
112 if not isinstance(proj,Projection):
113 self.debug("Skipping non-Projection "+proj.name)
114 else:
115 proj.learn()
116
117
118 self._normalize_weights(self.activity)
119
120
121
122 -class LISSOM(JointNormalizingCFSheet):
123 """
124 A Sheet class implementing the LISSOM algorithm
125 (Sirosh and Miikkulainen, Biological Cybernetics 71:66-78, 1994).
126
127 A LISSOM sheet is a JointNormalizingCFSheet slightly modified to
128 enforce a fixed number of settling steps. Settling is controlled
129 by the tsettle parameter; once that number of settling steps has
130 been reached, an external input is required before the sheet will
131 activate again.
132 """
133
134 mask_init_time=Integer(default=5,bounds=(0,None),doc="""
135 Determines when a new mask is initialized in each new iteration.
136
137 The mask is reset whenever new input comes in. Once the
138 activation_count (see tsettle) reaches mask_init_time, the mask
139 is initialized to reflect the current activity profile.""")
140
141 tsettle=Integer(default=8,bounds=(0,None),doc="""
142 Number of times to activate the LISSOM sheet for each external input event.
143
144 A counter is incremented each time an input is received from any
145 source, and once the counter reaches tsettle, the last activation
146 step is skipped so that there will not be any further recurrent
147 activation. The next external (i.e., afferent or feedback)
148 event will then start the counter over again.""")
149
150 continuous_learning = BooleanParameter(default=False, doc="""
151 Whether to modify the weights after every settling step.
152 If false, waits until settling is completed before doing learning.""")
153
154 output_fn = ClassSelectorParameter(OutputFn,default=PiecewiseLinear(lower_bound=0.1,upper_bound=0.65))
155
156 precedence = Number(0.6)
157
158 post_initialization_weights_output_fn = ClassSelectorParameter(
159 CFPOutputFn,default=None,doc="""
160 Weights output_fn which can be set after an initial normalization step""")
161
162
164 super(LISSOM,self).__init__(**params)
165 self.__counter_stack=[]
166 self.activation_count = 0
167 self.new_iteration = True
168
169
178
179
189
190
191
192
193
194
195
196
198 """
199 Pass the accumulated stimulation through self.output_fn and
200 send it out on the default output port.
201 """
202 if self.new_input:
203 self.new_input = False
204
205 if self.activation_count == self.mask_init_time:
206 self.mask.calculate()
207
208 if self.tsettle == 0:
209
210 self.activate()
211 self.learn()
212
213 elif self.activation_count == self.tsettle:
214
215
216
217
218 self.activation_count = 0
219 self.new_iteration = True
220 if (self.plastic and not self.continuous_learning):
221 self.learn()
222 else:
223 self.activate()
224 self.activation_count += 1
225 if (self.plastic and self.continuous_learning):
226 self.learn()
227
228
229
231 for proj in self.in_connections:
232 print proj.name, x, y
233 print proj.cf(x,y).weights
234
235