Home | History | Annotate | Download | only in gradients
      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:
     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 
     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 
     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 
     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 
     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 
     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 
    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 
    111 TEST_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 
    119 TEST_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 
    127 TEST_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 
    135 TEST_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 
    144 TEST_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 
    153 TEST_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 
    161 TEST_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 
    168 TEST_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 
    176 TEST_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 
    184 TEST_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 
    192 TEST_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 
    200 TEST_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 
    209 TEST_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 
    216 TEST_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 
    226 TEST_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 
    236 TEST_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 
    247 TEST_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 
    258 TEST_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 
    267 TEST_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 
    276 TEST_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 
    286 TEST_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 
    295 TEST_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 
    305 TEST_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 
    313 TEST_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 
    321 TEST_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 
    330 TEST_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 
    339 TEST_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 
    348 TEST_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