Skip to content

Commit 381c6a0

Browse files
authored
Merge pull request #9100 from pkuyym/fix-9049
Enhance sequence_expand operator
2 parents 5271c32 + 2c22552 commit 381c6a0

File tree

9 files changed

+305
-154
lines changed

9 files changed

+305
-154
lines changed

paddle/fluid/operators/math/math_function.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,8 @@ template struct RowwiseAdd<platform::CPUDeviceContext, double>;
371371

372372
template struct ColwiseSum<platform::CPUDeviceContext, float>;
373373
template struct ColwiseSum<platform::CPUDeviceContext, double>;
374+
template struct ColwiseSum<platform::CPUDeviceContext, int>;
375+
template struct ColwiseSum<platform::CPUDeviceContext, int64_t>;
374376

375377
template struct RowwiseSum<platform::CPUDeviceContext, float>;
376378
template struct RowwiseSum<platform::CPUDeviceContext, double>;

paddle/fluid/operators/math/math_function.cu

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,8 @@ struct RowwiseAdd<platform::CUDADeviceContext, T> {
422422
template struct RowwiseAdd<platform::CUDADeviceContext, float>;
423423
template struct RowwiseAdd<platform::CUDADeviceContext, double>;
424424
template struct ColwiseSum<platform::CUDADeviceContext, float>;
425+
template struct ColwiseSum<platform::CUDADeviceContext, int>;
426+
template struct ColwiseSum<platform::CUDADeviceContext, int64_t>;
425427
// template struct ColwiseSum<platform::CUDADeviceContext, double>;
426428
// The ColwiseSum<platform::CUDADeviceContext, double> failed in debug mode,
427429
// and only failed for this case. So reimplemented it.

paddle/fluid/operators/sequence_expand_op.cc

Lines changed: 124 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,79 @@ limitations under the License. */
1717
namespace paddle {
1818
namespace operators {
1919

20-
using framework::Tensor;
20+
using framework::LoDTensor;
2121

2222
class SequenceExpandOp : public framework::OperatorWithKernel {
2323
public:
2424
using framework::OperatorWithKernel::OperatorWithKernel;
2525

2626
protected:
2727
void InferShape(framework::InferShapeContext* ctx) const override {
28-
PADDLE_ENFORCE(ctx->HasInput("X"));
29-
PADDLE_ENFORCE(ctx->HasOutput("Out"));
30-
PADDLE_ENFORCE(ctx->HasInput("Y"));
31-
framework::DDim out_dim;
32-
auto y_dim = ctx->GetInputDim("Y");
33-
out_dim = ctx->GetInputDim("X");
34-
out_dim[0] = y_dim[0];
35-
ctx->ShareLoD("Y", "Out");
36-
ctx->SetOutputDim("Out", out_dim);
28+
PADDLE_ENFORCE(ctx->HasInput("X"),
29+
"Input(X) of SequenceExpandOp should not be null.");
30+
PADDLE_ENFORCE(ctx->HasInput("Y"),
31+
"Input(Y) of SequenceExpandOp should not be null.");
32+
PADDLE_ENFORCE(ctx->HasOutput("Out"),
33+
"Output(Out) of SequenceExpandOp should not be null.");
34+
35+
auto x_dims = ctx->GetInputDim("X");
36+
auto out_dims = x_dims;
37+
int ref_level = ctx->Attrs().Get<int>("ref_level");
38+
39+
PADDLE_ENFORCE_GE(x_dims.size(), 2,
40+
"Dimension number of Input(X) should be at least 2.");
41+
42+
if (ctx->IsRuntime()) {
43+
framework::Variable* x_var =
44+
boost::get<framework::Variable*>(ctx->GetInputVarPtrs("X")[0]);
45+
framework::Variable* y_var =
46+
boost::get<framework::Variable*>(ctx->GetInputVarPtrs("Y")[0]);
47+
48+
auto& x_lod = x_var->Get<LoDTensor>().lod();
49+
auto& y_lod = y_var->Get<LoDTensor>().lod();
50+
51+
PADDLE_ENFORCE_LE(x_lod.size(), 1,
52+
"Level number of Input(X)'s lod should not be "
53+
"greater than 1.");
54+
PADDLE_ENFORCE_GT(y_lod.size(), 0,
55+
"Level number of Input(Y)'s lod should be "
56+
"greater than 0.");
57+
PADDLE_ENFORCE(
58+
ref_level == -1 ||
59+
(ref_level >= 0 && ref_level < static_cast<int>(y_lod.size())),
60+
"Invlid `ref_level`, which should be either equal to -1 "
61+
"or in [0, %d)",
62+
y_lod.size());
63+
64+
if (ref_level == -1) ref_level = y_lod.size() - 1;
65+
66+
if (x_lod.size() > 0) {
67+
PADDLE_ENFORCE(x_lod[0].size() == y_lod[ref_level].size(),
68+
"Level number of Input(X)'s lod could be 0. Otherwise "
69+
"size of Input(X)'s first level lod should be equal to "
70+
"size of Input(Y)'s referred level lod.");
71+
}
72+
73+
int64_t out_first_dim = 0;
74+
if (y_lod[ref_level].size() <= 1) {
75+
out_first_dim = x_dims[0];
76+
} else {
77+
for (size_t i = 1; i < y_lod[ref_level].size(); ++i) {
78+
int x_seq_len = 1;
79+
if (x_lod.size() == 1) {
80+
x_seq_len = x_lod[0][i] - x_lod[0][i - 1];
81+
}
82+
out_first_dim +=
83+
(y_lod[ref_level][i] - y_lod[ref_level][i - 1]) * x_seq_len;
84+
}
85+
}
86+
out_dims[0] = out_first_dim;
87+
ctx->SetOutputDim("Out", out_dims);
88+
} else {
89+
out_dims[0] = -1;
90+
ctx->SetOutputDim("Out", out_dims);
91+
ctx->ShareLoD("X", /*->*/ "Out");
92+
}
3793
}
3894
};
3995

@@ -42,83 +98,81 @@ class SequenceExpandOpMaker : public framework::OpProtoAndCheckerMaker {
4298
SequenceExpandOpMaker(OpProto* proto, OpAttrChecker* op_checker)
4399
: OpProtoAndCheckerMaker(proto, op_checker) {
44100
AddInput("X",
45-
"(Tensor or LoDTensor) The input(X) of this operator can be a "
46-
"LoDTensor or a base Tensor.");
101+
"(LoDTensor, default LoDTensor<float>) A 2-D LoDTensor whose lod "
102+
"level is at most 1.");
47103
AddInput("Y",
48-
"(LoDTensor)The reference input(Y) of sequence_expand op."
49-
"It must be a LoDTensor with k-level(k>0)."
50-
"The input(X) will be expanded according to LOD of input(Y)."
51-
"The element numbers of last level in input(Y) "
52-
"must be equal to dims[0] of input(X).");
104+
"(LoDTensor, default LoDTensor<float>) Referred LoDTensor whose "
105+
"lod (specified level) is referred by Input(X).");
53106
AddOutput("Out",
54-
"(LodTensor)The output of sequence_expand op."
55-
"The lod of output will be as same as input(Y)'s lod.");
107+
"(LodTensor, default LoDTensor<float>) Output LoDTensor which is "
108+
"generated from Input(X) by referring lod of Input(Y).");
109+
AddAttr<int>("ref_level", "Specify lod level of Input(Y).").SetDefault(-1);
56110
AddComment(R"DOC(
57111
Sequence Expand Operator.
58112
59-
This operator expands input(X) according to LOD of input(Y).
113+
This operator expands `X` according to specified level lod of `Y`. Current
114+
implementation constaints that lod level of `X` should be at most 1. Attribute
115+
`ref_level` is used to specify which level lod of `Y` is referred to expand `X`.
116+
If set `ref_level` to -1, then last level lod of `Y` would be referred.
117+
Please note, rank of `X` should be at least 2, when the rank exceeds 2, `X`
118+
would be viewed as a 2-D tensor.
119+
60120
Following are cases to better explain how this works:
121+
61122
Case 1:
62123
63-
Given a 2-level LoDTensor input(X)
64-
X.lod = [[0, 2, 3],
65-
[0, 1, 3, 4]]
66-
X.data = [a, b, c, d]
124+
Given a 1-level LoDTensor input(X)
125+
X.lod = [[0, 2, 4]]
126+
X.data = [[a], [b], [c], [d]]
67127
X.dims = [4, 1]
68128
and input(Y)
69129
Y.lod = [[0, 2, 4],
70130
[0, 3, 6, 7, 8]]
71-
with condition len(Y.lod[-1]) -1 == X.dims[0]
72-
then we get 2-level LoDTensor
73-
Out.lod = [[0, 2, 4],
74-
[0, 3, 6, 7, 8]]
75-
Out.data = [a, a, a, b, b, b, c, d]
131+
ref_level: 0
132+
then we get 1-level LoDTensor
133+
Out.lod = [[0, 2, 4, 6, 8]]
134+
Out.data = [[a], [b], [a], [b], [c], [d], [c], [d]]
76135
Out.dims = [8, 1]
77136
78137
Case 2:
79138
139+
Given 1-level LoDTensor input(X)
140+
X.lod = [[0, 1, 4]]
141+
X.data = [[a], [b], [c], [d]]
142+
X.dims = [4, 1]
143+
and input(Y)
144+
Y.lod = [[0, 2, 4],
145+
[0, 3, 6, 6, 8]]
146+
ref_level: 0
147+
then we get 1-level LoDTensor
148+
Out.lod = [[0, 1, 2, 5, 8]]
149+
Out.data = [[a], [a], [b], [c], [d], [b], [c], [d]]
150+
Out.dims = [8, 1]
151+
152+
Case 3:
153+
80154
Given a common Tensor input(X)
81-
X.data = [a, b, c]
155+
X.data = [[a], [b], [c]]
82156
X.dims = [3, 1]
83157
and input(Y)
84158
Y.lod = [[0, 2, 3, 6]]
85-
with condition len(Y.lod[-1]) -1 == X.dims[0]
86-
then we get 1-level LoDTensor
87-
Out.lod = [[0, 2, 3, 6]]
88-
Out.data = [a, a, b, c, c, c]
159+
ref_level: -1
160+
then we get a common Tensor
161+
Out.data = [[a], [a], [b], [c], [c], [c]]
89162
Out.dims = [6, 1]
90163
91-
Case 3:
164+
Case 4:
92165
93166
Given a common Tensor input(X)
94167
X.data = [[a, b], [c, d], [e, f]]
95168
X.dims = [3, 2]
96169
and input(Y)
97170
Y.lod = [[0, 2, 3, 6]]
98-
with condition len(Y.lod[-1]) -1 == X.dims[0]
99-
then we get 1-level LoDTensor
100-
Out.lod = [[0, 2, 3, 6]]
101-
Out.data = [[a,b], [a,b] [c,d], [e, f], [e, f], [e, f]]
171+
ref_level: 0
172+
then we get a common LoDTensor
173+
Out.data = [[a, b], [a, b] [c, d], [e, f], [e, f], [e, f]]
102174
Out.dims = [6, 2]
103175
104-
Case 4:
105-
106-
Given 2-level a LoDTensor input(X)
107-
X.lod = [[0, 2, 3],
108-
[0, 1, 3, 4]]
109-
X.data = [a, b, c, d]
110-
X.dims = [4, 1]
111-
and input(Y)
112-
Y.lod = [[0, 2, 4],
113-
[0, 3, 6, 6, 8]]
114-
with condition len(Y.lod[-1]) -1 == X.dims[0]
115-
then we get 2-level LoDTensor
116-
Out.lod = [[0, 2, 4],
117-
[0, 3, 6, 6, 8]]
118-
Out.data = [a, a, a, b, b, b, d, d]
119-
Out.dims = [8, 1]
120-
121-
122176
)DOC");
123177
}
124178
};
@@ -129,12 +183,14 @@ class SequenceExpandOpGrad : public framework::OperatorWithKernel {
129183

130184
protected:
131185
void InferShape(framework::InferShapeContext* ctx) const override {
132-
PADDLE_ENFORCE(ctx->HasInput("X"));
133-
PADDLE_ENFORCE(ctx->HasInput("Out"));
186+
PADDLE_ENFORCE(ctx->HasInput("X"), "Input(X) should not be null.");
187+
PADDLE_ENFORCE(ctx->HasInput("Out"), "Input(Out) should not be null.");
134188
PADDLE_ENFORCE(ctx->HasInput(framework::GradVarName("Out")),
135-
"The input(Out@GRAD) should not be null");
189+
"Input(Out@GRAD) should not be null.");
190+
136191
auto x_dims = ctx->GetInputDim("X");
137192
auto x_grad_name = framework::GradVarName("X");
193+
138194
if (ctx->HasOutput(x_grad_name)) {
139195
ctx->SetOutputDim(x_grad_name, x_dims);
140196
}
@@ -149,7 +205,13 @@ REGISTER_OP(sequence_expand, ops::SequenceExpandOp, ops::SequenceExpandOpMaker,
149205
sequence_expand_grad, ops::SequenceExpandOpGrad);
150206
REGISTER_OP_CPU_KERNEL(
151207
sequence_expand,
152-
ops::SequenceExpandKernel<paddle::platform::CPUDeviceContext, float>);
208+
ops::SequenceExpandKernel<paddle::platform::CPUDeviceContext, float>,
209+
ops::SequenceExpandKernel<paddle::platform::CPUDeviceContext, double>,
210+
ops::SequenceExpandKernel<paddle::platform::CPUDeviceContext, int>,
211+
ops::SequenceExpandKernel<paddle::platform::CPUDeviceContext, int64_t>);
153212
REGISTER_OP_CPU_KERNEL(
154213
sequence_expand_grad,
155-
ops::SequenceExpandGradKernel<paddle::platform::CPUDeviceContext, float>);
214+
ops::SequenceExpandGradKernel<paddle::platform::CPUDeviceContext, float>,
215+
ops::SequenceExpandGradKernel<paddle::platform::CPUDeviceContext, double>,
216+
ops::SequenceExpandGradKernel<paddle::platform::CPUDeviceContext, int>,
217+
ops::SequenceExpandGradKernel<paddle::platform::CPUDeviceContext, int64_t>);

