scatter_op.h 4.3 KB
Newer Older
1
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.
Z
zchen0211 已提交
2 3 4 5 6 7 8 9 10 11 12 13 14 15

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

    http://www.apache.org/licenses/LICENSE-2.0

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. */

#pragma once
Y
Yi Wang 已提交
16 17
#include "paddle/fluid/framework/eigen.h"
#include "paddle/fluid/framework/op_registry.h"
18 19
#include "paddle/phi/kernels/funcs/gather.h"
#include "paddle/phi/kernels/funcs/scatter.h"
Z
zchen0211 已提交
20 21 22 23 24 25

namespace paddle {
namespace operators {

using Tensor = framework::Tensor;

Z
zchen0211 已提交
26
template <typename T>
Y
Yu Yang 已提交
27
class ScatterOpKernel : public framework::OpKernel<T> {
Z
zchen0211 已提交
28 29
 public:
  void Compute(const framework::ExecutionContext &ctx) const override {
30 31 32
    PADDLE_ENFORCE_EQ(
        platform::is_cpu_place(ctx.GetPlace()), true,
        platform::errors::PreconditionNotMet("This kernel only runs on CPU."));
D
dzhwinter 已提交
33 34
    auto *X = ctx.Input<Tensor>("X");
    auto *Ids = ctx.Input<Tensor>("Ids");
Z
zchen0211 已提交
35 36
    auto *Updates = ctx.Input<Tensor>("Updates");
    auto *Out = ctx.Output<Tensor>("Out");
37
    double overwrite = ctx.Attr<bool>("overwrite");
Z
zchen0211 已提交
38

39
    // In place output: Out = X, Out[Ids] = Updates
40
    framework::TensorCopy(*X, ctx.GetPlace(), Out);
41
    // Apply ScatterUpdate: Out[index] = Updates[:]
42 43 44 45 46 47 48 49 50 51
    const auto &index_type = Ids->dtype();
    bool index_type_match = index_type == phi::DataType::INT32 ||
                            index_type == phi::DataType::INT64;
    PADDLE_ENFORCE_EQ(
        index_type_match, true,
        platform::errors::InvalidArgument(
            "Index holds the wrong type, it holds [%s],"
            "but desires to be [%s] or [%s].",
            index_type, phi::DataType::INT32, phi::DataType::INT64));
    auto &dev_ctx = ctx.template device_context<phi::CPUContext>();
52
    if (overwrite) {
53 54
      if (index_type == phi::DataType::INT32) {
        phi::funcs::ScatterAssign<T, int32_t>(dev_ctx, *Updates, *Ids, Out);
55
      } else {
56
        phi::funcs::ScatterAssign<T, int64_t>(dev_ctx, *Updates, *Ids, Out);
57 58
      }
    } else {
59 60
      if (index_type == phi::DataType::INT32) {
        phi::funcs::ScatterAssignAdd<T, int32_t>(dev_ctx, *Updates, *Ids, Out);
61
      } else {
62
        phi::funcs::ScatterAssignAdd<T, int64_t>(dev_ctx, *Updates, *Ids, Out);
63 64
      }
    }
Z
zchen0211 已提交
65 66 67
  }
};

Z
zchen0211 已提交
68
template <typename T>
Y
Yu Yang 已提交
69
class ScatterGradientOpKernel : public framework::OpKernel<T> {
Z
zchen0211 已提交
70 71
 public:
  void Compute(const framework::ExecutionContext &ctx) const override {
72 73 74
    PADDLE_ENFORCE_EQ(
        platform::is_cpu_place(ctx.GetPlace()), true,
        platform::errors::PreconditionNotMet("This kernel only runs on CPU."));
D
dzhwinter 已提交
75
    auto *dX = ctx.Output<Tensor>(framework::GradVarName("X"));
Z
zchen0211 已提交
76
    auto *dUpdates = ctx.Output<Tensor>(framework::GradVarName("Updates"));
D
dzhwinter 已提交
77
    auto *Ids = ctx.Input<Tensor>("Ids");
Z
zchen0211 已提交
78
    auto *dOut = ctx.Input<Tensor>(framework::GradVarName("Out"));
Z
zchen0211 已提交
79

80 81 82
    const auto &index_type = Ids->dtype();
    bool index_type_match = index_type == phi::DataType::INT32 ||
                            index_type == phi::DataType::INT64;
S
ShenLiang 已提交
83 84 85 86 87
    PADDLE_ENFORCE_EQ(
        index_type_match, true,
        platform::errors::InvalidArgument(
            "scatter_op index holds the wrong type, it holds [%s],"
            "but desires to be [%s] or [%s]",
88
            index_type, phi::DataType::INT32, phi::DataType::INT64));
S
ShenLiang 已提交
89

90
    auto &dev_ctx = ctx.template device_context<phi::CPUContext>();
C
chengduo 已提交
91
    if (dX) {
92
      framework::TensorCopy(*dOut, ctx.GetPlace(), dX);
93 94
      if (index_type == phi::DataType::INT32) {
        phi::funcs::CPUScatterGradForX<T, int32_t>(dev_ctx, *Ids, dX);
S
ShenLiang 已提交
95
      } else {
96
        phi::funcs::CPUScatterGradForX<T, int64_t>(dev_ctx, *Ids, dX);
S
ShenLiang 已提交
97
      }
C
chengduo 已提交
98
    }
S
ShenLiang 已提交
99

C
chengduo 已提交
100 101 102
    if (dUpdates) {
      dUpdates->mutable_data<T>(ctx.GetPlace());
      // Gradient by Gather: dUpdates = dO[Ids]
103 104
      if (index_type == phi::DataType::INT32) {
        phi::funcs::CPUGather<T, int32_t>(dev_ctx, *dOut, *Ids, dUpdates);
105
      } else {
106
        phi::funcs::CPUGather<T, int64_t>(dev_ctx, *dOut, *Ids, dUpdates);
107
      }
C
chengduo 已提交
108
    }
Z
zchen0211 已提交
109 110 111 112 113
  }
};

}  // namespace operators
}  // namespace paddle