Skip to content

Commit ecef2e6

Browse files
authored
Merge pull request #4086 from guoshengCS/add-ReduceOp
Add reduce op
2 parents 38bca7d + e33b411 commit ecef2e6

File tree

5 files changed

+545
-0
lines changed

5 files changed

+545
-0
lines changed

paddle/operators/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@ function(op_library TARGET)
6161
# It's enough to just adding one operator to pybind
6262
file(APPEND ${pybind_file} "USE_OP(sigmoid);\n")
6363
endif()
64+
65+
# reduce_op contains several operators
66+
if ("${TARGET}" STREQUAL "reduce_op")
67+
set(pybind_flag 1)
68+
# It's enough to just adding one operator to pybind
69+
file(APPEND ${pybind_file} "USE_OP(reduce_sum);\n")
70+
endif()
6471

6572
# pybind USE_NO_KERNEL_OP
6673
file(READ ${TARGET}.cc TARGET_CONTENT)

paddle/operators/reduce_op.cc

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License. */
14+
15+
#include "paddle/operators/reduce_op.h"
16+
17+
namespace paddle {
18+
namespace operators {
19+
20+
using framework::Tensor;
21+
22+
class ReduceOp : public framework::OperatorWithKernel {
23+
public:
24+
using framework::OperatorWithKernel::OperatorWithKernel;
25+
26+
protected:
27+
void InferShape(framework::InferShapeContextBase *ctx) const override {
28+
PADDLE_ENFORCE(ctx->HasInput("X"),
29+
"Input(X) of ReduceOp should not be null.");
30+
PADDLE_ENFORCE(ctx->HasOutput("Out"),
31+
"Output(Out) of ReduceOp should not be null.");
32+
auto x_dims = ctx->GetInputDim("X");
33+
auto x_rank = x_dims.size();
34+
PADDLE_ENFORCE_LE(x_rank, 6, "Tensors with rank at most 6 are supported.");
35+
int dim = ctx->Attrs().Get<int>("dim");
36+
if (dim < 0) dim = x_rank + dim;
37+
PADDLE_ENFORCE_LT(
38+
dim, x_rank,
39+
"The dim should be in the range [-rank(input), rank(input)).");
40+
bool keep_dim = ctx->Attrs().Get<bool>("keep_dim");
41+
auto dims_vector = vectorize(x_dims);
42+
if (keep_dim || x_rank == 1) {
43+
dims_vector[dim] = 1;
44+
} else {
45+
dims_vector.erase(dims_vector.begin() + dim);
46+
}
47+
auto out_dims = framework::make_ddim(dims_vector);
48+
ctx->SetOutputDim("Out", out_dims);
49+
if (dim != 0) {
50+
// Only pass LoD when not reducing on the first dim.
51+
ctx->ShareLoD("X", /*->*/ "Out");
52+
}
53+
}
54+
};
55+
56+
class ReduceGradOp : public framework::OperatorWithKernel {
57+
public:
58+
using framework::OperatorWithKernel::OperatorWithKernel;
59+
60+
protected:
61+
void InferShape(framework::InferShapeContextBase *ctx) const override {
62+
PADDLE_ENFORCE(ctx->HasInput("X"), "Input(X) should not be null.");
63+
PADDLE_ENFORCE(ctx->HasInput(framework::GradVarName("Out")),
64+
"Input(Out@GRAD) should not be null.");
65+
auto x_dims = ctx->GetInputDim("X");
66+
auto x_rank = x_dims.size();
67+
PADDLE_ENFORCE_LE(x_rank, 6, "Tensors with rank at most 6 are supported.");
68+
int dim = ctx->Attrs().Get<int>("dim");
69+
if (dim < 0) dim = x_rank + dim;
70+
PADDLE_ENFORCE_LT(
71+
dim, x_rank,
72+
"The dim should be in the range [-rank(input), rank(input)).");
73+
auto x_grad_name = framework::GradVarName("X");
74+
if (ctx->HasOutput(x_grad_name)) {
75+
ctx->SetOutputDim(x_grad_name, x_dims);
76+
}
77+
}
78+
};
79+
80+
class ReduceOpMaker : public framework::OpProtoAndCheckerMaker {
81+
public:
82+
ReduceOpMaker(framework::OpProto *proto, framework::OpAttrChecker *op_checker)
83+
: OpProtoAndCheckerMaker(proto, op_checker) {
84+
AddInput(
85+
"X",
86+
"(Tensor) The input tensor. Tensors with rank at most 6 are supported");
87+
AddOutput("Out", "(Tensor) The result tensor.");
88+
AddAttr<int>(
89+
"dim",
90+
"(int, default 1) The dimension to reduce. "
91+
"Must be in the range [-rank(input), rank(input)). "
92+
"If `dim < 0`, the dim to reduce is `rank + dim`. "
93+
"Noting that reducing on the first dim will make the LoD info lost.")
94+
.SetDefault(0);
95+
AddAttr<bool>("keep_dim",
96+
"(bool, default false) "
97+
"If true, retain the reduced dimension with length 1.")
98+
.SetDefault(false);
99+
comment_ = R"DOC(
100+
{ReduceOP} operator computes the {reduce} of input tensor along the given dimension.
101+
The result tensor has 1 fewer dimension than the input unless `keep_dim` is true.
102+
)DOC";
103+
AddComment(comment_);
104+
}
105+
106+
protected:
107+
std::string comment_;
108+
109+
void Replace(std::string &src, std::string from, std::string to) {
110+
std::size_t len_from = std::strlen(from.c_str());
111+
std::size_t len_to = std::strlen(to.c_str());
112+
for (std::size_t pos = src.find(from); pos != std::string::npos;
113+
pos = src.find(from, pos + len_to)) {
114+
src.replace(pos, len_from, to);
115+
}
116+
}
117+
118+
void SetComment(std::string name, std::string op) {
119+
Replace(comment_, "{ReduceOP}", name);
120+
Replace(comment_, "{reduce}", op);
121+
}
122+
};
123+
124+
class ReduceSumOpMaker : public ReduceOpMaker {
125+
public:
126+
ReduceSumOpMaker(framework::OpProto *proto,
127+
framework::OpAttrChecker *op_checker)
128+
: ReduceOpMaker(proto, op_checker) {
129+
SetComment("ReduceSum", "sum");
130+
AddComment(comment_);
131+
}
132+
};
133+
134+
class ReduceMeanOpMaker : public ReduceOpMaker {
135+
public:
136+
ReduceMeanOpMaker(framework::OpProto *proto,
137+
framework::OpAttrChecker *op_checker)
138+
: ReduceOpMaker(proto, op_checker) {
139+
SetComment("ReduceMean", "mean");
140+
AddComment(comment_);
141+
}
142+
};
143+
144+
class ReduceMaxOpMaker : public ReduceOpMaker {
145+
public:
146+
ReduceMaxOpMaker(framework::OpProto *proto,
147+
framework::OpAttrChecker *op_checker)
148+
: ReduceOpMaker(proto, op_checker) {
149+
SetComment("ReduceMax", "max");
150+
AddComment(comment_);
151+
}
152+
};
153+
154+
class ReduceMinOpMaker : public ReduceOpMaker {
155+
public:
156+
ReduceMinOpMaker(framework::OpProto *proto,
157+
framework::OpAttrChecker *op_checker)
158+
: ReduceOpMaker(proto, op_checker) {
159+
SetComment("ReduceMin", "min");
160+
AddComment(comment_);
161+
}
162+
};
163+
164+
} // namespace operators
165+
} // namespace paddle
166+
167+
namespace ops = paddle::operators;
168+
169+
REGISTER_OP(reduce_sum, ops::ReduceOp, ops::ReduceSumOpMaker, reduce_sum_grad,
170+
ops::ReduceGradOp);
171+
REGISTER_OP_CPU_KERNEL(
172+
reduce_sum,
173+
ops::ReduceKernel<paddle::platform::CPUPlace, float, ops::SumFunctor>);
174+
REGISTER_OP_CPU_KERNEL(reduce_sum_grad,
175+
ops::ReduceGradKernel<paddle::platform::CPUPlace, float,
176+
ops::SumGradFunctor>);
177+
178+
REGISTER_OP(reduce_mean, ops::ReduceOp, ops::ReduceMeanOpMaker,
179+
reduce_mean_grad, ops::ReduceGradOp);
180+
REGISTER_OP_CPU_KERNEL(
181+
reduce_mean,
182+
ops::ReduceKernel<paddle::platform::CPUPlace, float, ops::MeanFunctor>);
183+
REGISTER_OP_CPU_KERNEL(reduce_mean_grad,
184+
ops::ReduceGradKernel<paddle::platform::CPUPlace, float,
185+
ops::MeanGradFunctor>);
186+
187+
REGISTER_OP(reduce_max, ops::ReduceOp, ops::ReduceMaxOpMaker, reduce_max_grad,
188+
ops::ReduceGradOp);
189+
REGISTER_OP_CPU_KERNEL(
190+
reduce_max,
191+
ops::ReduceKernel<paddle::platform::CPUPlace, float, ops::MaxFunctor>);
192+
REGISTER_OP_CPU_KERNEL(reduce_max_grad,
193+
ops::ReduceGradKernel<paddle::platform::CPUPlace, float,
194+
ops::MaxOrMinGradFunctor>);
195+
196+
REGISTER_OP(reduce_min, ops::ReduceOp, ops::ReduceMaxOpMaker, reduce_min_grad,
197+
ops::ReduceGradOp);
198+
REGISTER_OP_CPU_KERNEL(
199+
reduce_min,
200+
ops::ReduceKernel<paddle::platform::CPUPlace, float, ops::MinFunctor>);
201+
REGISTER_OP_CPU_KERNEL(reduce_min_grad,
202+
ops::ReduceGradKernel<paddle::platform::CPUPlace, float,
203+
ops::MaxOrMinGradFunctor>);

