reshape_op.cc 27.6 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 444
class ReshapeDoubleGradKernel {
 public:
  void operator()(const framework::ExecutionContext &ctx) const {
    auto *dd_x = ctx.Input<framework::Tensor>("DDX");
    auto *dd_out = ctx.Output<framework::Tensor>("DDOut");
445
    dd_out->mutable_data(ctx.GetPlace(), dd_x->type());
446

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

469 470 471 472 473 474 475 476 477 478 479
// 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) {}
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
  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);
  }
495 496 497 498 499 500 501 502 503 504
};

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();
505 506 507 508
    AddAttr<bool>(
        "use_quantizer",
        "(bool, default false) "
        "This parameter is no longer used. Use 'mkldnn_data_type' instead.")
509
        .SetDefault(false);
510 511 512 513
    AddAttr<std::string>(
        "mkldnn_data_type",
        "(string, default \"float32\"). Data type of mkldnn kernel")
        .SetDefault("float32")
514 515
        .InEnum({"float32", "int8", "bfloat16"})
        .AsExtra();
516 517 518
  }
};

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

524
  void Apply(GradOpPtr<T> grad_op) const override {
525
    grad_op->SetType("reshape2_grad");
H
hong 已提交
526 527 528 529
    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());
530 531 532
  }
};

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

538
  void Apply(GradOpPtr<T> grad_op) const override {
539
    grad_op->SetType("reshape2_grad_grad");
H
hong 已提交
540 541 542 543
    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());
544 545 546
  }
};

547 548 549 550 551 552 553 554 555
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 {
556 557 558
    PADDLE_ENFORCE_EQ(
        ctx->HasInput("XShape"), true,
        platform::errors::InvalidArgument("Input(XShape) shouldn't be null."));
559
    PADDLE_ENFORCE_EQ(ctx->HasInput(framework::GradVarName("Out")), true,
560 561
                      platform::errors::InvalidArgument(
                          "Input(Out@GRAD) shouldn't be null."));
562 563 564 565 566 567 568 569

    // 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);
570 571 572 573 574
  }

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

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

  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());
  }
590 591
};

592 593 594 595 596 597 598 599 600 601 602
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 {
603 604 605
    return framework::OpKernelType(
        OperatorWithKernel::IndicateVarDataType(ctx, "DDX"),
        ctx.device_context());
606 607 608 609 610 611 612 613 614 615 616 617 618
  }

  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());
  }
};

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

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

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

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

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

DECLARE_INFER_SHAPE_FUNCTOR(reshape2_grad_grad,
                            Reshape2DoubleGradInferShapeFunctor,
                            PD_INFER_META(phi::GeneralUnaryGradInferMeta));

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

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