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 "tensorflow/core/framework/allocator.h"
     17 #include "tensorflow/core/framework/fake_input.h"
     18 #include "tensorflow/core/framework/node_def_builder.h"
     19 #include "tensorflow/core/framework/op_kernel.h"
     20 #include "tensorflow/core/framework/tensor.h"
     21 #include "tensorflow/core/framework/tensor_testutil.h"
     22 #include "tensorflow/core/framework/types.h"
     23 #include "tensorflow/core/framework/types.pb.h"
     24 #include "tensorflow/core/kernels/ops_testutil.h"
     25 #include "tensorflow/core/kernels/ops_util.h"
     26 #include "tensorflow/core/lib/core/status_test_util.h"
     27 #include "tensorflow/core/platform/test.h"
     28 
     29 namespace tensorflow {
     30 
     31 class NonMaxSuppressionOpTest : public OpsTestBase {
     32  protected:
     33   void MakeOp(float iou_threshold) {
     34     TF_EXPECT_OK(NodeDefBuilder("non_max_suppression_op", "NonMaxSuppression")
     35                      .Input(FakeInput(DT_FLOAT))
     36                      .Input(FakeInput(DT_FLOAT))
     37                      .Input(FakeInput(DT_INT32))
     38                      .Attr("iou_threshold", iou_threshold)
     39                      .Finalize(node_def()));
     40     TF_EXPECT_OK(InitOp());
     41   }
     42 };
     43 
     44 TEST_F(NonMaxSuppressionOpTest, TestSelectFromThreeClusters) {
     45   MakeOp(.5);
     46   AddInputFromArray<float>(
     47       TensorShape({6, 4}),
     48       {0, 0,  1, 1,  0, 0.1f,  1, 1.1f,  0, -0.1f, 1, 0.9f,
     49        0, 10, 1, 11, 0, 10.1f, 1, 11.1f, 0, 100,   1, 101});
     50   AddInputFromArray<float>(TensorShape({6}), {.9f, .75f, .6f, .95f, .5f, .3f});
     51   AddInputFromArray<int>(TensorShape({}), {3});
     52   TF_ASSERT_OK(RunOpKernel());
     53 
     54   Tensor expected(allocator(), DT_INT32, TensorShape({3}));
     55   test::FillValues<int>(&expected, {3, 0, 5});
     56   test::ExpectTensorEqual<int>(expected, *GetOutput(0));
     57 }
     58 
     59 TEST_F(NonMaxSuppressionOpTest, TestSelectFromThreeClustersFlippedCoordinates) {
     60   MakeOp(.5);
     61   AddInputFromArray<float>(TensorShape({6, 4}),
     62                            {1, 1,  0, 0,  0, 0.1f,  1, 1.1f,  0, .9f, 1, -0.1f,
     63                             0, 10, 1, 11, 1, 10.1f, 0, 11.1f, 1, 101, 0, 100});
     64   AddInputFromArray<float>(TensorShape({6}), {.9f, .75f, .6f, .95f, .5f, .3f});
     65   AddInputFromArray<int>(TensorShape({}), {3});
     66   TF_ASSERT_OK(RunOpKernel());
     67 
     68   Tensor expected(allocator(), DT_INT32, TensorShape({3}));
     69   test::FillValues<int>(&expected, {3, 0, 5});
     70   test::ExpectTensorEqual<int>(expected, *GetOutput(0));
     71 }
     72 
     73 TEST_F(NonMaxSuppressionOpTest, TestSelectAtMostTwoBoxesFromThreeClusters) {
     74   MakeOp(.5);
     75   AddInputFromArray<float>(
     76       TensorShape({6, 4}),
     77       {0, 0,  1, 1,  0, 0.1f,  1, 1.1f,  0, -0.1f, 1, 0.9f,
     78        0, 10, 1, 11, 0, 10.1f, 1, 11.1f, 0, 100,   1, 101});
     79   AddInputFromArray<float>(TensorShape({6}), {.9f, .75f, .6f, .95f, .5f, .3f});
     80   AddInputFromArray<int>(TensorShape({}), {2});
     81   TF_ASSERT_OK(RunOpKernel());
     82 
     83   Tensor expected(allocator(), DT_INT32, TensorShape({2}));
     84   test::FillValues<int>(&expected, {3, 0});
     85   test::ExpectTensorEqual<int>(expected, *GetOutput(0));
     86 }
     87 
     88 TEST_F(NonMaxSuppressionOpTest, TestSelectAtMostThirtyBoxesFromThreeClusters) {
     89   MakeOp(.5);
     90   AddInputFromArray<float>(
     91       TensorShape({6, 4}),
     92       {0, 0,  1, 1,  0, 0.1f,  1, 1.1f,  0, -0.1f, 1, 0.9f,
     93        0, 10, 1, 11, 0, 10.1f, 1, 11.1f, 0, 100,   1, 101});
     94   AddInputFromArray<float>(TensorShape({6}), {.9f, .75f, .6f, .95f, .5f, .3f});
     95   AddInputFromArray<int>(TensorShape({}), {30});
     96   TF_ASSERT_OK(RunOpKernel());
     97 
     98   Tensor expected(allocator(), DT_INT32, TensorShape({3}));
     99   test::FillValues<int>(&expected, {3, 0, 5});
    100   test::ExpectTensorEqual<int>(expected, *GetOutput(0));
    101 }
    102 
    103 TEST_F(NonMaxSuppressionOpTest, TestSelectSingleBox) {
    104   MakeOp(.5);
    105   AddInputFromArray<float>(TensorShape({1, 4}), {0, 0, 1, 1});
    106   AddInputFromArray<float>(TensorShape({1}), {.9f});
    107   AddInputFromArray<int>(TensorShape({}), {3});
    108   TF_ASSERT_OK(RunOpKernel());
    109 
    110   Tensor expected(allocator(), DT_INT32, TensorShape({1}));
    111   test::FillValues<int>(&expected, {0});
    112   test::ExpectTensorEqual<int>(expected, *GetOutput(0));
    113 }
    114 
    115 TEST_F(NonMaxSuppressionOpTest, TestSelectFromTenIdenticalBoxes) {
    116   MakeOp(.5);
    117 
    118   int num_boxes = 10;
    119   std::vector<float> corners(num_boxes * 4);
    120   std::vector<float> scores(num_boxes);
    121   for (int i = 0; i < num_boxes; ++i) {
    122     corners[i * 4 + 0] = 0;
    123     corners[i * 4 + 1] = 0;
    124     corners[i * 4 + 2] = 1;
    125     corners[i * 4 + 3] = 1;
    126     scores[i] = .9;
    127   }
    128   AddInputFromArray<float>(TensorShape({num_boxes, 4}), corners);
    129   AddInputFromArray<float>(TensorShape({num_boxes}), scores);
    130   AddInputFromArray<int>(TensorShape({}), {3});
    131   TF_ASSERT_OK(RunOpKernel());
    132 
    133   Tensor expected(allocator(), DT_INT32, TensorShape({1}));
    134   test::FillValues<int>(&expected, {0});
    135   test::ExpectTensorEqual<int>(expected, *GetOutput(0));
    136 }
    137 
    138 TEST_F(NonMaxSuppressionOpTest, TestInconsistentBoxAndScoreShapes) {
    139   MakeOp(.5);
    140   AddInputFromArray<float>(
    141       TensorShape({6, 4}),
    142       {0, 0,  1, 1,  0, 0.1f,  1, 1.1f,  0, -0.1f, 1, 0.9f,
    143        0, 10, 1, 11, 0, 10.1f, 1, 11.1f, 0, 100,   1, 101});
    144   AddInputFromArray<float>(TensorShape({5}), {.9f, .75f, .6f, .95f, .5f});
    145   AddInputFromArray<int>(TensorShape({}), {30});
    146   Status s = RunOpKernel();
    147 
    148   ASSERT_FALSE(s.ok());
    149   EXPECT_TRUE(
    150       StringPiece(s.ToString()).contains("scores has incompatible shape"))
    151       << s;
    152 }
    153 
    154 TEST_F(NonMaxSuppressionOpTest, TestInvalidIOUThreshold) {
    155   MakeOp(1.2);
    156   AddInputFromArray<float>(TensorShape({1, 4}), {0, 0, 1, 1});
    157   AddInputFromArray<float>(TensorShape({1}), {.9f});
    158   AddInputFromArray<int>(TensorShape({}), {3});
    159   Status s = RunOpKernel();
    160 
    161   ASSERT_FALSE(s.ok());
    162   EXPECT_TRUE(
    163       StringPiece(s.ToString()).contains("iou_threshold must be in [0, 1]"))
    164       << s;
    165 }
    166 
    167 TEST_F(NonMaxSuppressionOpTest, TestEmptyInput) {
    168   MakeOp(.5);
    169   AddInputFromArray<float>(TensorShape({0, 4}), {});
    170   AddInputFromArray<float>(TensorShape({0}), {});
    171   AddInputFromArray<int>(TensorShape({}), {30});
    172   TF_ASSERT_OK(RunOpKernel());
    173 
    174   Tensor expected(allocator(), DT_INT32, TensorShape({0}));
    175   test::FillValues<int>(&expected, {});
    176   test::ExpectTensorEqual<int>(expected, *GetOutput(0));
    177 }
    178 
    179 //
    180 // NonMaxSuppressionV2Op Tests
    181 //
    182 
    183 class NonMaxSuppressionV2OpTest : public OpsTestBase {
    184  protected:
    185   void MakeOp() {
    186     TF_EXPECT_OK(NodeDefBuilder("non_max_suppression_op", "NonMaxSuppressionV2")
    187                      .Input(FakeInput(DT_FLOAT))
    188                      .Input(FakeInput(DT_FLOAT))
    189                      .Input(FakeInput(DT_INT32))
    190                      .Input(FakeInput(DT_FLOAT))
    191                      .Finalize(node_def()));
    192     TF_EXPECT_OK(InitOp());
    193   }
    194 };
    195 
    196 TEST_F(NonMaxSuppressionV2OpTest, TestSelectFromThreeClusters) {
    197   MakeOp();
    198   AddInputFromArray<float>(
    199       TensorShape({6, 4}),
    200       {0, 0,  1, 1,  0, 0.1f,  1, 1.1f,  0, -0.1f, 1, 0.9f,
    201        0, 10, 1, 11, 0, 10.1f, 1, 11.1f, 0, 100,   1, 101});
    202   AddInputFromArray<float>(TensorShape({6}), {.9f, .75f, .6f, .95f, .5f, .3f});
    203   AddInputFromArray<int>(TensorShape({}), {3});
    204   AddInputFromArray<float>(TensorShape({}), {.5f});
    205   TF_ASSERT_OK(RunOpKernel());
    206 
    207   Tensor expected(allocator(), DT_INT32, TensorShape({3}));
    208   test::FillValues<int>(&expected, {3, 0, 5});
    209   test::ExpectTensorEqual<int>(expected, *GetOutput(0));
    210 }
    211 
    212 TEST_F(NonMaxSuppressionV2OpTest,
    213        TestSelectFromThreeClustersFlippedCoordinates) {
    214   MakeOp();
    215   AddInputFromArray<float>(TensorShape({6, 4}),
    216                            {1, 1,  0, 0,  0, 0.1f,  1, 1.1f,  0, .9f, 1, -0.1f,
    217                             0, 10, 1, 11, 1, 10.1f, 0, 11.1f, 1, 101, 0, 100});
    218   AddInputFromArray<float>(TensorShape({6}), {.9f, .75f, .6f, .95f, .5f, .3f});
    219   AddInputFromArray<int>(TensorShape({}), {3});
    220   AddInputFromArray<float>(TensorShape({}), {.5f});
    221   TF_ASSERT_OK(RunOpKernel());
    222 
    223   Tensor expected(allocator(), DT_INT32, TensorShape({3}));
    224   test::FillValues<int>(&expected, {3, 0, 5});
    225   test::ExpectTensorEqual<int>(expected, *GetOutput(0));
    226 }
    227 
    228 TEST_F(NonMaxSuppressionV2OpTest, TestSelectAtMostTwoBoxesFromThreeClusters) {
    229   MakeOp();
    230   AddInputFromArray<float>(
    231       TensorShape({6, 4}),
    232       {0, 0,  1, 1,  0, 0.1f,  1, 1.1f,  0, -0.1f, 1, 0.9f,
    233        0, 10, 1, 11, 0, 10.1f, 1, 11.1f, 0, 100,   1, 101});
    234   AddInputFromArray<float>(TensorShape({6}), {.9f, .75f, .6f, .95f, .5f, .3f});
    235   AddInputFromArray<int>(TensorShape({}), {2});
    236   AddInputFromArray<float>(TensorShape({}), {.5f});
    237   TF_ASSERT_OK(RunOpKernel());
    238 
    239   Tensor expected(allocator(), DT_INT32, TensorShape({2}));
    240   test::FillValues<int>(&expected, {3, 0});
    241   test::ExpectTensorEqual<int>(expected, *GetOutput(0));
    242 }
    243 
    244 TEST_F(NonMaxSuppressionV2OpTest,
    245        TestSelectAtMostThirtyBoxesFromThreeClusters) {
    246   MakeOp();
    247   AddInputFromArray<float>(
    248       TensorShape({6, 4}),
    249       {0, 0,  1, 1,  0, 0.1f,  1, 1.1f,  0, -0.1f, 1, 0.9f,
    250        0, 10, 1, 11, 0, 10.1f, 1, 11.1f, 0, 100,   1, 101});
    251   AddInputFromArray<float>(TensorShape({6}), {.9f, .75f, .6f, .95f, .5f, .3f});
    252   AddInputFromArray<int>(TensorShape({}), {30});
    253   AddInputFromArray<float>(TensorShape({}), {.5f});
    254   TF_ASSERT_OK(RunOpKernel());
    255 
    256   Tensor expected(allocator(), DT_INT32, TensorShape({3}));
    257   test::FillValues<int>(&expected, {3, 0, 5});
    258   test::ExpectTensorEqual<int>(expected, *GetOutput(0));
    259 }
    260 
    261 TEST_F(NonMaxSuppressionV2OpTest, TestSelectSingleBox) {
    262   MakeOp();
    263   AddInputFromArray<float>(TensorShape({1, 4}), {0, 0, 1, 1});
    264   AddInputFromArray<float>(TensorShape({1}), {.9f});
    265   AddInputFromArray<int>(TensorShape({}), {3});
    266   AddInputFromArray<float>(TensorShape({}), {.5f});
    267   TF_ASSERT_OK(RunOpKernel());
    268 
    269   Tensor expected(allocator(), DT_INT32, TensorShape({1}));
    270   test::FillValues<int>(&expected, {0});
    271   test::ExpectTensorEqual<int>(expected, *GetOutput(0));
    272 }
    273 
    274 TEST_F(NonMaxSuppressionV2OpTest, TestSelectFromTenIdenticalBoxes) {
    275   MakeOp();
    276 
    277   int num_boxes = 10;
    278   std::vector<float> corners(num_boxes * 4);
    279   std::vector<float> scores(num_boxes);
    280   for (int i = 0; i < num_boxes; ++i) {
    281     corners[i * 4 + 0] = 0;
    282     corners[i * 4 + 1] = 0;
    283     corners[i * 4 + 2] = 1;
    284     corners[i * 4 + 3] = 1;
    285     scores[i] = .9;
    286   }
    287   AddInputFromArray<float>(TensorShape({num_boxes, 4}), corners);
    288   AddInputFromArray<float>(TensorShape({num_boxes}), scores);
    289   AddInputFromArray<int>(TensorShape({}), {3});
    290   AddInputFromArray<float>(TensorShape({}), {.5f});
    291   TF_ASSERT_OK(RunOpKernel());
    292 
    293   Tensor expected(allocator(), DT_INT32, TensorShape({1}));
    294   test::FillValues<int>(&expected, {0});
    295   test::ExpectTensorEqual<int>(expected, *GetOutput(0));
    296 }
    297 
    298 TEST_F(NonMaxSuppressionV2OpTest, TestInconsistentBoxAndScoreShapes) {
    299   MakeOp();
    300   AddInputFromArray<float>(
    301       TensorShape({6, 4}),
    302       {0, 0,  1, 1,  0, 0.1f,  1, 1.1f,  0, -0.1f, 1, 0.9f,
    303        0, 10, 1, 11, 0, 10.1f, 1, 11.1f, 0, 100,   1, 101});
    304   AddInputFromArray<float>(TensorShape({5}), {.9f, .75f, .6f, .95f, .5f});
    305   AddInputFromArray<int>(TensorShape({}), {30});
    306   AddInputFromArray<float>(TensorShape({}), {.5f});
    307   Status s = RunOpKernel();
    308 
    309   ASSERT_FALSE(s.ok());
    310   EXPECT_TRUE(
    311       StringPiece(s.ToString()).contains("scores has incompatible shape"))
    312       << s;
    313 }
    314 
    315 TEST_F(NonMaxSuppressionV2OpTest, TestInvalidIOUThreshold) {
    316   MakeOp();
    317   AddInputFromArray<float>(TensorShape({1, 4}), {0, 0, 1, 1});
    318   AddInputFromArray<float>(TensorShape({1}), {.9f});
    319   AddInputFromArray<int>(TensorShape({}), {3});
    320   AddInputFromArray<float>(TensorShape({}), {1.2f});
    321   Status s = RunOpKernel();
    322 
    323   ASSERT_FALSE(s.ok());
    324   EXPECT_TRUE(
    325       StringPiece(s.ToString()).contains("iou_threshold must be in [0, 1]"))
    326       << s;
    327 }
    328 
    329 TEST_F(NonMaxSuppressionV2OpTest, TestEmptyInput) {
    330   MakeOp();
    331   AddInputFromArray<float>(TensorShape({0, 4}), {});
    332   AddInputFromArray<float>(TensorShape({0}), {});
    333   AddInputFromArray<int>(TensorShape({}), {30});
    334   AddInputFromArray<float>(TensorShape({}), {.5f});
    335   TF_ASSERT_OK(RunOpKernel());
    336 
    337   Tensor expected(allocator(), DT_INT32, TensorShape({0}));
    338   test::FillValues<int>(&expected, {});
    339   test::ExpectTensorEqual<int>(expected, *GetOutput(0));
    340 }
    341 
    342 }  // namespace tensorflow
    343