PetaVision  Alpha
BinningLayer.cpp
1 #include "BinningLayer.hpp"
2 
3 namespace PV {
4 
5 BinningLayer::BinningLayer(const char *name, HyPerCol *hc) {
6  initialize_base();
7  initialize(name, hc);
8 }
9 
10 BinningLayer::BinningLayer() {
11  initialize_base();
12  // initialize() gets called by subclass's initialize method
13 }
14 
15 int BinningLayer::initialize_base() {
16  numChannels = 0;
17  return PV_SUCCESS;
18 }
19 
20 int BinningLayer::initialize(const char *name, HyPerCol *hc) {
21  int status = HyPerLayer::initialize(name, hc);
22  return status;
23 }
24 
25 int BinningLayer::ioParamsFillGroup(enum ParamsIOFlag ioFlag) {
26  int status = HyPerLayer::ioParamsFillGroup(ioFlag);
28  ioParam_binMin(ioFlag);
29  ioParam_binMax(ioFlag);
30  ioParam_delay(ioFlag);
31  ioParam_binSigma(ioFlag);
32  ioParam_zeroNeg(ioFlag);
33  ioParam_zeroDCR(ioFlag);
34  return status;
35 }
36 
37 void BinningLayer::ioParam_originalLayerName(enum ParamsIOFlag ioFlag) {
38  parent->parameters()->ioParamStringRequired(
39  ioFlag, name, "originalLayerName", &mOriginalLayerName);
40  assert(mOriginalLayerName);
41  if (ioFlag == PARAMS_IO_READ && mOriginalLayerName[0] == '\0') {
42  if (parent->columnId() == 0) {
43  ErrorLog().printf("%s: originalLayerName must be set.\n", getDescription_c());
44  }
45  MPI_Barrier(parent->getCommunicator()->communicator());
46  exit(EXIT_FAILURE);
47  }
48 }
49 
50 void BinningLayer::ioParam_binMin(enum ParamsIOFlag ioFlag) {
51  parent->parameters()->ioParamValue(ioFlag, name, "binMin", &mBinMin, mBinMin);
52 }
53 
54 void BinningLayer::ioParam_binMax(enum ParamsIOFlag ioFlag) {
55  pvAssert(!parent->parameters()->presentAndNotBeenRead(name, "binMin"));
56  parent->parameters()->ioParamValue(ioFlag, name, "binMax", &mBinMax, mBinMax);
57  if (ioFlag == PARAMS_IO_READ && mBinMax <= mBinMin) {
58  if (parent->columnId() == 0) {
59  ErrorLog().printf(
60  "%s: binMax (%f) must be greater than binMin (%f).\n",
61  getDescription_c(),
62  (double)mBinMax,
63  (double)mBinMin);
64  }
65  MPI_Barrier(parent->getCommunicator()->communicator());
66  exit(EXIT_FAILURE);
67  }
68 }
69 
70 void BinningLayer::ioParam_binSigma(enum ParamsIOFlag ioFlag) {
71  parent->parameters()->ioParamValue(ioFlag, name, "binSigma", &mBinSigma, mBinSigma);
72 }
73 
74 void BinningLayer::ioParam_delay(enum ParamsIOFlag ioFlag) {
75  parent->parameters()->ioParamValue(ioFlag, name, "delay", &mDelay, mDelay);
76 }
77 
78 void BinningLayer::ioParam_zeroNeg(enum ParamsIOFlag ioFlag) {
79  parent->parameters()->ioParamValue(ioFlag, name, "zeroNeg", &mZeroNeg, mZeroNeg);
80 }
81 
82 void BinningLayer::ioParam_zeroDCR(enum ParamsIOFlag ioFlag) {
83  parent->parameters()->ioParamValue(ioFlag, name, "zeroDCR", &mZeroDCR, mZeroDCR);
84 }
85 
86 // TODO read params for gaussian over features
87 
88 Response::Status
89 BinningLayer::communicateInitInfo(std::shared_ptr<CommunicateInitInfoMessage const> message) {
90  auto status = HyPerLayer::communicateInitInfo(message);
91  if (!Response::completed(status)) {
92  return status;
93  }
94  mOriginalLayer = message->lookup<HyPerLayer>(std::string(mOriginalLayerName));
95  if (mOriginalLayer == NULL) {
96  if (parent->columnId() == 0) {
97  ErrorLog().printf(
98  "%s: originalLayerName \"%s\" is not a layer in the HyPerCol.\n",
99  getDescription_c(),
100  mOriginalLayerName);
101  }
102  MPI_Barrier(parent->getCommunicator()->communicator());
103  exit(EXIT_FAILURE);
104  }
105  if (mOriginalLayer->getInitInfoCommunicatedFlag() == false) {
106  return Response::POSTPONE;
107  }
108  mOriginalLayer->synchronizeMarginWidth(this);
109  this->synchronizeMarginWidth(mOriginalLayer);
110  const PVLayerLoc *srcLoc = mOriginalLayer->getLayerLoc();
111  const PVLayerLoc *loc = getLayerLoc();
112  assert(srcLoc != NULL && loc != NULL);
113  if (srcLoc->nxGlobal != loc->nxGlobal || srcLoc->nyGlobal != loc->nyGlobal) {
114  if (parent->columnId() == 0) {
115  ErrorLog(errorMessage);
116  errorMessage.printf(
117  "%s: originalLayerName \"%s\" does not have the same dimensions.\n",
118  getDescription_c(),
119  mOriginalLayerName);
120  errorMessage.printf(
121  " original (nx=%d, ny=%d) versus (nx=%d, ny=%d)\n",
122  srcLoc->nxGlobal,
123  srcLoc->nyGlobal,
124  loc->nxGlobal,
125  loc->nyGlobal);
126  }
127  MPI_Barrier(parent->getCommunicator()->communicator());
128  exit(EXIT_FAILURE);
129  }
130  if (srcLoc->nf != 1) {
131  ErrorLog().printf(
132  "%s: originalLayerName \"%s\" can only have 1 feature.\n",
133  getDescription_c(),
134  mOriginalLayerName);
135  }
136  assert(srcLoc->nx == loc->nx && srcLoc->ny == loc->ny);
137  return Response::SUCCESS;
138 }
139 
140 Response::Status BinningLayer::allocateDataStructures() {
141  return HyPerLayer::allocateDataStructures();
142 }
143 
144 void BinningLayer::allocateV() {
145  // Allocate V does nothing since binning does not need a V layer
146  clayer->V = NULL;
147 }
148 
149 void BinningLayer::initializeV() { assert(getV() == NULL); }
150 
151 void BinningLayer::initializeActivity() {}
152 
153 Response::Status BinningLayer::updateState(double simTime, double dt) {
154  PVLayerLoc const *origLoc = mOriginalLayer->getLayerLoc();
155  PVLayerLoc const *currLoc = getLayerLoc();
156 
157  pvAssert(origLoc->nx == currLoc->nx);
158  pvAssert(origLoc->ny == currLoc->ny);
159  pvAssert(origLoc->nf == 1);
160  int nx = currLoc->nx;
161  int ny = currLoc->ny;
162 
163  pvAssert(origLoc->halo.lt == currLoc->halo.lt);
164  pvAssert(origLoc->halo.rt == currLoc->halo.rt);
165  pvAssert(origLoc->halo.dn == currLoc->halo.dn);
166  pvAssert(origLoc->halo.up == currLoc->halo.up);
167  PVHalo const *halo = &origLoc->halo;
168 
169  int numBins = currLoc->nf;
170  float binRange = mBinMax - mBinMin;
171  float stepSize = float(binRange) / numBins;
172 
173  int const nxExt = origLoc->nx + origLoc->halo.lt + origLoc->halo.rt;
174  int const nyExt = origLoc->ny + origLoc->halo.dn + origLoc->halo.up;
175 
176  float const *origData = mOriginalLayer->getLayerData(mDelay);
177  float *currActivity = getActivity();
178 
179  int nbatch = currLoc->nbatch;
180  pvAssert(origLoc->nbatch == currLoc->nbatch);
181  for (int b = 0; b < nbatch; b++) {
182  const float *origDataBatch = origData + b * nxExt * nyExt * origLoc->nf;
183  float *currABatch = currActivity + b * nxExt * nyExt * currLoc->nf;
184 
185 #ifdef PV_USE_OPENMP_THREADS
186 #pragma omp parallel for
187 #endif
188  for (int kExt = 0; kExt < nxExt * nyExt * currLoc->nf; kExt++) {
189  int iX = kxPos(kExt, nxExt, nyExt, currLoc->nf);
190  int iY = kyPos(kExt, nxExt, nyExt, currLoc->nf);
191  int iF = featureIndex(kExt, nxExt, nyExt, currLoc->nf);
192 
193  int origIndex = kIndex(iX, iY, 0, nxExt, nyExt, 1);
194  float inVal = origDataBatch[origIndex];
195  // If inVal is out of bounds in either binMax or binMin, set the value to be the maximum
196  // or minimum val
197  inVal = inVal < mBinMin ? mBinMin : inVal > mBinMax ? mBinMax : inVal;
198 
199  int const outOfBinValue = mZeroNeg ? 0 : -1;
200  if (mZeroDCR && inVal == 0) { // do-not-care region
201  currABatch[kExt] = outOfBinValue;
202  }
203  else {
204  // A sigma of zero means only the centered bin value should get input
205  if (mBinSigma == 0) {
206  int featureIdx = std::floor((inVal - mBinMin) / stepSize);
207  if (featureIdx >= numBins) {
208  featureIdx = numBins - 1;
209  }
210  currABatch[kExt] = iF == featureIdx ? 1 : outOfBinValue;
211  }
212  // sigma>0 means bin values have Gaussian decay as bins move farther from inVal.
213  // The width of the Gaussian is binValue multiplied by the bin width.
214  else {
215  float binCenter = ((float)iF + 0.5f) * stepSize;
216  currABatch[kExt] = calcGaussian(inVal - binCenter, mBinSigma * stepSize);
217  }
218  }
219  }
220  }
221  return Response::SUCCESS;
222 }
223 
224 float BinningLayer::calcGaussian(float x, float sigma) {
225  return std::exp(-x * x / (2 * sigma * sigma));
226 }
227 
228 BinningLayer::~BinningLayer() {
229  free(mOriginalLayerName);
230  clayer->V = NULL;
231 }
232 
233 } /* namespace PV */
void ioParam_zeroDCR(enum ParamsIOFlag ioFlag)
virtual int ioParamsFillGroup(enum ParamsIOFlag ioFlag) override
Definition: HyPerLayer.cpp:571
void ioParam_originalLayerName(enum ParamsIOFlag ioFlag)
void ioParam_binSigma(enum ParamsIOFlag ioFlag)
void ioParam_binMax(enum ParamsIOFlag ioFlag)
void ioParam_delay(enum ParamsIOFlag ioFlag)
int ioParamsFillGroup(enum ParamsIOFlag ioFlag) override
static bool completed(Status &a)
Definition: Response.hpp:49
void ioParam_zeroNeg(enum ParamsIOFlag ioFlag)
int initialize(const char *name, HyPerCol *hc)
Definition: HyPerLayer.cpp:129
void ioParam_binMin(enum ParamsIOFlag ioFlag)
const float * getLayerData(int delay=0)
bool getInitInfoCommunicatedFlag() const
Definition: BaseObject.hpp:95