Caffe2 - C++ API
A deep learning, cross platform ML framework
snpe_op_benchmark.cc
1 
17 #ifdef __ARM_NEON__
18 #include "caffe2/core/init.h"
19 #include "caffe2/core/operator.h"
20 #include "caffe2/core/tensor.h"
21 #include "caffe2/core/timer.h"
22 #include "caffe2/utils/proto_utils.h"
23 
24 #define TEST_REAL_DATA 0
25 // If you want to test with real data you may want to grab this
26 // script P57273314 and a 227x227 png of a cat or something.
27 #if TEST_REAL_DATA
28 #include "data_chw.h"
29 #include "data_hwc.h"
30 #define POPULATE_DATA(_n, _s, _l) do {\
31  Blob* _blob = ws.CreateBlob((_n));\
32  auto* _tensor = _blob->GetMutable<TensorCPU>();\
33  _tensor->Resize((_s));\
34  memcpy(_tensor->mutable_data<float>(), data_##_l, _tensor->nbytes());\
35 } while(0)
36 #else
37 // Rough test on static data
38 #define POPULATE_DATA(_n, _s, _l) do {\
39  Blob* _blob = ws.CreateBlob((_n));\
40  auto* _tensor = _blob->GetMutable<TensorCPU>();\
41  _tensor->Resize((_s));\
42  memset(_tensor->mutable_data<float>(), 1, _tensor->nbytes());\
43 } while(0)
44 #endif
45 
46 #include <cmath>
47 #include <random>
48 #include <iostream>
49 #include <fstream>
50 
51 namespace caffe2 {
52 
53 void AddConstInput(const vector<TIndex>& shape,
54  const float value,
55  const string& name,
56  Workspace* ws) {
57  DeviceOption option;
58  CPUContext context(option);
59  Blob* blob = ws->CreateBlob(name);
60  auto* tensor = blob->GetMutable<TensorCPU>();
61  tensor->Resize(shape);
62  math::Set<float, CPUContext>(tensor->size(), value,
63  tensor->mutable_data<float>(),
64  &context);
65 }
66 
67 void AddNoiseInput(const vector<TIndex>& shape,
68  const string& name,
69  Workspace* ws) {
70  DeviceOption option;
71  CPUContext context(option);
72  Blob* blob = ws->CreateBlob(name);
73  auto* tensor = blob->GetMutable<TensorCPU>();
74  tensor->Resize(shape);
75 
76  math::RandGaussian<float, CPUContext>(
77  tensor->size(),
78  0.0f, 10.0f,
79  tensor->mutable_data<float>(),
80  &context);
81 }
82 
83 
84 float snpe_run(int iters, Workspace& ws) {
85  const int H = 227;
86  const int W = 227;
87  const int C = 3;
88 
89  POPULATE_DATA("X_snpe", (caffe2::vector<caffe2::TIndex>{H, W, C}), hwc);
90 
91  OperatorDef def;
92  def.set_name("snpe_test");
93  def.set_type("SNPE");
94  def.add_input("X_snpe");
95  def.add_output("snpeout");
96  std::ostringstream model_buffer;
97  std::ifstream file("/data/local/tmp/squeeze_net.dlc", std::ios::in|std::ios::binary);
98  CAFFE_ENFORCE(file.is_open(), "Couldn't open test model.");
99  model_buffer << file.rdbuf();
100  CAFFE_ENFORCE(model_buffer.str().length() > 0, "Couldn't load model into string.");
101  def.add_arg()->CopyFrom(MakeArgument("model_buffer", model_buffer.str()));
102 
103  unique_ptr<OperatorBase> op(CreateOperator(def, &ws));
104  assert(op.get());
105  Timer timer;
106  timer.Start();
107  for (auto i = 0; i < iters; ++i) {
108  op->Run();
109  }
110  return timer.MicroSeconds();
111 }
112 
113 float caffe2_run(int iters, Workspace& ws) {
114  NetDef init_net;
115  NetDef predict_net;
116 
117  const int N = 1;
118  const int H = 227;
119  const int W = 227;
120  const int C = 3;
121 
122  ReadProtoFromBinaryFile("/data/local/tmp/squeeze_init_net.pb", &init_net);
123  ReadProtoFromBinaryFile("/data/local/tmp/squeeze_predict_net.pb", &predict_net);
124  ws.RunNetOnce(init_net);
125  POPULATE_DATA("data", (caffe2::vector<caffe2::TIndex>{N, C, H, W}), chw);
126  predict_net.set_name("SqueezeNet");
127  ws.CreateNet(predict_net);
128 
129  // Timing caffe2
130  Timer timer;
131  timer.Start();
132  for (auto i = 0; i < iters; ++i) {
133  ws.RunNet("SqueezeNet");
134  }
135  float us = timer.MicroSeconds();
136 
137  OperatorDef copy_def;
138  copy_def.set_type("Copy");
139  copy_def.set_name("Copy");
140  copy_def.add_input("softmaxout");
141  copy_def.add_output("caffe2out");
142  unique_ptr<OperatorBase> copy_op(CreateOperator(copy_def, &ws));
143  copy_op->Run();
144  return us;
145 }
146 
147 } // caffe2
148 
149 int main(int argc, char** argv) {
150  caffe2::GlobalInit(&argc, &argv);
152  int iters = 50;
153 
154  std::cout << "Testing caffe2...";
155  float t_caffe2 = caffe2::caffe2_run(iters, ws);
156  std::cout << "done!\nTesting snpe...";
157  float t_snpe = caffe2::snpe_run(iters, ws);
158  std::cout << "done!\n";
159 
160  caffe2::Blob* caffe2_out_blob = ws.GetBlob("caffe2out");
161  auto& caffe2_tensor = caffe2_out_blob->Get<caffe2::TensorCPU>();
162  caffe2::Blob* snpe_out_blob = ws.GetBlob("snpeout");
163  auto& snpe_tensor = snpe_out_blob->Get<caffe2::TensorCPU>();
164 
165  CAFFE_ENFORCE(snpe_tensor.size() == caffe2_tensor.size(), "Outputs are not the same!\n");
166 
167  float total_diff = 0;
168  float KL_divergence = 0;
169  float JS_divergence = 0;
170  float max = 0;
171  int max_index = 0;
172 
173  for (auto i = 0; i < snpe_tensor.size(); ++i) {
174  auto Q = caffe2_tensor.data<float>()[i];
175  auto P = snpe_tensor.data<float>()[i];
176  if (Q > max) {
177  max = Q;
178  max_index = i;
179  }
180  auto diff = fabs(P - Q);
181  auto avg = P + Q / 2;
182  if (P && Q) {
183  KL_divergence += P * log(P / Q);
184  JS_divergence += 0.5 * P * log(P / Q) + 0.5 * Q * log(Q / P);
185  }
186  total_diff += diff;
187  if (diff / avg > 0.10 && avg > 0.01) { // 10% difference and a non trivial confidence
188  std::cout << "Diff: " << diff << " (" << P << " vs " << Q << ")\n";
189  }
190  }
191 
192  float avg_diff = total_diff; // Avg difference as percentage (not a great metric)
193  printf("Average difference is %f%%\n", avg_diff * 100);
194  printf("JS Divergence is %f\n", JS_divergence); // Jensen-Shannon
195  printf("KL Divergence is %f\n", KL_divergence); // KullbackÔÇôLeibler
196  printf("Predicted %d with %f%% confidence\n", max_index, max * 100);
197 
198  printf ("Caffe2: %f microseconds.\n", t_caffe2);
199  printf ("SNPE: %f microseconds.\n", t_snpe);
200  printf ("SNPE impl %fx faster\n", t_caffe2/t_snpe);
201  return 0;
202 }
203 #else
204 // Compile for different targets.
205 int main() {
206  return 0;
207 }
208 #endif
Blob is a general container that hosts a typed pointer.
Definition: blob.h:41
bool GlobalInit(int *pargc, char ***pargv)
Initialize the global environment of caffe2.
Definition: init.cc:34
Workspace is a class that holds all the related objects created during runtime: (1) all blobs...
Definition: workspace.h:63
const Blob * GetBlob(const string &name) const
Gets the blob with the given name as a const pointer.
Definition: workspace.cc:180
Copyright (c) 2016-present, Facebook, Inc.
const T & Get() const
Gets the const reference of the stored object.
Definition: blob.h:91