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 #include <functional>
     17 #include <memory>
     18 #include <vector>
     19 
     20 #include "tensorflow/cc/ops/array_ops.h"
     21 #include "tensorflow/cc/ops/const_op.h"
     22 #include "tensorflow/core/common_runtime/kernel_benchmark_testlib.h"
     23 #include "tensorflow/core/framework/allocator.h"
     24 #include "tensorflow/core/framework/fake_input.h"
     25 #include "tensorflow/core/framework/node_def_builder.h"
     26 #include "tensorflow/core/framework/op_kernel.h"
     27 #include "tensorflow/core/framework/tensor.h"
     28 #include "tensorflow/core/framework/tensor_testutil.h"
     29 #include "tensorflow/core/framework/types.h"
     30 #include "tensorflow/core/kernels/ops_testutil.h"
     31 #include "tensorflow/core/lib/core/status_test_util.h"
     32 #include "tensorflow/core/platform/test_benchmark.h"
     33 
     34 namespace tensorflow {
     35 namespace {
     36 
     37 class DequantizeOpTest : public OpsTestBase {
     38  protected:
     39   template <typename T>
     40   void ComputeDequantizeMinCombinedUsingEigen(const Tensor& input,
     41                                               float min_range, float max_range,
     42                                               Tensor* output) {
     43     float half_range =
     44         !std::is_signed<T>::value
     45             ? 0.0f
     46             : (static_cast<float>(std::numeric_limits<T>::max()) -
     47                std::numeric_limits<T>::min() + 1) /
     48                   2.0f;
     49     const float scale_factor =
     50         (max_range - min_range) /
     51         (static_cast<float>(std::numeric_limits<T>::max()) -
     52          std::numeric_limits<T>::min());
     53     output->flat<float>() =
     54         ((input.flat<T>().template cast<int>().template cast<float>() +
     55           half_range) *
     56          scale_factor) +
     57         min_range;
     58   }
     59 
     60   // Compares dequantize min vs the same using eigen. This tests that a change
     61   // to not use eigen gives equivalent results to using eigen.
     62   template <typename T>
     63   void RunDequantizeMinCombinedTest(float min_range, float max_range) {
     64     TF_ASSERT_OK(NodeDefBuilder("dequantize_op", "Dequantize")
     65                      .Input(FakeInput(DataTypeToEnum<T>::v()))
     66                      .Input(FakeInput(DT_FLOAT))
     67                      .Input(FakeInput(DT_FLOAT))
     68                      .Attr("T", DataTypeToEnum<T>::v())
     69                      .Attr("mode", "MIN_COMBINED")
     70                      .Finalize(node_def()));
     71     TF_ASSERT_OK(InitOp());
     72 
     73     std::vector<T> input;
     74     for (int64 i = std::numeric_limits<T>::min();
     75          i < std::numeric_limits<T>::max(); ++i) {
     76       input.push_back(static_cast<T>(i));
     77     }
     78     TensorShape shape({static_cast<int64>(input.size())});
     79     AddInputFromArray<T>(shape, input);
     80     AddInputFromArray<float>(TensorShape({}), {min_range});
     81     AddInputFromArray<float>(TensorShape({}), {max_range});
     82     TF_ASSERT_OK(RunOpKernel());
     83     Tensor expected(allocator(), DT_FLOAT, shape);
     84     ComputeDequantizeMinCombinedUsingEigen<T>(GetInput(0), min_range, max_range,
     85                                               &expected);
     86     test::ExpectTensorEqual<float>(expected, *GetOutput(0));
     87   }
     88 
     89   template <typename T>
     90   void RunDequantizeScaledTest(float min_range, float max_range, int input_int,
     91                                float expected_output) {
     92     TF_ASSERT_OK(NodeDefBuilder("dequantize_op", "Dequantize")
     93                      .Input(FakeInput(DataTypeToEnum<T>::v()))
     94                      .Input(FakeInput(DT_FLOAT))
     95                      .Input(FakeInput(DT_FLOAT))
     96                      .Attr("T", DataTypeToEnum<T>::v())
     97                      .Attr("mode", "SCALED")
     98                      .Finalize(node_def()));
     99     TF_ASSERT_OK(InitOp());
    100 
    101     std::vector<T> input;
    102     input.push_back(static_cast<T>(input_int));
    103     TensorShape shape({static_cast<int64>(input.size())});
    104     AddInputFromArray<T>(shape, input);
    105     AddInputFromArray<float>(TensorShape({}), {min_range});
    106     AddInputFromArray<float>(TensorShape({}), {max_range});
    107     TF_ASSERT_OK(RunOpKernel());
    108     Tensor expected(allocator(), DT_FLOAT, shape);
    109     test::FillValues<float>(&expected, {expected_output});
    110     test::ExpectClose(expected, *GetOutput(0));
    111   }
    112 };
    113 
    114 TEST_F(DequantizeOpTest, DequantizeMinCombinedQuint8) {
    115   RunDequantizeMinCombinedTest<quint8>(0, 255.0f);
    116 }
    117 TEST_F(DequantizeOpTest, DequantizeMinCombinedQint8) {
    118   RunDequantizeMinCombinedTest<qint8>(0, 255.0f);
    119 }
    120 TEST_F(DequantizeOpTest, DequantizeMinCombinedQint16) {
    121   RunDequantizeMinCombinedTest<qint16>(0, 255.0f);
    122 }
    123 TEST_F(DequantizeOpTest, DequantizeMinCombinedQuint16) {
    124   RunDequantizeMinCombinedTest<quint16>(0, 255.0f);
    125 }
    126 
    127 TEST_F(DequantizeOpTest, DequantizeScaledQuint8Zero) {
    128   RunDequantizeScaledTest<quint8>(-255.0f, 127.0f, 0, 0.0);
    129 }
    130 TEST_F(DequantizeOpTest, DequantizeScaledQuint8ScaleIdentity) {
    131   RunDequantizeScaledTest<quint8>(-255.0f, 127.0f, 127, 127.0);
    132 }
    133 TEST_F(DequantizeOpTest, DequantizeScaledQuint8ScaleDown) {
    134   RunDequantizeScaledTest<quint8>(-1.0f, 2.0f, 255, 2.0);
    135 }
    136 TEST_F(DequantizeOpTest, DequantizeScaledQuint8ScaleUp) {
    137   RunDequantizeScaledTest<quint8>(200.0f, 400.0f, 255, 400.0);
    138 }
    139 
    140 TEST_F(DequantizeOpTest, DequantizeScaledQint8Zero) {
    141   RunDequantizeScaledTest<qint8>(-255.0f, 127.0f, 0, 0.0);
    142 }
    143 TEST_F(DequantizeOpTest, DequantizeScaledQint8ScaleIdentity) {
    144   RunDequantizeScaledTest<qint8>(-10.0f, 127.0f, -127, -127.0);
    145 }
    146 TEST_F(DequantizeOpTest, DequantizeScaledQint8ScaleDown) {
    147   RunDequantizeScaledTest<qint8>(-2.0f, 1.0f, -127, -2.0);
    148 }
    149 TEST_F(DequantizeOpTest, DequantizeScaledQint8ScaleUp) {
    150   RunDequantizeScaledTest<qint8>(-1.0f, 300.0f, 42, 99.212601);
    151 }
    152 
    153 template <typename T>
    154 static void BM_DequantizeMinCombinedCpu(int iters) {
    155   auto root = Scope::NewRootScope().ExitOnError();
    156   const int64 num_values = 1500 * 250;
    157   std::vector<T> inputs;
    158   inputs.reserve(num_values);
    159   for (int i = 0; i < num_values; ++i) inputs.push_back(i);
    160   ops::Dequantize(root, test::AsTensor<T>(inputs), test::AsScalar<float>(-1.5f),
    161                   test::AsScalar<float>(20.5f),
    162                   ops::Dequantize::Attrs().Mode("MIN_COMBINED"));
    163   TF_CHECK_OK(root.status());
    164   Graph* g = new Graph(OpRegistry::Global());
    165   TF_CHECK_OK(root.ToGraph(g));
    166 
    167   test::Benchmark("cpu", g).Run(iters);
    168   testing::BytesProcessed(iters * num_values * (sizeof(float) + sizeof(T)));
    169   testing::ItemsProcessed(iters);
    170 }
    171 
    172 static void BM_DequantizeMinCombinedCpuQuint16(int iters) {
    173   BM_DequantizeMinCombinedCpu<quint16>(iters);
    174 }
    175 
    176 static void BM_DequantizeMinCombinedCpuQint16(int iters) {
    177   BM_DequantizeMinCombinedCpu<qint16>(iters);
    178 }
    179 
    180 static void BM_DequantizeMinCombinedCpuQuint8(int iters) {
    181   BM_DequantizeMinCombinedCpu<quint8>(iters);
    182 }
    183 
    184 static void BM_DequantizeMinCombinedCpuQint8(int iters) {
    185   BM_DequantizeMinCombinedCpu<qint8>(iters);
    186 }
    187 
    188 BENCHMARK(BM_DequantizeMinCombinedCpuQuint16);
    189 BENCHMARK(BM_DequantizeMinCombinedCpuQint16);
    190 BENCHMARK(BM_DequantizeMinCombinedCpuQuint8);
    191 BENCHMARK(BM_DequantizeMinCombinedCpuQint8);
    192 
    193 }  // namespace
    194 }  // namespace tensorflow
    195