• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2016 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/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 
25 namespace tensorflow {
26 namespace {
27 
28 using namespace ops;  // NOLINT(build/namespaces)
29 using ops::internal::MirrorPadGrad;
30 
31 class ArrayGradTest : public ::testing::Test {
32  protected:
ArrayGradTest()33   ArrayGradTest() : scope_(Scope::NewRootScope()) {}
34 
RunTest(const Output & x,const TensorShape & x_shape,const Output & y,const TensorShape & y_shape)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 
RunTest(const OutputList & xs,const std::vector<TensorShape> & x_shapes,const OutputList & ys,const std::vector<TensorShape> & y_shapes)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 
TEST_F(ArrayGradTest,StackGrad_Axis0)56 TEST_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 
TEST_F(ArrayGradTest,StackGrad_Axis1)66 TEST_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 
TEST_F(ArrayGradTest,UnstackGrad_Axis0)76 TEST_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 
TEST_F(ArrayGradTest,UnstackGrad_Axis1)85 TEST_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 
TEST_F(ArrayGradTest,IdentityGrad)94 TEST_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 
TEST_F(ArrayGradTest,SplitGrad)101 TEST_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 
TEST_F(ArrayGradTest,FillGrad)111 TEST_F(ArrayGradTest, FillGrad) {
112   TensorShape x_shape({});
113   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
114   TensorShape y_shape({2, 5, 3});
115   auto y = Fill(scope_, {2, 5, 3}, x);
116   RunTest(x, x_shape, y, y_shape);
117 }
118 
TEST_F(ArrayGradTest,DiagGrad)119 TEST_F(ArrayGradTest, DiagGrad) {
120   TensorShape x_shape({5, 2});
121   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
122   auto y = Diag(scope_, x);
123   TensorShape y_shape({5, 2, 5, 2});
124   RunTest(x, x_shape, y, y_shape);
125 }
126 
TEST_F(ArrayGradTest,DiagPartGrad)127 TEST_F(ArrayGradTest, DiagPartGrad) {
128   TensorShape x_shape({5, 2, 5, 2});
129   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
130   auto y = DiagPart(scope_, x);
131   TensorShape y_shape({5, 2});
132   RunTest(x, x_shape, y, y_shape);
133 }
134 
TEST_F(ArrayGradTest,MatrixDiagGrad)135 TEST_F(ArrayGradTest, MatrixDiagGrad) {
136   TensorShape x_shape({5, 2});
137   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
138   auto y = MatrixDiag(scope_, x);
139   TensorShape y_shape({5, 2, 2});
140   RunTest(x, x_shape, y, y_shape);
141 }
142 
TEST_F(ArrayGradTest,MatrixBandPartGrad)143 TEST_F(ArrayGradTest, MatrixBandPartGrad) {
144   TensorShape shape({5, 5});
145   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(shape));
146   const int64 num_lower = 1;
147   const int64 num_upper = 2;
148   auto y = MatrixBandPart(scope_, x, num_lower, num_upper);
149   RunTest(x, shape, y, shape);
150 }
151 
TEST_F(ArrayGradTest,GatherNdGrad_SimpleIndexing)152 TEST_F(ArrayGradTest, GatherNdGrad_SimpleIndexing) {
153   TensorShape x_shape({2, 2});
154   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
155   auto indices = Const(scope_, {{0, 0}, {1, 1}});
156   TensorShape y_shape({2});
157   auto y = GatherNd(scope_, x, indices);
158   RunTest(x, x_shape, y, y_shape);
159 }
160 
TEST_F(ArrayGradTest,GatherNdGrad_SliceIndexing)161 TEST_F(ArrayGradTest, GatherNdGrad_SliceIndexing) {
162   TensorShape shape({2, 2});
163   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(shape));
164   auto indices = Const(scope_, {{1}, {0}});
165   auto y = GatherNd(scope_, x, indices);
166   RunTest(x, shape, y, shape);
167 }
168 
TEST_F(ArrayGradTest,CheckNumericsGrad)169 TEST_F(ArrayGradTest, CheckNumericsGrad) {
170   TensorShape shape({5, 2});
171   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(shape));
172   auto y = CheckNumerics(scope_, x, "CheckNumerics failed");
173   RunTest(x, shape, y, shape);
174 }
175 
TEST_F(ArrayGradTest,ReshapeGrad)176 TEST_F(ArrayGradTest, ReshapeGrad) {
177   TensorShape x_shape({5, 2});
178   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
179   TensorShape y_shape({2, 5});
180   auto y = Reshape(scope_, x, {2, 5});
181   RunTest(x, x_shape, y, y_shape);
182 }
183 
TEST_F(ArrayGradTest,ExpandDimsGrad)184 TEST_F(ArrayGradTest, ExpandDimsGrad) {
185   TensorShape x_shape({5, 2});
186   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
187   TensorShape y_shape({1, 5, 2});
188   auto y = ExpandDims(scope_, x, 0);
189   RunTest(x, x_shape, y, y_shape);
190 }
191 
TEST_F(ArrayGradTest,SqueezeGrad)192 TEST_F(ArrayGradTest, SqueezeGrad) {
193   TensorShape x_shape({1, 5, 1, 2});
194   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
195   TensorShape y_shape({5, 2});
196   auto y = Squeeze(scope_, x);
197   RunTest(x, x_shape, y, y_shape);
198 }
199 
TEST_F(ArrayGradTest,TransposeGrad)200 TEST_F(ArrayGradTest, TransposeGrad) {
201   TensorShape x_shape({5, 2});
202   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
203   TensorShape y_shape({2, 5});
204   auto y = Transpose(scope_, x, {1, 0});
205   RunTest(x, x_shape, y, y_shape);
206 }
207 
TEST_F(ArrayGradTest,ReverseSequenceGrad)208 TEST_F(ArrayGradTest, ReverseSequenceGrad) {
209   TensorShape shape({5, 2, 5});
210   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(shape));
211   auto seq_lengths = Const(scope_, {1, 2, 3, 4, 5});
212   // batch_dim defaults to 0.
213   auto y = ReverseSequence(scope_, x, seq_lengths, /* seq_dim */ 2);
214   RunTest(x, shape, y, shape);
215 }
216 
TEST_F(ArrayGradTest,ReverseGrad)217 TEST_F(ArrayGradTest, ReverseGrad) {
218   TensorShape shape({5, 2, 5});
219   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(shape));
220   auto y = Reverse(scope_, x, {0, 2});
221   RunTest(x, shape, y, shape);
222 }
223 
TEST_F(ArrayGradTest,ScatterNdGrad_SimpleIndexing)224 TEST_F(ArrayGradTest, ScatterNdGrad_SimpleIndexing) {
225   TensorShape updates_shape({4});
226   auto updates =
227       Placeholder(scope_, DT_FLOAT, Placeholder::Shape(updates_shape));
228   auto indices = Const(scope_, {{4}, {3}, {1}, {7}});
229   TensorShape y_shape({8});
230   auto y = ScatterNd(scope_, indices, updates, {8});
231   RunTest(updates, updates_shape, y, y_shape);
232 }
233 
TEST_F(ArrayGradTest,ScatterNdGrad_SliceIndexing)234 TEST_F(ArrayGradTest, ScatterNdGrad_SliceIndexing) {
235   TensorShape updates_shape({2, 4, 4});
236   auto updates =
237       Placeholder(scope_, DT_FLOAT, Placeholder::Shape(updates_shape));
238   auto indices = Const(scope_, {{0}, {2}});
239   TensorShape y_shape({4, 4, 4});
240   auto y = ScatterNd(scope_, indices, updates, {4, 4, 4});
241   RunTest(updates, updates_shape, y, y_shape);
242 }
243 
TEST_F(ArrayGradTest,ScatterNdNonAliasingAddGrad_SimpleIndexing)244 TEST_F(ArrayGradTest, ScatterNdNonAliasingAddGrad_SimpleIndexing) {
245   TensorShape updates_shape({4});
246   TensorShape input_shape({8});
247   auto input = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(input_shape));
248   auto updates =
249       Placeholder(scope_, DT_FLOAT, Placeholder::Shape(updates_shape));
250   auto indices = Const(scope_, {{4}, {3}, {1}, {7}});
251   auto y = ScatterNdNonAliasingAdd(scope_, input, indices, updates);
252   RunTest({input, updates}, {input_shape, updates_shape}, {y}, {input_shape});
253 }
254 
TEST_F(ArrayGradTest,ScatterNdNonAliasingAddGrad_SliceIndexing)255 TEST_F(ArrayGradTest, ScatterNdNonAliasingAddGrad_SliceIndexing) {
256   TensorShape updates_shape({2, 4, 4});
257   TensorShape input_shape({4, 4, 4});
258   auto input = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(input_shape));
259   auto updates =
260       Placeholder(scope_, DT_FLOAT, Placeholder::Shape(updates_shape));
261   auto indices = Const(scope_, {{0}, {2}});
262   auto y = ScatterNdNonAliasingAdd(scope_, input, indices, updates);
263   RunTest({input, updates}, {input_shape, updates_shape}, {y}, {input_shape});
264 }
265 
TEST_F(ArrayGradTest,PadGrad)266 TEST_F(ArrayGradTest, PadGrad) {
267   TensorShape x_shape({2, 3});
268   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
269   auto paddings = Const(scope_, {{1, 1}, {2, 2}});
270   TensorShape y_shape({4, 7});
271   auto y = Pad(scope_, x, paddings);
272   RunTest(x, x_shape, y, y_shape);
273 }
274 
TEST_F(ArrayGradTest,SpaceToBatchGrad)275 TEST_F(ArrayGradTest, SpaceToBatchGrad) {
276   TensorShape x_shape({1, 2, 2, 1});
277   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
278   auto paddings = Const(scope_, {{1, 1}, {1, 1}});
279   TensorShape y_shape({4, 2, 2, 1});
280   auto y = SpaceToBatch(scope_, x, paddings, /* block_size */ 2);
281   RunTest(x, x_shape, y, y_shape);
282 }
283 
TEST_F(ArrayGradTest,SpaceToBatchNdGrad)284 TEST_F(ArrayGradTest, SpaceToBatchNdGrad) {
285   TensorShape x_shape({2, 2, 4, 1});
286   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
287   auto block_shape = Const(scope_, {2, 2});
288   auto paddings = Const(scope_, {{0, 0}, {2, 0}});
289   TensorShape y_shape({8, 1, 3, 1});
290   auto y = SpaceToBatchND(scope_, x, block_shape, paddings);
291   RunTest(x, x_shape, y, y_shape);
292 }
293 
TEST_F(ArrayGradTest,BatchToSpaceGrad)294 TEST_F(ArrayGradTest, BatchToSpaceGrad) {
295   TensorShape x_shape({4, 2, 2, 1});
296   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
297   auto paddings = Const(scope_, {{1, 1}, {1, 1}});
298   TensorShape y_shape({1, 2, 2, 1});
299   auto y = BatchToSpace(scope_, x, paddings, /* block_size */ 2);
300   RunTest(x, x_shape, y, y_shape);
301 }
302 
TEST_F(ArrayGradTest,BatchToSpaceNdGrad)303 TEST_F(ArrayGradTest, BatchToSpaceNdGrad) {
304   TensorShape x_shape({8, 1, 3, 1});
305   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
306   auto block_shape = Const(scope_, {2, 2});
307   auto paddings = Const(scope_, {{0, 0}, {2, 0}});
308   TensorShape y_shape({2, 2, 4, 1});
309   auto y = BatchToSpaceND(scope_, x, block_shape, paddings);
310   RunTest(x, x_shape, y, y_shape);
311 }
312 
TEST_F(ArrayGradTest,SpaceToDepthGrad)313 TEST_F(ArrayGradTest, SpaceToDepthGrad) {
314   TensorShape x_shape({1, 2, 2, 1});
315   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
316   TensorShape y_shape({1, 1, 1, 4});
317   auto y = SpaceToDepth(scope_, x, /* block_size */ 2);
318   RunTest(x, x_shape, y, y_shape);
319 }
320 
TEST_F(ArrayGradTest,DepthToSpaceGrad)321 TEST_F(ArrayGradTest, DepthToSpaceGrad) {
322   TensorShape x_shape({1, 1, 1, 4});
323   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
324   TensorShape y_shape({1, 2, 2, 1});
325   auto y = DepthToSpace(scope_, x, /* block_size */ 2);
326   RunTest(x, x_shape, y, y_shape);
327 }
328 
TEST_F(ArrayGradTest,MirrorPadGrad_Reflect)329 TEST_F(ArrayGradTest, MirrorPadGrad_Reflect) {
330   TensorShape x_shape({2, 3});
331   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
332   auto paddings = Const(scope_, {{1, 1}, {2, 2}});
333   TensorShape y_shape({4, 7});
334   auto y = MirrorPad(scope_, x, paddings, "REFLECT");
335   RunTest(x, x_shape, y, y_shape);
336 }
337 
TEST_F(ArrayGradTest,MirrorPadGrad_Symmetric)338 TEST_F(ArrayGradTest, MirrorPadGrad_Symmetric) {
339   TensorShape x_shape({2, 3});
340   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
341   auto paddings = Const(scope_, {{1, 1}, {2, 2}});
342   TensorShape y_shape({4, 7});
343   auto y = MirrorPad(scope_, x, paddings, "SYMMETRIC");
344   RunTest(x, x_shape, y, y_shape);
345 }
346 
TEST_F(ArrayGradTest,MirrorPadGradGrad_Reflect)347 TEST_F(ArrayGradTest, MirrorPadGradGrad_Reflect) {
348   TensorShape x_shape({4, 7});
349   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
350   auto paddings = Const(scope_, {{1, 1}, {2, 2}});
351   TensorShape y_shape({2, 3});
352   auto y = MirrorPadGrad(scope_, x, paddings, "REFLECT");
353   RunTest(x, x_shape, y, y_shape);
354 }
355 
TEST_F(ArrayGradTest,MirrorPadGradGrad_Symmetric)356 TEST_F(ArrayGradTest, MirrorPadGradGrad_Symmetric) {
357   TensorShape x_shape({4, 7});
358   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
359   auto paddings = Const(scope_, {{1, 1}, {2, 2}});
360   TensorShape y_shape({2, 3});
361   auto y = MirrorPadGrad(scope_, x, paddings, "SYMMETRIC");
362   RunTest(x, x_shape, y, y_shape);
363 }
364 
TEST_F(ArrayGradTest,StridedSliceGrad)365 TEST_F(ArrayGradTest, StridedSliceGrad) {
366   TensorShape x_shape({6, 4, 4});
367   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
368 
369   // y = x[2:6:2, 1:3, 1:3]
370   auto y = StridedSlice(scope_, x, {2, 1, 1}, {6, 3, 3}, {2, 1, 1});
371   // y.shape = [2, 2, 2];
372   RunTest(x, x_shape, y, {2, 2, 2});
373 
374   // y = x[2:6:2, 1:3, 1:3]
375   // begin_mask = 1<<1 (ignore begin_index = 1)
376   // end_mask = 1<<2 (ignore end_index = 2)
377   y = StridedSlice(scope_, x, {2, 1, 1}, {6, 3, 3}, {2, 1, 1},
378                    StridedSlice::BeginMask(1 << 1).EndMask(1 << 2));
379   // y.shape = [2, 3, 3];
380   RunTest(x, x_shape, y, {2, 3, 3});
381 
382   // y = [tf.newaxis, 2:6:2, 1:3, 1:3]
383   y = StridedSlice(scope_, x, {0, 2, 1, 1}, {0, 6, 3, 3}, {1, 2, 1, 1},
384                    StridedSlice::NewAxisMask(1 << 0));
385   // y.shape = [1, 2, 2, 2];
386   RunTest(x, x_shape, y, {1, 2, 2, 2});
387 }
388 
TEST_F(ArrayGradTest,SliceGrad)389 TEST_F(ArrayGradTest, SliceGrad) {
390   TensorShape x_shape({3, 5, 3});
391   auto x = Placeholder(scope_, DT_FLOAT, Placeholder::Shape(x_shape));
392   auto y = Slice(scope_, x, {1, 2, 1}, {1, 3, 2});
393   RunTest(x, x_shape, y, {1, 3, 2});
394 }
395 
396 }  // namespace
397 }  // namespace tensorflow
398