Caffe2 - C++ API
A deep learning, cross platform ML framework
data_filler.cc
1 #include "caffe2/predictor/emulator/data_filler.h"
2 #include "caffe2/predictor/emulator/utils.h"
3 
4 namespace caffe2 {
5 namespace emulator {
6 
7 void DataNetFiller::fill_parameter(Workspace* ws) const {
8  // As we use initial parameter initialization for this BenchmarkState,
9  // we can just run the init_net
10  CAFFE_ENFORCE(
11  ws->RunNetOnce(init_net_),
12  "Failed running the init_net: ",
13  ProtoDebugString(init_net_));
14 }
15 
16 void DataNetFiller::fill_input_internal(TensorList_t* input_data) const {
17  Workspace ws;
18  CAFFE_ENFORCE(ws.RunNetOnce(data_net_));
19  for (const auto& name : input_names_) {
20  input_data->emplace_back(
21  BlobGetMutableTensor(ws.GetBlob(name), CPU)->Clone());
22  }
23 }
24 
25 static void fill_with_type(
26  const TensorFiller& filler,
27  const std::string& type,
28  TensorCPU* output) {
29  CPUContext context;
30  if (type == "float") {
31  filler.Fill<float>(output, &context);
32  } else if (type == "double") {
33  filler.Fill<double>(output, &context);
34  } else if (type == "uint8_t" || type == "unsigned char") {
35  filler.Fill<uint8_t>(output, &context);
36  } else if (type == "uint16_t") {
37  filler.Fill<uint16_t>(output, &context);
38  } else if (type == "int8_t") {
39  filler.Fill<int8_t>(output, &context);
40  } else if (type == "int16_t") {
41  filler.Fill<int16_t>(output, &context);
42  } else if (type == "int32_t" || type == "int") {
43  filler.Fill<int32_t>(output, &context);
44  } else if (type == "int64_t" || type == "long") {
45  filler.Fill<int64_t>(output, &context);
46  } else if (type == "bool") {
47  auto mutable_filler = filler;
48  mutable_filler.Min(0).Max(2).Fill<uint8_t>(output, &context);
49  } else {
50  throw std::invalid_argument("filler does not support type " + type);
51  }
52 }
53 
54 DataRandomFiller::DataRandomFiller(
55  const NetDef& run_net,
56  const std::vector<std::vector<std::vector<int64_t>>>& input_dims,
57  const std::vector<std::vector<std::string>>& input_types) {
58  // parse dimensions
59  CAFFE_ENFORCE_EQ(input_dims.size(), run_net.op_size());
60  CAFFE_ENFORCE_EQ(input_types.size(), run_net.op_size());
61 
62  // load op inputs and outputs
63  std::unordered_set<std::string> output_names;
64  for (size_t i = 0; i < run_net.op_size(); ++i) {
65  const auto& op = run_net.op(i);
66  const auto& op_dims = input_dims[i];
67  const auto& op_types = input_types[i];
68  CAFFE_ENFORCE(
69  op_dims.size() == op.input_size(),
70  op.name() + " has " + c10::to_string(op.input_size()) +
71  " inputs; while the input dimension size is " +
72  c10::to_string(op_dims.size()));
73  CAFFE_ENFORCE(
74  op_types.size() == op.input_size(),
75  op.name() + " has " + c10::to_string(op.input_size()) +
76  " inputs; while the input type size is " +
77  c10::to_string(op_types.size()));
78 
79  for (size_t j = 0; j < op.input_size(); ++j) {
80  inputs_[op.input(j)] =
81  std::make_pair(get_tensor_filler(op, j, op_dims), op_types[j]);
82  }
83 
84  // Hack, we normal have a path of
85  // length -> LengthsiRangeFill -> Gather -> w -> SparseLengthsWeighted*
86  // \---------------------------------------/
87  // So when we generate the value of length, we need to bound it to the size
88  // of weight input of Gather too
89  if (op.type().find("SparseLengthsWeighted") == 0 && i > 0) {
90  const auto& prev_op = run_net.op(i - 1);
91  if (prev_op.type() == "Gather") {
92  const auto& prev_dims = input_dims[i - 1];
93  VLOG(1) << "Setting max length value to " << prev_dims[0].front()
94  << " for " << op.input(3);
95  inputs_[op.input(3)].first.Max(prev_dims[0].front());
96  }
97  }
98 
99  for (size_t j = 0; j < op.output_size(); ++j) {
100  output_names.emplace(op.output(j));
101  }
102  }
103 
104  // load parameters
105  std::unordered_set<std::string> parameters;
106  for (size_t i = 0; i < run_net.arg_size(); ++i) {
107  const auto& arg = run_net.arg(i);
108  // TODO: replace "PredictorParameters" with the constant in OSS bbp
109  if (arg.has_name() && arg.name() == "PredictorParameters") {
110  parameters.reserve(arg.strings_size());
111  for (size_t j = 0; j < arg.strings_size(); ++j) {
112  parameters.emplace(arg.strings(j));
113  }
114  break;
115  }
116  }
117  if (parameters.size() == 0) {
118  VLOG(1) << "Fail to find any parameters";
119  }
120  for (const auto& param : parameters) {
121  // remove unused parameters
122  if (inputs_.find(param) != inputs_.end()) {
123  // inputs_[param] will be erase from inputs_ in the next step
124  parameters_.emplace(param, inputs_[param]);
125  }
126  }
127 
128  for (const auto& param : parameters_) {
129  inputs_.erase(param.first);
130  }
131  for (const auto& name : output_names) {
132  inputs_.erase(name);
133  }
134  CAFFE_ENFORCE(inputs_.size() > 0, "Empty input for run net");
135 
136  // generate input names
137  for (const auto& input : inputs_) {
138  input_names_.push_back(input.first);
139  }
140 }
141 
142 void DataRandomFiller::fill_parameter(Workspace* ws) const {
143  for (auto& param : parameters_) {
144  Blob* blob = ws->CreateBlob(param.first);
145  fill_with_type(
146  param.second.first,
147  param.second.second,
148  BlobGetMutableTensor(blob, CPU));
149  CAFFE_ENFORCE(ws->GetBlob(param.first)->GetRaw());
150  }
151 }
152 
153 void DataRandomFiller::fill_input_internal(TensorList_t* input_data) const {
154  for (auto& name : input_names_) {
155  input_data->emplace_back(CPU);
156  const auto& it = inputs_.find(name);
157  CAFFE_ENFORCE(it != inputs_.end());
158  fill_with_type(it->second.first, it->second.second, &input_data->back());
159  }
160 }
161 
162 TestDataRandomFiller::TestDataRandomFiller(
163  const NetDef& net,
164  const std::vector<std::vector<std::vector<int64_t>>>& inputDims,
165  const std::vector<std::vector<std::string>>& inputTypes)
166  : DataRandomFiller() {
167  std::unordered_set<std::string> outputNames;
168  // Determine blobs that are outputs of some ops (intermediate blobs).
169  for (auto opIdx = 0; opIdx < net.op_size(); ++opIdx) {
170  const auto& op = net.op(opIdx);
171  for (auto outputIdx = 0; outputIdx < op.output_size(); ++outputIdx) {
172  outputNames.emplace(op.output(outputIdx));
173  }
174  }
175  // Determine ops that have non-intermediate inputs.
176  std::unordered_set<size_t> opWithRequiredInputs;
177  for (auto opIdx = 0; opIdx < net.op_size(); ++opIdx) {
178  const auto& op = net.op(opIdx);
179  for (auto inputIdx = 0; inputIdx < op.input_size(); ++inputIdx) {
180  if (!outputNames.count(op.input(inputIdx))) {
181  opWithRequiredInputs.emplace(opIdx);
182  break;
183  }
184  }
185  }
186 
187  CAFFE_ENFORCE_EQ(inputDims.size(), opWithRequiredInputs.size());
188  CAFFE_ENFORCE_EQ(inputTypes.size(), opWithRequiredInputs.size());
189 
190  int counter = 0;
191  for (auto opIdx = 0; opIdx < net.op_size(); ++opIdx) {
192  if (!opWithRequiredInputs.count(opIdx)) {
193  // Skip intermediate ops.
194  continue;
195  }
196  const auto& op = net.op(opIdx);
197  const auto& op_dims = inputDims[counter];
198  const auto& op_types = inputTypes[counter];
199  ++counter;
200 
201  int countRequiredInputs = 0;
202  for (auto inputIdx = 0; inputIdx < op.input_size(); ++inputIdx) {
203  if (!outputNames.count(op.input(inputIdx))) {
204  ++countRequiredInputs;
205  }
206  }
207 
208  CAFFE_ENFORCE(
209  op_dims.size() == countRequiredInputs,
210  op.name() + " has " + c10::to_string(op.input_size()) +
211  " (required) inputs; while the input dimension size is " +
212  c10::to_string(op_dims.size()));
213  CAFFE_ENFORCE(
214  op_types.size() == countRequiredInputs,
215  op.name() + " has " + c10::to_string(op.input_size()) +
216  " (required) inputs; while the input type size is " +
217  c10::to_string(op_types.size()));
218 
219  int dimCounter = 0;
220  for (auto inputIdx = 0; inputIdx < op.input_size(); ++inputIdx) {
221  auto inputName = op.input(inputIdx);
222  if (outputNames.count(inputName)) {
223  // Skip intermediate inputs.
224  continue;
225  }
226  inputs_[inputName] = std::make_pair(
227  get_tensor_filler(op, dimCounter, op_dims), op_types[dimCounter]);
228  ++dimCounter;
229  }
230  }
231  CAFFE_ENFORCE(inputs_.size() > 0, "Empty input for run net");
232  // generate input names
233  for (const auto& input : inputs_) {
234  input_names_.push_back(input.first);
235  }
236 }
237 
238 void TestDataRandomFiller::fillInputToWorkspace(Workspace* workspace) const {
239  for (auto& name : input_names_) {
240  const auto& it = inputs_.find(name);
241  CAFFE_ENFORCE(it != inputs_.end());
242  auto* tensor =
243  BlobGetMutableTensor(workspace->CreateBlob(name), caffe2::CPU);
244  fill_with_type(it->second.first, it->second.second, tensor);
245  }
246 }
247 
248 } // namespace emulator
249 } // namespace caffe2
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...
Definition: blob.h:13