paddle/operators/reduce_op.cu

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License. */
14+
15+
#define EIGEN_USE_GPU
16+
#include "paddle/operators/reduce_op.h"
17+
18+
namespace ops = paddle::operators;
19+
20+
REGISTER_OP_GPU_KERNEL(
21+
reduce_sum,
22+
ops::ReduceKernel<paddle::platform::GPUPlace, float, ops::SumFunctor>);
23+
REGISTER_OP_GPU_KERNEL(reduce_sum_grad,
24+
ops::ReduceGradKernel<paddle::platform::GPUPlace, float,
25+
ops::SumGradFunctor>);
26+
27+
REGISTER_OP_GPU_KERNEL(
28+
reduce_mean,
29+
ops::ReduceKernel<paddle::platform::GPUPlace, float, ops::MeanFunctor>);
30+
REGISTER_OP_GPU_KERNEL(reduce_mean_grad,
31+
ops::ReduceGradKernel<paddle::platform::GPUPlace, float,
32+
ops::MeanGradFunctor>);
33+
34+
REGISTER_OP_GPU_KERNEL(
35+
reduce_max,
36+
ops::ReduceKernel<paddle::platform::GPUPlace, float, ops::MaxFunctor>);
37+
REGISTER_OP_GPU_KERNEL(reduce_max_grad,
38+
ops::ReduceGradKernel<paddle::platform::GPUPlace, float,
39+
ops::MaxOrMinGradFunctor>);
40+
41+
REGISTER_OP_GPU_KERNEL(
42+
reduce_min,
43+
ops::ReduceKernel<paddle::platform::GPUPlace, float, ops::MinFunctor>);
44+
REGISTER_OP_GPU_KERNEL(reduce_min_grad,
45+
ops::ReduceGradKernel<paddle::platform::GPUPlace, float,
46+
ops::MaxOrMinGradFunctor>);

0 commit comments

Comments
 (0)