PetaVision  Alpha
Retina.cpp
1 /*
2  * Retina.cpp
3  *
4  * Created on: Jul 29, 2008
5  *
6  */
7 
8 #include "Retina.hpp"
9 #include "HyPerLayer.hpp"
10 #include "include/default_params.h"
11 #include "io/io.hpp"
12 #include "io/randomstateio.hpp"
13 #include "utils/cl_random.h"
14 
15 #include <assert.h>
16 #include <cmath>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 
21 void Retina_spiking_update_state(
22  const int nbatch,
23  const int numNeurons,
24  const double timed,
25  const double dt,
26  const int nx,
27  const int ny,
28  const int nf,
29  const int lt,
30  const int rt,
31  const int dn,
32  const int up,
33  Retina_params *params,
34  taus_uint4 *rnd,
35  float *GSynHead,
36  float *activity,
37  float *prevTime);
38 
39 void Retina_nonspiking_update_state(
40  const int nbatch,
41  const int numNeurons,
42  const double timed,
43  const double dt,
44  const int nx,
45  const int ny,
46  const int nf,
47  const int lt,
48  const int rt,
49  const int dn,
50  const int up,
51  Retina_params *params,
52  float *GSynHead,
53  float *activity);
54 
55 namespace PV {
56 
57 Retina::Retina() {
58  initialize_base();
59  // Default constructor to be called by derived classes.
60  // It doesn't call Retina::initialize; instead, the derived class
61  // should explicitly call Retina::initialize in its own initialization,
62  // the way that Retina::initialize itself calls HyPerLayer::initialization.
63  // This way, virtual methods called by initialize will be overridden
64  // as expected.
65 }
66 
67 Retina::Retina(const char *name, HyPerCol *hc) {
68  initialize_base();
69  initialize(name, hc);
70 }
71 
72 Retina::~Retina() { delete randState; }
73 
74 int Retina::initialize_base() {
75  numChannels = NUM_RETINA_CHANNELS;
76  randState = NULL;
77  spikingFlag = true;
78  rParams.abs_refractory_period = 0.0f;
79  rParams.refractory_period = 0.0f;
80  rParams.beginStim = 0.0f;
81  rParams.endStim = -1.0;
82  rParams.burstDuration = 1000.0;
83  rParams.burstFreq = 1.0f;
84  rParams.probBase = 0.0f;
85  rParams.probStim = 1.0f;
86  return PV_SUCCESS;
87 }
88 
89 int Retina::initialize(const char *name, HyPerCol *hc) {
90  int status = HyPerLayer::initialize(name, hc);
91 
92  setRetinaParams(parent->parameters());
93 
94  return status;
95 }
96 
97 Response::Status
98 Retina::communicateInitInfo(std::shared_ptr<CommunicateInitInfoMessage const> message) {
99  auto status = HyPerLayer::communicateInitInfo(message);
100  if (parent->getNBatch() != 1) {
101  Fatal() << "Retina does not support batches yet, TODO\n";
102  }
103  return status;
104 }
105 
106 Response::Status Retina::allocateDataStructures() {
107  auto status = HyPerLayer::allocateDataStructures();
108  if (!Response::completed(status)) {
109  return status;
110  }
111 
112  assert(!parent->parameters()->presentAndNotBeenRead(name, "spikingFlag"));
113  if (spikingFlag) {
114  // // a random state variable is needed for every neuron/clthread
115  const PVLayerLoc *loc = getLayerLoc();
116  // Allocate extended loc
117  randState = new Random(loc, true);
118  status = Response::SUCCESS;
119  }
120 
121  return status;
122 }
123 
124 void Retina::allocateV() { clayer->V = NULL; }
125 
126 void Retina::initializeV() { assert(getV() == NULL); }
127 
128 void Retina::initializeActivity() { updateState(parent->simulationTime(), parent->getDeltaTime()); }
129 
130 int Retina::ioParamsFillGroup(enum ParamsIOFlag ioFlag) {
131  int status = HyPerLayer::ioParamsFillGroup(ioFlag);
132  ioParam_spikingFlag(ioFlag);
133  ioParam_foregroundRate(ioFlag);
134  ioParam_backgroundRate(ioFlag);
135  ioParam_beginStim(ioFlag);
136  ioParam_endStim(ioFlag);
137  ioParam_burstFreq(ioFlag);
138  ioParam_burstDuration(ioFlag);
139  ioParam_refractoryPeriod(ioFlag);
140  ioParam_absRefractoryPeriod(ioFlag);
141 
142  return status;
143 }
144 
145 void Retina::ioParam_InitVType(enum ParamsIOFlag ioFlag) {
146  parent->parameters()->handleUnnecessaryParameter(name, "InitVType");
147  return;
148 }
149 
150 void Retina::ioParam_spikingFlag(enum ParamsIOFlag ioFlag) {
151  parent->parameters()->ioParamValue(ioFlag, name, "spikingFlag", &spikingFlag, true);
152 }
153 
154 void Retina::ioParam_foregroundRate(enum ParamsIOFlag ioFlag) {
155  PVParams *params = parent->parameters();
156  parent->parameters()->ioParamValue(ioFlag, name, "foregroundRate", &probStimParam, 1.0f);
157 }
158 
159 void Retina::ioParam_backgroundRate(enum ParamsIOFlag ioFlag) {
160  PVParams *params = parent->parameters();
161  parent->parameters()->ioParamValue(ioFlag, name, "backgroundRate", &probBaseParam, 0.0f);
162 }
163 
164 void Retina::ioParam_beginStim(enum ParamsIOFlag ioFlag) {
165  parent->parameters()->ioParamValue(ioFlag, name, "beginStim", &rParams.beginStim, 0.0);
166 }
167 
168 void Retina::ioParam_endStim(enum ParamsIOFlag ioFlag) {
169  parent->parameters()->ioParamValue(ioFlag, name, "endStim", &rParams.endStim, (double)FLT_MAX);
170  if (ioFlag == PARAMS_IO_READ && rParams.endStim < 0)
171  rParams.endStim = FLT_MAX;
172 }
173 
174 void Retina::ioParam_burstFreq(enum ParamsIOFlag ioFlag) {
175  parent->parameters()->ioParamValue(ioFlag, name, "burstFreq", &rParams.burstFreq, 1.0f);
176 }
177 
178 void Retina::ioParam_burstDuration(enum ParamsIOFlag ioFlag) {
179  parent->parameters()->ioParamValue(
180  ioFlag, name, "burstDuration", &rParams.burstDuration, 1000.0f);
181 }
182 
183 void Retina::ioParam_refractoryPeriod(enum ParamsIOFlag ioFlag) {
184  assert(!parent->parameters()->presentAndNotBeenRead(name, "spikingFlag"));
185  if (spikingFlag) {
186  parent->parameters()->ioParamValue(
187  ioFlag, name, "refractoryPeriod", &rParams.refractory_period, (float)REFRACTORY_PERIOD);
188  }
189 }
190 
191 void Retina::ioParam_absRefractoryPeriod(enum ParamsIOFlag ioFlag) {
192  assert(!parent->parameters()->presentAndNotBeenRead(name, "spikingFlag"));
193  if (spikingFlag) {
194  parent->parameters()->ioParamValue(
195  ioFlag,
196  name,
197  "absRefractoryPeriod",
198  &rParams.abs_refractory_period,
199  (float)ABS_REFRACTORY_PERIOD);
200  }
201 }
202 
203 int Retina::setRetinaParams(PVParams *p) {
204 
205  float dt_sec = (float)parent->getDeltaTime() * 0.001f; // seconds
206  float probStim = probStimParam * dt_sec;
207  if (probStim > 1.0f) {
208  probStim = 1.0f;
209  }
210  float probBase = probBaseParam * dt_sec;
211  if (probBase > 1.0f) {
212  probBase = 1.0f;
213  }
214 
215  // default parameters
216  //
217  rParams.probStim = probStim;
218  rParams.probBase = probBase;
219 
220  return 0;
221 }
222 
223 Response::Status Retina::readStateFromCheckpoint(Checkpointer *checkpointer) {
224  if (initializeFromCheckpointFlag) {
225  auto status = HyPerLayer::readStateFromCheckpoint(checkpointer);
226  if (!Response::completed(status)) {
227  return status;
228  }
229  readRandStateFromCheckpoint(checkpointer);
230  return Response::SUCCESS;
231  }
232  else {
233  return Response::NO_ACTION;
234  }
235 }
236 
237 void Retina::readRandStateFromCheckpoint(Checkpointer *checkpointer) {
238  checkpointer->readNamedCheckpointEntry(
239  std::string(name), std::string("rand_state.pvp"), false /*not constant*/);
240 }
241 
242 Response::Status Retina::registerData(Checkpointer *checkpointer) {
243  auto status = HyPerLayer::registerData(checkpointer);
244  if (!Response::completed(status)) {
245  return status;
246  }
247  if (spikingFlag) {
248  pvAssert(randState != nullptr);
249  checkpointRandState(checkpointer, "rand_state", randState, true /*extended*/);
250  }
251  return Response::SUCCESS;
252 }
253 
255 
273 Response::Status Retina::updateState(double timed, double dt) {
274  const int nx = clayer->loc.nx;
275  const int ny = clayer->loc.ny;
276  const int nf = clayer->loc.nf;
277  const int nbatch = clayer->loc.nbatch;
278  const PVHalo *halo = &clayer->loc.halo;
279 
280  float *GSynHead = GSyn[0];
281  float *activity = clayer->activity->data;
282 
283  if (spikingFlag == 1) {
284  Retina_spiking_update_state(
285  nbatch,
286  getNumNeurons(),
287  timed,
288  dt,
289  nx,
290  ny,
291  nf,
292  halo->lt,
293  halo->rt,
294  halo->dn,
295  halo->up,
296  &rParams,
297  randState->getRNG(0),
298  GSynHead,
299  activity,
300  clayer->prevActivity);
301  }
302  else {
303  Retina_nonspiking_update_state(
304  nbatch,
305  getNumNeurons(),
306  timed,
307  dt,
308  nx,
309  ny,
310  nf,
311  halo->lt,
312  halo->rt,
313  halo->dn,
314  halo->up,
315  &rParams,
316  GSynHead,
317  activity);
318  }
319 
320 #ifdef DEBUG_PRINT
321  char filename[132];
322  sprintf(filename, "r_%d.tiff", (int)(2 * timed));
323  this->writeActivity(filename, timed);
324 
325  DebugLog(debugRetina);
326  debugRetina().printf("----------------\n");
327  for (int k = 0; k < 6; k++) {
328  debugRetina().printf("host:: k==%d h_exc==%f h_inh==%f\n", k, phiExc[k], phiInh[k]);
329  }
330  debugRetina().printf("----------------\n");
331 
332 #endif // DEBUG_PRINT
333  return Response::SUCCESS;
334 }
335 
336 } // namespace PV
337 
339 //
340 // implementation of Retina kernels
341 //
342 
343 /*
344  * Spiking method for Retina
345  * Returns 1 if an event should occur, 0 otherwise. This is a stochastic model.
346  *
347  * REMARKS:
348  * - During ABS_REFRACTORY_PERIOD a neuron does not spike
349  * - The neurons that correspond to stimuli (on Image pixels)
350  * spike with probability probStim.
351  * - The neurons that correspond to background image pixels
352  * spike with probability probBase.
353  * - After ABS_REFRACTORY_PERIOD the spiking probability
354  * grows exponentially to probBase and probStim respectively.
355  * - The burst of the retina is periodic with period T set by
356  * T = 1000/burstFreq in milliseconds
357  * - When the time t is such that mT < t < mT + burstDuration, where m is
358  * an integer, the burstStatus is set to 1.
359  * - The burstStatus is also determined by the condition that
360  * beginStim < t < endStim. These parameters are set in the input
361  * params file params.stdp
362  * - sinAmp modulates the spiking probability only when burstDuration <= 0
363  * or burstFreq = 0
364  * - probSpike is set to probBase for all neurons.
365  * - for neurons exposed to Image on pixels, probSpike increases with probStim.
366  * - When the probability is negative, the neuron does not spike.
367  *
368  * NOTES:
369  * - time is measured in milliseconds.
370  *
371  */
372 
373 static inline float calcBurstStatus(double timed, Retina_params *params) {
374  float burstStatus;
375  if (params->burstDuration <= 0 || params->burstFreq == 0) {
376  burstStatus = cosf(2.0f * PI * (float)timed * params->burstFreq / 1000.0f);
377  }
378  else {
379  burstStatus = fmodf((float)timed, 1000.0f / params->burstFreq);
380  burstStatus = burstStatus < params->burstDuration;
381  }
382  burstStatus *= (int)((timed >= params->beginStim) && (timed < params->endStim));
383  return burstStatus;
384 }
385 
386 static inline int
387 spike(float timed,
388  float dt,
389  float prev,
390  float stimFactor,
391  taus_uint4 *rnd_state,
392  float burst_status,
393  Retina_params *params) {
394  float probSpike;
395 
396  // input parameters
397  //
398  float probBase = params->probBase;
399  float probStim = params->probStim * stimFactor;
400 
401  // see if neuron is in a refractory period
402  //
403  if ((timed - prev) < params->abs_refractory_period) {
404  return 0;
405  }
406  else {
407  float delta = timed - prev - params->abs_refractory_period;
408  float refract = 1.0f - expf(-delta / params->refractory_period);
409  refract = (refract < 0) ? 0 : refract;
410  probBase *= refract;
411  probStim *= refract;
412  }
413 
414  probSpike = probBase;
415 
416  probSpike += probStim * burst_status; // negative prob is OK
417  // probSpike is spikes per millisecond; conversion to expected number of spikes in dt takes place
418  // in setRetinaParams
419 
420  *rnd_state = cl_random_get(*rnd_state);
421  int spike_flag = (cl_random_prob(*rnd_state) < probSpike);
422  return spike_flag;
423 }
424 
425 //
426 // update the state of a retinal layer (spiking)
427 //
428 // assume called with 1D kernel
429 //
430 void Retina_spiking_update_state(
431  const int nbatch,
432  const int numNeurons,
433  const double timed,
434  const double dt,
435 
436  const int nx,
437  const int ny,
438  const int nf,
439  const int lt,
440  const int rt,
441  const int dn,
442  const int up,
443 
444  Retina_params *params,
445  taus_uint4 *rnd,
446  float *GSynHead,
447  float *activity,
448  float *prevTime) {
449 
450  float *phiExc = &GSynHead[CHANNEL_EXC * nbatch * numNeurons];
451  float *phiInh = &GSynHead[CHANNEL_INH * nbatch * numNeurons];
452  for (int b = 0; b < nbatch; b++) {
453  taus_uint4 *rndBatch = rnd + b * nx * ny * nf;
454  float *phiExcBatch = phiExc + b * nx * ny * nf;
455  float *phiInhBatch = phiInh + b * nx * ny * nf;
456  float *prevTimeBatch = prevTime + b * (nx + lt + rt) * (ny + up + dn) * nf;
457  float *activityBatch = activity + b * (nx + lt + rt) * (ny + up + dn) * nf;
458  int k;
459  float burst_status = calcBurstStatus(timed, params);
460  for (k = 0; k < nx * ny * nf; k++) {
461  int kex = kIndexExtended(k, nx, ny, nf, lt, rt, dn, up);
462  //
463  // kernel (nonheader part) begins here
464  //
465  // load local variables from global memory
466  //
467  taus_uint4 l_rnd = rndBatch[k];
468  float l_phiExc = phiExcBatch[k];
469  float l_phiInh = phiInhBatch[k];
470  float l_prev = prevTimeBatch[kex];
471  float l_activ;
472  l_activ = (float)spike(
473  (float)timed,
474  (float)dt,
475  l_prev,
476  (l_phiExc - l_phiInh),
477  &l_rnd,
478  burst_status,
479  params);
480  l_prev = (l_activ > 0.0f) ? (float)timed : l_prev;
481  // store local variables back to global memory
482  //
483  rndBatch[k] = l_rnd;
484  prevTimeBatch[kex] = l_prev;
485  activityBatch[kex] = l_activ;
486  }
487  }
488 }
489 
490 //
491 // update the state of a retinal layer (non-spiking)
492 //
493 // assume called with 1D kernel
494 //
495 void Retina_nonspiking_update_state(
496  const int nbatch,
497  const int numNeurons,
498  const double timed,
499  const double dt,
500 
501  const int nx,
502  const int ny,
503  const int nf,
504  const int lt,
505  const int rt,
506  const int dn,
507  const int up,
508 
509  Retina_params *params,
510  float *GSynHead,
511  float *activity) {
512  int k;
513  float burstStatus = calcBurstStatus(timed, params);
514 
515  float *phiExc = &GSynHead[CHANNEL_EXC * nbatch * numNeurons];
516  float *phiInh = &GSynHead[CHANNEL_INH * nbatch * numNeurons];
517 
518  for (int b = 0; b < nbatch; b++) {
519  float *phiExcBatch = phiExc + b * nx * ny * nf;
520  float *phiInhBatch = phiInh + b * nx * ny * nf;
521  float *activityBatch = activity + b * (nx + lt + rt) * (ny + up + dn) * nf;
522  for (k = 0; k < nx * ny * nf; k++) {
523  int kex = kIndexExtended(k, nx, ny, nf, lt, rt, dn, up);
524  //
525  // kernel (nonheader part) begins here
526  //
527 
528  // load local variables from global memory
529  //
530  float l_phiExc = phiExcBatch[k];
531  float l_phiInh = phiInhBatch[k];
532  float l_activ;
533  // adding base prob should not change default behavior
534  l_activ = burstStatus * params->probStim * (l_phiExc - l_phiInh) + params->probBase;
535  // store local variables back to global memory
536  //
537  activityBatch[kex] = l_activ;
538  }
539  }
540 }
virtual int ioParamsFillGroup(enum ParamsIOFlag ioFlag) override
Definition: HyPerLayer.cpp:571
virtual int ioParamsFillGroup(enum ParamsIOFlag ioFlag) override
Definition: Retina.cpp:130
static bool completed(Status &a)
Definition: Response.hpp:49
int initialize(const char *name, HyPerCol *hc)
Definition: HyPerLayer.cpp:129
virtual void ioParam_InitVType(enum ParamsIOFlag ioFlag) override
initVType: Specifies how to initialize the V buffer.
Definition: Retina.cpp:145
virtual Response::Status updateState(double time, double dt) override
Updates the state of the Retina.
Definition: Retina.cpp:273