PetaVision  Alpha
FilenameParsingGroundTruthLayer.cpp
1 /*
2  * FilenameParsingGroundTruthLayer.cpp
3  *
4  * Created on: Nov 10, 2014
5  * Author: wchavez
6  */
7 
8 #include "FilenameParsingGroundTruthLayer.hpp"
9 
10 #include <algorithm>
11 #include <cstdlib>
12 #include <fstream>
13 #include <iostream>
14 #include <sstream>
15 #include <string>
16 #include <vector>
17 
18 namespace PV {
19 FilenameParsingGroundTruthLayer::FilenameParsingGroundTruthLayer(const char *name, HyPerCol *hc) {
20  initialize(name, hc);
21 }
22 
23 FilenameParsingGroundTruthLayer::~FilenameParsingGroundTruthLayer() {
24  free(mInputLayerName);
25  free(mClassListFileName);
26 }
27 
29  int status = HyPerLayer::ioParamsFillGroup(ioFlag);
30  ioParam_classList(ioFlag);
31  ioParam_inputLayerName(ioFlag);
34  return status;
35 }
36 
38  parent->parameters()->ioParamValue(
39  ioFlag, name, "gtClassTrueValue", &mGtClassTrueValue, 1.0f, false);
40 }
41 
43  parent->parameters()->ioParamValue(
44  ioFlag, name, "gtClassFalseValue", &mGtClassFalseValue, -1.0f, false);
45 }
46 
48  parent->parameters()->ioParamStringRequired(ioFlag, name, "inputLayerName", &mInputLayerName);
49 }
50 
52  parent->parameters()->ioParamString(
53  ioFlag, name, "classList", &mClassListFileName, mClassListFileName, false);
54  if (mClassListFileName == nullptr) {
55  WarnLog() << getName()
56  << ": No classList specified. Looking for classes.txt in output directory.\n";
57  }
58 }
59 
60 Response::Status FilenameParsingGroundTruthLayer::registerData(Checkpointer *checkpointer) {
61  // Belongs in registerData and not allocateDataStructures because the
62  // default path for the class list is the output path, which is available
63  // only in registerData through the checkpointer argument.
64  // But is this the best default?
65  auto status = HyPerLayer::registerData(checkpointer);
66  if (!Response::completed(status)) {
67  return status;
68  }
69 
70  std::ifstream inputFile;
71  std::string outPath("");
72 
73  if (mClassListFileName != nullptr) {
74  outPath += std::string(mClassListFileName);
75  }
76  else {
77  outPath += checkpointer->getOutputPath();
78  outPath += "/classes.txt";
79  }
80 
81  inputFile.open(outPath.c_str(), std::ifstream::in);
82  FatalIf(!inputFile.is_open(), "%s: Unable to open file %s\n", getName(), outPath.c_str());
83 
84  mClasses.clear();
85  std::string line;
86  while (getline(inputFile, line)) {
87  mClasses.push_back(line);
88  }
89  inputFile.close();
90 
91  std::size_t numFeatures = (std::size_t)getLayerLoc()->nf;
92  FatalIf(
93  numFeatures != mClasses.size(),
94  "%s has %d features but classList \"%s\" has %zu categories.\n",
95  getDescription_c(),
96  getLayerLoc()->nf,
97  outPath.c_str(),
98  mClasses.size());
99  return Response::SUCCESS;
100 }
101 
102 Response::Status FilenameParsingGroundTruthLayer::communicateInitInfo(
103  std::shared_ptr<CommunicateInitInfoMessage const> message) {
104  mInputLayer = message->lookup<InputLayer>(std::string(mInputLayerName));
105  FatalIf(
106  mInputLayer == nullptr && parent->columnId() == 0,
107  "%s: inputLayerName \"%s\" is not a layer in the HyPerCol.\n",
108  getDescription_c(),
109  mInputLayerName);
110  FatalIf(
111  mInputLayer->getPhase() <= getPhase(),
112  "%s: The phase of layer %s (%d) must be greater than the phase of the "
113  "FilenameParsingGroundTruthLayer (%d)\n",
114  getName(),
115  mInputLayerName,
116  mInputLayer->getPhase(),
117  getPhase());
118  return Response::SUCCESS;
119 }
120 
121 bool FilenameParsingGroundTruthLayer::needUpdate(double time, double dt) {
122  return mInputLayer->needUpdate(parent->simulationTime(), parent->getDeltaTime());
123 }
124 
125 Response::Status FilenameParsingGroundTruthLayer::updateState(double time, double dt) {
126  update_timer->start();
127  float *A = getCLayer()->activity->data;
128  const PVLayerLoc *loc = getLayerLoc();
129  int numNeurons = getNumNeurons();
130  int const localBatchWidth = getLayerLoc()->nbatch;
131  int const blockBatchWidth = getMPIBlock()->getBatchDimension() * localBatchWidth;
132  for (int b = 0; b < blockBatchWidth; b++) {
133  int const mpiBlockBatchIndex = b / localBatchWidth; // integer division
134  int const localBatchIndex = b % localBatchWidth;
135 
136  std::vector<float> fileMatches(mClasses.size());
137  if (getMPIBlock()->getRank() == 0) {
138  std::string currentFilename =
139  mInputLayer->getCurrentFilename(localBatchIndex, mpiBlockBatchIndex).c_str();
140  for (auto ci = (std::size_t)0; ci < mClasses.size(); ci++) {
141  std::size_t match = currentFilename.find(mClasses.at(ci));
142  fileMatches[ci] = match != std::string::npos ? mGtClassTrueValue : mGtClassFalseValue;
143  }
144  }
145  // It seems clunky to send each process all the fileMatches, when
146  // they'll only use only the fileMatches for the correct MPIBlock
147  // batch index. Use MPI_Send/MPI_Recv? Create more MPI_Comm's?
148  MPI_Bcast(fileMatches.data(), fileMatches.size(), MPI_FLOAT, 0, getMPIBlock()->getComm());
149 
150  if (getMPIBlock()->getBatchIndex() != mpiBlockBatchIndex) {
151  continue;
152  }
153 
154  float *ABatch = A + localBatchIndex * getNumExtended();
155  for (int i = 0; i < numNeurons; i++) {
156  int nExt = kIndexExtended(
157  i,
158  loc->nx,
159  loc->ny,
160  loc->nf,
161  loc->halo.lt,
162  loc->halo.rt,
163  loc->halo.dn,
164  loc->halo.up);
165  int fi = featureIndex(
166  nExt,
167  loc->nx + loc->halo.rt + loc->halo.lt,
168  loc->ny + loc->halo.dn + loc->halo.up,
169  loc->nf);
170  ABatch[nExt] = fileMatches[fi];
171  }
172  }
173  update_timer->stop();
174  return Response::SUCCESS;
175 }
176 
177 } // end namespace PV
virtual int ioParamsFillGroup(enum ParamsIOFlag ioFlag) override
Definition: HyPerLayer.cpp:571
int ioParamsFillGroup(enum ParamsIOFlag ioFlag) override
MPI_Comm getComm() const
Definition: MPIBlock.hpp:90
virtual std::string const & getCurrentFilename(int localBatchElement, int mpiBatchIndex) const
Definition: InputLayer.hpp:216
virtual void ioParam_gtClassFalseValue(enum ParamsIOFlag ioFlag)
gtClassFalseValue: defines value to be set for the neurons that do not match the classes.txt classifer
static bool completed(Status &a)
Definition: Response.hpp:49
int getRank() const
Definition: MPIBlock.hpp:100
virtual bool needUpdate(double time, double dt) override
int initialize(const char *name, HyPerCol *hc)
Definition: HyPerLayer.cpp:129
int getBatchDimension() const
Definition: MPIBlock.hpp:135
virtual void ioParam_gtClassTrueValue(enum ParamsIOFlag ioFlag)
gtClassTrueValue: defines value to be set for the neuron that matches classes.txt classifer ...
virtual bool needUpdate(double simTime, double dt)
int getBatchIndex() const
Definition: MPIBlock.hpp:171
virtual void ioParam_inputLayerName(enum ParamsIOFlag ioFlag)
movieLayerName: lists name of the movie layer from which the imageListPath is used to parse the class...
virtual void ioParam_classList(enum ParamsIOFlag ioFlag)
clasList: path to the .txt file that holds the list of imageListPath features that will parse to diff...