Package topo :: Package sheets :: Module lissom
[hide private]
[frames] | no frames]

Source Code for Module topo.sheets.lissom

  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   
25 -class JointNormalizingCFSheet(CFSheet):
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 # JABALERT: Should check that whenever a connection is added to a 56 # group, it has the same no of cfs as the existing connections. 57
58 - def start(self):
59 self._normalize_weights()
60 61
62 - def compute_joint_norm_totals(self,projlist,mask):
63 """ 64 Compute norm_total for each CF in each projection from a group to be normalized jointly. 65 """ 66 67 # Assumes that all Projections in the list have the same r,c size 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
81 - def _normalize_weights(self,mask = None):
82 """ 83 Apply the weights_output_fn for every group of Projections. 84 85 The mask is telling which neurons need to be normalized. 86 """ 87 88 if(mask == None): 89 mask = Numeric.ones(self.shape,activity_type) 90 91 for key,projlist in self._grouped_in_projections('JointNormalize'): 92 if key == None: 93 normtype='Independent' 94 else: 95 normtype='Joint' 96 self.compute_joint_norm_totals(projlist,mask) 97 98 self.debug(normtype + "ly normalizing:") 99 100 for p in projlist: 101 p.apply_learn_output_fn(mask) 102 self.debug(' ',p.name)
103 104
105 - def learn(self):
106 """ 107 Call the learn() method on every Projection to the Sheet, and 108 call the output functions (jointly if necessary). 109 """ 110 # Ask all projections to learn independently 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 # Apply output function in groups determined by dest_port 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
163 - def __init__(self,**params):
164 super(LISSOM,self).__init__(**params) 165 self.__counter_stack=[] 166 self.activation_count = 0 167 self.new_iteration = True
168 169
170 - def start(self):
171 self._normalize_weights() 172 if self.post_initialization_weights_output_fn is not None: 173 for proj in self.in_connections: 174 if not isinstance(proj,Projection): 175 self.debug("Skipping non-Projection ") 176 else: 177 proj.weights_output_fn=self.post_initialization_weights_output_fn
178 179
180 - def input_event(self,conn,data):
181 # On a new afferent input, clear the activity 182 if self.new_iteration: 183 self.new_iteration = False 184 self.activity *= 0.0 185 for proj in self.in_connections: 186 proj.activity *= 0.0 187 self.mask.reset() 188 super(LISSOM,self).input_event(conn,data)
189 190 191 ### JABALERT! There should be some sort of warning when 192 ### tsettle times the input delay is larger than the input period. 193 ### Right now it seems to do strange things in that case (does it 194 ### settle at all after the first iteration?), but of course that 195 ### is arguably an error condition anyway (and should thus be 196 ### flagged).
197 - def process_current_time(self):
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 # Special case: behave just like a CFSheet 210 self.activate() 211 self.learn() 212 213 elif self.activation_count == self.tsettle: 214 # Once we have been activated the required number of times 215 # (determined by tsettle), reset various counters, learn 216 # if appropriate, and avoid further activation until an 217 # external event arrives. 218 self.activation_count = 0 219 self.new_iteration = True # used by input_event when it is called 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 # print the weights of a unit
230 - def printwts(self,x,y):
231 for proj in self.in_connections: 232 print proj.name, x, y 233 print proj.cf(x,y).weights
234 235
236 - def state_push(self,**args):
237 super(LISSOM,self).state_push(**args) 238 self.__counter_stack.