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