reshape_op.cc 27.7 KB
Newer Older
1
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.
Y
Yibing Liu 已提交
2

L
Luo Tao 已提交
3 4 5
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Y
Yibing Liu 已提交
6

L
Luo Tao 已提交
7
    http://www.apache.org/licenses/LICENSE-2.0
Y
Yibing Liu 已提交
8

L
Luo Tao 已提交
9 10 11 12 13
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
Y
Yibing Liu 已提交
14

Y
Yi Wang 已提交
15
#include <string>
W
wanghuancoder 已提交
16

17
#include "paddle/fluid/framework/infershape_utils.h"
Y
yuyang18 已提交
18
#include "paddle/fluid/framework/op_registry.h"
19
#include "paddle/fluid/framework/phi_utils.h"
Y
Yi Wang 已提交
20

21 22 23
// only can include the headers in paddle/phi/api dirs
#include "paddle/phi/api/lib/utils/tensor_utils.h"
#include "paddle/phi/backends/cpu/cpu_context.h"
24
#include "paddle/phi/common/int_array.h"
25
#include "paddle/phi/core/infermeta_utils.h"
26
#include "paddle/phi/infermeta/backward.h"
27
#include "paddle/phi/infermeta/unary.h"
28 29
#include "paddle/phi/kernels/reshape_grad_kernel.h"
#include "paddle/phi/kernels/reshape_kernel.h"
30

W
wanghuancoder 已提交
31 32 33 34 35 36 37 38 39 40
namespace paddle {
namespace framework {
class InferShapeContext;
class OpDesc;
}  // namespace framework
namespace imperative {
class OpBase;
}  // namespace imperative
}  // namespace paddle

Y
Yibing Liu 已提交
41 42 43
namespace paddle {
namespace operators {

44 45
using Tensor = framework::Tensor;

Y
yuyang18 已提交
46 47 48 49 50 51 52 53
class ReshapeOp : public framework::OperatorWithKernel {
 public:
  ReshapeOp(const std::string &type, const framework::VariableNameMap &inputs,
            const framework::VariableNameMap &outputs,
            const framework::AttributeMap &attrs)
      : OperatorWithKernel(type, inputs, outputs, attrs) {}

  void InferShape(framework::InferShapeContext *ctx) const override {
54
    PADDLE_ENFORCE_EQ(ctx->HasInput("X"), true,
55 56
                      platform::errors::InvalidArgument(
                          "Input(X) of ReshapeOp should not be null."));
57
    PADDLE_ENFORCE_EQ(ctx->HasOutput("Out"), true,
58 59
                      platform::errors::InvalidArgument(
                          "Output(Out) of ReshapeOp should not be null."));
Y
yuyang18 已提交
60

61 62
    if (ctx->HasInputs("ShapeTensor")) {
      // top prority shape
63
      auto ShapeTensor = ctx->Inputs("ShapeTensor");
64 65
      PADDLE_ENFORCE_GT(
          ShapeTensor.size(), 0,
66 67 68 69 70
          platform::errors::InvalidArgument(
              "When `shape` in ReshapeOp is a list or tuple "
              "which contains Tensor, the shape's size can't be zero. "
              "But received shape's size is %d.",
              ShapeTensor.size()));
71 72 73 74 75 76 77
      auto infer_shape = ctx->Attrs().Get<std::vector<int>>("shape");
      const int64_t copy_dim_val = 0;
      auto in_dims = ctx->GetInputDim("X");
      for (size_t i = 0; i < infer_shape.size(); ++i) {
        if (infer_shape[i] == copy_dim_val) {
          PADDLE_ENFORCE_LT(
              static_cast<int>(i), in_dims.size(),
78 79 80 81 82
              platform::errors::InvalidArgument(
                  "The index of 0 in `shape` must be less than "
                  "the input tensor X's dimensions. But received shape[%d] "
                  "= 0, X's dimensions = %d, X's shape = [%s].",
                  i, in_dims.size(), in_dims));
83 84 85
          infer_shape[i] = in_dims[i];
        }
      }
86
      auto infer_out_dims = phi::make_ddim(infer_shape);
87 88 89
      ctx->SetOutputDim("Out", infer_out_dims);
      return;
    }
Y
yuyang18 已提交
90

91 92 93 94 95 96 97 98
    const std::vector<int> &shape = ctx->Attrs().Get<std::vector<int>>("shape");
    if (ctx->HasInput("Shape") && shape.empty()) {
      auto shape_dims = ctx->GetInputDim("Shape");
      int num_ele = 1;
      for (int i = 0; i < shape_dims.size(); ++i) {
        num_ele *= shape_dims[i];
      }
      auto vec_dims = std::vector<int>(num_ele, -1);
99
      auto out_dims = phi::make_ddim(vec_dims);
100 101
      ctx->SetOutputDim("Out", out_dims);
      ctx->ShareLoD("X", /*->*/ "Out");
102 103
      return;
    }
104 105

    if (ctx->HasInput("Shape") && !shape.empty() && ctx->IsRuntime()) {
Y
yuyang18 已提交
106 107 108 109 110
      // If true, set the shape of Output(Out) according to Input(Shape) in
      // ReshapeKernel with ExecutionContext. Also check LoD in ReshapeKernel.
      ctx->ShareLoD("X", /*->*/ "Out");
      return;
    }
111

112 113 114 115
    PADDLE_ENFORCE_EQ(!shape.empty(), true,
                      platform::errors::InvalidArgument(
                          "The parameter 'shape' in ReshapeOp must be set. "
                          "But received 'shape' is empty."));
Y
yuyang18 已提交
116 117 118 119 120 121 122 123 124 125 126 127
    auto x_dims = ctx->GetInputDim("X");
    auto out_dims = ValidateShape(shape, x_dims);
    ctx->SetOutputDim("Out", out_dims);
    if (x_dims[0] == out_dims[0]) {
      // Only pass LoD when the first dimension of output and Input(X)
      // are the same.
      ctx->ShareLoD("X", /*->*/ "Out");
    }
  }

