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