1 """
2 LISSOM and related sheet classes.
3
4 $Id: lissom.py 11316 2010-07-27 17:52:53Z ceball $
5 """
6 __version__='$Revision: 11316 $'
7
8 from numpy import zeros,ones
9 import copy
10
11 import param
12
13 import topo
14
15 from topo.base.projection import Projection
16 from topo.base.sheet import activity_type
17 from topo.base.simulation import EPConnectionEvent
18 from topo.transferfn.basic import PiecewiseLinear
19 from topo.sheet import JointNormalizingCFSheet
20
21
22 -class LISSOM(JointNormalizingCFSheet):
23 """
24 A Sheet class implementing the LISSOM algorithm
25 (Sirosh and Miikkulainen, Biological Cybernetics 71:66-78, 1994).
26
27 A LISSOM sheet is a JointNormalizingCFSheet slightly modified to
28 enforce a fixed number of settling steps. Settling is controlled
29 by the tsettle parameter; once that number of settling steps has
30 been reached, an external input is required before the sheet will
31 activate again.
32 """
33
34 strict_tsettle = param.Parameter(default = None,doc="""
35 If non-None, delay sending output until activation_count reaches this value.""")
36
37 mask_init_time=param.Integer(default=5,bounds=(0,None),doc="""
38 Determines when a new mask is initialized in each new iteration.
39
40 The mask is reset whenever new input comes in. Once the
41 activation_count (see tsettle) reaches mask_init_time, the mask
42 is initialized to reflect the current activity profile.""")
43
44 tsettle=param.Integer(default=8,bounds=(0,None),doc="""
45 Number of times to activate the LISSOM sheet for each external input event.
46
47 A counter is incremented each time an input is received from any
48 source, and once the counter reaches tsettle, the last activation
49 step is skipped so that there will not be any further recurrent
50 activation. The next external (i.e., afferent or feedback)
51 event will then start the counter over again.""")
52
53 continuous_learning = param.Boolean(default=False, doc="""
54 Whether to modify the weights after every settling step.
55 If false, waits until settling is completed before doing learning.""")
56
57 output_fns = param.HookList(default=[PiecewiseLinear(lower_bound=0.1,upper_bound=0.65)])
58
59 precedence = param.Number(0.6)
60
61 post_initialization_weights_output_fns = param.HookList([],doc="""
62 If not empty, weights output_fns that will replace the
63 existing ones after an initial normalization step.""")
64
65 beginning_of_iteration = param.HookList(default=[],instantiate=False,doc="""
66 List of callables to be executed at the beginning of each iteration.""")
67
68 end_of_iteration = param.HookList(default=[],instantiate=False,doc="""
69 List of callables to be executed at the end of each iteration.""")
70
71
73 super(LISSOM,self).__init__(**params)
74 self.__counter_stack=[]
75 self.activation_count = 0
76 self.new_iteration = True
77
78
87
88
99
100
101
102
103
104
105
106
139
140
141
143 for proj in self.in_connections:
144 print proj.name, x, y
145 print proj.cfs[x,y].weights
146
147
151
152
154 super(LISSOM,self).state_pop(**args)
155 self.activation_count,self.new_iteration=self.__counter_stack.pop()
156
172
173
175 """
176 LISSOM sheet extended to allow joint auto-scaling of Afferent input projections.
177
178 An exponentially weighted average is used to calculate the average
179 joint activity across all jointly-normalized afferent projections.
180 This average is then used to calculate a scaling factor for the
181 current afferent activity and for the afferent learning rate.
182
183 The target average activity for the afferent projections depends
184 on the statistics of the input; if units are activated more often
185 (e.g. the number of Gaussian patterns on the retina during each
186 iteration is increased) the target average activity should be
187 larger in order to maintain a constant average response to similar
188 inputs in V1. The target activity for learning rate scaling does
189 not need to change, because the learning rate should be scaled
190 regardless of what causes the change in average activity.
191 """
192
193
194
195
196
197 target = param.Number(default=0.045, doc="""
198 Target average activity for jointly scaled projections.""")
199
200
201 target_lr = param.Number(default=0.045, doc="""
202 Target average activity for jointly scaled projections.
203
204 Used for calculating a learning rate scaling factor.""")
205
206 smoothing = param.Number(default=0.999, doc="""
207 Influence of previous activity, relative to current, for computing the average.""")
208
209 apply_scaling = param.Boolean(default=True, doc="""Whether to apply the scaling factors.""")
210
211 precedence = param.Number(0.65)
212
213
215 super(JointScaling,self).__init__(**params)
216 self.x_avg=None
217 self.sf=None
218 self.lr_sf=None
219 self.scaled_x_avg=None
220 self.__current_state_stack=[]
221
223 """
224 Calculate current scaling factors based on the target and previous average joint activities.
225
226 Keeps track of the scaled average for debugging. Could be
227 overridden by a subclass to calculate the factors differently.
228 """
229
230 if self.plastic:
231 self.sf *=0.0
232 self.lr_sf *=0.0
233 self.sf += self.target/self.x_avg
234 self.lr_sf += self.target_lr/self.x_avg
235 self.x_avg = (1.0-self.smoothing)*joint_total + self.smoothing*self.x_avg
236 self.scaled_x_avg = (1.0-self.smoothing)*joint_total*self.sf + self.smoothing*self.scaled_x_avg
237
238
240 """
241 Scale jointly normalized projections together.
242
243 Assumes that the projections to be jointly scaled are those
244 that are being jointly normalized. Calculates the joint total
245 of the grouped projections, and uses this to calculate the
246 scaling factor.
247 """
248 joint_total = zeros(self.shape, activity_type)
249
250 for key,projlist in self._grouped_in_projections('JointNormalize'):
251 if key is not None:
252 if key =='Afferent':
253 for proj in projlist:
254 joint_total += proj.activity
255 self.calculate_joint_sf(joint_total)
256 if self.apply_scaling:
257 for proj in projlist:
258 proj.activity *= self.sf
259 if hasattr(proj.learning_fn,'learning_rate_scaling_factor'):
260 proj.learning_fn.update_scaling_factor(self.lr_sf)
261 else:
262 raise ValueError("Projections to be joint scaled must have a learning_fn that supports scaling, such as CFPLF_PluginScaled")
263
264 else:
265 raise ValueError("Only Afferent scaling currently supported")
266
267
269 """
270 Compute appropriate scaling factors, apply them, and collect resulting activity.
271
272 Scaling factors are first computed for each set of jointly
273 normalized projections, and the resulting activity patterns
274 are then scaled. Then the activity is collected from each
275 projection, combined to calculate the activity for this sheet,
276 and the result is sent out.
277 """
278
279 self.activity *= 0.0
280
281 if self.x_avg is None:
282 self.x_avg=self.target*ones(self.shape, activity_type)
283 if self.scaled_x_avg is None:
284 self.scaled_x_avg=self.target*ones(self.shape, activity_type)
285 if self.sf is None:
286 self.sf=ones(self.shape, activity_type)
287 if self.lr_sf is None:
288 self.lr_sf=ones(self.shape, activity_type)
289
290
291
292 if self.activation_count == 0:
293 self.do_joint_scaling()
294
295 for proj in self.in_connections:
296 self.activity += proj.activity
297
298 if self.apply_output_fns:
299 for of in self.output_fns:
300 of(self.activity)
301
302 self.send_output(src_port='Activity',data=self.activity)
303
304
309
310
314
315
316
317 -def schedule_events(sheet_str="topo.sim['V1']",st=0.5,aff_name="Afferent",
318 ids=1.0,ars=1.0,increase_inhibition=False):
319 """
320 Convenience function for scheduling a default set of events
321 typically used with a LISSOM sheet. The parameters used
322 are the defaults from Miikkulainen, Bednar, Choe, and Sirosh
323 (2005), Computational Maps in the Visual Cortex, Springer.
324
325 Note that Miikulainen 2005 specifies only one output_fn for the
326 LISSOM sheet; where these scheduled actions operate on an
327 output_fn, they do so only on the first output_fn in the sheet's
328 list of output_fns.
329
330 Installs afferent learning rate changes for any projection whose
331 name contains the keyword specified by aff_name (typically
332 "Afferent").
333
334 The st argument determines the timescale relative to a
335 20000-iteration simulation, and results in the default
336 10000-iteration simulation for the default st=0.5.
337
338 The ids argument specifies the input density scale, i.e. how much
339 input there is at each iteration, on average, relative to the
340 default. The ars argument specifies how much to scale the
341 afferent learning rate, if necessary.
342
343 If increase_inhibition is true, gradually increases the strength
344 of the inhibitory connection, typically used for natural image
345 simulations.
346 """
347
348
349 topo.sim.startup_commands.append("from topo import sheet")
350
351
352
353 LE=sheet_str+".projections()['LateralExcitatory']"
354
355 topo.sim.schedule_command( 200*st,LE+'.change_bounds(sheet.BoundingBox(radius=0.06250))')
356 topo.sim.schedule_command( 500*st,LE+'.change_bounds(sheet.BoundingBox(radius=0.04375))')
357 topo.sim.schedule_command( 1000*st,LE+'.change_bounds(sheet.BoundingBox(radius=0.03500))')
358 topo.sim.schedule_command( 2000*st,LE+'.change_bounds(sheet.BoundingBox(radius=0.02800))')
359 topo.sim.schedule_command( 3000*st,LE+'.change_bounds(sheet.BoundingBox(radius=0.02240))')
360 topo.sim.schedule_command( 4000*st,LE+'.change_bounds(sheet.BoundingBox(radius=0.01344))')
361 topo.sim.schedule_command( 5000*st,LE+'.change_bounds(sheet.BoundingBox(radius=0.00806))')
362 topo.sim.schedule_command( 6500*st,LE+'.change_bounds(sheet.BoundingBox(radius=0.00484))')
363 topo.sim.schedule_command( 8000*st,LE+'.change_bounds(sheet.BoundingBox(radius=0.00290))')
364 topo.sim.schedule_command(20000*st,LE+'.change_bounds(sheet.BoundingBox(radius=0.00174))')
365
366
367 idss=("" if ids==1 else "/%3.1f"%ids)
368 estr='%s.learning_rate=%%s%s*%s.n_units'%(LE,idss,LE)
369
370 topo.sim.schedule_command( 200*st,estr%'0.12168')
371 topo.sim.schedule_command( 500*st,estr%'0.06084')
372 topo.sim.schedule_command( 1000*st,estr%'0.06084')
373 topo.sim.schedule_command( 2000*st,estr%'0.06084')
374 topo.sim.schedule_command( 3000*st,estr%'0.06084')
375 topo.sim.schedule_command( 4000*st,estr%'0.06084')
376 topo.sim.schedule_command( 5000*st,estr%'0.06084')
377 topo.sim.schedule_command( 6500*st,estr%'0.06084')
378 topo.sim.schedule_command( 8000*st,estr%'0.06084')
379 topo.sim.schedule_command(20000*st,estr%'0.06084')
380
381
382 if increase_inhibition:
383 LI=sheet_str+".projections()['LateralInhibitory']"
384 istr='%s.learning_rate=%%s%s'%(LI,idss)
385
386 topo.sim.schedule_command( 1000*st,istr%'1.80873/5.0*2.0')
387 topo.sim.schedule_command( 2000*st,istr%'1.80873/5.0*3.0')
388 topo.sim.schedule_command( 5000*st,istr%'1.80873/5.0*5.0')
389
390 topo.sim.schedule_command( 1000*st,LI+'.strength=-2.2')
391 topo.sim.schedule_command( 2000*st,LI+'.strength=-2.6')
392
393
394
395 sheet_=eval(sheet_str)
396 projs = [pn for pn in sheet_.projections().keys() if pn.count(aff_name)]
397 num_aff=len(projs)
398 arss="" if ars==1.0 else "*%3.1f"%ars
399 for pn in projs:
400 ps="%s.projections()['%s'].learning_rate=%%s%s%s" % \
401 (sheet_str,pn,idss if num_aff==1 else "%s/%d"%(idss,num_aff),arss)
402 topo.sim.schedule_command( 500*st,ps%('0.6850'))
403 topo.sim.schedule_command( 2000*st,ps%('0.5480'))
404 topo.sim.schedule_command( 4000*st,ps%('0.4110'))
405 topo.sim.schedule_command(20000*st,ps%('0.2055'))
406
407
408 bstr = sheet_str+'.output_fns[0].lower_bound=%5.3f;'+\
409 sheet_str+'.output_fns[0].upper_bound=%5.3f'
410 lbi=sheet_.output_fns[0].lower_bound
411 ubi=sheet_.output_fns[0].upper_bound
412
413 topo.sim.schedule_command( 200*st,bstr%(lbi+0.01,ubi+0.01))
414 topo.sim.schedule_command( 500*st,bstr%(lbi+0.02,ubi+0.02))
415 topo.sim.schedule_command( 1000*st,bstr%(lbi+0.05,ubi+0.03))
416 topo.sim.schedule_command( 2000*st,bstr%(lbi+0.08,ubi+0.05))
417 topo.sim.schedule_command( 3000*st,bstr%(lbi+0.10,ubi+0.08))
418 topo.sim.schedule_command( 4000*st,bstr%(lbi+0.10,ubi+0.11))
419 topo.sim.schedule_command( 5000*st,bstr%(lbi+0.11,ubi+0.14))
420 topo.sim.schedule_command( 6500*st,bstr%(lbi+0.12,ubi+0.17))
421 topo.sim.schedule_command( 8000*st,bstr%(lbi+0.13,ubi+0.20))
422 topo.sim.schedule_command(20000*st,bstr%(lbi+0.14,ubi+0.23))
423
424
425 topo.sim.schedule_command(12000*st,'pass')
426 topo.sim.schedule_command(16000*st,'pass')
427
428
429 topo.sim.schedule_command( 2000*st,sheet_str+'.tsettle=10')
430 topo.sim.schedule_command( 5000*st,sheet_str+'.tsettle=11')
431 topo.sim.schedule_command( 6500*st,sheet_str+'.tsettle=12')
432 topo.sim.schedule_command( 8000*st,sheet_str+'.tsettle=13')
433