  static framework::DDim ValidateShape(const std::vector<int> shape,
                                       const framework::DDim &in_dims) {
128 129
    const int64_t in_size = phi::product(in_dims);
    auto in_dims_vec = phi::vectorize(in_dims);
C
chengduo 已提交
130 131
    bool all_positive = std::all_of(in_dims_vec.cbegin(), in_dims_vec.cend(),
                                    [](int64_t i) { return i > 0; });
Y
yuyang18 已提交
132 133 134 135 136 137 138 139 140 141
    // only one dimension can be set to -1, whose size will be automatically
    // infered.
    const int64_t unk_dim_val = -1;
    const int64_t copy_dim_val = 0;

    std::vector<int64_t> output_shape(shape.size(), 0);
    int64_t capacity = 1;
    int unk_dim_idx = -1;
    for (size_t i = 0; i < shape.size(); ++i) {
      if (shape[i] == unk_dim_val) {
142 143
        PADDLE_ENFORCE_EQ(
            unk_dim_idx, -1,
144 145 146
            platform::errors::InvalidArgument(
                "Only one dimension value of 'shape' in ReshapeOp can "
                "be -1. But received shape = [%s], shape[%d] is also -1.",
147
                phi::make_ddim(shape), i));
Y
yuyang18 已提交
148 149
        unk_dim_idx = i;
      } else if (shape[i] == copy_dim_val) {
150 151
        PADDLE_ENFORCE_LT(
            static_cast<int>(i), in_dims.size(),
152 153 154 155 156
            platform::errors::InvalidArgument(
                "The index of 0 in `shape` must be less than "
                "the input tensor X's dimensions. "
                "But received shape = [%s], shape[%d] = 0, X's shape = [%s], "
                "X's dimensions = %d.",
157
                phi::make_ddim(shape), i, in_dims, in_dims.size()));
Y
yuyang18 已提交
158
      } else {
159 160
        PADDLE_ENFORCE_GT(
            shape[i], 0,
161 162
            platform::errors::InvalidArgument(
                "Each dimension value of 'shape' in ReshapeOp must not "
T
tianshuo78520a 已提交
163
                "be negative except one unknown dimension. "
164
                "But received  shape = [%s], shape[%d] = %d.",
165
                phi::make_ddim(shape), i, shape[i]));
Y
yuyang18 已提交
166 167
      }

168 169
      // NOTE all non-zero values will be converted to True (include negative
      // value)
Y
yuyang18 已提交
170 171 172 173 174 175
      capacity *= (shape[i] ? shape[i] : in_dims[i]);
      output_shape[i] =
          (shape[i] ? static_cast<int64_t>(shape[i]) : in_dims[i]);
    }

    if (unk_dim_idx != -1) {
C
chengduo 已提交
176
      if (all_positive) {
Y
yuyang18 已提交
177 178 179 180 181
        // in_size < 0 and is un-determinate in compile time, skip the check,
        // for example, in_dims = [-1, 8, 1, 1], shape = [-1, 3, 8],
        // capacity = -24, in_size = -8, output_shape[0] = 0
        // the following check will fail.
        output_shape[unk_dim_idx] = -in_size / capacity;
182 183 184 185 186 187 188
        PADDLE_ENFORCE_EQ(
            output_shape[unk_dim_idx] * capacity, -in_size,
            platform::errors::InvalidArgument(
                "The 'shape' attribute in ReshapeOp is invalid. "
                "The input tensor X'size must be divisible by known "
                "capacity of 'shape'. "
                "But received X's shape = [%s], X's size = %d, "
189
                "'shape' is [%s], known capacity of 'shape' is %d.",
190
                in_dims, in_size, phi::make_ddim(shape), capacity));
Y
yuyang18 已提交
191 192 193 194
      } else {
        output_shape[unk_dim_idx] = -1;
      }
    } else {
Y
Yamei-Lee 已提交
195 196 197
      if (all_positive) {
        PADDLE_ENFORCE_EQ(
            capacity, in_size,
198 199 200 201 202 203
            platform::errors::InvalidArgument(
                "The 'shape' in ReshapeOp is invalid. "
                "The input tensor X'size must be equal to the capacity of "
                "'shape'. "
                "But received X's shape = [%s], X's size = %d, 'shape' is "
                "[%s], the capacity of 'shape' is %d.",
204
                in_dims, in_size, phi::make_ddim(shape), capacity));
Y
Yamei-Lee 已提交
205
      }
Y
yuyang18 已提交
206
    }
207 208 209 210 211

    // support reshape with zero-input(input tensor with product(shape) == 0)
    // by now we require that if the input tensor is zero shape, the target
    // shape of output must be zero
    if (in_size == 0) {
J
JZ-LIANG 已提交
212
      PADDLE_ENFORCE_LE(
213 214 215 216 217 218
          capacity, in_size,
          platform::errors::InvalidArgument(
              "The 'shape' in ReshapeOp is invalid. "
              "The input tensor X's shape = [%s], X's capacity = %d."
              "But the target shape of Out is [%s],  the "
              "capacity of 'Out' is %d.",
219
              in_dims, in_size, phi::make_ddim(shape), capacity));
220 221
    }

222
    return phi::make_ddim(output_shape);
Y
yuyang18 已提交
223 224 225 226 227
  }

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext &ctx) const override {
228 229 230 231
    auto input_data_type =
        framework::OperatorWithKernel::IndicateVarDataType(ctx, "X");

    return framework::OpKernelType(input_data_type, ctx.GetPlace());
Y
yuyang18 已提交
232
  }
233 234 235 236 237 238 239 240 241 242

