array_grad_test.cc revision 8fe32029f77b287a207c3bc3e0127fb35a3e23da
1/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.
2
3Licensed under the Apache License, Version 2.0 (the "License");
4you may not use this file except in compliance with the License.
5You may obtain a copy of the License at
6
7    http://www.apache.org/licenses/LICENSE-2.0
8
9Unless required by applicable law or agreed to in writing, software
10distributed under the License is distributed on an "AS IS" BASIS,
11WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12See the License for the specific language governing permissions and
13limitations under the License.
14==============================================================================*/
15
16#include "tensorflow/cc/framework/grad_op_registry.h"
17#include "tensorflow/cc/framework/gradient_checker.h"
18#include "tensorflow/cc/framework/testutil.h"
19#include "tensorflow/cc/gradients/grad_testutil.h"
20#include "tensorflow/cc/ops/array_ops_internal.h"
21#include "tensorflow/cc/ops/standard_ops.h"
22#include "tensorflow/core/framework/tensor_testutil.h"
23#include "tensorflow/core/lib/core/status_test_util.h"
24
25namespace tensorflow {
26using namespace ops;  // NOLINT(build/namespaces)
27using ops::internal::MirrorPadGrad;
28
29namespace {
30
31class ArrayGradTest : public ::testing::Test {
32 protected:
33  ArrayGradTest() : scope_(Scope::NewRootScope()) {}
34
35  void RunTest(const Output& x, const TensorShape& x_shape, const Output& y,
36               const TensorShape& y_shape) {
37    TF_ASSERT_OK(scope_.status());
38    float max_error;
39    TF_ASSERT_OK(ComputeGradientError(scope_, {x}, {x_shape}, {y}, {y_shape},
40                                      &max_error));
41    EXPECT_LT(max_error, 1e-3);
42  }
43
44  void RunTest(const OutputList& xs, const std::vector<TensorShape>& x_shapes,
45               const OutputList& ys, const std::vector<TensorShape>& y_shapes) {
46    TF_ASSERT_OK(scope_.status());
47    float max_error;
48    TF_ASSERT_OK(
49        ComputeGradientError(scope_, xs, x_shapes, ys, y_shapes, &max_error));
50    EXPECT_LT(max_error, 1e-3);
51  }
52
53  Scope scope_;
54};
55
56TEST_F(ArrayGradTest, PackGrad_Axis0) {
57  TensorShape x_shape({1, 2, 3});
58  std::vector<Output> xs;
59  xs.push_back(Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape)));
60  xs.push_back(Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape)));
61  auto y = Pack(scope_, xs, Pack::Axis(0));
62  TensorShape y_shape({2, 1, 2, 3});
63  RunTest(xs, {x_shape, x_shape}, {y}, {y_shape});
64}
65
66TEST_F(ArrayGradTest, PackGrad_Axis1) {
67  TensorShape x_shape({1, 2, 3});
68  std::vector<Output> xs;
69  xs.push_back(Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape)));
70  xs.push_back(Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape)));
71  auto y = Pack(scope_, xs, Pack::Axis(1));
72  TensorShape y_shape({1, 2, 2, 3});
73  RunTest(xs, {x_shape, x_shape}, {y}, {y_shape});
74}
75
76TEST_F(ArrayGradTest, UnpackGrad_Axis0) {
77  TensorShape x_shape({4, 2, 3});
78  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
79  // Unpacking the first dimension results in 4 outputs.
80  std::vector<TensorShape> y_shapes(4, TensorShape({2, 3}));
81  auto y = Unpack(scope_, x, 4, Unpack::Axis(0));
82  RunTest({x}, {x_shape}, y.output, y_shapes);
83}
84
85TEST_F(ArrayGradTest, UnpackGrad_Axis1) {
86  TensorShape x_shape({4, 2, 3});
87  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
88  // Unpacking the second dimension results in 2 outputs.
89  std::vector<TensorShape> y_shapes(2, TensorShape({4, 3}));
90  auto y = Unpack(scope_, x, 2, Unpack::Axis(1));
91  RunTest({x}, {x_shape}, y.output, y_shapes);
92}
93
94TEST_F(ArrayGradTest, IdentityGrad) {
95  TensorShape shape({5, 2});
96  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(shape));
97  auto y = Identity(scope_, x);
98  RunTest(x, shape, y, shape);
99}
100
101TEST_F(ArrayGradTest, SplitGrad) {
102  TensorShape x_shape({5, 2});
103  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
104  // Split along the second dimension.
105  auto split_dim = Const(scope_, 1, {});
106  auto y = Split(scope_, split_dim, x, /* num_split */ 2);
107  TensorShape y_shape = TensorShape({5, 1});
108  RunTest({x}, {x_shape}, y.output, {y_shape, y_shape});
109}
110
111TEST_F(ArrayGradTest, DiagGrad) {
112  TensorShape x_shape({5, 2});
113  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
114  auto y = Diag(scope_, x);
115  TensorShape y_shape({5, 2, 5, 2});
116  RunTest(x, x_shape, y, y_shape);
117}
118
119TEST_F(ArrayGradTest, DiagPartGrad) {
120  TensorShape x_shape({5, 2, 5, 2});
121  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
122  auto y = DiagPart(scope_, x);
123  TensorShape y_shape({5, 2});
124  RunTest(x, x_shape, y, y_shape);
125}
126
127TEST_F(ArrayGradTest, MatrixDiagGrad) {
128  TensorShape x_shape({5, 2});
129  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
130  auto y = MatrixDiag(scope_, x);
131  TensorShape y_shape({5, 2, 2});
132  RunTest(x, x_shape, y, y_shape);
133}
134
135TEST_F(ArrayGradTest, MatrixBandPartGrad) {
136  TensorShape shape({5, 5});
137  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(shape));
138  const int64 num_lower = 1;
139  const int64 num_upper = 2;
140  auto y = MatrixBandPart(scope_, x, num_lower, num_upper);
141  RunTest(x, shape, y, shape);
142}
143
144TEST_F(ArrayGradTest, GatherNdGrad_SimpleIndexing) {
145  TensorShape x_shape({2, 2});
146  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
147  auto indices = Const(scope_, {{0, 0}, {1, 1}});
148  TensorShape y_shape({2});
149  auto y = GatherNd(scope_, x, indices);
150  RunTest(x, x_shape, y, y_shape);
151}
152
153TEST_F(ArrayGradTest, GatherNdGrad_SliceIndexing) {
154  TensorShape shape({2, 2});
155  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(shape));
156  auto indices = Const(scope_, {{1}, {0}});
157  auto y = GatherNd(scope_, x, indices);
158  RunTest(x, shape, y, shape);
159}
160
161TEST_F(ArrayGradTest, CheckNumericsGrad) {
162  TensorShape shape({5, 2});
163  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(shape));
164  auto y = CheckNumerics(scope_, x, "CheckNumerics failed");
165  RunTest(x, shape, y, shape);
166}
167
168TEST_F(ArrayGradTest, ReshapeGrad) {
169  TensorShape x_shape({5, 2});
170  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
171  TensorShape y_shape({2, 5});
172  auto y = Reshape(scope_, x, {2, 5});
173  RunTest(x, x_shape, y, y_shape);
174}
175
176TEST_F(ArrayGradTest, ExpandDimsGrad) {
177  TensorShape x_shape({5, 2});
178  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
179  TensorShape y_shape({1, 5, 2});
180  auto y = ExpandDims(scope_, x, 0);
181  RunTest(x, x_shape, y, y_shape);
182}
183
184TEST_F(ArrayGradTest, SqueezeGrad) {
185  TensorShape x_shape({1, 5, 1, 2});
186  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
187  TensorShape y_shape({5, 2});
188  auto y = Squeeze(scope_, x);
189  RunTest(x, x_shape, y, y_shape);
190}
191
192TEST_F(ArrayGradTest, TransposeGrad) {
193  TensorShape x_shape({5, 2});
194  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
195  TensorShape y_shape({2, 5});
196  auto y = Transpose(scope_, x, {1, 0});
197  RunTest(x, x_shape, y, y_shape);
198}
199
200TEST_F(ArrayGradTest, ReverseSequenceGrad) {
201  TensorShape shape({5, 2, 5});
202  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(shape));
203  auto seq_lengths = Const(scope_, {1, 2, 3, 4, 5});
204  // batch_dim defaults to 0.
205  auto y = ReverseSequence(scope_, x, seq_lengths, /* seq_dim */ 2);
206  RunTest(x, shape, y, shape);
207}
208
209TEST_F(ArrayGradTest, ReverseGrad) {
210  TensorShape shape({5, 2, 5});
211  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(shape));
212  auto y = Reverse(scope_, x, {0, 2});
213  RunTest(x, shape, y, shape);
214}
215
216TEST_F(ArrayGradTest, ScatterNdGrad_SimpleIndexing) {
217  TensorShape updates_shape({4});
218  auto updates =
219      Placeholder(scope_, DT_FLOAT, Placeholder::Shape(updates_shape));
220  auto indices = Const(scope_, {{4}, {3}, {1}, {7}});
221  TensorShape y_shape({8});
222  auto y = ScatterNd(scope_, indices, updates, {8});
223  RunTest(updates, updates_shape, y, y_shape);
224}
225
226TEST_F(ArrayGradTest, ScatterNdGrad_SliceIndexing) {
227  TensorShape updates_shape({2, 4, 4});
228  auto updates =
229      Placeholder(scope_, DT_FLOAT, Placeholder::Shape(updates_shape));
230  auto indices = Const(scope_, {{0}, {2}});
231  TensorShape y_shape({4, 4, 4});
232  auto y = ScatterNd(scope_, indices, updates, {4, 4, 4});
233  RunTest(updates, updates_shape, y, y_shape);
234}
235
236TEST_F(ArrayGradTest, PadGrad) {
237  TensorShape x_shape({2, 3});
238  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
239  auto paddings = Const(scope_, {{1, 1}, {2, 2}});
240  TensorShape y_shape({4, 7});
241  auto y = Pad(scope_, x, paddings);
242  RunTest(x, x_shape, y, y_shape);
243}
244
245TEST_F(ArrayGradTest, SpaceToBatchGrad) {
246  TensorShape x_shape({1, 2, 2, 1});
247  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
248  auto paddings = Const(scope_, {{1, 1}, {1, 1}});
249  TensorShape y_shape({4, 2, 2, 1});
250  auto y = SpaceToBatch(scope_, x, paddings, /* block_size */ 2);
251  RunTest(x, x_shape, y, y_shape);
252}
253
254TEST_F(ArrayGradTest, SpaceToBatchNdGrad) {
255  TensorShape x_shape({2, 2, 4, 1});
256  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
257  auto block_shape = Const(scope_, {2, 2});
258  auto paddings = Const(scope_, {{0, 0}, {2, 0}});
259  TensorShape y_shape({8, 1, 3, 1});
260  auto y = SpaceToBatchND(scope_, x, block_shape, paddings);
261  RunTest(x, x_shape, y, y_shape);
262}
263
264TEST_F(ArrayGradTest, BatchToSpaceGrad) {
265  TensorShape x_shape({4, 2, 2, 1});
266  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
267  auto paddings = Const(scope_, {{1, 1}, {1, 1}});
268  TensorShape y_shape({1, 2, 2, 1});
269  auto y = BatchToSpace(scope_, x, paddings, /* block_size */ 2);
270  RunTest(x, x_shape, y, y_shape);
271}
272
273TEST_F(ArrayGradTest, BatchToSpaceNdGrad) {
274  TensorShape x_shape({8, 1, 3, 1});
275  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
276  auto block_shape = Const(scope_, {2, 2});
277  auto paddings = Const(scope_, {{0, 0}, {2, 0}});
278  TensorShape y_shape({2, 2, 4, 1});
279  auto y = BatchToSpaceND(scope_, x, block_shape, paddings);
280  RunTest(x, x_shape, y, y_shape);
281}
282
283TEST_F(ArrayGradTest, SpaceToDepthGrad) {
284  TensorShape x_shape({1, 2, 2, 1});
285  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
286  TensorShape y_shape({1, 1, 1, 4});
287  auto y = SpaceToDepth(scope_, x, /* block_size */ 2);
288  RunTest(x, x_shape, y, y_shape);
289}
290
291TEST_F(ArrayGradTest, DepthToSpaceGrad) {
292  TensorShape x_shape({1, 1, 1, 4});
293  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
294  TensorShape y_shape({1, 2, 2, 1});
295  auto y = DepthToSpace(scope_, x, /* block_size */ 2);
296  RunTest(x, x_shape, y, y_shape);
297}
298
299TEST_F(ArrayGradTest, MirrorPadGrad_Reflect) {
300  TensorShape x_shape({2, 3});
301  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
302  auto paddings = Const(scope_, {{1, 1}, {2, 2}});
303  TensorShape y_shape({4, 7});
304  auto y = MirrorPad(scope_, x, paddings, "REFLECT");
305  RunTest(x, x_shape, y, y_shape);
306}
307
308TEST_F(ArrayGradTest, MirrorPadGrad_Symmetric) {
309  TensorShape x_shape({2, 3});
310  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
311  auto paddings = Const(scope_, {{1, 1}, {2, 2}});
312  TensorShape y_shape({4, 7});
313  auto y = MirrorPad(scope_, x, paddings, "SYMMETRIC");
314  RunTest(x, x_shape, y, y_shape);
315}
316
317TEST_F(ArrayGradTest, MirrorPadGradGrad_Reflect) {
318  TensorShape x_shape({4, 7});
319  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
320  auto paddings = Const(scope_, {{1, 1}, {2, 2}});
321  TensorShape y_shape({2, 3});
322  auto y = MirrorPadGrad(scope_, x, paddings, "REFLECT");
323  RunTest(x, x_shape, y, y_shape);
324}
325
326TEST_F(ArrayGradTest, MirrorPadGradGrad_Symmetric) {
327  TensorShape x_shape({4, 7});
328  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
329  auto paddings = Const(scope_, {{1, 1}, {2, 2}});
330  TensorShape y_shape({2, 3});
331  auto y = MirrorPadGrad(scope_, x, paddings, "SYMMETRIC");
332  RunTest(x, x_shape, y, y_shape);
333}
334
335}  // namespace
336}  // namespace tensorflow
337