Package topo :: Package transferfn :: Module misc
[hide private]
[frames] | no frames]

Source Code for Module topo.transferfn.misc

  1  """ 
  2  Transfer functions with more complex dependencies. 
  3   
  4  $Id: basic.py 10790 2009-11-21 17:51:33Z antolikjan $ 
  5  """ 
  6  __version__='$Revision: 10790 $' 
  7   
  8  import copy 
  9   
 10  import numpy, numpy.random 
 11  from numpy import ones 
 12   
 13  import param 
 14   
 15  import topo 
 16  import topo.base.functionfamily 
 17   
 18  from topo.base.arrayutil import clip_lower,array_argmax 
 19  from topo.base.patterngenerator import PatternGenerator,Constant 
 20  from topo.base.boundingregion import BoundingBox 
 21  from topo.base.sheetcoords import SheetCoordinateSystem 
 22   
 23  from topo.transferfn.basic import TransferFn,TransferFnWithState 
 24  from topo.pattern.basic import Gaussian 
 25   
 26   
 27  # Not suitable for basic.py due to its dependence on patterns. 
28 -class PatternCombine(TransferFn):
29 """ 30 Combine the supplied pattern with one generated using a 31 PatternGenerator. 32 33 Useful for operations like adding noise or masking out lesioned 34 items or around the edges of non-rectangular shapes. 35 """ 36 generator = param.ClassSelector(PatternGenerator, 37 default=Constant(), doc=""" 38 Pattern to combine with the supplied matrix.""") 39 40 operator = param.Parameter(numpy.multiply,precedence=0.98,doc=""" 41 Binary Numeric function used to combine the two patterns. 42 43 Any binary Numeric array "ufunc" returning the same type of 44 array as the operands and supporting the reduce operator is 45 allowed here. See topo.pattern.basic.Composite.operator for 46 more details. 47 """) 48
49 - def __call__(self,x):
50 ###JABHACKALERT: Need to set it up to be independent of 51 #density; right now only things like random numbers work 52 #reasonably 53 rows,cols = x.shape 54 bb = BoundingBox(points=((0,0), (rows,cols))) 55 generated_pattern = self.generator(bounds=bb,xdensity=1,ydensity=1).transpose() 56 new_pattern = self.operator(x, generated_pattern) 57 x *= 0.0 58 x += new_pattern
59 60 61 62 # Not suitable for basic.py due to its dependence on patterns.
63 -class KernelMax(TransferFn):
64 """ 65 Replaces the given matrix with a kernel function centered around the maximum value. 66 67 This operation is usually part of the Kohonen SOM algorithm, and 68 approximates a series of lateral interactions resulting in a 69 single activity bubble. 70 71 The radius of the kernel (i.e. the surround) is specified by the 72 parameter 'radius', which should be set before using __call__. 73 The shape of the surround is determined by the 74 neighborhood_kernel_generator, and can be any PatternGenerator 75 instance, or any function accepting bounds, density, radius, and 76 height to return a kernel matrix. 77 """ 78 kernel_radius = param.Number(default=0.0,bounds=(0,None),doc=""" 79 Kernel radius in Sheet coordinates.""") 80 81 neighborhood_kernel_generator = param.ClassSelector(PatternGenerator, 82 default=Gaussian(x=0.0,y=0.0,aspect_ratio=1.0), 83 doc="Neighborhood function") 84 85 crop_radius_multiplier = param.Number(default=3.0,doc=""" 86 Factor by which the radius should be multiplied, when deciding 87 how far from the winner to keep evaluating the kernel.""") 88 89 density=param.Number(1.0,bounds=(0,None),doc=""" 90 Density of the Sheet whose matrix we act on, for use 91 in converting from matrix to Sheet coordinates.""") 92
93 - def __call__(self,x):
94 rows,cols = x.shape 95 radius = self.density*self.kernel_radius 96 crop_radius = int(max(1.25,radius*self.crop_radius_multiplier)) 97 98 # find out the matrix coordinates of the winner 99 wr,wc = array_argmax(x) 100 101 # convert to sheet coordinates 102 wy = rows-wr-1 103 104 # Optimization: Calculate the bounding box around the winner 105 # in which weights will be changed 106 cmin = max(wc-crop_radius, 0) 107 cmax = min(wc+crop_radius+1,cols) 108 rmin = max(wr-crop_radius, 0) 109 rmax = min(wr+crop_radius+1,rows) 110 ymin = max(wy-crop_radius, 0) 111 ymax = min(wy+crop_radius+1,rows) 112 bb = BoundingBox(points=((cmin,ymin), (cmax,ymax))) 113 114 # generate the kernel matrix and insert it into the correct 115 # part of the output array 116 kernel = self.neighborhood_kernel_generator(bounds=bb,xdensity=1,ydensity=1, 117 size=2*radius,x=wc+0.5,y=wy+0.5) 118 x *= 0.0 119 x[rmin:rmax,cmin:cmax] = kernel
120 121 122
123 -class HalfRectify(TransferFn):
124 """ 125 Transfer function that applies a half-wave rectification (clips at zero) 126 """ 127 t_init = param.Number(default=0.0,doc="""The initial value of threshold at which output becomes non-zero..""") 128 129 130 gain = param.Number(default=1.0,doc="""The neuronal gain""") 131 132 randomized_init = param.Boolean(False,doc=""" 133 Whether to randomize the initial t parameter.""") 134 135 noise_magnitude = param.Number(default=0.1,doc=""" 136 The magnitude of the additive noise to apply to the t_init 137 parameter at initialization.""") 138
139 - def __init__(self,**params):
140 super(TransferFn,self).__init__(**params) 141 self.first_call = True
142 143
144 - def __call__(self,x):
145 if self.first_call: 146 self.first_call = False 147 if self.randomized_init: 148 self.t = ones(x.shape, x.dtype.char) * self.t_init + \ 149 (topo.pattern.random.UniformRandom()(xdensity=x.shape[0],ydensity=x.shape[1])-0.5)*self.noise_magnitude*2 150 else: 151 self.t = ones(x.shape, x.dtype.char) * self.t_init 152 153 x -= self.t 154 clip_lower(x,0) 155 x *= self.gain
156 157 158
159 -class HomeostaticResponse(TransferFnWithState):
160 """ 161 Adapts the parameters of a linear threshold function to maintain a 162 constant desired average activity. 163 """ 164 165 target_activity = param.Number(default=0.024,doc=""" 166 The target average activity.""") 167 168 linear_slope = param.Number(default=1.0,doc=""" 169 Slope of the linear portion above threshold.""") 170 171 t_init = param.Number(default=0.15,doc=""" 172 Initial value of the threshold.""") 173 174 learning_rate = param.Number(default=0.001,doc=""" 175 Learning rate for homeostatic plasticity.""") 176 177 smoothing = param.Number(default=0.999,doc=""" 178 Weighting of previous activity vs. current activity when 179 calculating the average.""") 180 181 randomized_init = param.Boolean(False,doc=""" 182 Whether to randomize the initial t parameter.""") 183 184 noise_magnitude = param.Number(default=0.1,doc=""" 185 The magnitude of the additive noise to apply to the t_init 186 parameter at initialization.""") 187
188 - def __init__(self,**params):
189 super(HomeostaticResponse,self).__init__(**params) 190 self.first_call = True 191 self.__current_state_stack=[] 192 self.t=None # To allow state_push at init 193 self.y_avg=None # To allow state_push at init
194
195 - def __call__(self,x):
196 if self.first_call: 197 self.first_call = False 198 if self.randomized_init: 199 # CEBALERT: UniformRandom's seed should be available 200 # as a parameter. 201 self.t = ones(x.shape, x.dtype.char) * self.t_init + \ 202 (topo.pattern.random.UniformRandom() \ 203 (xdensity=x.shape[0],ydensity=x.shape[1]) \ 204 -0.5)*self.noise_magnitude*2 205 else: 206 self.t = ones(x.shape, x.dtype.char) * self.t_init 207 208 self.y_avg = ones(x.shape, x.dtype.char) * self.target_activity 209 210 x_orig = copy.copy(x) 211 x -= self.t 212 clip_lower(x,0) 213 x *= self.linear_slope 214 215 if self.plastic & (float(topo.sim.time()) % 1.0 >= 0.54): 216 self.y_avg = (1.0-self.smoothing)*x + self.smoothing*self.y_avg 217 self.t += self.learning_rate * (self.y_avg - self.target_activity)
218 219
220 - def state_push(self):
221 self.__current_state_stack.append((copy.copy(self.t), 222 copy.copy(self.y_avg), 223 copy.copy(self.first_call))) 224 super(HomeostaticResponse, self).state_push()
225 226
227 - def state_pop(self):
228 self.t, self.y_avg, self.first_call = self.__current_state_stack.pop() 229 super(HomeostaticResponse, self).state_pop()
230 231 232
233 -class AttributeTrackingTF(TransferFnWithState):
234 """ 235 Keeps track of attributes of a specified Parameterized over time, for analysis or plotting. 236 237 Useful objects to track include sheets (e.g. "topo.sim['V1']"), 238 projections ("topo.sim['V1'].projections['LateralInhibitory']"), 239 or an output_function. 240 241 Any attribute whose value is a matrix the same size as the 242 activity matrix can be tracked. Only specified units within this 243 matrix will be tracked. 244 245 If no object is specified, this function will keep track of the 246 incoming activity over time. 247 248 The results are stored in a dictionary named 'values', as (time, 249 value) pairs indexed by the parameter name and unit. For 250 instance, if the value of attribute 'x' is v for unit (0.0,0.0) 251 at time t, values['x'][(0.0,0.0)]=(t,v). 252 253 Updating of the tracked values can be disabled temporarily using 254 the plastic parameter. 255 """ 256 257 # ALERT: Need to make this read-only, because it can't be changed 258 # after instantiation unless _object is also changed. Or else 259 # need to make _object update whenever object is changed and 260 # _object has already been set. 261 object = param.Parameter(default=None, doc=""" 262 Parameterized instance whose parameters will be tracked. 263 264 If this parameter's value is a string, it will be evaluated first 265 (by calling Python's eval() function). This feature is designed to 266 allow circular references, so that the OF can track the object that 267 owns it, without causing problems for recursive traversal (as for 268 script_repr()).""") 269 # There may be some way to achieve the above without using eval(), which would be better. 270 #JLALERT When using this function snapshots cannot be saved because of problem with eval() 271 272 attrib_names = param.List(default=[], doc=""" 273 List of names of the function object's parameters that should be stored.""") 274 275 units = param.List(default=[(0.0,0.0)], doc=""" 276 Sheet coordinates of the unit(s) for which parameter values will be stored.""") 277 278 step = param.Number(default=1, doc=""" 279 How often to update the tracked values. 280 281 For instance, step=1 means to update them every time this OF is 282 called; step=2 means to update them every other time.""") 283 284 coordframe = param.Parameter(default=None,doc=""" 285 The SheetCoordinateSystem to use to convert the position 286 into matrix coordinates. If this parameter's value is a string, 287 it will be evaluated first(by calling Python's eval() function). 288 This feature is designed to allow circular references, 289 so that the OF can track the object that 290 owns it, without causing problems for recursive traversal (as for 291 script_repr()).""") 292
293 - def __init__(self,**params):
294 super(AttributeTrackingTF,self).__init__(**params) 295 self.values={} 296 self.n_step = 0 297 self._object=None 298 self._coordframe=None 299 for p in self.attrib_names: 300 self.values[p]={} 301 for u in self.units: 302 self.values[p][u]=[]
303 304 305
306 - def __call__(self,x):
307 308 if self._object==None: 309 if isinstance(self.object,str): 310 self._object=eval(self.object) 311 else: 312 self._object=self.object 313 314 if self._coordframe == None: 315 if isinstance(self.coordframe,str) and isinstance(self._object,SheetCoordinateSystem): 316 raise ValueError(str(self._object)+"is already a coordframe, no need to specify coordframe") 317 elif isinstance(self._object,SheetCoordinateSystem): 318 self._coordframe=self._object 319 elif isinstance(self.coordframe,str): 320 self._coordframe=eval(self.coordframe) 321 else: 322 raise ValueError("A coordinate frame (e.g. coordframe=topo.sim['V1']) must be specified in order to track"+str(self._object)) 323 324 325 #collect values on each appropriate step 326 self.n_step += 1 327 328 if self.n_step == self.step: 329 self.n_step = 0 330 if self.plastic: 331 for p in self.attrib_names: 332 if p=="x": 333 value_matrix=x 334 else: 335 value_matrix= getattr(self._object, p) 336 337 for u in self.units: 338 mat_u=self._coordframe.sheet2matrixidx(u[0],u[1]) 339 self.values[p][u].append((topo.sim.time(),value_matrix[mat_u]))
340 341 342 343 __all__ = list(set([k for k,v in locals().items() if isinstance(v,type) and issubclass(v,TransferFn)])) 344