  framework::OpKernelType GetKernelTypeForVar(
      const std::string &var_name, const Tensor &tensor,
      const framework::OpKernelType &expected_kernel_type) const override {
    if (var_name == "ShapeTensor") {
      return expected_kernel_type;
    }
    return framework::OpKernelType(expected_kernel_type.data_type_,
                                   tensor.place(), tensor.layout());
  }
Y
yuyang18 已提交
243 244
};

Y
Yibing Liu 已提交
245 246
class ReshapeOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
Y
Yu Yang 已提交
247
  void Make() override {
248 249
    AddInput("X", "(Tensor). The input tensor of reshape operator.");
    AddInput("Shape",
250 251 252
             "(Tensor<int32>, optional). Target shape of reshape operator. "
             "It has a higher priority than Attr(shape) but a lower priority "
             "than Input(ShapeTensor). The Attr(shape) still should be "
T
tianshuo78520a 已提交
253
             "set correctly to guarantee shape inference in compile time.")
254
        .AsDispensable();
255 256
    AddInput(
        "ShapeTensor",
257 258 259 260
        "(vector<Tensor<int32>>, optional). Target shape of reshape operator. "
        "It has the highest priority compare with Input(Shape) and "
        "Attr(shape)."
        "The shape of the element in vector must be [1].")
261 262
        .AsDuplicable()
        .AsDispensable();
263
    AddOutput("Out", "(Tensor). The output tensor of reshape operator.");
C
caoying03 已提交
264
    AddAttr<std::vector<int>>(
265 266 267 268
        "shape",
        "(std::vector<int>) Target shape of reshape operator."
        "It has the lowest priority compare with Input(Shape) and "
        " Input(ShapeTensor).")
269
        .SetDefault({});
270 271
    AddAttr<bool>("use_mkldnn",
                  "(bool, default false) Only used in mkldnn kernel")
Z
zmx 已提交
272 273
        .SetDefault(false)
        .AsExtra();
K
kexinzhao 已提交
274 275
    AddComment(R"DOC(
Reshape Operator.
Y
Yibing Liu 已提交
276

277 278
Reshape Input(X) into the shape specified by Attr(shape) or Input(Shape). The
data in Input(X) are unchanged.
Y
Yibing Liu 已提交
279

C
caoying03 已提交
280
Examples:
Y
Yibing Liu 已提交
281

C
caoying03 已提交
282 283 284 285
1. Given a 3-D tensor Input(X) with a shape [2, 4, 6], and the target shape
specified by Attr(shape) is [6, 8], the reshape operator will transform Input(X)
into a 2-D tensor with shape [6, 8] and leaving Input(X)'s data unchanged.

286
2. Given a 3-D tensor Input(X) with a shape [2, 4, 6], and the target shape
C
caoying03 已提交
287 288 289 290 291 292
specified by Attr(shape) is [2, 3, -1, 2], the reshape operator will transform
Input(X) into a 4-D tensor with shape [2, 3, 4, 2] and leaving Input(X)'s data
unchanged. In this case, one and only dimension of Attr(shape) can be set to -1,
the value of this dimension is inferred from the total element number of
Input(X) and remaining dimensions.

293
3. Given a 3-D tensor Input(X) with a shape [2, 4, 6], and the target shape
C
caoying03 已提交
294 295 296 297
specified by Attr(shape) is [-1, 0, 3, 2], the reshape operator will transform
Input(X) into a 4-D tensor with shape [2, 4, 3, 2] and leaving Input(X)'s data
unchanged. In this case, besides -1, 0 means the actual dimension value is going
to be copied from the corresponding dimension of Input(X).
Y
Yibing Liu 已提交
298

C
caoying03 已提交
299
Note:
Y
Yibing Liu 已提交
300

C
caoying03 已提交
301 302 303
1. One and only one dimension in Attr(shape) can be set -1. In this case,
the actual dimension value will be infered from the total element number of
Input(X) and remaining dimensions.
304 305

2. More than one dimensions in Attr(shape) can be set to 0, which means the real
C
caoying03 已提交
306
dimension value will be copied from Input(X) at runtime. Note that the index of
G
guosheng 已提交
307
0 can not exceed Rank(X). For example, Input(X) is a 3-D tensor with shape
C
caoying03 已提交
308
[2, 3, 4], Attr(shape) = [2, 3, 2, 0] is an invalid input.
309 310

3. Input(Shape) has a higher priority than Attr(shape) if it is provided, while
T
tianshuo78520a 已提交
311
Attr(shape) still should be set correctly to guarantee shape inference in
312
compile-time.
Y
Yibing Liu 已提交
313

Y
Yibing Liu 已提交
314 315 316 317 318 319 320 321 322 323 324 325
)DOC");
  }
};

