scatter_op.cc 6.6 KB
Newer Older
1
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.
Z
zchen0211 已提交
2

Z
zchen0211 已提交
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
Z
zchen0211 已提交
6

Z
zchen0211 已提交
7
    http://www.apache.org/licenses/LICENSE-2.0
Z
zchen0211 已提交
8

Z
zchen0211 已提交
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. */
Z
zchen0211 已提交
14

Y
Yi Wang 已提交
15
#include "paddle/fluid/operators/scatter_op.h"
S
sneaxiy 已提交
16
#include <memory>
17
#include "paddle/pten/core/ddim.h"
Z
zchen0211 已提交
18 19 20 21 22 23 24 25

namespace paddle {
namespace operators {

class ScatterOp : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

26
  void InferShape(framework::InferShapeContext* ctx) const override {
27 28 29 30 31 32 33 34 35 36 37 38
    PADDLE_ENFORCE_EQ(ctx->HasInput("X"), true,
                      platform::errors::InvalidArgument(
                          "Input(X) of ScatterOp should not be null."));
    PADDLE_ENFORCE_EQ(ctx->HasInput("Ids"), true,
                      platform::errors::InvalidArgument(
                          "Input(Ids) of ScatterOp should not be null."));
    PADDLE_ENFORCE_EQ(ctx->HasInput("Updates"), true,
                      platform::errors::InvalidArgument(
                          "Input(Updates) of ScatterOp should not be null."));
    PADDLE_ENFORCE_EQ(ctx->HasOutput("Out"), true,
                      platform::errors::InvalidArgument(
                          "Output(Out) of ScatterOp should not be null."));
39

Q
Qiao Longfei 已提交
40
    auto updates_dims = ctx->GetInputDim("Updates");
D
dzhwinter 已提交
41
    auto ref_dims = ctx->GetInputDim("X");
42 43
    PADDLE_ENFORCE_EQ(
        ctx->GetInputDim("Ids").size(), 1,
K
Kqnonrime 已提交
44 45 46 47
        platform::errors::InvalidArgument(
            "The size of Input(Ids)'s shape should be equal to 1, but "
            "received the rank of Input(Ids) is %d.",
            ctx->GetInputDim("Ids").size()));
48 49 50
    PADDLE_ENFORCE_EQ(
        ref_dims.size(), updates_dims.size(),
        platform::errors::InvalidArgument(
K
Kqnonrime 已提交
51 52 53 54 55 56 57 58 59 60 61
            "Input(X) and Input(Updates) should have the same shape size, "
            "but received the size of Input(x)'s shape is %d, the size of "
            "Input(Updates)'s shape is %d.",
            ref_dims.size(), updates_dims.size()));
    PADDLE_ENFORCE_EQ(
        ctx->GetInputDim("Updates")[0], ctx->GetInputDim("Ids")[0],
        platform::errors::InvalidArgument(
            "Input(Updates) and Input(Ids) should have same batch-size, but"
            " received Input(Updates)'s batch-size is %d, Input(Ids)'s "
            "batch-size is %d.",
            ctx->GetInputDim("Updates")[0], ctx->GetInputDim("Ids")[0]));
Q
Qiao Longfei 已提交
62
    ctx->SetOutputDim("Out", ref_dims);
S
ShenLiang 已提交
63
    ctx->ShareLoD("X", /*->*/ "Out");
Z
zchen0211 已提交
64
  }
Y
Yu Yang 已提交
65

66
 protected:
67
  framework::OpKernelType GetExpectedKernelType(
Y
Yu Yang 已提交
68
      const framework::ExecutionContext& ctx) const override {
69 70 71
    return framework::OpKernelType(
        OperatorWithKernel::IndicateVarDataType(ctx, "X"),
        ctx.device_context());
Y
Yu Yang 已提交
72
  }
Z
zchen0211 已提交
73 74 75 76 77 78
};

class ScatterGradOp : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

79
  void InferShape(framework::InferShapeContext* ctx) const override {
C
chengduo 已提交
80 81 82 83 84 85 86 87
    if (ctx->HasOutput(framework::GradVarName("Updates"))) {
      ctx->SetOutputDim(framework::GradVarName("Updates"),
                        ctx->GetInputDim("Updates"));
    }
    if (ctx->HasOutput(framework::GradVarName("X"))) {
      ctx->SetOutputDim(framework::GradVarName("X"),
                        ctx->GetInputDim(framework::GradVarName("Out")));
    }
Z
zchen0211 已提交
88
  }
Y
Yu Yang 已提交
89

90
 protected:
91
  framework::OpKernelType GetExpectedKernelType(
Y
Yu Yang 已提交
92
      const framework::ExecutionContext& ctx) const override {
93 94 95
    return framework::OpKernelType(OperatorWithKernel::IndicateVarDataType(
                                       ctx, framework::GradVarName("Out")),
                                   ctx.device_context());
Y
Yu Yang 已提交
96
  }
Z
zchen0211 已提交
97 98 99 100
};

class ScatterOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
Y
Yu Yang 已提交
101
  void Make() override {
D
dzhwinter 已提交
102 103
    AddInput("X", "The source input of scatter op");
    AddInput("Ids", "The index input of scatter op where X will be updated");
104 105
    AddInput("Updates", "The updated value of scatter op");
    AddOutput("Out", "The output of scatter op");
106
    AddAttr<bool>("overwrite",
T
tianshuo78520a 已提交
107
                  "(bool, default: True) "
108 109 110 111 112 113
                  "The mode that updating the output when has same index,"
                  "If True, use the overwrite mode to update the output"
                  "of the same index, if False, use the accumulate mode to"
                  "update the output of the same index,Default value is True."
                  "You can set overwrite=False to implement scatter_add.")
        .SetDefault(true);
Z
zchen0211 已提交
114
    AddComment(R"DOC(
K
kexinzhao 已提交
115
Scatter Operator.
Z
zchen0211 已提交
116

K
kexinzhao 已提交
117 118 119
This operator obtains output by updating the input on selected indices on the first axis:

$$
D
dzhwinter 已提交
120
Out = X \\
121
Out[Ids] = Updates
K
kexinzhao 已提交
122 123
$$

Z
zchen0211 已提交
124 125 126
)DOC");
  }
};
Q
Qiao Longfei 已提交
127

H
hong 已提交
128 129
template <typename T>
class ScatterGradMaker : public framework::SingleGradOpMaker<T> {
S
sneaxiy 已提交
130
 public:
H
hong 已提交
131
  using framework::SingleGradOpMaker<T>::SingleGradOpMaker;
S
sneaxiy 已提交
132 133

 protected:
134
  void Apply(GradOpPtr<T> op) const override {
S
sneaxiy 已提交
135
    op->SetType("scatter_grad");
H
hong 已提交
136 137 138 139 140 141 142
    op->SetInput("Ids", this->Input("Ids"));
    op->SetInput("Updates", this->Input("Updates"));
    op->SetInput(framework::GradVarName("Out"), this->OutputGrad("Out"));
    op->SetOutput(framework::GradVarName("X"), this->InputGrad("X"));
    op->SetOutput(framework::GradVarName("Updates"),
                  this->InputGrad("Updates"));
    op->SetAttrMap(this->Attrs());
S
sneaxiy 已提交
143 144 145
  }
};

146
DECLARE_NO_NEED_BUFFER_VARS_INFERER(ScatterGradNoNeedBufferVarsInferer,
Z
Zeng Jinle 已提交
147
                                    "Updates");
S
sneaxiy 已提交
148

149 150
DECLARE_INPLACE_OP_INFERER(ScatterInplaceInferer, {"X", "Out"});

Z
zchen0211 已提交
151 152 153 154
}  // namespace operators
}  // namespace paddle

namespace ops = paddle::operators;
Y
Yang Yang 已提交
155
REGISTER_OPERATOR(scatter, ops::ScatterOp, ops::ScatterOpMaker,
H
hong 已提交
156
                  ops::ScatterGradMaker<paddle::framework::OpDesc>,
157 158
                  ops::ScatterGradMaker<paddle::imperative::OpBase>,
                  ops::ScatterInplaceInferer);
S
sneaxiy 已提交
159
REGISTER_OPERATOR(scatter_grad, ops::ScatterGradOp,
S
ShenLiang 已提交
160
                  ops::ScatterGradNoNeedBufferVarsInferer);
161 162 163 164 165 166 167
REGISTER_OP_CPU_KERNEL(scatter, ops::ScatterOpKernel<float>,
                       ops::ScatterOpKernel<double>, ops::ScatterOpKernel<int>,
                       ops::ScatterOpKernel<int64_t>);
REGISTER_OP_CPU_KERNEL(scatter_grad, ops::ScatterGradientOpKernel<float>,
                       ops::ScatterGradientOpKernel<double>,
                       ops::ScatterGradientOpKernel<int>,
                       ops::ScatterGradientOpKernel<int64_t>);