• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 
16 #define EIGEN_USE_THREADS
17 
18 #include <functional>
19 #include <memory>
20 #include <vector>
21 
22 #include "tensorflow/cc/client/client_session.h"
23 #include "tensorflow/cc/ops/array_ops.h"
24 #include "tensorflow/cc/ops/const_op.h"
25 #include "tensorflow/cc/ops/math_ops.h"
26 #include "tensorflow/core/framework/tensor_testutil.h"
27 #include "tensorflow/core/framework/types.h"
28 #include "tensorflow/core/framework/types.pb.h"
29 #include "tensorflow/core/kernels/ops_util.h"
30 #include "tensorflow/core/kernels/quantization_utils.h"
31 #include "tensorflow/core/lib/core/status_test_util.h"
32 #include "tensorflow/core/platform/test.h"
33 
34 namespace tensorflow {
35 namespace ops {
36 namespace {
37 
TestMul(const std::vector<int64> & x_shape,const std::vector<float> & x_values,float x_min_value,float x_max_value,const std::vector<int64> & y_shape,const std::vector<float> & y_values,float y_min_value,float y_max_value,const std::vector<int64> & expected_shape,const std::vector<float> & expected_values,double tolerance)38 void TestMul(const std::vector<int64>& x_shape,
39              const std::vector<float>& x_values, float x_min_value,
40              float x_max_value, const std::vector<int64>& y_shape,
41              const std::vector<float>& y_values, float y_min_value,
42              float y_max_value, const std::vector<int64>& expected_shape,
43              const std::vector<float>& expected_values, double tolerance) {
44   Scope root = Scope::NewRootScope();
45 
46   Tensor x_float_tensor(DT_FLOAT, TensorShape(x_shape));
47   test::FillValues<float>(&x_float_tensor, x_values);
48   Tensor x_quantized_tensor(DT_QUINT8, x_float_tensor.shape());
49   FloatTensorToQuantizedInPlace<quint8>(x_float_tensor, x_min_value,
50                                         x_max_value, &x_quantized_tensor);
51   Output x =
52       Const(root.WithOpName("x"), Input::Initializer(x_quantized_tensor));
53   Output x_min = Const(root.WithOpName("x_min"), x_min_value);
54   Output x_max = Const(root.WithOpName("x_max"), x_max_value);
55 
56   Tensor y_float_tensor(DT_FLOAT, TensorShape(y_shape));
57   test::FillValues<float>(&y_float_tensor, y_values);
58   Tensor y_quantized_tensor(DT_QUINT8, y_float_tensor.shape());
59   FloatTensorToQuantizedInPlace<quint8>(y_float_tensor, y_min_value,
60                                         y_max_value, &y_quantized_tensor);
61   Output y =
62       Const(root.WithOpName("y"), Input::Initializer(y_quantized_tensor));
63   Output y_min = Const(root.WithOpName("y_min"), y_min_value);
64   Output y_max = Const(root.WithOpName("y_max"), y_max_value);
65 
66   QuantizedMul mul =
67       QuantizedMul(root.WithOpName("mul"), x, y, x_min, x_max, y_min, y_max);
68 
69   TF_EXPECT_OK(root.status());
70 
71   ClientSession session(root);
72   std::vector<Tensor> outputs;
73 
74   TF_EXPECT_OK(session.Run(ClientSession::FeedType(),
75                            {mul.z, mul.min_z, mul.max_z}, &outputs));
76 
77   const Tensor& z_quantized = outputs[0];
78   const float z_min = outputs[1].flat<float>()(0);
79   const float z_max = outputs[2].flat<float>()(0);
80 
81   Tensor z_float = QuantizedTensorToFloat<qint32>(z_quantized, z_min, z_max);
82   Tensor expected_z_float(DT_FLOAT, TensorShape(expected_shape));
83   test::FillValues<float>(&expected_z_float, expected_values);
84   test::ExpectTensorNear<float>(expected_z_float, z_float, tolerance);
85 }
86 
TestMulShape(const std::vector<int64> & x_shape,const std::vector<int64> & y_shape)87 void TestMulShape(const std::vector<int64>& x_shape,
88                   const std::vector<int64>& y_shape) {
89   const size_t x_num_elements = TensorShape(x_shape).num_elements();
90   std::vector<float> x_values(x_num_elements);
91   for (int i = 0; i < x_num_elements; ++i) {
92     x_values[i] = i % 256;
93   }
94   const float x_min_value = 0.0f;
95   const float x_max_value = 256.0f;
96 
97   const size_t y_num_elements = TensorShape(y_shape).num_elements();
98   std::vector<float> y_values(y_num_elements);
99   for (int i = 0; i < y_num_elements; ++i) {
100     y_values[i] = ((i + 23) % 123) - 50;
101   }
102   const float y_min_value = -150.0f;
103   const float y_max_value = 150.0f;
104 
105   Scope root = Scope::NewRootScope();
106 
107   Tensor x_float_tensor(DT_FLOAT, TensorShape(x_shape));
108   test::FillValues<float>(&x_float_tensor, x_values);
109   Output x = Const(root.WithOpName("x"), Input::Initializer(x_float_tensor));
110 
111   Tensor y_float_tensor(DT_FLOAT, TensorShape(y_shape));
112   test::FillValues<float>(&y_float_tensor, y_values);
113   Output y = Const(root.WithOpName("y"), Input::Initializer(y_float_tensor));
114 
115   Mul mul = Mul(root.WithOpName("mul"), x, y);
116 
117   TF_EXPECT_OK(root.status());
118 
119   ClientSession session(root);
120   std::vector<Tensor> outputs;
121   TF_EXPECT_OK(session.Run(ClientSession::FeedType(), {mul.z}, &outputs));
122 
123   const Tensor& expected_values_tensor = outputs[0];
124   const float* expected_values_data =
125       expected_values_tensor.flat<float>().data();
126   std::vector<float> expected_values(
127       expected_values_data,
128       expected_values_data + expected_values_tensor.NumElements());
129   std::vector<int64> expected_shape;
130   for (const int64_t dim : expected_values_tensor.shape().dim_sizes()) {
131     expected_shape.push_back(dim);
132   }
133   TestMul(x_shape, x_values, x_min_value, x_max_value, y_shape, y_values,
134           y_min_value, y_max_value, expected_shape, expected_values, 256.0);
135 }
136 
TimeMul(const std::vector<int64> & x_shape,const std::vector<int64> & y_shape,int64_t iterations)137 void TimeMul(const std::vector<int64>& x_shape,
138              const std::vector<int64>& y_shape, int64_t iterations) {
139   TestMulShape(x_shape, y_shape);
140 
141   Scope root = Scope::NewRootScope();
142 
143   Tensor x_quantized_tensor(DT_QUINT8, TensorShape(x_shape));
144   Output placeholder = Placeholder(root.WithOpName("placeholder"), DT_QUINT8);
145   Output x_min = Const(root.WithOpName("x_min"), 0.0f);
146   Output x_max = Const(root.WithOpName("x_max"), 1.0f);
147 
148   Tensor y_quantized_tensor(DT_QUINT8, TensorShape(y_shape));
149   Output y =
150       Const(root.WithOpName("y"), Input::Initializer(y_quantized_tensor));
151   Output y_min = Const(root.WithOpName("y_min"), 0.0f);
152   Output y_max = Const(root.WithOpName("y_max"), 1.0f);
153 
154   QuantizedMul mul = QuantizedMul(root.WithOpName("mul"), placeholder, y, x_min,
155                                   x_max, y_min, y_max);
156 
157   TF_EXPECT_OK(root.status());
158 
159   ClientSession session(root);
160   std::vector<Tensor> outputs;
161 
162   int64_t total_duration = 0;
163   for (int i = 0; i < iterations; ++i) {
164     const int64_t start_time = Env::Default()->NowMicros();
165     TF_EXPECT_OK(session.Run({{placeholder, x_quantized_tensor}},
166                              {mul.z, mul.min_z, mul.max_z}, &outputs));
167     const int64_t end_time = Env::Default()->NowMicros();
168     total_duration += end_time - start_time;
169   }
170   const int64_t one_run_duration = total_duration / iterations;
171 
172   const int64_t num_ops = outputs[0].NumElements();
173 
174   const double million_ops_per_second =
175       (iterations * num_ops) / static_cast<double>(total_duration);
176 
177   LOG(INFO) << "TimeMul: " << TensorShape(x_shape).DebugString() << " * "
178             << TensorShape(y_shape).DebugString()
179             << ": iterations=" << iterations
180             << ", MOps/s=" << million_ops_per_second
181             << ", one_run_duration=" << one_run_duration
182             << ", total_duration=" << total_duration;
183 }
184 
TestManualScalar()185 void TestManualScalar() {
186   TestMul(
187       {10}, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f}, 0.0f,
188       10.0f, {1}, {10.0f}, -100.0f, 100.0f, {10},
189       {10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f},
190       3.0f);
191   TestMul(
192       {1}, {10.0f}, -100.0f, 100.0f, {10},
193       {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f}, 0.0f,
194       10.0f, {10},
195       {10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f},
196       3.0f);
197 }
198 
TestScalar()199 void TestScalar() {
200   TestMulShape({100}, {1});
201   TestMulShape({1}, {100});
202 }
203 
TestManualVector()204 void TestManualVector() {
205   TestMul({10}, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f},
206           0.0f, 10.0f, {10},
207           {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f}, 0.0f,
208           10.0f, {10},
209           {1.0f, 4.0f, 9.0f, 16.0f, 25.0f, 36.0f, 49.0f, 64.0f, 81.0f, 100.0f},
210           3.0f);
211 }
212 
TestVector()213 void TestVector() { TestMulShape({100}, {100}); }
214 
TestManualVectorTimesTensor()215 void TestManualVectorTimesTensor() {
216   TestMul(
217       {10}, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f}, 0.0f,
218       10.0f, {2, 10},
219       {1.0f,  2.0f,  3.0f,  4.0f,  5.0f,  6.0f,  7.0f,  8.0f,  9.0f,  10.0f,
220        11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f, 20.0f},
221       0.0f, 20.0f, {2, 10}, {1.0f,  4.0f,  9.0f,   16.0f,  25.0f,  36.0f, 49.0f,
222                              64.0f, 81.0f, 100.0f, 11.0f,  24.0f,  39.0f, 56.0f,
223                              75.0f, 96.0f, 119.0f, 144.0f, 171.0f, 200.0f},
224       3.0f);
225   TestMul({2, 10}, {1.0f,  2.0f,  3.0f,  4.0f,  5.0f,  6.0f,  7.0f,
226                     8.0f,  9.0f,  10.0f, 11.0f, 12.0f, 13.0f, 14.0f,
227                     15.0f, 16.0f, 17.0f, 18.0f, 19.0f, 20.0f},
228           0.0f, 20.0f, {10},
229           {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f}, 0.0f,
230           10.0f, {2, 10}, {1.0f,  4.0f,  9.0f,   16.0f,  25.0f,  36.0f, 49.0f,
231                            64.0f, 81.0f, 100.0f, 11.0f,  24.0f,  39.0f, 56.0f,
232                            75.0f, 96.0f, 119.0f, 144.0f, 171.0f, 200.0f},
233           3.0f);
234   TestMul(
235       {5, 2}, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f},
236       0.0f, 10.0f, {2, 5, 2},
237       {1.0f,  2.0f,  3.0f,  4.0f,  5.0f,  6.0f,  7.0f,  8.0f,  9.0f,  10.0f,
238        11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f, 20.0f},
239       0.0f, 20.0f, {2, 5, 2},
240       {1.0f,  4.0f,  9.0f,   16.0f,  25.0f,  36.0f, 49.0f,
241        64.0f, 81.0f, 100.0f, 11.0f,  24.0f,  39.0f, 56.0f,
242        75.0f, 96.0f, 119.0f, 144.0f, 171.0f, 200.0f},
243       3.0f);
244 }
245 
TestVectorTimesTensor()246 void TestVectorTimesTensor() {
247   TestMulShape({100}, {2, 100});
248   TestMulShape({2, 100}, {100});
249   TestMulShape({5, 2}, {2, 5, 2});
250 }
251 
BenchmarkTensorScalar()252 void BenchmarkTensorScalar() {
253   TimeMul({200}, {1}, 10000);
254   TimeMul({10000}, {1}, 1000);
255   TimeMul({1000000}, {1}, 100);
256   TimeMul({10000000}, {1}, 100);
257 }
258 
BenchmarkVector()259 void BenchmarkVector() {
260   TimeMul({200}, {200}, 10000);
261   TimeMul({10000}, {10000}, 1000);
262   TimeMul({1000000}, {1000000}, 100);
263   TimeMul({10000000}, {10000000}, 100);
264 }
265 
BenchmarkVectorTimesTensor()266 void BenchmarkVectorTimesTensor() {
267   TimeMul({10, 20}, {20}, 10000);
268   TimeMul({10, 1000}, {1000}, 1000);
269   TimeMul({1000, 1000}, {1000}, 100);
270   TimeMul({10000, 1000}, {1000}, 100);
271   TimeMul({100, 100}, {100}, 1000);
272   TimeMul({10000, 100}, {100}, 100);
273   TimeMul({100000, 100}, {100}, 100);
274 }
275 
276 }  // namespace
277 }  // namespace ops
278 }  // namespace tensorflow
279 
280 #define RUN_TEST(t) \
281   TEST(QuantizedAddOpTest, t) { tensorflow::ops::t(); }
282 
283 RUN_TEST(TestManualScalar);
284 RUN_TEST(TestManualVector);
285 RUN_TEST(TestManualVectorTimesTensor);
286 RUN_TEST(TestScalar);
287 RUN_TEST(TestVector);
288 RUN_TEST(TestVectorTimesTensor);
289 
290 #if defined(__ANDROID__)
291 
292 RUN_TEST(BenchmarkTensorScalar);
293 RUN_TEST(BenchmarkVector);
294 RUN_TEST(BenchmarkVectorTimesTensor);
295 
296 #endif  // __ANDROID__
297 
main(int argc,char ** argv)298 int main(int argc, char** argv) {
299   // On Linux, add: absl::SetFlag(&FLAGS_logtostderr, true);
300   ::testing::InitGoogleTest(&argc, argv);
301   return RUN_ALL_TESTS();
302 }
303