Caffe2 - C++ API
A deep learning, cross platform ML framework
speed_benchmark.cc
1 
17 #include <string>
18 
19 #include "caffe2/core/blob_serialization.h"
20 #include "caffe2/core/init.h"
21 #include "caffe2/core/logging.h"
22 #include "caffe2/core/operator.h"
23 #include "caffe2/core/tensor_int8.h"
24 #ifdef CAFFE2_OPTIMIZER
25 #include "caffe2/opt/optimizer.h"
26 #endif
27 #include "caffe2/proto/caffe2_pb.h"
28 #include "caffe2/utils/proto_utils.h"
29 #include "caffe2/utils/string_utils.h"
30 
31 C10_DEFINE_string(net, "", "The given net to benchmark.");
32 C10_DEFINE_string(init_net, "", "The given net to initialize any parameters.");
33 C10_DEFINE_string(
34  input,
35  "",
36  "Input that is needed for running the network. If "
37  "multiple input needed, use comma separated string.");
38 C10_DEFINE_string(
39  input_file,
40  "",
41  "Input file that contain the serialized protobuf for "
42  "the input blobs. If multiple input needed, use comma "
43  "separated string. Must have the same number of items "
44  "as input does.");
45 C10_DEFINE_string(
46  input_dims,
47  "",
48  "Alternate to input_files, if all inputs are simple "
49  "float TensorCPUs, specify the dimension using comma "
50  "separated numbers. If multiple input needed, use "
51  "semicolon to separate the dimension of different "
52  "tensors.");
53 C10_DEFINE_string(input_type, "", "Input type (uint8_t/float)");
54 C10_DEFINE_string(
55  output,
56  "",
57  "Output that should be dumped after the execution "
58  "finishes. If multiple outputs are needed, use comma "
59  "separated string. If you want to dump everything, pass "
60  "'*' as the output value.");
61 C10_DEFINE_string(
62  output_folder,
63  "",
64  "The folder that the output should be written to. This "
65  "folder must already exist in the file system.");
66 C10_DEFINE_int(warmup, 0, "The number of iterations to warm up.");
67 C10_DEFINE_int(iter, 10, "The number of iterations to run.");
68 C10_DEFINE_int(opt, 0, "The level of optimization to run automatically.");
69 C10_DEFINE_bool(
70  run_individual,
71  false,
72  "Whether to benchmark individual operators.");
73 
74 C10_DEFINE_bool(force_engine, false, "Force engine field for all operators");
75 C10_DEFINE_string(engine, "", "Forced engine field value");
76 C10_DEFINE_bool(force_algo, false, "Force algo arg for all operators");
77 C10_DEFINE_string(algo, "", "Forced algo arg value");
78 
79 using std::string;
80 using std::unique_ptr;
81 using std::vector;
82 
83 int main(int argc, char** argv) {
84  caffe2::GlobalInit(&argc, &argv);
85  unique_ptr<caffe2::Workspace> workspace(new caffe2::Workspace());
86 
87  // Run initialization network.
88  caffe2::NetDef net_def;
89  CAFFE_ENFORCE(ReadProtoFromFile(FLAGS_init_net, &net_def));
90  CAFFE_ENFORCE(workspace->RunNetOnce(net_def));
91 
92  // Load input.
93  if (FLAGS_input.size()) {
94  vector<string> input_names = caffe2::split(',', FLAGS_input);
95  if (FLAGS_input_file.size()) {
96  vector<string> input_files = caffe2::split(',', FLAGS_input_file);
97  CAFFE_ENFORCE_EQ(
98  input_names.size(),
99  input_files.size(),
100  "Input name and file should have the same number.");
101  for (int i = 0; i < input_names.size(); ++i) {
102  caffe2::BlobProto blob_proto;
103  CAFFE_ENFORCE(caffe2::ReadProtoFromFile(input_files[i], &blob_proto));
104  DeserializeBlob(blob_proto, workspace->CreateBlob(input_names[i]));
105  }
106  } else if (FLAGS_input_dims.size() || FLAGS_input_type.size()) {
107  CAFFE_ENFORCE_GE(
108  FLAGS_input_dims.size(),
109  0,
110  "Input dims must be specified when input tensors are used.");
111  CAFFE_ENFORCE_GE(
112  FLAGS_input_type.size(),
113  0,
114  "Input type must be specified when input tensors are used.");
115 
116  vector<string> input_dims_list = caffe2::split(';', FLAGS_input_dims);
117  CAFFE_ENFORCE_EQ(
118  input_names.size(),
119  input_dims_list.size(),
120  "Input name and dims should have the same number of items.");
121  vector<string> input_type_list = caffe2::split(';', FLAGS_input_type);
122  CAFFE_ENFORCE_EQ(
123  input_names.size(),
124  input_type_list.size(),
125  "Input name and type should have the same number of items.");
126  for (size_t i = 0; i < input_names.size(); ++i) {
127  vector<string> input_dims_str = caffe2::split(',', input_dims_list[i]);
128  vector<int> input_dims;
129  for (const string& s : input_dims_str) {
130  input_dims.push_back(c10::stoi(s));
131  }
132  caffe2::Blob* blob = workspace->GetBlob(input_names[i]);
133  if (blob == nullptr) {
134  blob = workspace->CreateBlob(input_names[i]);
135  }
136  if (input_type_list[i] == "uint8_t") {
139  CHECK_NOTNULL(tensor);
140  tensor->t.Resize(input_dims);
141  tensor->t.mutable_data<uint8_t>();
142  } else if (input_type_list[i] == "float") {
143  caffe2::TensorCPU* tensor = BlobGetMutableTensor(blob, caffe2::CPU);
144  CHECK_NOTNULL(tensor);
145  tensor->Resize(input_dims);
146  tensor->mutable_data<float>();
147  } else {
148  CAFFE_THROW("Unsupported input type: ", input_type_list[i]);
149  }
150  }
151  } else {
152  CAFFE_THROW(
153  "You requested input tensors, but neither input_file nor "
154  "input_dims is set.");
155  }
156  }
157 
158  // Run main network.
159  CAFFE_ENFORCE(ReadProtoFromFile(FLAGS_net, &net_def));
160  if (!net_def.has_name()) {
161  net_def.set_name("benchmark");
162  }
163  // force changing engine and algo
164  if (FLAGS_force_engine) {
165  LOG(INFO) << "force engine be: " << FLAGS_engine;
166  for (const auto& op : net_def.op()) {
167  const_cast<caffe2::OperatorDef*>(&op)->set_engine(FLAGS_engine);
168  }
169  }
170  if (FLAGS_force_algo) {
171  LOG(INFO) << "force algo be: " << FLAGS_algo;
172  for (const auto& op : net_def.op()) {
173  caffe2::GetMutableArgument(
174  "algo", true, const_cast<caffe2::OperatorDef*>(&op))
175  ->set_s(FLAGS_algo);
176  }
177  }
178  if (FLAGS_opt) {
179 #ifdef CAFFE2_OPTIMIZER
180  net_def = caffe2::opt::optimize(net_def, workspace.get(), FLAGS_opt);
181 #else
182  LOG(WARNING) << "Caffe2 not compiled with optimization passes.";
183 #endif
184  }
185 
186  caffe2::NetBase* net = workspace->CreateNet(net_def);
187  CHECK_NOTNULL(net);
188  CAFFE_ENFORCE(net->Run());
189  net->TEST_Benchmark(FLAGS_warmup, FLAGS_iter, FLAGS_run_individual);
190 
191  string output_prefix =
192  FLAGS_output_folder.size() ? FLAGS_output_folder + "/" : "";
193  if (FLAGS_output.size()) {
194  vector<string> output_names = caffe2::split(',', FLAGS_output);
195  if (FLAGS_output == "*") {
196  output_names = workspace->Blobs();
197  }
198  for (const string& name : output_names) {
199  CAFFE_ENFORCE(
200  workspace->HasBlob(name),
201  "You requested a non-existing blob: ",
202  name);
203  string serialized = SerializeBlob(*workspace->GetBlob(name), name);
204  string output_filename = output_prefix + name;
205  caffe2::WriteStringToFile(serialized, output_filename.c_str());
206  }
207  }
208 
209  return 0;
210 }
virtual vector< float > TEST_Benchmark(const int, const int, const bool)
Benchmarks a network.
Definition: net.cc:193
Blob is a general container that hosts a typed pointer.
Definition: blob.h:24
void DeserializeBlob(const string &content, Blob *result)
Deserializes from a string containing either BlobProto or TensorProto.
Workspace is a class that holds all the related objects created during runtime: (1) all blobs...
Definition: workspace.h:47
T * GetMutable()
Gets a mutable pointer to the stored object.
Definition: blob.h:100
bool GlobalInit(int *pargc, char ***pargv)
Initialize the global environment of caffe2.
Definition: init.cc:44
void SerializeBlob(const Blob &blob, const string &name, BlobSerializerBase::SerializationAcceptor acceptor, int chunk_size)
Serializes the given blob, if possible.