class ReshapeGradOp : public framework::OperatorWithKernel {
 public:
  ReshapeGradOp(const std::string &type,
                const framework::VariableNameMap &inputs,
                const framework::VariableNameMap &outputs,
                const framework::AttributeMap &attrs)
      : OperatorWithKernel(type, inputs, outputs, attrs) {}

326
  void InferShape(framework::InferShapeContext *ctx) const override {
327 328 329
    PADDLE_ENFORCE_EQ(
        ctx->HasInput("X"), true,
        platform::errors::InvalidArgument("Input(X) shouldn't be null."));
330
    PADDLE_ENFORCE_EQ(ctx->HasInput(framework::GradVarName("Out")), true,
331 332
                      platform::errors::InvalidArgument(
                          "Input(Out@GRAD) shouldn't be null."));
Q
Qiao Longfei 已提交
333
    ctx->SetOutputDim(framework::GradVarName("X"), ctx->GetInputDim("X"));
Y
Yibing Liu 已提交
334
  }
335 336 337 338

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext &ctx) const override {
339 340 341 342
    auto input_data_type =
        framework::OperatorWithKernel::IndicateVarDataType(ctx, "X");

    return framework::OpKernelType(input_data_type, ctx.GetPlace());
343
  }
Y
Yibing Liu 已提交
344 345
};

