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/register_types.h"
     21 #include "tensorflow/core/framework/tensor.h"
     22 #include "tensorflow/core/framework/tensor_testutil.h"
     23 #include "tensorflow/core/framework/tensor_util.h"
     24 #include "tensorflow/core/framework/types.h"
     25 #include "tensorflow/core/framework/types.pb.h"
     26 #include "tensorflow/core/kernels/ops_testutil.h"
     27 #include "tensorflow/core/kernels/ops_util.h"
     28 #include "tensorflow/core/lib/core/status_test_util.h"
     29 #include "tensorflow/core/platform/test.h"
     30 
     31 namespace tensorflow {
     32 
     33 class CropAndResizeOpTest : public OpsTestBase {
     34  protected:
     35   template <typename T>
     36   void MakeOp(float extrapolation_value) {
     37     TF_EXPECT_OK(NodeDefBuilder("crop_and_resize_op", "CropAndResize")
     38                      .Input(FakeInput(DataTypeToEnum<T>::value))
     39                      .Input(FakeInput(DT_FLOAT))
     40                      .Input(FakeInput(DT_INT32))
     41                      .Input(FakeInput(DT_INT32))
     42                      .Attr("extrapolation_value", extrapolation_value)
     43                      .Finalize(node_def()));
     44     TF_EXPECT_OK(InitOp());
     45   }
     46 };
     47 
     48 #define REGISTER_TEST(T)                                               \
     49   TEST_F(CropAndResizeOpTest, TestCropAndResize##T) {                  \
     50     MakeOp<T>(0);                                                      \
     51     AddInputFromArray<T>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});     \
     52     AddInputFromArray<float>(TensorShape({1, 4}), {0, 0, 1, 1});       \
     53     AddInputFromArray<int32>(TensorShape({1}), {0});                   \
     54     AddInputFromArray<int32>(TensorShape({2}), {1, 1});                \
     55     TF_ASSERT_OK(RunOpKernel());                                       \
     56                                                                        \
     57     Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 1, 1, 1})); \
     58     test::FillValues<float>(&expected, {2.5});                         \
     59     test::ExpectTensorEqual<float>(expected, *GetOutput(0));           \
     60   }
     61 
     62 REGISTER_TEST(float)
     63 REGISTER_TEST(double)
     64 REGISTER_TEST(uint8)
     65 REGISTER_TEST(uint16)
     66 REGISTER_TEST(int8)
     67 REGISTER_TEST(int16)
     68 REGISTER_TEST(int32)
     69 REGISTER_TEST(int64)
     70 
     71 #undef REGISTER_TEST
     72 
     73 TEST_F(CropAndResizeOpTest, TestCropAndResize2x2To1x1Uint8) {
     74   MakeOp<uint8>(0);
     75   // Input:
     76   //  1, 2
     77   //  3, 4
     78   AddInputFromArray<uint8>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
     79   AddInputFromArray<float>(TensorShape({1, 4}), {0, 0, 1, 1});
     80   AddInputFromArray<int32>(TensorShape({1}), {0});
     81   AddInputFromArray<int32>(TensorShape({2}), {1, 1});
     82   TF_ASSERT_OK(RunOpKernel());
     83 
     84   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 1, 1, 1}));
     85   test::FillValues<float>(&expected, {2.5});
     86   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
     87 }
     88 
     89 TEST_F(CropAndResizeOpTest, TestCropAndResize2x2To1x1Flipped) {
     90   MakeOp<float>(0);
     91   // Input:
     92   //  1, 2
     93   //  3, 4
     94   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
     95   AddInputFromArray<float>(TensorShape({1, 4}), {1, 1, 0, 0});
     96   AddInputFromArray<int32>(TensorShape({1}), {0});
     97   AddInputFromArray<int32>(TensorShape({2}), {1, 1});
     98   TF_ASSERT_OK(RunOpKernel());
     99 
    100   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 1, 1, 1}));
    101   test::FillValues<float>(&expected, {2.5});
    102   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
    103 }
    104 
    105 TEST_F(CropAndResizeOpTest, TestCropAndResize2x2To3x3) {
    106   MakeOp<float>(0);
    107   // Input:
    108   //  1, 2
    109   //  3, 4
    110   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
    111   AddInputFromArray<float>(TensorShape({1, 4}), {0, 0, 1, 1});
    112   AddInputFromArray<int32>(TensorShape({1}), {0});
    113   AddInputFromArray<int32>(TensorShape({2}), {3, 3});
    114   TF_ASSERT_OK(RunOpKernel());
    115 
    116   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 3, 3, 1}));
    117   // clang-format off
    118   test::FillValues<float>(&expected,
    119     {1,  1.5,  2,
    120      2,  2.5,  3,
    121      3,  3.5,  4});
    122   // clang-format on
    123   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
    124 }
    125 
    126 TEST_F(CropAndResizeOpTest, TestCropAndResize2x2To3x3Flipped) {
    127   MakeOp<float>(0);
    128   // Input:
    129   //  1, 2
    130   //  3, 4
    131   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
    132   AddInputFromArray<float>(TensorShape({1, 4}), {1, 1, 0, 0});
    133   AddInputFromArray<int32>(TensorShape({1}), {0});
    134   AddInputFromArray<int32>(TensorShape({2}), {3, 3});
    135   TF_ASSERT_OK(RunOpKernel());
    136 
    137   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 3, 3, 1}));
    138   // clang-format off
    139   test::FillValues<float>(&expected,
    140     {4,  3.5,  3,
    141      3,  2.5,  2,
    142      2,  1.5,  1});
    143   // clang-format on
    144   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
    145 }
    146 
    147 TEST_F(CropAndResizeOpTest, TestCropAndResize3x3To2x2) {
    148   MakeOp<float>(0);
    149   // Input:
    150   //  1, 2, 3
    151   //  4, 5, 6
    152   //  7, 8, 9
    153   AddInputFromArray<float>(TensorShape({1, 3, 3, 1}),
    154                            {1, 2, 3, 4, 5, 6, 7, 8, 9});
    155   AddInputFromArray<float>(TensorShape({2, 4}), {0, 0, 1, 1, 0, 0, 0.5, 0.5});
    156   AddInputFromArray<int32>(TensorShape({2}), {0, 0});
    157   AddInputFromArray<int32>(TensorShape({2}), {2, 2});
    158   TF_ASSERT_OK(RunOpKernel());
    159 
    160   Tensor expected(allocator(), DT_FLOAT, TensorShape({2, 2, 2, 1}));
    161 
    162   // clang-format off
    163   test::FillValues<float>(&expected,
    164     {1,  3,
    165      7,  9,
    166      1,  2,
    167      4,  5});
    168   // clang-format on
    169   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
    170 }
    171 
    172 TEST_F(CropAndResizeOpTest, TestCropAndResize3x3To2x2Flipped) {
    173   MakeOp<float>(0);
    174   // Input:
    175   //  1, 2, 3
    176   //  4, 5, 6
    177   //  7, 8, 9
    178   AddInputFromArray<float>(TensorShape({1, 3, 3, 1}),
    179                            {1, 2, 3, 4, 5, 6, 7, 8, 9});
    180   AddInputFromArray<float>(TensorShape({2, 4}), {1, 1, 0, 0, 0.5, 0.5, 0, 0});
    181   AddInputFromArray<int32>(TensorShape({2}), {0, 0});
    182   AddInputFromArray<int32>(TensorShape({2}), {2, 2});
    183   TF_ASSERT_OK(RunOpKernel());
    184 
    185   Tensor expected(allocator(), DT_FLOAT, TensorShape({2, 2, 2, 1}));
    186 
    187   // clang-format off
    188   test::FillValues<float>(&expected,
    189     {9,  7,
    190      3,  1,
    191      5,  4,
    192      2,  1});
    193   // clang-format on
    194   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
    195 }
    196 
    197 TEST_F(CropAndResizeOpTest, TestCropAndResize2x2To3x3Extrapolated) {
    198   const float v = -1;
    199   MakeOp<float>(v);
    200   // Input:
    201   //  1, 2
    202   //  3, 4
    203   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
    204   AddInputFromArray<float>(TensorShape({1, 4}), {-1, -1, 1, 1});
    205   AddInputFromArray<int32>(TensorShape({1}), {0});
    206   AddInputFromArray<int32>(TensorShape({2}), {3, 3});
    207   TF_ASSERT_OK(RunOpKernel());
    208 
    209   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 3, 3, 1}));
    210   // clang-format off
    211   test::FillValues<float>(&expected,
    212     {v,  v,  v,
    213      v,  1,  2,
    214      v,  3,  4});
    215   // clang-format on
    216   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
    217 }
    218 
    219 TEST_F(CropAndResizeOpTest, TestCropAndResize2x2To3x3NoCrop) {
    220   MakeOp<float>(0);
    221   // Input:
    222   //  1, 2
    223   //  3, 4
    224   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
    225   AddInputFromArray<float>(TensorShape({0, 4}), {});
    226   AddInputFromArray<int32>(TensorShape({0}), {});
    227   AddInputFromArray<int32>(TensorShape({2}), {3, 3});
    228   TF_ASSERT_OK(RunOpKernel());
    229 
    230   Tensor expected(allocator(), DT_FLOAT, TensorShape({0, 3, 3, 1}));
    231   // clang-format off
    232   test::FillValues<float>(&expected, {});
    233   // clang-format on
    234   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
    235 }
    236 
    237 TEST_F(CropAndResizeOpTest, TestInvalidInputShape) {
    238   MakeOp<float>(0);
    239   AddInputFromArray<float>(TensorShape({2, 2, 1}), {1, 2, 3, 4});
    240   AddInputFromArray<float>(TensorShape({1, 4}), {0, 0, 1, 1});
    241   AddInputFromArray<int32>(TensorShape({1}), {0});
    242   AddInputFromArray<int32>(TensorShape({2}), {4, 4});
    243   Status s = RunOpKernel();
    244   ASSERT_FALSE(s.ok());
    245   EXPECT_TRUE(StringPiece(s.ToString()).contains("input image must be 4-D"))
    246       << s;
    247 }
    248 
    249 TEST_F(CropAndResizeOpTest, TestInvalidBoxIndexShape) {
    250   MakeOp<float>(0);
    251   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
    252   AddInputFromArray<float>(TensorShape({1, 4}), {0, 0, 1, 1});
    253   AddInputFromArray<int32>(TensorShape({2}), {0, 0});
    254   AddInputFromArray<int32>(TensorShape({2}), {4, 4});
    255   Status s = RunOpKernel();
    256   ASSERT_FALSE(s.ok());
    257   EXPECT_TRUE(
    258       StringPiece(s.ToString()).contains("box_index has incompatible shape"))
    259       << s;
    260 }
    261 
    262 TEST_F(CropAndResizeOpTest, TestInvalidBoxIndex) {
    263   MakeOp<float>(0);
    264   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
    265   AddInputFromArray<float>(TensorShape({1, 4}), {0, 0, 1, 1});
    266   AddInputFromArray<int32>(TensorShape({1}), {1});
    267   AddInputFromArray<int32>(TensorShape({2}), {3, 3});
    268   Status s = RunOpKernel();
    269   ASSERT_FALSE(s.ok());
    270   EXPECT_TRUE(StringPiece(s.ToString())
    271                   .contains("box_index has values outside [0, batch_size)"))
    272       << s;
    273 }
    274 
    275 TEST_F(CropAndResizeOpTest, TestWithSharding) {
    276   MakeOp<float>(0);
    277   // Generate a relatively large input (999x999) so that sharding happens.
    278   const int kLength = 999;  // Length of the input. Must use an odd number.
    279   const int kHalf = (kLength + 1) / 2;  // Half size for the cropped result.
    280 
    281   // Input:
    282   //  0, 1, 2, ..., 998
    283   //  0, 1, 2, ..., 998
    284   //  ... (altogether 999 lines)
    285   //  0, 1, 2, ..., 998
    286   AddInput<float>(TensorShape({1, kLength, kLength, 1}),
    287                   [kLength](int i) -> float { return i % kLength; });
    288   AddInputFromArray<float>(TensorShape({2, 4}),
    289                            {0, 0, 0.5, 0.5, 0.5, 0.5, 1, 1});
    290   AddInputFromArray<int32>(TensorShape({2}), {0, 0});
    291   AddInputFromArray<int32>(TensorShape({2}), {kHalf, kHalf});
    292 
    293   TF_ASSERT_OK(RunOpKernel());
    294 
    295   // Generate result tensor.
    296   // Result 1:
    297   //  0, 1, 2, ..., 499
    298   //  ... (altogether 500 lines)
    299   //  0, 1, 2, ..., 499
    300   Tensor result1(allocator(), DT_FLOAT, TensorShape({1, kHalf, kHalf, 1}));
    301   test::FillFn<float>(&result1, [kHalf](int i) -> float { return i % kHalf; });
    302 
    303   // Result 2:
    304   //  499, 500, 501, ..., 998
    305   //  ... (altogether 500 lines)
    306   //  499, 500, 501, ..., 998
    307   Tensor result2(allocator(), DT_FLOAT, TensorShape({1, kHalf, kHalf, 1}));
    308   test::FillFn<float>(
    309       &result2, [kHalf](int i) -> float { return i % kHalf + kHalf - 1; });
    310 
    311   // Expected result is the concat of the two tensors.
    312   Tensor expected(allocator(), DT_FLOAT, TensorShape({2, kHalf, kHalf, 1}));
    313   TF_ASSERT_OK(tensor::Concat({result1, result2}, &expected));
    314 
    315   // Compare result.
    316   test::ExpectTensorEqual<float>(expected, *GetOutput(0));
    317 }
    318 
    319 }  // namespace tensorflow
    320