• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/common_runtime/device_factory.h"
17 #include "tensorflow/core/framework/allocator.h"
18 #include "tensorflow/core/framework/fake_input.h"
19 #include "tensorflow/core/framework/node_def_builder.h"
20 #include "tensorflow/core/framework/op_kernel.h"
21 #include "tensorflow/core/framework/tensor.h"
22 #include "tensorflow/core/framework/tensor_testutil.h"
23 #include "tensorflow/core/framework/types.h"
24 #include "tensorflow/core/framework/types.pb.h"
25 #include "tensorflow/core/kernels/ops_testutil.h"
26 #include "tensorflow/core/kernels/ops_util.h"
27 #include "tensorflow/core/lib/core/status_test_util.h"
28 #include "tensorflow/core/lib/random/random.h"
29 #include "tensorflow/core/lib/strings/str_util.h"
30 #include "tensorflow/core/platform/test.h"
31 #include "tensorflow/core/platform/test_benchmark.h"
32 #include "tensorflow/core/public/session_options.h"
33 
34 namespace tensorflow {
35 enum class TestDevice { CPU, GPU };
36 
37 class ResizeBilinearOpTestBase
38     : public OpsTestBase,
39       public ::testing::WithParamInterface<TestDevice> {
40  protected:
ResizeBilinearOpTestBase()41   explicit ResizeBilinearOpTestBase()
42       : align_corners_(false), half_pixel_centers_(false) {}
43 
SetUp()44   void SetUp() override {
45     if (GetParam() == TestDevice::GPU) {
46       std::unique_ptr<Device> device_gpu(
47           DeviceFactory::NewDevice("GPU", {}, "/job:a/replica:0/task:0"));
48       SetDevice(DEVICE_GPU, std::move(device_gpu));
49     }
50 
51     TF_EXPECT_OK(NodeDefBuilder("resize_bilinear_op", "ResizeBilinear")
52                      .Input(FakeInput(DT_FLOAT))
53                      .Input(FakeInput(DT_INT32))
54                      .Attr("align_corners", align_corners_)
55                      .Attr("half_pixel_centers", half_pixel_centers_)
56                      .Finalize(node_def()));
57     TF_EXPECT_OK(InitOp());
58   }
59 
SetRandomImageInput(const TensorShape & shape)60   const Tensor* SetRandomImageInput(const TensorShape& shape) {
61     inputs_.clear();
62 
63     CHECK_EQ(shape.dims(), 4) << "All images must have 4 dimensions.";
64     bool is_ref = IsRefType(input_types_[inputs_.size()]);
65     Tensor* input = new Tensor(allocator(), DataTypeToEnum<float>::v(), shape);
66     input->flat<float>().setRandom();
67     tensors_.push_back(input);
68     if (is_ref) {
69       CHECK_EQ(RemoveRefType(input_types_[inputs_.size()]),
70                DataTypeToEnum<float>::v());
71       inputs_.push_back({&lock_for_refs_, input});
72     } else {
73       CHECK_EQ(input_types_[inputs_.size()], DataTypeToEnum<float>::v());
74       inputs_.push_back({nullptr, input});
75     }
76     return input;
77   }
78 
79   // This is the straight forward unoptimized implementation of resize bilinear
80   // We use this to confirm that the optimized version is exactly identical.
ResizeBilinearBaseline(TTypes<float,4>::ConstTensor images,TTypes<float,4>::Tensor output)81   void ResizeBilinearBaseline(TTypes<float, 4>::ConstTensor images,
82                               TTypes<float, 4>::Tensor output) {
83     const int batch = images.dimension(0);
84     const int64 in_height = images.dimension(1);
85     const int64 in_width = images.dimension(2);
86     const int channels = images.dimension(3);
87 
88     ASSERT_EQ(batch, output.dimension(0));
89     ASSERT_EQ(channels, output.dimension(3));
90 
91     const int64 out_height = output.dimension(1);
92     const int64 out_width = output.dimension(2);
93 
94     const float height_scale = in_height / static_cast<float>(out_height);
95     const float width_scale = in_width / static_cast<float>(out_width);
96 
97     for (int b = 0; b < batch; ++b) {
98       for (int64 y = 0; y < out_height; ++y) {
99         const float in_y =
100             half_pixel_centers_
101                 ? (static_cast<float>(y) + 0.5f) * height_scale - 0.5f
102                 : y * height_scale;
103         const int64 top_y_index =
104             std::max(static_cast<int64>(floorf(in_y)), static_cast<int64>(0));
105         const int64 bottom_y_index =
106             std::min(static_cast<int64>(ceilf(in_y)), in_height - 1);
107         const float y_lerp = in_y - std::floor(in_y);
108         for (int64 x = 0; x < out_width; ++x) {
109           const float in_x =
110               half_pixel_centers_
111                   ? (static_cast<float>(x) + 0.5f) * width_scale - 0.5f
112                   : x * width_scale;
113           const int64 left_x_index =
114               std::max(static_cast<int64>(floorf(in_x)), static_cast<int64>(0));
115           const int64 right_x_index =
116               std::min(static_cast<int64>(ceilf(in_x)), in_width - 1);
117           const float x_lerp = in_x - std::floor(in_x);
118           for (int c = 0; c < channels; ++c) {
119             const float top_left = images(b, top_y_index, left_x_index, c);
120             const float top_right = images(b, top_y_index, right_x_index, c);
121             const float bottom_left =
122                 images(b, bottom_y_index, left_x_index, c);
123             const float bottom_right =
124                 images(b, bottom_y_index, right_x_index, c);
125             const float top = top_left + (top_right - top_left) * x_lerp;
126             const float bottom =
127                 bottom_left + (bottom_right - bottom_left) * x_lerp;
128             output(b, y, x, c) = top + (bottom - top) * y_lerp;
129           }
130         }
131       }
132     }
133   }
134 
TestResize(int batch_size,int input_width,int input_height,int channels,int output_width,int output_height)135   void TestResize(int batch_size, int input_width, int input_height,
136                   int channels, int output_width, int output_height) {
137     const TensorShape shape({batch_size, input_width, input_height, channels});
138     const Tensor* input = SetRandomImageInput(shape);
139     AddInputFromArray<int32>(TensorShape({2}), {output_width, output_height});
140     TF_ASSERT_OK(RunOpKernel());
141 
142     std::unique_ptr<Tensor> expected(new Tensor(
143         allocator(), DataTypeToEnum<float>::v(),
144         TensorShape({batch_size, output_width, output_height, channels})));
145     ResizeBilinearBaseline(input->tensor<float, 4>(),
146                            expected->tensor<float, 4>());
147     test::ExpectClose(*expected, *GetOutput(0), /*atol=*/4e-5);
148   }
149 
RunManyRandomTests(int channels)150   void RunManyRandomTests(int channels) {
151     for (int batch_size : {1, 2, 5}) {
152       for (int in_w : {2, 4, 7, 20, 165}) {
153         for (int in_h : {1, 3, 5, 8, 100, 233}) {
154           for (int target_height : {1, 2, 3, 50, 113}) {
155             for (int target_width : {target_height, target_height / 2 + 1}) {
156               TestResize(batch_size, in_w, in_h, channels, target_width,
157                          target_height);
158             }
159           }
160         }
161       }
162     }
163   }
164 
165   bool align_corners_;
166   bool half_pixel_centers_;
167 };
168 
169 class ResizeBilinearOpTest : public ResizeBilinearOpTestBase {
170  public:
ResizeBilinearOpTest()171   ResizeBilinearOpTest() {}
172 };
173 
174 class ResizeBilinearHalfPixelCentersOpTest : public ResizeBilinearOpTestBase {
175  public:
ResizeBilinearHalfPixelCentersOpTest()176   ResizeBilinearHalfPixelCentersOpTest() { half_pixel_centers_ = true; }
177 };
178 
179 class ResizeBilinearOpAlignCornersTest : public ResizeBilinearOpTestBase {
180  public:
ResizeBilinearOpAlignCornersTest()181   ResizeBilinearOpAlignCornersTest() { align_corners_ = true; }
182 };
183 
TEST_P(ResizeBilinearOpTest,TestResizeRandomDataSeveralInputsSizes1Channel)184 TEST_P(ResizeBilinearOpTest, TestResizeRandomDataSeveralInputsSizes1Channel) {
185   RunManyRandomTests(1);
186 }
187 
TEST_P(ResizeBilinearOpTest,TestResizeRandomDataSeveralInputsSizes3Channels)188 TEST_P(ResizeBilinearOpTest, TestResizeRandomDataSeveralInputsSizes3Channels) {
189   RunManyRandomTests(3);
190 }
191 
TEST_P(ResizeBilinearOpTest,TestResizeRandomDataSeveralInputsSizes4Channels)192 TEST_P(ResizeBilinearOpTest, TestResizeRandomDataSeveralInputsSizes4Channels) {
193   RunManyRandomTests(4);
194 }
195 
TEST_P(ResizeBilinearOpTest,TestBilinear2x2To1x1)196 TEST_P(ResizeBilinearOpTest, TestBilinear2x2To1x1) {
197   // Input:
198   //  1, 2
199   //  3, 4
200   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
201   AddInputFromArray<int32>(TensorShape({2}), {1, 1});
202   TF_ASSERT_OK(RunOpKernel());
203 
204   // When scaling down, we have to arbitrarily pick a pixel from the
205   // original input. In this case, we choose the top/left most pixel.
206   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 1, 1, 1}));
207   test::FillValues<float>(&expected, {1.0});
208   test::ExpectClose(expected, *GetOutput(0));
209 }
210 
TEST_P(ResizeBilinearOpTest,TestBilinearRandom2x2To1x1)211 TEST_P(ResizeBilinearOpTest, TestBilinearRandom2x2To1x1) {
212   const Tensor* input = SetRandomImageInput(TensorShape({1, 2, 2, 1}));
213   AddInputFromArray<int32>(TensorShape({2}), {1, 1});
214   TF_ASSERT_OK(RunOpKernel());
215 
216   // When scaling down, we have to arbitrarily pick a pixel from the
217   // original input. In this case, we choose the top/left most pixel.
218   Tensor* output = GetOutput(0);
219   std::unique_ptr<Tensor> expected(new Tensor(
220       allocator(), DataTypeToEnum<float>::v(), TensorShape({1, 1, 1, 1})));
221   ResizeBilinearBaseline(input->tensor<float, 4>(),
222                          expected->tensor<float, 4>());
223   EXPECT_EQ(input->flat<float>()(0), output->flat<float>()(0));
224   test::ExpectClose(*expected, *output);
225 }
226 
TEST_P(ResizeBilinearOpAlignCornersTest,TestBilinearAlignCorners2x2To1x1)227 TEST_P(ResizeBilinearOpAlignCornersTest, TestBilinearAlignCorners2x2To1x1) {
228   // Input:
229   //  1, 2
230   //  3, 4
231   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
232   AddInputFromArray<int32>(TensorShape({2}), {1, 1});
233   TF_ASSERT_OK(RunOpKernel());
234 
235   // When scaling down, we have to arbitrarily pick a pixel from the
236   // original input. In this case, we choose the top/left most pixel.
237   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 1, 1, 1}));
238   test::FillValues<float>(&expected, {1.0});
239   test::ExpectClose(expected, *GetOutput(0));
240 }
241 
TEST_P(ResizeBilinearOpTest,TestBilinear2x2To3x3)242 TEST_P(ResizeBilinearOpTest, TestBilinear2x2To3x3) {
243   // Input:
244   //  1, 2
245   //  3, 4
246   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
247   AddInputFromArray<int32>(TensorShape({2}), {3, 3});
248   TF_ASSERT_OK(RunOpKernel());
249 
250   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 3, 3, 1}));
251 
252   // clang-format off
253   test::FillValues<float>(&expected,
254     {1,        5.0f / 3,  2,
255      7.0f / 3, 3,         10.0f / 3,
256      3,        11.0f / 3, 4});
257 
258   // clang-format on
259   test::ExpectClose(expected, *GetOutput(0));
260 }
261 
TEST_P(ResizeBilinearOpAlignCornersTest,TestBilinearAlignCorners2x2To3x3)262 TEST_P(ResizeBilinearOpAlignCornersTest, TestBilinearAlignCorners2x2To3x3) {
263   // Input:
264   //  1, 2
265   //  3, 4
266   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
267   AddInputFromArray<int32>(TensorShape({2}), {3, 3});
268   TF_ASSERT_OK(RunOpKernel());
269 
270   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 3, 3, 1}));
271 
272   // The corners exactly align with the original corners, and we bilinear
273   // interpolate the values in between.
274 
275   // clang-format off
276   test::FillValues<float>(&expected,
277     {1,  1.5,  2,
278      2,  2.5,  3,
279      3,  3.5,  4});
280 
281   // clang-format on
282   test::ExpectClose(expected, *GetOutput(0));
283 }
284 
TEST_P(ResizeBilinearOpTest,TestBilinear3x3To2x2)285 TEST_P(ResizeBilinearOpTest, TestBilinear3x3To2x2) {
286   // Input:
287   //  1, 2, 3
288   //  4, 5, 6
289   //  7, 8, 9
290   AddInputFromArray<float>(TensorShape({1, 3, 3, 1}),
291                            {1, 2, 3, 4, 5, 6, 7, 8, 9});
292   AddInputFromArray<int32>(TensorShape({2}), {2, 2});
293   TF_ASSERT_OK(RunOpKernel());
294 
295   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 2, 2, 1}));
296 
297   // clang-format off
298   test::FillValues<float>(&expected,
299     {1,   2.5,
300      5.5,   7});
301 
302   // clang-format on
303   test::ExpectClose(expected, *GetOutput(0));
304 }
305 
TEST_P(ResizeBilinearOpAlignCornersTest,TestBilinearAlignCorners3x3To2x2)306 TEST_P(ResizeBilinearOpAlignCornersTest, TestBilinearAlignCorners3x3To2x2) {
307   // Input:
308   //  1, 2, 3
309   //  4, 5, 6
310   //  7, 8, 9
311   AddInputFromArray<float>(TensorShape({1, 3, 3, 1}),
312                            {1, 2, 3, 4, 5, 6, 7, 8, 9});
313   AddInputFromArray<int32>(TensorShape({2}), {2, 2});
314   TF_ASSERT_OK(RunOpKernel());
315 
316   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 2, 2, 1}));
317 
318   // clang-format off
319   test::FillValues<float>(&expected,
320     {1,  3,
321      7,  9});
322 
323   // clang-format on
324   test::ExpectClose(expected, *GetOutput(0));
325 }
326 
TEST_P(ResizeBilinearOpTest,TestBilinear3x3To4x4)327 TEST_P(ResizeBilinearOpTest, TestBilinear3x3To4x4) {
328   // Input:
329   //  1, 2, 3,
330   //  4, 5, 6,
331   //  7, 8, 9
332   AddInputFromArray<float>(TensorShape({1, 3, 3, 1}),
333                            {1, 2, 3, 4, 5, 6, 7, 8, 9});
334   AddInputFromArray<int32>(TensorShape({2}), {4, 4});
335   TF_ASSERT_OK(RunOpKernel());
336 
337   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 4, 4, 1}));
338   // clang-format off
339   test::FillValues<float>(&expected,
340     {1, 1.75, 2.5, 3,
341      3.25, 4, 4.75, 5.25,
342      5.5, 6.25, 7, 7.5,
343      7,  7.75, 8.5, 9});
344 
345   // clang-format on
346   test::ExpectClose(expected, *GetOutput(0));
347 }
348 
TEST_P(ResizeBilinearOpTest,TestBilinear4x4To3x3)349 TEST_P(ResizeBilinearOpTest, TestBilinear4x4To3x3) {
350   // Input:
351   //  1,  2,  3,  4
352   //  5,  6,  7,  8
353   //  9, 10, 11, 12
354   // 13, 14, 15, 16
355   AddInputFromArray<float>(
356       TensorShape({1, 4, 4, 1}),
357       {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16});
358   AddInputFromArray<int32>(TensorShape({2}), {3, 3});
359   TF_ASSERT_OK(RunOpKernel());
360 
361   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 3, 3, 1}));
362 
363   // clang-format off
364   test::FillValues<float>(&expected,
365     {1,        7.0f/3, 11.0f/3,
366      19.0f/3, 23.0f/3, 27.0f/3,
367      35.0f/3, 39.0f/3, 43.0f/3});
368 
369   // clang-format on
370   test::ExpectClose(expected, *GetOutput(0));
371 }
372 
TEST_P(ResizeBilinearHalfPixelCentersOpTest,TestDownsamples)373 TEST_P(ResizeBilinearHalfPixelCentersOpTest, TestDownsamples) {
374   TestResize(4, 298, 297, 3, 61, 71);
375 }
376 
TEST_P(ResizeBilinearHalfPixelCentersOpTest,TestUpsamples)377 TEST_P(ResizeBilinearHalfPixelCentersOpTest, TestUpsamples) {
378   TestResize(4, 61, 71, 3, 298, 297);
379 }
380 
TEST_P(ResizeBilinearOpAlignCornersTest,TestBilinearAlignCorners4x4To3x3)381 TEST_P(ResizeBilinearOpAlignCornersTest, TestBilinearAlignCorners4x4To3x3) {
382   // Input:
383   //  1,  2,  3,  4
384   //  5,  6,  7,  8
385   //  9, 10, 11, 12
386   // 13, 14, 15, 16
387   AddInputFromArray<float>(
388       TensorShape({1, 4, 4, 1}),
389       {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16});
390   AddInputFromArray<int32>(TensorShape({2}), {3, 3});
391   TF_ASSERT_OK(RunOpKernel());
392 
393   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 3, 3, 1}));
394 
395   // clang-format off
396   test::FillValues<float>(&expected,
397     { 1,  2.5,  4,
398       7,  8.5, 10,
399      13, 14.5, 16});
400 
401   // clang-format on
402   test::ExpectClose(expected, *GetOutput(0));
403 }
404 
TEST_P(ResizeBilinearOpTest,TestBilinear2x2To3x3Batch2)405 TEST_P(ResizeBilinearOpTest, TestBilinear2x2To3x3Batch2) {
406   // Input:
407   //  1, 2
408   //  3, 4
409   //
410   // repeated twice
411   AddInputFromArray<float>(TensorShape({2, 2, 2, 1}), {1, 2, 3, 4, 1, 2, 3, 4});
412   AddInputFromArray<int32>(TensorShape({2}), {3, 3});
413   TF_ASSERT_OK(RunOpKernel());
414 
415   Tensor expected(allocator(), DT_FLOAT, TensorShape({2, 3, 3, 1}));
416   // clang-format off
417   test::FillValues<float>(&expected,
418     {1, 5.0f/3, 2, 7.0f/3, 3, 10.0f/3, 3, 11.0f/3, 4,
419      1, 5.0f/3, 2, 7.0f/3, 3, 10.0f/3, 3, 11.0f/3, 4
420     });
421   // clang-format on
422   test::ExpectClose(expected, *GetOutput(0));
423 }
424 
TEST_P(ResizeBilinearOpTest,TestBilinear2x2x2To3x3x2)425 TEST_P(ResizeBilinearOpTest, TestBilinear2x2x2To3x3x2) {
426   AddInputFromArray<float>(TensorShape({1, 2, 2, 2}),
427                            {1, -1, 2, -2, 3, -3, 4, -4});
428   AddInputFromArray<int32>(TensorShape({2}), {3, 3});
429   TF_ASSERT_OK(RunOpKernel());
430 
431   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 3, 3, 2}));
432   // clang-format off
433   test::FillValues<float>(&expected,
434     {
435       1,       -1,
436       5.0f/3,  -5.0f/3,
437       2,       -2,
438       7.0f/3,  -7.0f/3,
439       3,       -3,
440       10.0f/3, -10.0f/3,
441       3,       -3,
442       11.0f/3, -11.0f/3,
443       4,       -4
444     });
445   // clang-format on
446   test::ExpectClose(expected, *GetOutput(0));
447 }
448 
TEST_P(ResizeBilinearOpTest,TestBilinear2x2To4x4)449 TEST_P(ResizeBilinearOpTest, TestBilinear2x2To4x4) {
450   // Input:
451   //  1, 2
452   //  3, 4
453   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
454   AddInputFromArray<int32>(TensorShape({2}), {4, 4});
455   TF_ASSERT_OK(RunOpKernel());
456 
457   Tensor expected(allocator(), DT_FLOAT, TensorShape({1, 4, 4, 1}));
458   // clang-format off
459   test::FillValues<float>(&expected,
460     {1,  1.5, 2, 2,
461      2,  2.5, 3, 3,
462      3,  3.5, 4, 4,
463      3,  3.5, 4, 4});
464   // clang-format on
465   test::ExpectClose(expected, *GetOutput(0));
466 }
467 
468 // similar_size case
TEST_P(ResizeBilinearOpTest,Test1_1c)469 TEST_P(ResizeBilinearOpTest, Test1_1c) { TestResize(1, 183, 299, 1, 299, 299); }
TEST_P(ResizeBilinearOpTest,Test1_3c)470 TEST_P(ResizeBilinearOpTest, Test1_3c) { TestResize(1, 183, 299, 3, 299, 299); }
471 
472 // Significantly smaller: scale_up case
TEST_P(ResizeBilinearOpTest,Test2_1c)473 TEST_P(ResizeBilinearOpTest, Test2_1c) { TestResize(1, 141, 186, 1, 299, 299); }
TEST_P(ResizeBilinearOpTest,Test2_3c)474 TEST_P(ResizeBilinearOpTest, Test2_3c) { TestResize(1, 141, 186, 3, 299, 299); }
475 
476 // Significantly larger: scale_down case
TEST_P(ResizeBilinearOpTest,Test3_1c)477 TEST_P(ResizeBilinearOpTest, Test3_1c) { TestResize(1, 749, 603, 1, 299, 299); }
TEST_P(ResizeBilinearOpTest,Test3_3c)478 TEST_P(ResizeBilinearOpTest, Test3_3c) { TestResize(1, 749, 603, 3, 299, 299); }
479 
480 // Exactly the same size
TEST_P(ResizeBilinearOpTest,Test4_1c)481 TEST_P(ResizeBilinearOpTest, Test4_1c) { TestResize(1, 299, 299, 1, 299, 299); }
TEST_P(ResizeBilinearOpTest,Test4_3c)482 TEST_P(ResizeBilinearOpTest, Test4_3c) { TestResize(1, 299, 299, 3, 299, 299); }
483 
484 // Slightly smaller: similar_size case
TEST_P(ResizeBilinearOpTest,Test5_1c)485 TEST_P(ResizeBilinearOpTest, Test5_1c) { TestResize(1, 298, 297, 1, 299, 299); }
TEST_P(ResizeBilinearOpTest,Test5_3c)486 TEST_P(ResizeBilinearOpTest, Test5_3c) { TestResize(1, 298, 297, 3, 299, 299); }
487 
488 // Slightly bigger: similar_size case
TEST_P(ResizeBilinearOpTest,Test6_1c)489 TEST_P(ResizeBilinearOpTest, Test6_1c) { TestResize(1, 304, 303, 1, 299, 299); }
TEST_P(ResizeBilinearOpTest,Test6_3c)490 TEST_P(ResizeBilinearOpTest, Test6_3c) { TestResize(1, 304, 303, 3, 299, 299); }
491 
TEST_P(ResizeBilinearOpTest,TestInvalidOutputSize)492 TEST_P(ResizeBilinearOpTest, TestInvalidOutputSize) {
493   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
494   AddInputFromArray<int32>(TensorShape({2}), {0, 0});
495   Status s = RunOpKernel();
496   EXPECT_TRUE(absl::StrContains(
497       s.ToString(), "Invalid argument: output dimensions must be positive"))
498       << s;
499 }
500 
TEST_P(ResizeBilinearOpTest,TestInvalidInputShape)501 TEST_P(ResizeBilinearOpTest, TestInvalidInputShape) {
502   AddInputFromArray<float>(TensorShape({2, 2, 1}), {1, 2, 3, 4});
503   AddInputFromArray<int32>(TensorShape({2}), {4, 4});
504   Status s = RunOpKernel();
505   EXPECT_TRUE(absl::StrContains(
506       s.ToString(), "Invalid argument: input must be 4-dimensional"))
507       << s;
508 }
509 
TEST_P(ResizeBilinearOpTest,TestInvalidSizeDim)510 TEST_P(ResizeBilinearOpTest, TestInvalidSizeDim) {
511   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
512   AddInputFromArray<int32>(TensorShape({2, 1}), {4, 4});
513   Status s = RunOpKernel();
514   EXPECT_TRUE(absl::StrContains(
515       s.ToString(), "Invalid argument: shape_t must be 1-dimensional"))
516       << s;
517 }
518 
TEST_P(ResizeBilinearOpTest,TestInvalidSizeElements)519 TEST_P(ResizeBilinearOpTest, TestInvalidSizeElements) {
520   AddInputFromArray<float>(TensorShape({1, 2, 2, 1}), {1, 2, 3, 4});
521   AddInputFromArray<int32>(TensorShape({3}), {4, 4, 1});
522   Status s = RunOpKernel();
523   EXPECT_TRUE(absl::StrContains(
524       s.ToString(), "Invalid argument: shape_t must have two elements"))
525       << s;
526 }
527 
528 INSTANTIATE_TEST_SUITE_P(ResizeBilinearOpTestCpu, ResizeBilinearOpTest,
529                          ::testing::Values(TestDevice::CPU));
530 INSTANTIATE_TEST_SUITE_P(ResizeBilinearHalfPixelCentersOpTestCpu,
531                          ResizeBilinearHalfPixelCentersOpTest,
532                          ::testing::Values(TestDevice::CPU));
533 INSTANTIATE_TEST_SUITE_P(ResizeBilinearOpAlignCornersTestCpu,
534                          ResizeBilinearOpAlignCornersTest,
535                          ::testing::Values(TestDevice::CPU));
536 #if GOOGLE_CUDA || TENSORFLOW_USE_ROCM
537 // Instantiate tests for GPU.
538 INSTANTIATE_TEST_SUITE_P(ResizeBilinearOpTestGpu, ResizeBilinearOpTest,
539                          ::testing::Values(TestDevice::GPU));
540 INSTANTIATE_TEST_SUITE_P(ResizeBilinearHalfPixelCentersOpTestGpu,
541                          ResizeBilinearHalfPixelCentersOpTest,
542                          ::testing::Values(TestDevice::GPU));
543 INSTANTIATE_TEST_SUITE_P(ResizeBilinearOpAlignCornersTestGpu,
544                          ResizeBilinearOpAlignCornersTest,
545                          ::testing::Values(TestDevice::GPU));
546 #endif  // GOOGLE_CUDA || TENSORFLOW_USE_ROCM
547 
548 class ResizeBM : public ResizeBilinearOpTest {
549  public:
TestBody()550   void TestBody() override {}
SetUpBenchmark(int input_width,int input_height,int num_channels,int output_width,int output_height)551   void SetUpBenchmark(int input_width, int input_height, int num_channels,
552                       int output_width, int output_height) {
553     TF_EXPECT_OK(NodeDefBuilder("resize_bilinear_op", "ResizeBilinear")
554                      .Input(FakeInput(DT_FLOAT))
555                      .Input(FakeInput(DT_INT32))
556                      .Attr("align_corners", align_corners_)
557                      .Attr("half_pixel_centers", half_pixel_centers_)
558                      .Finalize(node_def()));
559     TF_EXPECT_OK(InitOp());
560     const TensorShape shape(
561         {/*batch_size*/ 1, input_width, input_height, num_channels});
562     SetRandomImageInput(shape);
563     AddInputFromArray<int32>(TensorShape({2}), {output_width, output_height});
564   }
565 
566   using ResizeBilinearOpTest::RunOpKernel;
567 };
568 
569 #ifdef PLATFORM_GOOGLE
570 
BM_Resize(benchmark::State & state)571 void BM_Resize(benchmark::State& state) {
572   ResizeBM bench;
573   bench.SetUpBenchmark(640, 480, 3, 1024, 768);
574   for (const auto _ : state) {
575     CHECK(bench.RunOpKernel().ok());
576   }
577 }
578 BENCHMARK(BM_Resize);
579 
580 #endif
581 
582 }  // namespace tensorflow
583