Y
yuyang18 已提交
346 347 348 349 350
class ReshapeKernel {
 public:
  void operator()(const framework::ExecutionContext &ctx) const {
    auto *out = ctx.Output<framework::LoDTensor>("Out");
    auto *in = ctx.Input<framework::LoDTensor>("X");
Y
yuyang18 已提交
351

352 353
    auto list_new_shape_tensor =
        ctx.MultiInput<framework::Tensor>("ShapeTensor");
354 355 356
    auto *shape_tensor = ctx.HasInput("Shape")
                             ? ctx.Input<framework::LoDTensor>("Shape")
                             : nullptr;
357
    phi::IntArray pt_scalar_shape;
358 359
    if (list_new_shape_tensor.size() > 0) {
      // have shape tensor
360
      std::vector<phi::DenseTensor> pt_vec_shape;
361 362 363 364
      for (auto &tensor : list_new_shape_tensor) {
        if (platform::is_gpu_place(tensor->place()) ||
            platform::is_xpu_place(tensor->place())) {
          framework::Tensor temp;
365 366
          paddle::framework::TensorCopySync(*tensor, platform::CPUPlace(),
                                            &temp);
367
          pt_vec_shape.push_back(std::move(temp));
368
        } else {
369
          pt_vec_shape.push_back(*tensor);
370 371
        }
      }
372
      pt_scalar_shape = phi::IntArray(pt_vec_shape);
373
    } else if (shape_tensor) {
374
      phi::DenseTensor pt_shape;
375 376 377
      if (platform::is_gpu_place(shape_tensor->place()) ||
          platform::is_xpu_place(shape_tensor->place())) {
        framework::Tensor temp;
378 379
        paddle::framework::TensorCopySync(*shape_tensor, platform::CPUPlace(),
                                          &temp);
380
        pt_shape = std::move(temp);
381
      } else {
382
        pt_shape = *shape_tensor;
383
      }
384
      pt_scalar_shape = phi::IntArray(pt_shape);
385
    } else {
386
      auto &shape_attr = ctx.Attr<std::vector<int>>("shape");
387
      pt_scalar_shape = phi::IntArray(shape_attr);
388 389 390
    }
    if (platform::is_cpu_place(ctx.GetPlace())) {
      auto &dev_ctx = ctx.device_context<platform::CPUDeviceContext>();
391 392
      phi::ReshapeKernel(static_cast<const phi::CPUContext &>(dev_ctx), *in,
                         pt_scalar_shape, out);
393
    }
394
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
395 396
    if (platform::is_gpu_place(ctx.GetPlace())) {
      auto &dev_ctx = ctx.device_context<platform::CUDADeviceContext>();
397 398
      phi::ReshapeKernel(static_cast<const phi::GPUContext &>(dev_ctx), *in,
                         pt_scalar_shape, out);
399
    }
400 401
#endif
#ifdef PADDLE_WITH_XPU
402 403
    if (platform::is_xpu_place(ctx.GetPlace())) {
      auto &dev_ctx = ctx.device_context<platform::XPUDeviceContext>();
404 405
      phi::ReshapeKernel(static_cast<const phi::XPUContext &>(dev_ctx), *in,
                         pt_scalar_shape, out);
406
    }
407
#endif
Y
yuyang18 已提交
408
  }
Y
yuyang18 已提交
409 410 411 412 413 414 415
};

class ReshapeGradKernel {
 public:
  void operator()(const framework::ExecutionContext &ctx) const {
    auto *d_out = ctx.Input<framework::Tensor>(framework::GradVarName("Out"));
    auto *d_x = ctx.Output<framework::Tensor>(framework::GradVarName("X"));
416
    d_x->mutable_data(ctx.GetPlace(), d_out->type());
417 418 419

    if (platform::is_cpu_place(ctx.GetPlace())) {
      auto &dev_ctx = ctx.device_context<platform::CPUDeviceContext>();
420 421
      phi::ReshapeGradKernel(static_cast<const phi::CPUContext &>(dev_ctx),
                             *d_out, d_x);
422 423 424 425
    }
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
    if (platform::is_gpu_place(ctx.GetPlace())) {
      auto &dev_ctx = ctx.device_context<platform::CUDADeviceContext>();
426 427
      phi::ReshapeGradKernel(static_cast<const phi::GPUContext &>(dev_ctx),
                             *d_out, d_x);
428 429 430 431 432
    }
#endif
#ifdef PADDLE_WITH_XPU
    if (platform::is_xpu_place(ctx.GetPlace())) {
      auto &dev_ctx = ctx.device_context<platform::XPUDeviceContext>();
433 434
      phi::ReshapeGradKernel(static_cast<const phi::XPUContext &>(dev_ctx),
                             *d_out, d_x);
435 436
    }
#endif
Y
yuyang18 已提交
437
  }
Y
yuyang18 已提交
438 439
};

