array_grad_test.cc revision e6b011763a60d239972c8c6c0f36536ab6f885a3
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<float, float, float>(
40        scope_, {x}, {x_shape}, {y}, {y_shape}, &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((ComputeGradientError<float, float, float>(
49        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, StackGrad_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 = Stack(scope_, xs, Stack::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, StackGrad_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 = Stack(scope_, xs, Stack::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, UnstackGrad_Axis0) {
77  TensorShape x_shape({4, 2, 3});
78  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
79  // Unstacking the first dimension results in 4 outputs.
80  std::vector<TensorShape> y_shapes(4, TensorShape({2, 3}));
81  auto y = Unstack(scope_, x, 4, Unstack::Axis(0));
82  RunTest({x}, {x_shape}, y.output, y_shapes);
83}
84
85TEST_F(ArrayGradTest, UnstackGrad_Axis1) {
86  TensorShape x_shape({4, 2, 3});
87  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
88  // Unstacking the second dimension results in 2 outputs.
89  std::vector<TensorShape> y_shapes(2, TensorShape({4, 3}));
90  auto y = Unstack(scope_, x, 2, Unstack::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, ScatterNdNonAliasingAddGrad_SimpleIndexing) {
237  TensorShape updates_shape({4});
238  TensorShape input_shape({8});
239  auto input = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(input_shape));
240  auto updates =
241      Placeholder(scope_, DT_FLOAT, Placeholder::Shape(updates_shape));
242  auto indices = Const(scope_, {{4}, {3}, {1}, {7}});
243  auto y = ScatterNdNonAliasingAdd(scope_, input, indices, updates);
244  RunTest({input, updates}, {input_shape, updates_shape}, {y}, {input_shape});
245}
246
247TEST_F(ArrayGradTest, ScatterNdNonAliasingAddGrad_SliceIndexing) {
248  TensorShape updates_shape({2, 4, 4});
249  TensorShape input_shape({4, 4, 4});
250  auto input = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(input_shape));
251  auto updates =
252      Placeholder(scope_, DT_FLOAT, Placeholder::Shape(updates_shape));
253  auto indices = Const(scope_, {{0}, {2}});
254  auto y = ScatterNdNonAliasingAdd(scope_, input, indices, updates);
255  RunTest({input, updates}, {input_shape, updates_shape}, {y}, {input_shape});
256}
257
258TEST_F(ArrayGradTest, PadGrad) {
259  TensorShape x_shape({2, 3});
260  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
261  auto paddings = Const(scope_, {{1, 1}, {2, 2}});
262  TensorShape y_shape({4, 7});
263  auto y = Pad(scope_, x, paddings);
264  RunTest(x, x_shape, y, y_shape);
265}
266
267TEST_F(ArrayGradTest, SpaceToBatchGrad) {
268  TensorShape x_shape({1, 2, 2, 1});
269  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
270  auto paddings = Const(scope_, {{1, 1}, {1, 1}});
271  TensorShape y_shape({4, 2, 2, 1});
272  auto y = SpaceToBatch(scope_, x, paddings, /* block_size */ 2);
273  RunTest(x, x_shape, y, y_shape);
274}
275
276TEST_F(ArrayGradTest, SpaceToBatchNdGrad) {
277  TensorShape x_shape({2, 2, 4, 1});
278  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
279  auto block_shape = Const(scope_, {2, 2});
280  auto paddings = Const(scope_, {{0, 0}, {2, 0}});
281  TensorShape y_shape({8, 1, 3, 1});
282  auto y = SpaceToBatchND(scope_, x, block_shape, paddings);
283  RunTest(x, x_shape, y, y_shape);
284}
285
286TEST_F(ArrayGradTest, BatchToSpaceGrad) {
287  TensorShape x_shape({4, 2, 2, 1});
288  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
289  auto paddings = Const(scope_, {{1, 1}, {1, 1}});
290  TensorShape y_shape({1, 2, 2, 1});
291  auto y = BatchToSpace(scope_, x, paddings, /* block_size */ 2);
292  RunTest(x, x_shape, y, y_shape);
293}
294
295TEST_F(ArrayGradTest, BatchToSpaceNdGrad) {
296  TensorShape x_shape({8, 1, 3, 1});
297  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
298  auto block_shape = Const(scope_, {2, 2});
299  auto paddings = Const(scope_, {{0, 0}, {2, 0}});
300  TensorShape y_shape({2, 2, 4, 1});
301  auto y = BatchToSpaceND(scope_, x, block_shape, paddings);
302  RunTest(x, x_shape, y, y_shape);
303}
304
305TEST_F(ArrayGradTest, SpaceToDepthGrad) {
306  TensorShape x_shape({1, 2, 2, 1});
307  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
308  TensorShape y_shape({1, 1, 1, 4});
309  auto y = SpaceToDepth(scope_, x, /* block_size */ 2);
310  RunTest(x, x_shape, y, y_shape);
311}
312
313TEST_F(ArrayGradTest, DepthToSpaceGrad) {
314  TensorShape x_shape({1, 1, 1, 4});
315  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
316  TensorShape y_shape({1, 2, 2, 1});
317  auto y = DepthToSpace(scope_, x, /* block_size */ 2);
318  RunTest(x, x_shape, y, y_shape);
319}
320
321TEST_F(ArrayGradTest, MirrorPadGrad_Reflect) {
322  TensorShape x_shape({2, 3});
323  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
324  auto paddings = Const(scope_, {{1, 1}, {2, 2}});
325  TensorShape y_shape({4, 7});
326  auto y = MirrorPad(scope_, x, paddings, "REFLECT");
327  RunTest(x, x_shape, y, y_shape);
328}
329
330TEST_F(ArrayGradTest, MirrorPadGrad_Symmetric) {
331  TensorShape x_shape({2, 3});
332  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
333  auto paddings = Const(scope_, {{1, 1}, {2, 2}});
334  TensorShape y_shape({4, 7});
335  auto y = MirrorPad(scope_, x, paddings, "SYMMETRIC");
336  RunTest(x, x_shape, y, y_shape);
337}
338
339TEST_F(ArrayGradTest, MirrorPadGradGrad_Reflect) {
340  TensorShape x_shape({4, 7});
341  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
342  auto paddings = Const(scope_, {{1, 1}, {2, 2}});
343  TensorShape y_shape({2, 3});
344  auto y = MirrorPadGrad(scope_, x, paddings, "REFLECT");
345  RunTest(x, x_shape, y, y_shape);
346}
347
348TEST_F(ArrayGradTest, MirrorPadGradGrad_Symmetric) {
349  TensorShape x_shape({4, 7});
350  auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
351  auto paddings = Const(scope_, {{1, 1}, {2, 2}});
352  TensorShape y_shape({2, 3});
353  auto y = MirrorPadGrad(scope_, x, paddings, "SYMMETRIC");
354  RunTest(x, x_shape, y, y_shape);
355}
356
357}  // namespace
358}  // namespace tensorflow
359