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 
     19 #include "tensorflow/core/framework/allocator.h"
     20 #include "tensorflow/core/framework/fake_input.h"
     21 #include "tensorflow/core/framework/node_def_builder.h"
     22 #include "tensorflow/core/framework/op_kernel.h"
     23 #include "tensorflow/core/framework/summary.pb.h"
     24 #include "tensorflow/core/framework/tensor.h"
     25 #include "tensorflow/core/framework/types.h"
     26 #include "tensorflow/core/framework/types.pb.h"
     27 #include "tensorflow/core/kernels/ops_testutil.h"
     28 #include "tensorflow/core/kernels/ops_util.h"
     29 #include "tensorflow/core/lib/core/status_test_util.h"
     30 #include "tensorflow/core/lib/histogram/histogram.h"
     31 #include "tensorflow/core/lib/strings/strcat.h"
     32 #include "tensorflow/core/platform/env.h"
     33 #include "tensorflow/core/platform/logging.h"
     34 #include "tensorflow/core/platform/protobuf.h"
     35 #include "tensorflow/core/platform/test.h"
     36 
     37 namespace tensorflow {
     38 namespace {
     39 
     40 static void EXPECT_SummaryMatches(const Summary& actual,
     41                                   const string& expected_str) {
     42   Summary expected;
     43   CHECK(protobuf::TextFormat::ParseFromString(expected_str, &expected));
     44   EXPECT_EQ(expected.DebugString(), actual.DebugString());
     45 }
     46 
     47 class SummaryScalarOpTest : public OpsTestBase {
     48  protected:
     49   void MakeOp(DataType dt) {
     50     TF_ASSERT_OK(NodeDefBuilder("myop", "ScalarSummary")
     51                      .Input(FakeInput())
     52                      .Input(FakeInput(dt))
     53                      .Finalize(node_def()));
     54     TF_ASSERT_OK(InitOp());
     55   }
     56 };
     57 
     58 TEST_F(SummaryScalarOpTest, SimpleFloat) {
     59   MakeOp(DT_FLOAT);
     60 
     61   // Feed and run
     62   AddInputFromArray<string>(TensorShape({3}), {"tag1", "tag2", "tag3"});
     63   AddInputFromArray<float>(TensorShape({3}), {1.0f, -0.73f, 10000.0f});
     64   TF_ASSERT_OK(RunOpKernel());
     65 
     66   // Check the output size.
     67   Tensor* out_tensor = GetOutput(0);
     68   ASSERT_EQ(0, out_tensor->dims());
     69   Summary summary;
     70   ParseProtoUnlimited(&summary, out_tensor->scalar<string>()());
     71   EXPECT_SummaryMatches(summary, R"(
     72       value { tag: 'tag1' simple_value: 1.0 }
     73       value { tag: 'tag2' simple_value: -0.73 }
     74       value { tag: 'tag3' simple_value: 10000.0 }
     75   )");
     76 }
     77 
     78 TEST_F(SummaryScalarOpTest, SimpleDouble) {
     79   MakeOp(DT_DOUBLE);
     80 
     81   // Feed and run
     82   AddInputFromArray<string>(TensorShape({3}), {"tag1", "tag2", "tag3"});
     83   AddInputFromArray<double>(TensorShape({3}), {1.0, -0.73, 10000.0});
     84   TF_ASSERT_OK(RunOpKernel());
     85 
     86   // Check the output size.
     87   Tensor* out_tensor = GetOutput(0);
     88   ASSERT_EQ(0, out_tensor->dims());
     89   Summary summary;
     90   ParseProtoUnlimited(&summary, out_tensor->scalar<string>()());
     91   EXPECT_SummaryMatches(summary, R"(
     92       value { tag: 'tag1' simple_value: 1.0 }
     93       value { tag: 'tag2' simple_value: -0.73 }
     94       value { tag: 'tag3' simple_value: 10000.0 }
     95   )");
     96 }
     97 
     98 TEST_F(SummaryScalarOpTest, SimpleHalf) {
     99   MakeOp(DT_HALF);
    100 
    101   // Feed and run
    102   AddInputFromList<string>(TensorShape({3}), {"tag1", "tag2", "tag3"});
    103   AddInputFromList<Eigen::half>(TensorShape({3}), {1.0, -2.0, 10000.0});
    104   TF_ASSERT_OK(RunOpKernel());
    105 
    106   // Check the output size.
    107   Tensor* out_tensor = GetOutput(0);
    108   ASSERT_EQ(0, out_tensor->dims());
    109   Summary summary;
    110   ParseProtoUnlimited(&summary, out_tensor->scalar<string>()());
    111   EXPECT_SummaryMatches(summary, R"(
    112       value { tag: 'tag1' simple_value: 1.0 }
    113       value { tag: 'tag2' simple_value: -2.0 }
    114       value { tag: 'tag3' simple_value: 10000.0 }
    115   )");
    116 }
    117 
    118 TEST_F(SummaryScalarOpTest, Error_MismatchedSize) {
    119   MakeOp(DT_FLOAT);
    120 
    121   // Feed and run
    122   AddInputFromArray<string>(TensorShape({2}), {"tag1", "tag2"});
    123   AddInputFromArray<float>(TensorShape({3}), {1.0f, -0.73f, 10000.0f});
    124   Status s = RunOpKernel();
    125   EXPECT_TRUE(StringPiece(s.ToString()).contains("not the same shape")) << s;
    126 }
    127 
    128 TEST_F(SummaryScalarOpTest, Error_WrongDimsTags) {
    129   MakeOp(DT_FLOAT);
    130 
    131   // Feed and run
    132   AddInputFromArray<string>(TensorShape({2, 1}), {"tag1", "tag2"});
    133   AddInputFromArray<float>(TensorShape({2}), {1.0f, -0.73f});
    134   Status s = RunOpKernel();
    135   EXPECT_TRUE(
    136       StringPiece(s.ToString()).contains("tags and values not the same shape"))
    137       << s;
    138 }
    139 
    140 TEST_F(SummaryScalarOpTest, Error_WrongDimsValues) {
    141   MakeOp(DT_FLOAT);
    142 
    143   // Feed and run
    144   AddInputFromArray<string>(TensorShape({2}), {"tag1", "tag2"});
    145   AddInputFromArray<float>(TensorShape({2, 1}), {1.0f, -0.73f});
    146   Status s = RunOpKernel();
    147   EXPECT_TRUE(
    148       StringPiece(s.ToString()).contains("tags and values not the same shape"))
    149       << s;
    150 }
    151 
    152 // --------------------------------------------------------------------------
    153 // SummaryHistoOp
    154 // --------------------------------------------------------------------------
    155 class SummaryHistoOpTest : public OpsTestBase {
    156  protected:
    157   void MakeOp(DataType dt) {
    158     TF_ASSERT_OK(NodeDefBuilder("myop", "HistogramSummary")
    159                      .Input(FakeInput())
    160                      .Input(FakeInput(dt))
    161                      .Finalize(node_def()));
    162     TF_ASSERT_OK(InitOp());
    163   }
    164 };
    165 
    166 TEST_F(SummaryHistoOpTest, SimpleFloat) {
    167   MakeOp(DT_FLOAT);
    168 
    169   // Feed and run
    170   AddInputFromArray<string>(TensorShape({}), {"taghisto"});
    171   AddInputFromArray<float>(TensorShape({3, 2}),
    172                            {0.1f, -0.7f, 4.1f, 4., 5.f, 4.f});
    173   TF_ASSERT_OK(RunOpKernel());
    174 
    175   // Check the output size.
    176   Tensor* out_tensor = GetOutput(0);
    177   ASSERT_EQ(0, out_tensor->dims());
    178   Summary summary;
    179   ParseProtoUnlimited(&summary, out_tensor->scalar<string>()());
    180   ASSERT_EQ(summary.value_size(), 1);
    181   EXPECT_EQ(summary.value(0).tag(), "taghisto");
    182   histogram::Histogram histo;
    183   EXPECT_TRUE(histo.DecodeFromProto(summary.value(0).histo()));
    184   EXPECT_EQ(
    185       "Count: 6  Average: 2.7500  StdDev: 2.20\n"
    186       "Min: -0.7000  Median: 3.9593  Max: 5.0000\n"
    187       "------------------------------------------------------\n"
    188       "[      -0.76,      -0.69 )       1  16.667%  16.667% ###\n"
    189       "[      0.093,        0.1 )       1  16.667%  33.333% ###\n"
    190       "[        3.8,        4.2 )       3  50.000%  83.333% ##########\n"
    191       "[        4.6,        5.1 )       1  16.667% 100.000% ###\n",
    192       histo.ToString());
    193 }
    194 
    195 TEST_F(SummaryHistoOpTest, SimpleDouble) {
    196   MakeOp(DT_DOUBLE);
    197 
    198   // Feed and run
    199   AddInputFromArray<string>(TensorShape({}), {"taghisto"});
    200   AddInputFromArray<double>(TensorShape({3, 2}), {0.1, -0.7, 4.1, 4., 5., 4.});
    201   TF_ASSERT_OK(RunOpKernel());
    202 
    203   // Check the output size.
    204   Tensor* out_tensor = GetOutput(0);
    205   ASSERT_EQ(0, out_tensor->dims());
    206   Summary summary;
    207   ParseProtoUnlimited(&summary, out_tensor->scalar<string>()());
    208   ASSERT_EQ(summary.value_size(), 1);
    209   EXPECT_EQ(summary.value(0).tag(), "taghisto");
    210   histogram::Histogram histo;
    211   EXPECT_TRUE(histo.DecodeFromProto(summary.value(0).histo()));
    212   EXPECT_EQ(
    213       "Count: 6  Average: 2.7500  StdDev: 2.20\n"
    214       "Min: -0.7000  Median: 3.9593  Max: 5.0000\n"
    215       "------------------------------------------------------\n"
    216       "[      -0.76,      -0.69 )       1  16.667%  16.667% ###\n"
    217       "[      0.093,        0.1 )       1  16.667%  33.333% ###\n"
    218       "[        3.8,        4.2 )       3  50.000%  83.333% ##########\n"
    219       "[        4.6,        5.1 )       1  16.667% 100.000% ###\n",
    220       histo.ToString());
    221 }
    222 
    223 TEST_F(SummaryHistoOpTest, SimpleHalf) {
    224   MakeOp(DT_HALF);
    225 
    226   // Feed and run
    227   AddInputFromList<string>(TensorShape({}), {"taghisto"});
    228   AddInputFromList<Eigen::half>(TensorShape({3, 2}),
    229                                 {0.1, -0.7, 4.1, 4., 5., 4.});
    230   TF_ASSERT_OK(RunOpKernel());
    231 
    232   // Check the output size.
    233   Tensor* out_tensor = GetOutput(0);
    234   ASSERT_EQ(0, out_tensor->dims());
    235   Summary summary;
    236   ParseProtoUnlimited(&summary, out_tensor->scalar<string>()());
    237   ASSERT_EQ(summary.value_size(), 1);
    238   EXPECT_EQ(summary.value(0).tag(), "taghisto");
    239   histogram::Histogram histo;
    240   EXPECT_TRUE(histo.DecodeFromProto(summary.value(0).histo()));
    241   EXPECT_EQ(
    242       "Count: 6  Average: 2.7502  StdDev: 2.20\n"
    243       "Min: -0.7002  Median: 3.9593  Max: 5.0000\n"
    244       "------------------------------------------------------\n"
    245       "[      -0.76,      -0.69 )       1  16.667%  16.667% ###\n"
    246       "[      0.093,        0.1 )       1  16.667%  33.333% ###\n"
    247       "[        3.8,        4.2 )       3  50.000%  83.333% ##########\n"
    248       "[        4.6,        5.1 )       1  16.667% 100.000% ###\n",
    249       histo.ToString());
    250 }
    251 
    252 TEST_F(SummaryHistoOpTest, Error_WrongDimsTags) {
    253   MakeOp(DT_FLOAT);
    254 
    255   // Feed and run
    256   AddInputFromArray<string>(TensorShape({2, 1}), {"tag1", "tag2"});
    257   AddInputFromArray<float>(TensorShape({2}), {1.0f, -0.73f});
    258   Status s = RunOpKernel();
    259   EXPECT_TRUE(StringPiece(s.ToString()).contains("tags must be scalar")) << s;
    260 }
    261 
    262 TEST_F(SummaryHistoOpTest, Error_TooManyTagValues) {
    263   MakeOp(DT_FLOAT);
    264 
    265   // Feed and run
    266   AddInputFromArray<string>(TensorShape({2}), {"tag1", "tag2"});
    267   AddInputFromArray<float>(TensorShape({2, 1}), {1.0f, -0.73f});
    268   Status s = RunOpKernel();
    269   EXPECT_TRUE(StringPiece(s.ToString()).contains("tags must be scalar")) << s;
    270 }
    271 
    272 // --------------------------------------------------------------------------
    273 // SummaryMergeOp
    274 // --------------------------------------------------------------------------
    275 class SummaryMergeOpTest : public OpsTestBase {
    276  protected:
    277   void MakeOp(int num_inputs) {
    278     TF_ASSERT_OK(NodeDefBuilder("myop", "MergeSummary")
    279                      .Input(FakeInput(num_inputs))
    280                      .Finalize(node_def()));
    281     TF_ASSERT_OK(InitOp());
    282   }
    283 };
    284 
    285 TEST_F(SummaryMergeOpTest, Simple) {
    286   MakeOp(1);
    287 
    288   // Feed and run
    289   Summary s1;
    290   ASSERT_TRUE(protobuf::TextFormat::ParseFromString(
    291       "value { tag: \"tag1\" simple_value: 1.0 } "
    292       "value { tag: \"tag2\" simple_value: -0.73 } ",
    293       &s1));
    294   Summary s2;
    295   ASSERT_TRUE(protobuf::TextFormat::ParseFromString(
    296       "value { tag: \"tag3\" simple_value: 10000.0 }", &s2));
    297   Summary s3;
    298   ASSERT_TRUE(protobuf::TextFormat::ParseFromString(
    299       "value { tag: \"tag4\" simple_value: 11.0 }", &s3));
    300 
    301   AddInputFromArray<string>(
    302       TensorShape({3}),
    303       {s1.SerializeAsString(), s2.SerializeAsString(), s3.SerializeAsString()});
    304   TF_ASSERT_OK(RunOpKernel());
    305 
    306   // Check the output size.
    307   Tensor* out_tensor = GetOutput(0);
    308   ASSERT_EQ(0, out_tensor->dims());
    309   Summary summary;
    310   ParseProtoUnlimited(&summary, out_tensor->scalar<string>()());
    311 
    312   EXPECT_SummaryMatches(summary,
    313                         "value { tag: \"tag1\" simple_value: 1.0 } "
    314                         "value { tag: \"tag2\" simple_value: -0.73 } "
    315                         "value { tag: \"tag3\" simple_value: 10000.0 }"
    316                         "value { tag: \"tag4\" simple_value: 11.0 }");
    317 }
    318 
    319 TEST_F(SummaryMergeOpTest, Simple_MultipleInputs) {
    320   MakeOp(3);
    321 
    322   // Feed and run
    323   Summary s1;
    324   ASSERT_TRUE(protobuf::TextFormat::ParseFromString(
    325       "value { tag: \"tag1\" simple_value: 1.0 } "
    326       "value { tag: \"tag2\" simple_value: -0.73 } ",
    327       &s1));
    328   Summary s2;
    329   ASSERT_TRUE(protobuf::TextFormat::ParseFromString(
    330       "value { tag: \"tag3\" simple_value: 10000.0 }", &s2));
    331   Summary s3;
    332   ASSERT_TRUE(protobuf::TextFormat::ParseFromString(
    333       "value { tag: \"tag4\" simple_value: 11.0 }", &s3));
    334 
    335   AddInputFromArray<string>(TensorShape({}), {s1.SerializeAsString()});
    336   AddInputFromArray<string>(TensorShape({}), {s2.SerializeAsString()});
    337   AddInputFromArray<string>(TensorShape({}), {s3.SerializeAsString()});
    338   TF_ASSERT_OK(RunOpKernel());
    339 
    340   // Check the output size.
    341   Tensor* out_tensor = GetOutput(0);
    342   ASSERT_EQ(0, out_tensor->dims());
    343   Summary summary;
    344   ParseProtoUnlimited(&summary, out_tensor->scalar<string>()());
    345 
    346   EXPECT_SummaryMatches(summary,
    347                         "value { tag: \"tag1\" simple_value: 1.0 } "
    348                         "value { tag: \"tag2\" simple_value: -0.73 } "
    349                         "value { tag: \"tag3\" simple_value: 10000.0 }"
    350                         "value { tag: \"tag4\" simple_value: 11.0 }");
    351 }
    352 
    353 TEST_F(SummaryMergeOpTest, Error_MismatchedSize) {
    354   MakeOp(1);
    355 
    356   // Feed and run
    357   Summary s1;
    358   ASSERT_TRUE(protobuf::TextFormat::ParseFromString(
    359       "value { tag: \"tag1\" simple_value: 1.0 } "
    360       "value { tag: \"tagduplicate\" simple_value: -0.73 } ",
    361       &s1));
    362   Summary s2;
    363   ASSERT_TRUE(protobuf::TextFormat::ParseFromString(
    364       "value { tag: \"tagduplicate\" simple_value: 1.0 } ", &s2));
    365   AddInputFromArray<string>(TensorShape({2}),
    366                             {s1.SerializeAsString(), s2.SerializeAsString()});
    367   Status s = RunOpKernel();
    368   EXPECT_TRUE(StringPiece(s.ToString()).contains("Duplicate tag")) << s;
    369 }
    370 
    371 }  // namespace
    372 }  // namespace tensorflow
    373