440 441 442 443
class ReshapeDoubleGradKernel {
 public:
  void operator()(const framework::ExecutionContext &ctx) const {
    auto *dd_x = ctx.Input<framework::Tensor>("DDX");
444
    auto *d_out = ctx.Input<framework::Tensor>("DOut");
445
    auto *dd_out = ctx.Output<framework::Tensor>("DDOut");
446
    dd_out->mutable_data(ctx.GetPlace(), dd_x->type());
447

448 449
    if (platform::is_cpu_place(ctx.GetPlace())) {
      auto &dev_ctx = ctx.device_context<platform::CPUDeviceContext>();
450
      phi::ReshapeDoubleGradKernel(
451
          static_cast<const phi::CPUContext &>(dev_ctx), *d_out, *dd_x, dd_out);
452 453 454 455
    }
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
    if (platform::is_gpu_place(ctx.GetPlace())) {
      auto &dev_ctx = ctx.device_context<platform::CUDADeviceContext>();
456
      phi::ReshapeDoubleGradKernel(
457
          static_cast<const phi::GPUContext &>(dev_ctx), *d_out, *dd_x, dd_out);
458 459 460 461 462
    }
#endif
#ifdef PADDLE_WITH_XPU
    if (platform::is_xpu_place(ctx.GetPlace())) {
      auto &dev_ctx = ctx.device_context<platform::XPUDeviceContext>();
463
      phi::ReshapeDoubleGradKernel(
464
          static_cast<const phi::XPUContext &>(dev_ctx), *d_out, *dd_x, dd_out);
465 466
    }
#endif
467 468 469
  }
};

470 471 472 473 474 475 476 477 478 479 480
// FIXME(zcd): reshape2 adds an intermediate output(XShape) based on reshape,
// the XShape is used to carry the shape and lod of X which will be used in
// reshape_grad, in this way, the framework can reuse the memory of X
// immediately the reshape_op is finished.
// Considering compatibility issues, we could not fix reshape_op
class Reshape2Op : public ReshapeOp {
 public:
  Reshape2Op(const std::string &type, const framework::VariableNameMap &inputs,
             const framework::VariableNameMap &outputs,
             const framework::AttributeMap &attrs)
      : ReshapeOp(type, inputs, outputs, attrs) {}
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
  void InferShape(framework::InferShapeContext *ctx) const override {
    PADDLE_ENFORCE_EQ(ctx->HasOutput("XShape"), true,
                      platform::errors::InvalidArgument(
                          "Output(XShape) of ReshapeOp should not be null."));
    const auto &x_dims = ctx->GetInputDim("X");
    std::vector<int64_t> xshape_dims(x_dims.size() + 1);
    xshape_dims[0] = 0;
    for (int i = 0; i < x_dims.size(); ++i) {
      xshape_dims[i + 1] = x_dims[i];
    }
    ctx->SetOutputDim("XShape", phi::make_ddim(xshape_dims));
    ctx->ShareLoD("X", /*->*/ "XShape");

    ReshapeOp::InferShape(ctx);
  }
496 497 498 499 500 501 502 503 504 505
};

class Reshape2OpMaker : public ReshapeOpMaker {
 public:
  void Make() override {
    ReshapeOpMaker::Make();
    AddOutput("XShape",
              "XShape is just used to store the shape and lod of X, which will "
              "be used in FlattenGradOp.")
        .AsIntermediate();
506 507 508 509
    AddAttr<bool>(
        "use_quantizer",
        "(bool, default false) "
        "This parameter is no longer used. Use 'mkldnn_data_type' instead.")
510
        .SetDefault(false);
511 512 513 514
    AddAttr<std::string>(
        "mkldnn_data_type",
        "(string, default \"float32\"). Data type of mkldnn kernel")
        .SetDefault("float32")
515 516
        .InEnum({"float32", "int8", "bfloat16"})
        .AsExtra();
517 518 519
  }
};

