@@ -17,23 +17,79 @@ limitations under the License. */
17
17
namespace paddle {
18
18
namespace operators {
19
19
20
- using framework::Tensor ;
20
+ using framework::LoDTensor ;
21
21
22
22
class SequenceExpandOp : public framework ::OperatorWithKernel {
23
23
public:
24
24
using framework::OperatorWithKernel::OperatorWithKernel;
25
25
26
26
protected:
27
27
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
+ }
37
93
}
38
94
};
39
95
@@ -42,83 +98,81 @@ class SequenceExpandOpMaker : public framework::OpProtoAndCheckerMaker {
42
98
SequenceExpandOpMaker (OpProto* proto, OpAttrChecker* op_checker)
43
99
: OpProtoAndCheckerMaker(proto, op_checker) {
44
100
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 ." );
47
103
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)." );
53
106
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 );
56
110
AddComment (R"DOC(
57
111
Sequence Expand Operator.
58
112
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
+
60
120
Following are cases to better explain how this works:
121
+
61
122
Case 1:
62
123
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]]
67
127
X.dims = [4, 1]
68
128
and input(Y)
69
129
Y.lod = [[0, 2, 4],
70
130
[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]]
76
135
Out.dims = [8, 1]
77
136
78
137
Case 2:
79
138
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
+
80
154
Given a common Tensor input(X)
81
- X.data = [a, b, c ]
155
+ X.data = [[a], [b], [c] ]
82
156
X.dims = [3, 1]
83
157
and input(Y)
84
158
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]]
89
162
Out.dims = [6, 1]
90
163
91
- Case 3 :
164
+ Case 4 :
92
165
93
166
Given a common Tensor input(X)
94
167
X.data = [[a, b], [c, d], [e, f]]
95
168
X.dims = [3, 2]
96
169
and input(Y)
97
170
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]]
102
174
Out.dims = [6, 2]
103
175
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
-
122
176
)DOC" );
123
177
}
124
178
};
@@ -129,12 +183,14 @@ class SequenceExpandOpGrad : public framework::OperatorWithKernel {
129
183
130
184
protected:
131
185
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. " );
134
188
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
+
136
191
auto x_dims = ctx->GetInputDim (" X" );
137
192
auto x_grad_name = framework::GradVarName (" X" );
193
+
138
194
if (ctx->HasOutput (x_grad_name)) {
139
195
ctx->SetOutputDim (x_grad_name, x_dims);
140
196
}
@@ -149,7 +205,13 @@ REGISTER_OP(sequence_expand, ops::SequenceExpandOp, ops::SequenceExpandOpMaker,
149
205
sequence_expand_grad, ops::SequenceExpandOpGrad);
150
206
REGISTER_OP_CPU_KERNEL (
151
207
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 >);
153
212
REGISTER_OP_CPU_KERNEL (
154
213
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 >);
0 commit comments