Home | History | Annotate | Download | only in kernels
      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 
     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 
     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 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 
    137 void TimeMul(const std::vector<int64>& x_shape,
    138              const std::vector<int64>& y_shape, int64 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 total_duration = 0;
    163   for (int i = 0; i < iterations; ++i) {
    164     const int64 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 end_time = Env::Default()->NowMicros();
    168     total_duration += end_time - start_time;
    169   }
    170   const int64 one_run_duration = total_duration / iterations;
    171 
    172   const int64 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 
    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 
    199 void TestScalar() {
    200   TestMulShape({100}, {1});
    201   TestMulShape({1}, {100});
    202 }
    203 
    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 
    213 void TestVector() { TestMulShape({100}, {100}); }
    214 
    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 
    246 void TestVectorTimesTensor() {
    247   TestMulShape({100}, {2, 100});
    248   TestMulShape({2, 100}, {100});
    249   TestMulShape({5, 2}, {2, 5, 2});
    250 }
    251 
    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 
    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 
    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 
    298 int main(int argc, char** argv) {
    299   // On Linux, add: FLAGS_logtostderr = true;
    300   ::testing::InitGoogleTest(&argc, argv);
    301   return RUN_ALL_TESTS();
    302 }
    303