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