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 <vector>
     18 
     19 #include "tensorflow/core/common_runtime/device.h"
     20 #include "tensorflow/core/common_runtime/device_factory.h"
     21 #include "tensorflow/core/framework/allocator.h"
     22 #include "tensorflow/core/framework/fake_input.h"
     23 #include "tensorflow/core/framework/node_def_builder.h"
     24 #include "tensorflow/core/framework/op_kernel.h"
     25 #include "tensorflow/core/framework/tensor.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_testutil.h"
     30 #include "tensorflow/core/kernels/ops_util.h"
     31 #include "tensorflow/core/platform/test.h"
     32 #include "tensorflow/core/platform/test_benchmark.h"
     33 #include "tensorflow/core/public/session.h"
     34 
     35 namespace tensorflow {
     36 
     37 namespace {
     38 
     39 class SparseToDenseTest : public OpsTestBase {
     40  protected:
     41   void MakeOp(int dim, DataType index_type, DataType value_type) {
     42     TF_ASSERT_OK(NodeDefBuilder("sparsetodense", "SparseToDense")
     43                      .Input(FakeInput(index_type))
     44                      .Input(FakeInput(index_type))
     45                      .Input(FakeInput(value_type))
     46                      .Input(FakeInput(value_type))
     47                      .Finalize(node_def()));
     48     TF_ASSERT_OK(InitOp());
     49   }
     50 };
     51 
     52 TEST_F(SparseToDenseTest, OneD_OneValue) {
     53   MakeOp(1, DT_INT32, DT_FLOAT);
     54 
     55   // sparse_indices
     56   AddInputFromArray<int32>(TensorShape({3}), {1, 3, 4});
     57   // output_shape
     58   AddInputFromArray<int32>(TensorShape({1}), {5});
     59   // sparse_values
     60   AddInputFromArray<float>(TensorShape({}), {2});
     61   // default_value
     62   AddInputFromArray<float>(TensorShape({}), {-2});
     63 
     64   TF_ASSERT_OK(RunOpKernel());
     65 
     66   Tensor expected(allocator(), DT_FLOAT, {5});
     67   test::FillValues<float>(&expected, {-2, 2, -2, 2, 2});
     68   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
     69 }
     70 
     71 TEST_F(SparseToDenseTest, OneD_OneValue_int64_double) {
     72   MakeOp(1, DT_INT64, DT_DOUBLE);
     73 
     74   // sparse_indices
     75   AddInputFromArray<int64>(TensorShape({3}), {1, 3, 4});
     76   // output_shape
     77   AddInputFromArray<int64>(TensorShape({1}), {5});
     78   // sparse_values
     79   AddInputFromArray<double>(TensorShape({}), {2});
     80   // default_value
     81   AddInputFromArray<double>(TensorShape({}), {-2});
     82 
     83   TF_ASSERT_OK(RunOpKernel());
     84 
     85   Tensor expected(allocator(), DT_DOUBLE, {5});
     86   test::FillValues<double>(&expected, {-2, 2, -2, 2, 2});
     87   test::ExpectTensorEqual<double>(expected, *GetOutput(0));
     88 }
     89 
     90 TEST_F(SparseToDenseTest, OneD_MultValues) {
     91   MakeOp(1, DT_INT32, DT_FLOAT);
     92 
     93   // sparse_indices
     94   AddInputFromArray<int32>({3}, {1, 3, 4});
     95   // output_shape
     96   AddInputFromArray<int32>({1}, {5});
     97   // sparse_values
     98   AddInputFromArray<float>({3}, {3, 4, 5});
     99   // default_value
    100   AddInputFromArray<float>({}, {-2});
    101 
    102   TF_ASSERT_OK(RunOpKernel());
    103 
    104   Tensor expected(allocator(), DT_FLOAT, {5});
    105   test::FillValues<float>(&expected, {-2, 3, -2, 4, 5});
    106   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
    107 }
    108 
    109 TEST_F(SparseToDenseTest, TwoD_OneValue) {
    110   MakeOp(2, DT_INT32, DT_FLOAT);
    111 
    112   // sparse_indices
    113   AddInputFromArray<int32>(TensorShape({3, 2}), {0, 1, 0, 2, 2, 3});
    114   // output_shape
    115   AddInputFromArray<int32>(TensorShape({2}), {3, 4});
    116   // sparse_values
    117   AddInputFromArray<float>(TensorShape({}), {2});
    118   // default_value
    119   AddInputFromArray<float>(TensorShape({}), {-2});
    120 
    121   TF_ASSERT_OK(RunOpKernel());
    122 
    123   Tensor expected(allocator(), DT_FLOAT, {3, 4});
    124   expected.flat<float>().setConstant(-2);
    125   expected.tensor<float, 2>()(0, 1) = 2;
    126   expected.tensor<float, 2>()(0, 2) = 2;
    127   expected.tensor<float, 2>()(2, 3) = 2;
    128   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
    129 }
    130 
    131 TEST_F(SparseToDenseTest, TwoD_MultValues) {
    132   MakeOp(2, DT_INT32, DT_FLOAT);
    133 
    134   // sparse_indices
    135   AddInputFromArray<int32>(TensorShape({3, 2}), {0, 1, 0, 2, 2, 3});
    136   // output_shape
    137   AddInputFromArray<int32>(TensorShape({2}), {3, 4});
    138   // sparse_values
    139   AddInputFromArray<float>(TensorShape({3}), {3, 4, 5});
    140   // default_value
    141   AddInputFromArray<float>(TensorShape({}), {-2});
    142 
    143   TF_ASSERT_OK(RunOpKernel());
    144 
    145   Tensor expected(allocator(), DT_FLOAT, {3, 4});
    146   expected.flat<float>().setConstant(-2);
    147   expected.tensor<float, 2>()(0, 1) = 3;
    148   expected.tensor<float, 2>()(0, 2) = 4;
    149   expected.tensor<float, 2>()(2, 3) = 5;
    150   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
    151 }
    152 
    153 TEST_F(SparseToDenseTest, ThreeD_OneValue) {
    154   MakeOp(3, DT_INT32, DT_FLOAT);
    155 
    156   // sparse_indices
    157   AddInputFromArray<int32>(TensorShape({3, 3}), {0, 1, 1, 0, 2, 0, 2, 3, 1});
    158   // output_shape
    159   AddInputFromArray<int32>(TensorShape({3}), {3, 4, 2});
    160   // sparse_values
    161   AddInputFromArray<float>(TensorShape({}), {2});
    162   // default_value
    163   AddInputFromArray<float>(TensorShape({}), {-2});
    164 
    165   TF_ASSERT_OK(RunOpKernel());
    166 
    167   Tensor expected(allocator(), DT_FLOAT, {3, 4, 2});
    168   expected.flat<float>().setConstant(-2);
    169   expected.tensor<float, 3>()(0, 1, 1) = 2;
    170   expected.tensor<float, 3>()(0, 2, 0) = 2;
    171   expected.tensor<float, 3>()(2, 3, 1) = 2;
    172   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
    173 }
    174 
    175 TEST_F(SparseToDenseTest, ThreeD_MultValues) {
    176   MakeOp(3, DT_INT32, DT_FLOAT);
    177 
    178   // sparse_indices
    179   AddInputFromArray<int32>(TensorShape({3, 3}), {0, 1, 1, 0, 2, 0, 2, 3, 1});
    180   // output_shape
    181   AddInputFromArray<int32>(TensorShape({3}), {3, 4, 2});
    182   // sparse_values
    183   AddInputFromArray<float>(TensorShape({3}), {3, 4, 5});
    184   // default_value
    185   AddInputFromArray<float>(TensorShape({}), {-2});
    186 
    187   TF_ASSERT_OK(RunOpKernel());
    188 
    189   Tensor expected(allocator(), DT_FLOAT, {3, 4, 2});
    190   expected.flat<float>().setConstant(-2);
    191   expected.tensor<float, 3>()(0, 1, 1) = 3;
    192   expected.tensor<float, 3>()(0, 2, 0) = 4;
    193   expected.tensor<float, 3>()(2, 3, 1) = 5;
    194   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
    195 }
    196 
    197 }  // namespace
    198 
    199 static int BM_Arg(int ndim, int n) { return (ndim * 1000000) + n; }
    200 static int NDIM_from_arg(int bm_arg) { return bm_arg / 1000000; }
    201 static int N_from_arg(int bm_arg) { return bm_arg % 1000000; }
    202 
    203 static void BM_SparseToDense(int iters, const int bm_arg) {
    204   const int NDIM = NDIM_from_arg(bm_arg);
    205   const int N = N_from_arg(bm_arg);
    206   // TODO(zhifengc): Switch to use kernel_benchmark_testlib.h
    207   tensorflow::testing::StopTiming();
    208 
    209   const int IndexDim = (NDIM == 1) ? 0 : 1;
    210 
    211   std::unique_ptr<Device> device(
    212       DeviceFactory::NewDevice("CPU", {}, "/job:a/replica:0/task:0"));
    213 
    214   gtl::InlinedVector<TensorValue, 4> inputs;
    215 
    216   // Create a dense tensor with dims [1, ..., 1, N]
    217   Tensor output_shape(DT_INT32, TensorShape({NDIM}));
    218   Tensor sparse_indices(DT_INT32, TensorShape({N, NDIM}));
    219   Tensor sparse_values(DT_FLOAT, TensorShape({N}));
    220   Tensor default_value(DT_FLOAT, TensorShape({}));
    221   auto output_shape_t = output_shape.vec<int32>();
    222   for (int d = 0; d < NDIM; ++d) {
    223     output_shape_t(d) = (d == IndexDim) ? N : 3;
    224   }
    225 
    226   auto sparse_indices_t = sparse_indices.matrix<int32>();
    227   for (int n = 0; n < N; ++n) {
    228     for (int d = 0; d < NDIM; ++d)
    229       sparse_indices_t(n, d) = (d == IndexDim) ? n : 0;
    230   }
    231 
    232   for (auto* ptr :
    233        {&sparse_indices, &output_shape, &sparse_values, &default_value}) {
    234     inputs.push_back({nullptr, ptr});
    235   }
    236 
    237   NodeDef sparse_node_def;
    238   TF_CHECK_OK(NodeDefBuilder("sparsetodense", "SparseToDense")
    239                   .Input(FakeInput(DT_INT32))
    240                   .Input(FakeInput(DT_INT32))
    241                   .Input(FakeInput(DT_FLOAT))
    242                   .Input(FakeInput(DT_FLOAT))
    243                   .Finalize(&sparse_node_def));
    244 
    245   Status status;
    246   std::unique_ptr<OpKernel> op(CreateOpKernel(DEVICE_CPU, device.get(),
    247                                               cpu_allocator(), sparse_node_def,
    248                                               TF_GRAPH_DEF_VERSION, &status));
    249 
    250   OpKernelContext::Params params;
    251   params.device = device.get();
    252   params.frame_iter = FrameAndIter(0, 0);
    253   params.inputs = &inputs;
    254   params.op_kernel = op.get();
    255   std::vector<AllocatorAttributes> attrs;
    256   test::SetOutputAttrs(&params, &attrs);
    257 
    258   std::unique_ptr<OpKernelContext> sparse_context(new OpKernelContext(&params));
    259   op->Compute(sparse_context.get());
    260   tensorflow::testing::StartTiming();
    261   for (int i = 0; i < iters; ++i) {
    262     delete sparse_context->release_output(0).tensor;
    263     op->Compute(sparse_context.get());
    264     TF_ASSERT_OK(sparse_context->status());
    265   }
    266   tensorflow::testing::StopTiming();
    267 
    268   // processing input, mainly
    269   int64 bytes_per_iter = static_cast<int64>((N + N * NDIM) * sizeof(float));
    270 
    271   tensorflow::testing::BytesProcessed(bytes_per_iter * iters);
    272 }
    273 
    274 BENCHMARK(BM_SparseToDense)
    275     ->Arg(BM_Arg(1, 10))
    276     ->Arg(BM_Arg(1, 100))
    277     ->Arg(BM_Arg(1, 1000))
    278     ->Arg(BM_Arg(1, 10000))
    279     ->Arg(BM_Arg(2, 10))
    280     ->Arg(BM_Arg(2, 100))
    281     ->Arg(BM_Arg(2, 1000))
    282     ->Arg(BM_Arg(2, 10000))
    283     ->Arg(BM_Arg(3, 10))
    284     ->Arg(BM_Arg(3, 100))
    285     ->Arg(BM_Arg(3, 1000))
    286     ->Arg(BM_Arg(3, 10000))
    287     ->Arg(BM_Arg(5, 10))
    288     ->Arg(BM_Arg(5, 100))
    289     ->Arg(BM_Arg(5, 1000))
    290     ->Arg(BM_Arg(5, 10000));
    291 
    292 }  // namespace tensorflow
    293