Caffe2 - C++ API
A deep learning, cross platform ML framework
caffe2_benchmark.cc
1 #include <fstream>
2 #include <iterator>
3 #include <string>
4 
5 #include "caffe2/core/blob_serialization.h"
6 #include "caffe2/core/init.h"
7 #include "caffe2/core/logging.h"
8 #include "caffe2/core/operator.h"
9 #include "caffe2/proto/caffe2.pb.h"
10 #include "caffe2/share/contrib/observers/observer_config.h"
11 #include "caffe2/utils/proto_utils.h"
12 #include "caffe2/utils/string_utils.h"
13 
14 CAFFE2_DEFINE_string(
15  backend,
16  "builtin",
17  "The backend to use when running the model. The allowed "
18  "backend choices are: builtin, default, nnpack, eigen, mkl");
19 CAFFE2_DEFINE_string(
20  init_net,
21  "",
22  "The given net to initialize any parameters.");
23 CAFFE2_DEFINE_string(
24  input,
25  "",
26  "Input that is needed for running the network. If "
27  "multiple input needed, use comma separated string.");
28 CAFFE2_DEFINE_string(
29  input_dims,
30  "",
31  "Alternate to input_files, if all inputs are simple "
32  "float TensorCPUs, specify the dimension using comma "
33  "separated numbers. If multiple input needed, use "
34  "semicolon to separate the dimension of different "
35  "tensors.");
36 CAFFE2_DEFINE_string(
37  input_file,
38  "",
39  "Input file that contain the serialized protobuf for "
40  "the input blobs. If multiple input needed, use comma "
41  "separated string. Must have the same number of items "
42  "as input does.");
43 CAFFE2_DEFINE_string(
44  input_type,
45  "float",
46  "Input type when specifying the input dimension."
47  "The supported types are float, uint8_t.");
48 CAFFE2_DEFINE_int(iter, 10, "The number of iterations to run.");
49 CAFFE2_DEFINE_string(net, "", "The given net to benchmark.");
50 CAFFE2_DEFINE_string(
51  output,
52  "",
53  "Output that should be dumped after the execution "
54  "finishes. If multiple outputs are needed, use comma "
55  "separated string. If you want to dump everything, pass "
56  "'*' as the output value.");
57 CAFFE2_DEFINE_string(
58  output_folder,
59  "",
60  "The folder that the output should be written to. This "
61  "folder must already exist in the file system.");
62 CAFFE2_DEFINE_bool(
63  run_individual,
64  false,
65  "Whether to benchmark individual operators.");
66 CAFFE2_DEFINE_bool(
67  text_output,
68  false,
69  "Whether to write out output in text format for regression purpose.");
70 CAFFE2_DEFINE_int(warmup, 0, "The number of iterations to warm up.");
71 
72 using std::string;
73 using std::unique_ptr;
74 using std::vector;
75 
76 static void writeTextOutput(
77  caffe2::TensorCPU* tensor,
78  const string& output_prefix,
79  const string& name) {
80  string output_name = output_prefix + "/" + name + ".txt";
82  caffe2::BlobProto blob_proto;
83  ser.Serialize(
84  *tensor, output_name, blob_proto.mutable_tensor(), 0, tensor->size());
85  blob_proto.set_name(output_name);
86  blob_proto.set_type("Tensor");
87  CAFFE_ENFORCE(blob_proto.has_tensor());
88  caffe2::TensorProto tensor_proto = blob_proto.tensor();
89  vector<float> data;
90  switch (tensor_proto.data_type()) {
91  case caffe2::TensorProto::FLOAT: {
92  std::copy(
93  tensor_proto.float_data().begin(),
94  tensor_proto.float_data().end(),
95  std::back_inserter(data));
96  break;
97  }
98  case caffe2::TensorProto::INT32: {
99  std::copy(
100  tensor_proto.int32_data().begin(),
101  tensor_proto.int32_data().end(),
102  std::back_inserter(data));
103  break;
104  }
105  default:
106  CAFFE_THROW("Unimplemented Blob type.");
107  }
108  std::ofstream output_file(output_name);
109  std::ostream_iterator<float> output_iterator(output_file, "\n");
110  std::copy(data.begin(), data.end(), output_iterator);
111 }
112 
113 int main(int argc, char** argv) {
114  caffe2::GlobalInit(&argc, &argv);
116  unique_ptr<caffe2::Workspace> workspace(new caffe2::Workspace());
117 
118  // Run initialization network.
119  caffe2::NetDef init_net_def;
120  CAFFE_ENFORCE(ReadProtoFromFile(caffe2::FLAGS_init_net, &init_net_def));
121  CAFFE_ENFORCE(workspace->RunNetOnce(init_net_def));
122 
123  // Load input.
124  if (caffe2::FLAGS_input.size()) {
125  vector<string> input_names = caffe2::split(',', caffe2::FLAGS_input);
126  if (caffe2::FLAGS_input_file.size()) {
127  vector<string> input_files = caffe2::split(',', caffe2::FLAGS_input_file);
128  CAFFE_ENFORCE_EQ(
129  input_names.size(),
130  input_files.size(),
131  "Input name and file should have the same number.");
132  for (int i = 0; i < input_names.size(); ++i) {
133  caffe2::BlobProto blob_proto;
134  CAFFE_ENFORCE(caffe2::ReadProtoFromFile(input_files[i], &blob_proto));
135  workspace->CreateBlob(input_names[i])->Deserialize(blob_proto);
136  }
137  } else if (caffe2::FLAGS_input_dims.size()) {
138  vector<string> input_dims_list =
139  caffe2::split(';', caffe2::FLAGS_input_dims);
140  CAFFE_ENFORCE_EQ(
141  input_names.size(),
142  input_dims_list.size(),
143  "Input name and dims should have the same number of items.");
144  for (int i = 0; i < input_names.size(); ++i) {
145  vector<string> input_dims_str = caffe2::split(',', input_dims_list[i]);
146  vector<int> input_dims;
147  for (const string& s : input_dims_str) {
148  input_dims.push_back(caffe2::stoi(s));
149  }
150  if (!workspace->HasBlob(input_names[i])) {
151  workspace->CreateBlob(input_names[i]);
152  }
153  caffe2::TensorCPU* tensor =
154  workspace->GetBlob(input_names[i])->GetMutable<caffe2::TensorCPU>();
155  tensor->Resize(input_dims);
156  if (caffe2::FLAGS_input_type == "float") {
157  tensor->mutable_data<float>();
158  } else {
159  CAFFE_ENFORCE(
160  caffe2::FLAGS_input_type == "uint8_t",
161  "Only supported input types are: float, uint8_t");
162  tensor->mutable_data<uint8_t>();
163  }
164  }
165  } else {
166  CAFFE_THROW(
167  "You requested input tensors, but neither input_file nor "
168  "input_dims is set.");
169  }
170  }
171 
172  // Run main network.
173  caffe2::NetDef net_def;
174  CAFFE_ENFORCE(ReadProtoFromFile(caffe2::FLAGS_net, &net_def));
175  if (caffe2::FLAGS_backend != "builtin") {
176  std::string engine = caffe2::FLAGS_backend == "nnpack" ? "NNPACK" :
177  caffe2::FLAGS_backend == "eigen" ? "EIGEN" :
178  caffe2::FLAGS_backend == "mkl" ? "MKLDNN" :
179  caffe2::FLAGS_backend == "default" ? "" : "NONE";
180  CAFFE_ENFORCE(engine != "NONE", "Backend is not supported");
181  for (int i = 0; i < net_def.op_size(); i++) {
182  caffe2::OperatorDef* op_def = net_def.mutable_op(i);
183  op_def->set_engine(engine);
184  }
185  }
186 
187  caffe2::NetBase* net = workspace->CreateNet(net_def);
188  CHECK_NOTNULL(net);
189 
190  LOG(INFO) << "Starting benchmark.";
191  caffe2::ObserverConfig::initSampleRate(
192  1, 1, 1, caffe2::FLAGS_run_individual, caffe2::FLAGS_warmup);
193  LOG(INFO) << "Running warmup runs.";
194  for (int i = 0; i < caffe2::FLAGS_warmup; ++i) {
195  CAFFE_ENFORCE(net->Run(), "Warmup run ", i, " has failed.");
196  }
197 
198  LOG(INFO) << "Main runs.";
199  CAFFE_ENFORCE(
200  caffe2::FLAGS_iter >= 0,
201  "Number of main runs should be non negative, provided ",
202  caffe2::FLAGS_iter,
203  ".");
204  for (int i = 0; i < caffe2::FLAGS_iter; ++i) {
205  caffe2::ObserverConfig::initSampleRate(1, 1, 1, 0, caffe2::FLAGS_warmup);
206  CAFFE_ENFORCE(net->Run(), "Main run ", i, " has failed.");
207  if (caffe2::FLAGS_run_individual) {
208  caffe2::ObserverConfig::initSampleRate(1, 1, 1, 1, caffe2::FLAGS_warmup);
209  CAFFE_ENFORCE(net->Run(), "Main run ", i, " with operator has failed.");
210  }
211  }
212 
213  string output_prefix = caffe2::FLAGS_output_folder.size()
214  ? caffe2::FLAGS_output_folder + "/"
215  : "";
216  if (caffe2::FLAGS_output.size()) {
217  vector<string> output_names = caffe2::split(',', caffe2::FLAGS_output);
218  if (caffe2::FLAGS_output == "*") {
219  output_names = workspace->Blobs();
220  }
221  for (const string& name : output_names) {
222  CAFFE_ENFORCE(
223  workspace->HasBlob(name),
224  "You requested a non-existing blob: ",
225  name);
226  if (caffe2::FLAGS_text_output) {
227  auto blob = workspace->GetBlob(name)->GetMutable<caffe2::TensorCPU>();
228  writeTextOutput(blob, output_prefix, name);
229  } else {
230  string serialized = workspace->GetBlob(name)->Serialize(name);
231  string output_filename = output_prefix + name;
232  caffe2::WriteStringToFile(serialized, output_filename.c_str());
233  }
234  }
235  }
236 
237  return 0;
238 }
bool GlobalInit(int *pargc, char ***pargv)
Initialize the global environment of caffe2.
Definition: init.cc:34
TensorSerializer is the serializer for Tensors.
TIndex size() const
Returns the size (i.e.
Definition: tensor.h:609
T * mutable_data()
Returns a typed pointer of the underlying storage.
Definition: tensor.h:594
Workspace is a class that holds all the related objects created during runtime: (1) all blobs...
Definition: workspace.h:63
void Serialize(const Blob &blob, const string &name, SerializationAcceptor acceptor) override
Serializes a Blob.
void Resize(Ts...dim_source)
Resizes a tensor.
Definition: tensor.h:304
void ShowLogInfoToStderr()
A utility to allow one to show log info to stderr after the program starts.
Definition: logging.cc:212