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