Package topo :: Package learningfn :: Module projfn
[hide private]
[frames] | no frames]

Source Code for Module topo.learningfn.projfn

  1  """ 
  2  Learning functions for Projections. 
  3   
  4   
  5  For example, CFProjectionLearningFunctions compute a new set of 
  6  ConnectionFields when given an input and output pattern and a set of 
  7  ConnectionField objects. 
  8   
  9  $Id: projfn.py 11316 2010-07-27 17:52:53Z ceball $ 
 10  """ 
 11  __version__ = "$Revision: 11316 $" 
 12   
 13  from numpy import ones,zeros 
 14  import numpy.oldnumeric as Numeric 
 15  from numpy.oldnumeric import Float 
 16   
 17  import param 
 18   
 19  from topo.base.cf import CFPLearningFn 
 20  from topo.base.sheet import activity_type 
 21  from topo.base.functionfamily import Hebbian,LearningFn 
 22  # Imported here so that all ProjectionLearningFns will be in the same package 
 23  from topo.base.cf import CFPLF_Identity,CFPLF_Plugin 
 24   
 25  from basic import BCMFixed 
 26   
 27   
28 -class CFPLF_EuclideanHebbian(CFPLearningFn):
29 """ 30 Hebbian CFProjection learning rule based on Euclidean distance. 31 32 Learning is driven by the distance from the input pattern to the 33 weights, scaled by the current activity. To implement a Kohonen 34 SOM algorithm, the activity should be the neighborhood kernel 35 centered around the winning unit, as implemented by KernelMax. 36 """ 37 # CEBERRORALERT: ignoring the sheet mask
38 - def __call__(self, iterator, input_activity, output_activity, learning_rate, **params):
39 # This learning function does not need to scale the learning 40 # rate like some do, so it does not use constant_sum_connection_rate() 41 42 cfs = iterator.flatcfs 43 rows,cols = output_activity.shape 44 for r in xrange(rows): 45 for c in xrange(cols): 46 flati = r*cols+c 47 out = output_activity.flat[flati] 48 if out !=0: 49 rate = learning_rate * out 50 cf = cfs[flati] 51 X = cf.get_input_matrix(input_activity) 52 cf.weights += rate * (X - cf.weights) 53 54 # CEBHACKALERT: see ConnectionField.__init__() 55 cf.weights *= cf.mask
56 57 58 59 #### JABHACKALERT: Untested 60 ##class CFPLF_BCM(CFPLearningFn): 61 ## """ 62 ## Bienenstock, Cooper, and Munro (1982) learning rule with sliding threshold. 63 ## 64 ## (See Dayan and Abbott, 2001, equation 8.12, 8.13). 65 ## 66 ## Activities change only when there is both pre- and post-synaptic activity. 67 ## Threshold is adjusted based on recent firing rates. 68 ## """ 69 ## single_cf_fn = param.ClassSelector(LearningFn,default=BCMFixed()) 70 ## 71 ## unit_threshold_0=param.Number(default=0.5,bounds=(0,None), 72 ## doc="Initial value of threshold between LTD and LTP; actual value computed based on recent history.") 73 ## unit_threshold_learning_rate=param.Number(default=0.1,bounds=(0,None), 74 ## doc="Amount by which the unit_threshold is adjusted for each activity calculation.") 75 ## 76 ## def __call__(self, iterator, input_activity, output_activity, learning_rate, **params): 77 ## cfs = iterator.proj._cfs 78 ## # Initialize thresholds the first time we learn the size of the output_activity. 79 ## if not hasattr(self,'unit_thresholds'): 80 ## self.unit_thresholds=ones(output_activity.shape,Float32)*self.unit_threshold_0 81 ## 82 ## rows,cols = output_activity.shape 83 ## 84 ## # JABALERT: Is this correct? 85 ## single_connection_learning_rate = self.constant_sum_connection_rate(iterator.proj_n_units,learning_rate) 86 ## 87 ## # avoid evaluating these references each time in the loop 88 ## single_cf_fn = self.single_cf_fn 89 ## for r in xrange(rows): 90 ## for c in xrange(cols): 91 ## cf = cfs[r][c] 92 ## input_act = cf.get_input_matrix(input_activity) 93 ## unit_activity = output_activity[r,c] 94 ## threshold=self.unit_thresholds[r,c] 95 ## #print cf.weights, type(cf.weights) 96 ## #print input_act, type(input_act) 97 ## #print single_connection_learning_rate,unit_activity,threshold, (unit_activity-threshold) 98 ## cf.weights += (single_connection_learning_rate * unit_activity * (unit_activity-threshold)) * input_act 99 ## self.unit_thresholds[r,c] += self.unit_threshold_learning_rate*(unit_activity*unit_activity-threshold) 100 ## 101 ## # CEBHACKALERT: see ConnectionField.__init__() 102 ## cf.weights *= cf.mask 103 104 105
106 -class CFPLF_Trace(CFPLearningFn):
107 """ 108 LearningFn that incorporates a trace of recent activity, 109 not just the current activity. 110 111 Based on P. Foldiak (1991), "Learning Invariance from 112 Transformation Sequences", Neural Computation 3:194-200. Also see 113 Sutton and Barto (1981) and Wallis and Rolls (1997). 114 115 Incorporates a decay term to keep the weight vector bounded, and 116 so it does not normally require any output_fn normalization for 117 stability. 118 119 NOT YET TESTED. 120 """ 121 122 trace_strength=param.Number(default=0.5,bounds=(0.0,1.0), 123 doc="How much the learning is dominated by the activity trace, relative to the current value.") 124 125 single_cf_fn = param.ClassSelector(LearningFn,default=Hebbian(), 126 doc="LearningFn that will be applied to each CF individually.") 127
128 - def __call__(self, iterator, input_activity, output_activity, learning_rate, **params):
129 single_connection_learning_rate = self.constant_sum_connection_rate(iterator.proj_n_units,learning_rate) 130 single_cf_fn = self.single_cf_fn 131 ##Initialise traces to zero if they don't already exist 132 if not hasattr(self,'traces'): 133 self.traces=zeros(output_activity.shape,activity_type) 134 for cf,i in iterator(): 135 unit_activity = output_activity.flat[i] 136 # print "unit activity is",unit_activity 137 # print "self trace is",self.traces[r,c] 138 new_trace = (self.trace_strength*unit_activity)+((1-self.trace_strength)*self.traces.flat[i]) 139 # print "and is now",new_trace 140 self.traces.flat[i] = new_trace 141 cf.weights += single_connection_learning_rate * new_trace * \ 142 (cf.get_input_matrix(input_activity) - cf.weights) 143 144 #CEBHACKALERT: see ConnectionField.__init__() 145 cf.weights *= cf.mask
146 147 148
149 -class CFPLF_OutstarHebbian(CFPLearningFn):
150 """ 151 CFPLearningFunction applying the specified (default is Hebbian) 152 single_cf_fn to each CF, where normalization is done in an outstar-manner. 153 154 Presumably does not need a separate output_fn for normalization. 155 156 NOT YET TESTED. 157 """ 158 single_cf_fn = param.ClassSelector(LearningFn,default=Hebbian(), 159 doc="LearningFn that will be applied to each CF individually.") 160 161 outstar_wsum = None 162
163 - def __call__(self, iterator, input_activity, output_activity, learning_rate, **params):
164 single_connection_learning_rate = self.constant_sum_connection_rate(iterator.proj_n_units,learning_rate) 165 # avoid evaluating these references each time in the loop 166 single_cf_fn = self.single_cf_fn 167 outstar_wsum = zeros(input_activity.shape) 168 for cf,i in iterator(): 169 single_cf_fn(cf.get_input_matrix(input_activity), 170 output_activity.flat[i], cf.weights, single_connection_learning_rate) 171 # Outstar normalization 172 wrows,wcols = cf.weights.shape 173 for wr in xrange(wrows): 174 for wc in xrange(wcols): 175 outstar_wsum[wr][wc] += cf.weights[wr][wc] 176 177 # CEBHACKALERT: see ConnectionField.__init__() 178 cf.weights *= cf.mask
179 180 181 182
183 -class HomeoSynaptic(CFPLearningFn):
184 """ 185 Learning function using homeostatic synaptic scaling from 186 Sullivan & de Sa, "Homeostatic Synaptic Scaling in Self-Organizing Maps", 187 Neural Networks (2006), 19(6-7):734-43. 188 189 Does not necessarily require output_fn normalization for stability. 190 """ 191 single_cf_fn = param.ClassSelector(LearningFn,default=Hebbian(), 192 doc="LearningFn that will be applied to each CF individually") 193 194 beta_n = param.Number(default=0.01,bounds=(0,None), 195 doc="homeostatic learning rate") 196 197 beta_c = param.Number(default=0.005,bounds=(0,None), 198 doc="time window over which the neuron's firing rate is averaged") 199 200 activity_target = param.Number(default=0.1,bounds=(0,None), 201 doc="Target average activity") 202 203 #debug = param.Boolean(default=False,doc="Print average activity values") 204 #beta_n = param.Number(default=0.00033,bounds=(0,None),doc="Homeostatic learning rate") #Too small? 205 #beta_c = param.Number(default=0.000033,bounds=(0,None),doc="Time window over which the neuron's firing rate is averaged") 206
207 - def __init__(self,**params):
208 super(HomeoSynaptic,self).__init__(**params) 209 self.temp_hist = [] 210 self.ave_hist = []
211
212 - def __call__(self, iterator, input_activity, output_activity, learning_rate, **params):
213 """ 214 Update the value of the given weights matrix based on the 215 input_activity matrix (of the same size as the weights matrix) 216 and the response of this unit (the unit_activity), governed by 217 a per-connection learning rate. 218 """ 219 if not hasattr(self,'averages'): 220 self.averages = ones(output_activity.shape,Float) * 0.1 221 222 223 # normalize initial weights to 1.0 224 for cf,i in iterator(): 225 current_norm_value = 1.0*Numeric.sum(abs(cf.weights.ravel())) 226 if current_norm_value != 0: 227 factor = (1.0/current_norm_value) 228 cf.weights *= factor 229 230 # compute recent average of output activity 231 self.averages = self.beta_c * output_activity + (1.0-self.beta_c) * self.averages 232 activity_norm = 1.0 + self.beta_n * \ 233 ((self.averages - self.activity_target)/self.activity_target) 234 235 single_connection_learning_rate = self.constant_sum_connection_rate(iterator.proj_n_units,learning_rate) 236 237 # avoid evaluating these references each time in the loop 238 single_cf_fn = self.single_cf_fn 239 for cf,i in iterator(): 240 single_cf_fn(cf.get_input_matrix(input_activity), 241 output_activity.flat[i], cf.weights, single_connection_learning_rate) 242 243 # homeostatic normalization 244 cf.weights /= activity_norm.flat[i] 245 246 # CEBHACKALERT: see ConnectionField.__init__() 247 cf.weights *= cf.mask 248 249 # For analysis only; can be removed (in which case also remove the initializations above) 250 # CEBALERT: I changed [0][7] to [0]! 251 self.ave_hist.append(self.averages.flat[0]) 252 self.temp_hist.append (Numeric.sum(abs(iterator.flatcfs[0].weights.ravel())))
253 254 255 256
257 -class CFPLF_PluginScaled(CFPLearningFn):
258 """ 259 CFPLearningFunction applying the specified single_cf_fn to each CF. 260 Scales the single-connection learning rate by a scaling factor 261 that is different for each individual unit. Thus each individual 262 connection field uses a different learning rate. 263 """ 264 265 single_cf_fn = param.ClassSelector(LearningFn,default=Hebbian(), 266 doc="Accepts a LearningFn that will be applied to each CF individually.") 267 268 learning_rate_scaling_factor = param.Parameter(default=None, 269 doc="Matrix of scaling factors for scaling the learning rate of each CF individually.") 270 271
272 - def __call__(self, iterator, input_activity, output_activity, learning_rate, **params):
273 """Apply the specified single_cf_fn to every CF.""" 274 275 if self.learning_rate_scaling_factor is None: 276 self.learning_rate_scaling_factor = ones(output_activity.shape) 277 278 single_cf_fn = self.single_cf_fn 279 single_connection_learning_rate = self.constant_sum_connection_rate(iterator.proj_n_units,learning_rate) 280 281 for cf,i in iterator(): 282 sc_learning_rate = self.learning_rate_scaling_factor.flat[i] * single_connection_learning_rate 283 single_cf_fn(cf.get_input_matrix(input_activity), 284 output_activity.flat[i], cf.weights, sc_learning_rate) 285 # CEBHACKALERT: see ConnectionField.__init__() re. mask & output fn 286 cf.weights *= cf.mask
287 288
289 - def update_scaling_factor(self, new_scaling_factor):
290 """Update the single-connection learning rate scaling factor.""" 291 self.learning_rate_scaling_factor = new_scaling_factor
292