1 /* Copyright 2019 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/lib/strings/str_util.h"
30 #include "tensorflow/core/platform/test.h"
31
32 namespace tensorflow {
33
34 class MirrorPadOpTest : public OpsTestBase {
35 protected:
36 template <typename T>
MakeOp(const string & mode)37 void MakeOp(const string& mode) {
38 TF_EXPECT_OK(NodeDefBuilder("mirror_pad_op", "MirrorPad")
39 .Input(FakeInput(DataTypeToEnum<T>::value))
40 .Input(FakeInput(DT_INT32))
41 .Attr("mode", mode)
42 .Finalize(node_def()));
43 TF_EXPECT_OK(InitOp());
44 }
45 };
46
47 #define REGISTER_TEST(T) \
48 TEST_F(MirrorPadOpTest, TestMirrorPadReflect##T) { \
49 MakeOp<T>("REFLECT"); \
50 AddInputFromArray<T>(TensorShape({1, 2, 3, 1}), {1, 2, 3, 4, 5, 6}); \
51 AddInputFromArray<int32>(TensorShape({4, 2}), {0, 0, 1, 1, 2, 2, 0, 0}); \
52 TF_ASSERT_OK(RunOpKernel()); \
53 \
54 Tensor expected(allocator(), DataTypeToEnum<T>::value, \
55 TensorShape({1, 4, 7, 1})); \
56 test::FillValues<T>(&expected, \
57 {6, 5, 4, 5, 6, 5, 4, 3, 2, 1, 2, 3, 2, 1, \
58 6, 5, 4, 5, 6, 5, 4, 3, 2, 1, 2, 3, 2, 1}); \
59 test::ExpectTensorEqual<T>(expected, *GetOutput(0)); \
60 } \
61 \
62 TEST_F(MirrorPadOpTest, TestMirrorPadSymmetric##T) { \
63 MakeOp<T>("SYMMETRIC"); \
64 AddInputFromArray<T>(TensorShape({1, 2, 1, 3}), {1, 2, 3, 4, 5, 6}); \
65 AddInputFromArray<int32>(TensorShape({4, 2}), {1, 1, 0, 0, 0, 0, 2, 2}); \
66 TF_ASSERT_OK(RunOpKernel()); \
67 \
68 Tensor expected(allocator(), DataTypeToEnum<T>::value, \
69 TensorShape({3, 2, 1, 7})); \
70 test::FillValues<T>( \
71 &expected, \
72 {2, 1, 1, 2, 3, 3, 2, 5, 4, 4, 5, 6, 6, 5, 2, 1, 1, 2, 3, 3, 2, \
73 5, 4, 4, 5, 6, 6, 5, 2, 1, 1, 2, 3, 3, 2, 5, 4, 4, 5, 6, 6, 5}); \
74 test::ExpectTensorEqual<T>(expected, *GetOutput(0)); \
75 }
76
77 REGISTER_TEST(float)
REGISTER_TEST(double)78 REGISTER_TEST(double)
79 REGISTER_TEST(uint8)
80 REGISTER_TEST(uint16)
81 REGISTER_TEST(int8)
82 REGISTER_TEST(int16)
83 REGISTER_TEST(int32)
84 REGISTER_TEST(int64)
85
86 #undef REGISTER_TEST
87
88 TEST_F(MirrorPadOpTest, TestMirrorPadReflectLargeInput) {
89 MakeOp<float>("REFLECT");
90 // Generate a relatively large input
91 const int kInput = 1000;
92 const int kPad = 10;
93 const int kOutput = kInput + 2 * kPad;
94
95 // Input:
96 // 0, 1, 2, ..., 999
97 // 0, 1, 2, ..., 999
98 // ... (altogether 1000 lines)
99 // 0, 1, 2, ..., 999
100 AddInput<float>(TensorShape({1, kInput, kInput, 1}),
101 [=](int i) -> float { return i % kInput; });
102 AddInputFromArray<int32>(TensorShape({4, 2}),
103 {0, 0, kPad, kPad, kPad, kPad, 0, 0});
104 TF_ASSERT_OK(RunOpKernel());
105
106 Tensor expected(allocator(), DT_FLOAT, TensorShape({1, kOutput, kOutput, 1}));
107 test::FillFn<float>(&expected, [=](int i) -> float {
108 i = i % kOutput;
109 if (0 <= i && i < kPad)
110 return kPad - i;
111 else if (kPad <= i && i < kInput + kPad)
112 return i - kPad;
113 else if (kInput + kPad <= i && i < kOutput)
114 return 2 * kInput + kPad - 2 - i;
115 else
116 return -1;
117 });
118
119 test::ExpectTensorEqual<float>(expected, *GetOutput(0));
120 }
121
TEST_F(MirrorPadOpTest,TestMirrorPadSymmetricLargeInput)122 TEST_F(MirrorPadOpTest, TestMirrorPadSymmetricLargeInput) {
123 MakeOp<float>("SYMMETRIC");
124 // Generate a relatively large input
125 const int kInput = 1000;
126 const int kPad = 10;
127 const int kOutput = kInput + 2 * kPad;
128
129 // Input:
130 // 0, 1, 2, ..., 999
131 // 0, 1, 2, ..., 999
132 // ... (altogether 1000 lines)
133 // 0, 1, 2, ..., 999
134 AddInput<float>(TensorShape({1, kInput, kInput, 1}),
135 [=](int i) -> float { return i % kInput; });
136 AddInputFromArray<int32>(TensorShape({4, 2}),
137 {0, 0, kPad, kPad, kPad, kPad, 0, 0});
138 TF_ASSERT_OK(RunOpKernel());
139
140 Tensor expected(allocator(), DT_FLOAT, TensorShape({1, kOutput, kOutput, 1}));
141 test::FillFn<float>(&expected, [=](int i) -> float {
142 i = i % kOutput;
143 if (0 <= i && i < kPad)
144 return kPad - i - 1;
145 else if (kPad <= i && i < kInput + kPad)
146 return i - kPad;
147 else if (kInput + kPad <= i && i < kOutput)
148 return 2 * kInput + kPad - 1 - i;
149 else
150 return -1;
151 });
152
153 test::ExpectTensorEqual<float>(expected, *GetOutput(0));
154 }
155
156 class MirrorPadGradOpTest : public OpsTestBase {
157 protected:
158 template <typename T>
MakeOp(const string & mode)159 void MakeOp(const string& mode) {
160 TF_EXPECT_OK(NodeDefBuilder("mirror_pad_grad_op", "MirrorPadGrad")
161 .Input(FakeInput(DataTypeToEnum<T>::value))
162 .Input(FakeInput(DT_INT32))
163 .Attr("mode", mode)
164 .Finalize(node_def()));
165 TF_EXPECT_OK(InitOp());
166 }
167 };
168
169 #define REGISTER_TEST(T) \
170 TEST_F(MirrorPadGradOpTest, TestMirrorPadGradReflect##T) { \
171 MakeOp<T>("REFLECT"); \
172 AddInput<T>(TensorShape({1, 4, 7, 1}), [](int i) -> T { return i % 7; }); \
173 AddInputFromArray<int32>(TensorShape({4, 2}), {0, 0, 1, 1, 2, 2, 0, 0}); \
174 TF_ASSERT_OK(RunOpKernel()); \
175 \
176 Tensor expected(allocator(), DataTypeToEnum<T>::value, \
177 TensorShape({1, 2, 3, 1})); \
178 test::FillValues<T>(&expected, {16, 18, 8, 16, 18, 8}); \
179 test::ExpectTensorEqual<T>(expected, *GetOutput(0)); \
180 } \
181 \
182 TEST_F(MirrorPadGradOpTest, TestMirrorPadGradSymmetric##T) { \
183 MakeOp<T>("SYMMETRIC"); \
184 AddInput<T>(TensorShape({3, 2, 1, 7}), [](int i) -> T { return i % 7; }); \
185 AddInputFromArray<int32>(TensorShape({4, 2}), {1, 1, 0, 0, 0, 0, 2, 2}); \
186 TF_ASSERT_OK(RunOpKernel()); \
187 \
188 Tensor expected(allocator(), DataTypeToEnum<T>::value, \
189 TensorShape({1, 2, 1, 3})); \
190 test::FillValues<T>(&expected, {9, 27, 27, 9, 27, 27}); \
191 test::ExpectTensorEqual<T>(expected, *GetOutput(0)); \
192 }
193
194 REGISTER_TEST(float)
195 REGISTER_TEST(double)
196 REGISTER_TEST(uint8)
197 REGISTER_TEST(uint16)
198 REGISTER_TEST(int8)
199 REGISTER_TEST(int16)
200 REGISTER_TEST(int32)
201 REGISTER_TEST(int64)
202
203 #undef REGISTER_TEST
204
205 } // namespace tensorflow
206