H
hong 已提交
520 521
template <typename T>
class Reshape2GradMaker : public framework::SingleGradOpMaker<T> {
522
 public:
H
hong 已提交
523
  using framework::SingleGradOpMaker<T>::SingleGradOpMaker;
524

525
  void Apply(GradOpPtr<T> grad_op) const override {
526
    grad_op->SetType("reshape2_grad");
H
hong 已提交
527 528 529 530
    grad_op->SetInput("XShape", this->Output("XShape"));
    grad_op->SetInput(framework::GradVarName("Out"), this->OutputGrad("Out"));
    grad_op->SetOutput(framework::GradVarName("X"), this->InputGrad("X"));
    grad_op->SetAttrMap(this->Attrs());
531 532 533
  }
};

H
hong 已提交
534 535
template <typename T>
class Reshape2DoubleGradMaker : public framework::SingleGradOpMaker<T> {
536
 public:
H
hong 已提交
537
  using framework::SingleGradOpMaker<T>::SingleGradOpMaker;
538

539
  void Apply(GradOpPtr<T> grad_op) const override {
540
    grad_op->SetType("reshape2_grad_grad");
H
hong 已提交
541 542 543 544
    grad_op->SetInput("DOut", this->Input(framework::GradVarName("Out")));
    grad_op->SetInput("DDX", this->OutputGrad(framework::GradVarName("X")));
    grad_op->SetOutput("DDOut", this->InputGrad(framework::GradVarName("Out")));
    grad_op->SetAttrMap(this->Attrs());
545 546 547
  }
};

548 549 550 551 552 553 554 555 556
class Reshape2GradOp : public framework::OperatorWithKernel {
 public:
  Reshape2GradOp(const std::string &type,
                 const framework::VariableNameMap &inputs,
                 const framework::VariableNameMap &outputs,
                 const framework::AttributeMap &attrs)
      : OperatorWithKernel(type, inputs, outputs, attrs) {}

  void InferShape(framework::InferShapeContext *ctx) const override {
557 558 559
    PADDLE_ENFORCE_EQ(
        ctx->HasInput("XShape"), true,
        platform::errors::InvalidArgument("Input(XShape) shouldn't be null."));
560
    PADDLE_ENFORCE_EQ(ctx->HasInput(framework::GradVarName("Out")), true,
561 562
                      platform::errors::InvalidArgument(
                          "Input(Out@GRAD) shouldn't be null."));
563 564 565 566 567 568 569 570

    // Construct MetaTensor for InferMeta Func
    using CompatMetaTensor = framework::CompatMetaTensor;
    CompatMetaTensor xshape(ctx->GetInputVarPtrs("XShape")[0],
                            ctx->IsRuntime());
    CompatMetaTensor dx(ctx->GetOutputVarPtrs(framework::GradVarName("X"))[0],
                        ctx->IsRuntime());
    phi::KernelWithXShapeInferMeta(xshape, &dx);
571 572 573 574 575
  }

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext &ctx) const override {
576 577 578 579
    auto input_data_type = framework::OperatorWithKernel::IndicateVarDataType(
        ctx, framework::GradVarName("Out"));

    return framework::OpKernelType(input_data_type, ctx.GetPlace());
580
  }
581 582 583 584 585 586 587 588 589 590

  framework::OpKernelType GetKernelTypeForVar(
      const std::string &var_name, const Tensor &tensor,
      const framework::OpKernelType &expected_kernel_type) const override {
    if (var_name == "ShapeTensor") {
      return expected_kernel_type;
    }
    return framework::OpKernelType(expected_kernel_type.data_type_,
                                   tensor.place(), tensor.layout());
  }
591 592
};

593 594 595 596 597 598 599 600 601 602 603
class Reshape2DoubleGradOp : public framework::OperatorWithKernel {
 public:
  Reshape2DoubleGradOp(const std::string &type,
                       const framework::VariableNameMap &inputs,
                       const framework::VariableNameMap &outputs,
                       const framework::AttributeMap &attrs)
      : OperatorWithKernel(type, inputs, outputs, attrs) {}

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext &ctx) const override {
604 605 606
    return framework::OpKernelType(
        OperatorWithKernel::IndicateVarDataType(ctx, "DDX"),
        ctx.device_context());
607 608 609 610 611 612 613 614 615 616 617 618 619
  }

  framework::OpKernelType GetKernelTypeForVar(
      const std::string &var_name, const Tensor &tensor,
      const framework::OpKernelType &expected_kernel_type) const override {
    if (var_name == "ShapeTensor") {
      return expected_kernel_type;
    }
    return framework::OpKernelType(expected_kernel_type.data_type_,
                                   tensor.place(), tensor.layout());
  }
};