paddle/fluid/operators/sequence_expand_op.cu

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,14 @@ limitations under the License. */
1818
namespace ops = paddle::operators;
1919
REGISTER_OP_CUDA_KERNEL(
2020
sequence_expand,
21-
ops::SequenceExpandKernel<paddle::platform::CUDADeviceContext, float>);
21+
ops::SequenceExpandKernel<paddle::platform::CUDADeviceContext, float>,
22+
ops::SequenceExpandKernel<paddle::platform::CUDADeviceContext, double>,
23+
ops::SequenceExpandKernel<paddle::platform::CUDADeviceContext, int>,
24+
ops::SequenceExpandKernel<paddle::platform::CUDADeviceContext, int64_t>);
2225
REGISTER_OP_CUDA_KERNEL(
2326
sequence_expand_grad,
24-
ops::SequenceExpandGradKernel<paddle::platform::CUDADeviceContext, float>);
27+
ops::SequenceExpandGradKernel<paddle::platform::CUDADeviceContext, float>,
28+
ops::SequenceExpandGradKernel<paddle::platform::CUDADeviceContext, double>,
29+
ops::SequenceExpandGradKernel<paddle::platform::CUDADeviceContext, int>,
30+
ops::SequenceExpandGradKernel<paddle::platform::CUDADeviceContext,
31+
int64_t>);

0 commit comments

Comments
 (0)