620 621
DECLARE_INPLACE_OP_INFERER(ReshapeOpInplaceInferer, {"X", "Out"});
DECLARE_INPLACE_OP_INFERER(ReshapeGradInplaceInferer,
622 623
                           {framework::GradVarName("Out"),
                            framework::GradVarName("X")});
624 625
DECLARE_INPLACE_OP_INFERER(ReshapeDoubleGradInplaceInferer, {"DDX", "DDOut"});
DECLARE_NO_NEED_BUFFER_VARS_INFERER(ReshapeDoubleGradOpNoNeedBufferVarInferer,
Z
Zeng Jinle 已提交
626
                                    "DOut");
D
dzhwinter 已提交
627

Y
Yibing Liu 已提交
628 629 630
}  // namespace operators
}  // namespace paddle
namespace ops = paddle::operators;
631
namespace plat = paddle::platform;
Y
Yibing Liu 已提交
632

H
hong 已提交
633 634 635 636
REGISTER_OPERATOR(
    reshape, ops::ReshapeOp, ops::ReshapeOpMaker,
    paddle::framework::DefaultGradOpMaker<paddle::framework::OpDesc, true>,
    paddle::framework::DefaultGradOpMaker<paddle::imperative::OpBase, true>,
637
    ops::ReshapeOpInplaceInferer);
D
dzhwinter 已提交
638
REGISTER_OPERATOR(reshape_grad, ops::ReshapeGradOp,
639
                  ops::ReshapeGradInplaceInferer);
640

641
REGISTER_OP_CPU_KERNEL_FUNCTOR(reshape, float, ops::ReshapeKernel, double,
642 643 644
                               ops::ReshapeKernel, int16_t, ops::ReshapeKernel,
                               int, ops::ReshapeKernel, int64_t,
                               ops::ReshapeKernel);
645
REGISTER_OP_CPU_KERNEL_FUNCTOR(reshape_grad, float, ops::ReshapeGradKernel,
646 647
                               double, ops::ReshapeGradKernel, int16_t,
                               ops::ReshapeGradKernel, int,
648 649
                               ops::ReshapeGradKernel, int64_t,
                               ops::ReshapeGradKernel);
650

651
REGISTER_OPERATOR(reshape2, ops::Reshape2Op, ops::Reshape2OpMaker,
H
hong 已提交
652 653
                  ops::Reshape2GradMaker<paddle::framework::OpDesc>,
                  ops::Reshape2GradMaker<paddle::imperative::OpBase>,
654
                  ops::ReshapeOpInplaceInferer);
D
dzhwinter 已提交
655
REGISTER_OPERATOR(reshape2_grad, ops::Reshape2GradOp,
H
hong 已提交
656 657
                  ops::Reshape2DoubleGradMaker<paddle::framework::OpDesc>,
                  ops::Reshape2DoubleGradMaker<paddle::imperative::OpBase>,
658
                  ops::ReshapeGradInplaceInferer);
659 660 661

DECLARE_INFER_SHAPE_FUNCTOR(reshape2_grad_grad,
                            Reshape2DoubleGradInferShapeFunctor,
662
                            PD_INFER_META(phi::ReshapeDoubleGradInferMeta));
663

664
REGISTER_OPERATOR(reshape2_grad_grad, ops::Reshape2DoubleGradOp,
665
                  ops::ReshapeDoubleGradInplaceInferer,
666 667
                  ops::ReshapeDoubleGradOpNoNeedBufferVarInferer,
                  Reshape2DoubleGradInferShapeFunctor);
668

669
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
670
REGISTER_OP_CUDA_KERNEL_FUNCTOR(reshape, float, ops::ReshapeKernel, double,
671 672 673 674 675
                                ops::ReshapeKernel, int16_t, ops::ReshapeKernel,
                                int, ops::ReshapeKernel, uint8_t,
                                ops::ReshapeKernel, int64_t, ops::ReshapeKernel,
                                plat::float16, ops::ReshapeKernel,
                                plat::bfloat16, ops::ReshapeKernel);
676
REGISTER_OP_CUDA_KERNEL_FUNCTOR(reshape_grad, float, ops::ReshapeGradKernel,
677 678 679
                                double, ops::ReshapeGradKernel, int16_t,
                                ops::ReshapeKernel, int, ops::ReshapeGradKernel,
                                int64_t, ops::ReshapeGradKernel, uint8_t,
680
                                ops::ReshapeGradKernel, plat::float16,
681
                                ops::ReshapeGradKernel, plat::bfloat16,
682
                                ops::ReshapeGradKernel);
683
#endif