Skip to content

Commit c3de69a

Browse files
committed
Complete sequence_pad_op and its CPU kernel. Add unittests
1 parent 1715251 commit c3de69a

File tree

6 files changed

+234
-135
lines changed

6 files changed

+234
-135
lines changed

paddle/fluid/operators/math/sequence_padding.cc

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,10 @@ class PaddingLoDTensorFunctor<platform::CPUDeviceContext, T> {
7070
std::vector<T> pad_value = {0}, int pad_seq_len = -1,
7171
int lod_level = 0, bool norm_by_times = false,
7272
const PadLayout layout = kBatchLengthWidth) {
73-
auto seq_offsets = framework::ToAbsOffset(seq_tensor.lod())[lod_level];
74-
auto seq_tensor_dims = seq_tensor.dims();
75-
auto pad_tensor_dims = pad_tensor->dims();
73+
auto seq_lod = seq_tensor.lod();
74+
const auto seq_offsets = framework::ToAbsOffset(seq_lod)[lod_level];
75+
const auto& seq_tensor_dims = seq_tensor.dims();
76+
const auto& pad_tensor_dims = pad_tensor->dims();
7677
if (pad_seq_len == -1) {
7778
pad_seq_len = MaximumSequenceLength(seq_offsets);
7879
}
@@ -91,12 +92,21 @@ class PaddingLoDTensorFunctor<platform::CPUDeviceContext, T> {
9192

9293
// fill padding value
9394
T* pad_data = pad_tensor->data<T>();
94-
for (int i = 0; i < pad_tensor->numel() / step_width; ++i) {
95-
memcpy(pad_data, pad_value.data(), step_width * sizeof(T));
95+
for (int i = 0; i < pad_tensor->numel(); i += step_width) {
96+
memcpy(pad_data + i, pad_value.data(), step_width * sizeof(T));
9697
}
9798

9899
CopyValidData<T>(pad_tensor, &seq_tensor, seq_offsets, pad_seq_len,
99100
step_width, norm_by_times, kSeqToPad, layout);
101+
102+
// Set pad_tensor's lod info if possible
103+
if (layout == kBatchLengthWidth) {
104+
framework::LoD pad_lod(seq_lod.begin() + lod_level, seq_lod.end());
105+
for (size_t i = 0; i < pad_lod[0].size(); ++i) {
106+
pad_lod[0][i] = i * pad_seq_len;
107+
}
108+
pad_tensor->set_lod(pad_lod);
109+
}
100110
}
101111
};
102112

@@ -109,8 +119,8 @@ class UnpaddingLoDTensorFunctor<platform::CPUDeviceContext, T> {
109119
int lod_level = 0, bool norm_by_times = false,
110120
const PadLayout& layout = kBatchLengthWidth) {
111121
auto seq_offsets = framework::ToAbsOffset(seq_tensor->lod())[lod_level];
112-
auto seq_tensor_dims = seq_tensor->dims();
113-
auto pad_tensor_dims = pad_tensor.dims();
122+
const auto& seq_tensor_dims = seq_tensor->dims();
123+
const auto& pad_tensor_dims = pad_tensor.dims();
114124
if (pad_seq_len == -1) {
115125
pad_seq_len = MaximumSequenceLength(seq_offsets);
116126
}

paddle/fluid/operators/math/sequence_padding.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,6 @@ inline static void CheckDims(const framework::DDim& seq_tensor_dims,
4444
"Value of 1st dimension of the sequence tensor should be "
4545
"equal to sum of lengths of all sequences.");
4646

47-
PADDLE_ENFORCE(seq_tensor_dims.size() == 1 || seq_tensor_dims.size() == 2,
48-
"seq_tensor's rank should be 1 or 2.");
49-
5047
PADDLE_ENFORCE(seq_tensor_dims.size() + 1 == pad_tensor_dims.size() ||
5148
seq_tensor_dims.size() == pad_tensor_dims.size(),
5249
"pad_tensor's rank should be 1 greater than seq_tensor's "

paddle/fluid/operators/sequence_pad_op.cc

Lines changed: 54 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -21,82 +21,85 @@ class SequencePadOp : public framework::OperatorWithKernel {
2121
public:
2222
using framework::OperatorWithKernel::OperatorWithKernel;
2323

24+
protected:
2425
void InferShape(framework::InferShapeContext* ctx) const override {
2526
PADDLE_ENFORCE(ctx->HasInput("X"),
2627
"Input(X) of SequencePadOp should not be null.");
28+
PADDLE_ENFORCE(ctx->HasInput("PadValue"),
29+
"Input(PadValue) of SequencePadOp should not be null.");
2730
PADDLE_ENFORCE(ctx->HasOutput("Out"),
2831
"Output(Out) of SequencePadOp should not be null.");
2932

3033
auto x_dims = ctx->GetInputDim("X");
34+
PADDLE_ENFORCE_GE(x_dims.size(), 2,
35+
"The rank of Input(x) can't be less than 2.");
36+
auto time_step_dims = framework::slice_ddim(x_dims, 1, x_dims.size());
37+
auto pad_value_dims = ctx->GetInputDim("PadValue");
38+
PADDLE_ENFORCE(pad_value_dims == framework::make_ddim({1}) ||
39+
pad_value_dims == time_step_dims,
40+
"The Input(PadValue) must be a scalar or a tensor whose "
41+
"shape equals to time steps in sequences");
3142

32-
PADDLE_ENFORCE_EQ(x_dims.size(), 2,
33-
"Only support 2-D tensor, rank of Input(X) should be 2.");
34-
35-
int lod_level = ctx->Attrs().Get<int>("lod_level");
36-
37-
int64_t max_len = -1;
38-
int64_t seq_num = -1;
39-
int x_lod_size = -1;
43+
int batch_dim_size = -1;
4044

4145
if (ctx->IsRuntime()) {
46+
// run time
4247
framework::Variable* x_var =
4348
boost::get<framework::Variable*>(ctx->GetInputVarPtrs("X")[0]);
44-
45-
auto& x_lod = x_var->Get<LoDTensor>().lod();
46-
47-
x_lod_size = x_lod.size();
48-
49-
auto x_abs_offset = framework::ToAbsOffset(x_lod)[lod_level];
50-
51-
PADDLE_ENFORCE_EQ(x_dims[0], static_cast<int64_t>(x_abs_offset.back()),
52-
"The first dimension of `X` should be equal to sum "
53-
"of all sequences' length.");
54-
55-
seq_num = x_abs_offset.size() - 1;
56-
57-
for (int64_t i = 1; i <= seq_num; ++i) {
58-
int64_t seq_len = x_abs_offset[i] - x_abs_offset[i - 1];
59-
max_len = max_len < seq_len ? seq_len : max_len;
49+
const auto& x_lod = x_var->Get<LoDTensor>().lod();
50+
PADDLE_ENFORCE(!x_lod.empty(), "The Input(X) must hold lod info.");
51+
const auto& x_lod_0 = x_lod[0];
52+
PADDLE_ENFORCE_GE(x_lod_0.size(), 2,
53+
"The Input(X)'s lod info is corrupted.");
54+
PADDLE_ENFORCE_EQ(
55+
x_dims[0], static_cast<int64_t>(x_lod_0.back()),
56+
"The Input(X)'s lod info mismatches the actual tensor shape.");
57+
58+
int seq_num = x_lod_0.size() - 1;
59+
int max_seq_len = math::MaximumSequenceLength(x_lod_0);
60+
int padded_length = ctx->Attrs().Get<int>("padded_length");
61+
if (padded_length == -1) {
62+
padded_length = max_seq_len;
6063
}
64+
PADDLE_ENFORCE_GE(padded_length, max_seq_len,
65+
"The Attr(padded_length) must be -1 or an int greater "
66+
"than the length of the longest original sequence.");
67+
batch_dim_size = padded_length * seq_num;
6168
} else {
69+
// compile time
6270
framework::VarDesc* x_desc =
6371
boost::get<framework::VarDesc*>(ctx->GetInputVarPtrs("X")[0]);
64-
x_lod_size = x_desc->GetLoDLevel();
72+
PADDLE_ENFORCE_GE(x_desc->GetLoDLevel(), 1);
6573
}
6674

67-
PADDLE_ENFORCE(lod_level >= 0 && lod_level < x_lod_size,
68-
"Invalid `lod_level` which should be at least 0 and less "
69-
"than maximum lod level of `X`");
70-
71-
ctx->SetOutputDim("Out", {seq_num, max_len, x_dims[1]});
72-
}
73-
74-
protected:
75-
framework::OpKernelType GetExpectedKernelType(
76-
const framework::ExecutionContext& ctx) const override {
77-
return framework::OpKernelType(
78-
framework::ToDataType(ctx.Input<framework::LoDTensor>("X")->type()),
79-
ctx.device_context());
75+
auto out_dims = x_dims;
76+
out_dims[0] = batch_dim_size;
77+
ctx->SetOutputDim("Out", out_dims);
8078
}
8179
};
8280

8381
class SequencePadOpMaker : public framework::OpProtoAndCheckerMaker {
8482
public:
85-
SequencePadOpMaker(OpProto* proto, OpAttrChecker* op_checker)
86-
: OpProtoAndCheckerMaker(proto, op_checker) {
83+
void Make() override {
8784
AddInput("X",
8885
"(LoDTensor, default LoDTensor<float>) Input variable which "
89-
"should contain lod information. Length of each sequence would "
90-
"be computed from the most bottom level lod.");
91-
AddOutput("Out",
92-
"(Tensor) Output variable which would be a common tensor "
93-
"without lod. Each sequence would be padded to the maximum "
94-
"length.");
95-
AddAttr<float>("lod_level",
96-
"(int, default 0) Specify which level lod to referred to.");
97-
AddAttr<float>("pad_value",
98-
"(float, default 0.0) Specify which value to be padded to "
99-
"the end of each sequence.");
86+
"should contain lod information.");
87+
AddInput("PadValue",
88+
"(LoDTensor), this Tensor holds values that will be fill into "
89+
"padded steps. It can be a scalar or a tensor whose shape equals "
90+
"to time steps in sequences. If it's a scalar, it will be "
91+
"automatically broadcasted to the shape of time step.");
92+
AddOutput(
93+
"Out",
94+
"(LoDTensor) The output vairable, which contains padded sequences.");
95+
AddAttr<int>(
96+
"padded_length",
97+
"The length of padded sequences. It can be setted to -1 or "
98+
"any positive int. When it is -1, all sequences will be padded up to "
99+
"the length of the longest one among them; when it a certain positive "
100+
"value, it must be greater than the length of the longest original "
101+
"sequence.")
102+
.SetDefault(-1);
100103
AddComment(R"DOC(
101104
102105
)DOC");

paddle/fluid/operators/sequence_pad_op.cu

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,13 @@ limitations under the License. */
1717
namespace ops = paddle::operators;
1818
REGISTER_OP_CUDA_KERNEL(
1919
sequence_pad,
20-
ops::SequencePadOpKernel<paddle::platform::CUDADeviceContext, float>);
20+
ops::SequencePadOpKernel<paddle::platform::CUDADeviceContext, float>,
21+
ops::SequencePadOpKernel<paddle::platform::CUDADeviceContext, double>,
22+
ops::SequencePadOpKernel<paddle::platform::CUDADeviceContext, int>,
23+
ops::SequencePadOpKernel<paddle::platform::CUDADeviceContext, int64_t>);
2124
REGISTER_OP_CUDA_KERNEL(
2225
sequence_pad_grad,
23-
ops::SequencePadGradOpKernel<paddle::platform::CUDADeviceContext, float>);
26+
ops::SequencePadGradOpKernel<paddle::platform::CUDADeviceContext, float>,
27+
ops::SequencePadGradOpKernel<paddle::platform::CUDADeviceContext, double>,
28+
ops::SequencePadGradOpKernel<paddle::platform::CUDADeviceContext, int>,
29+
ops::SequencePadGradOpKernel<paddle::platform::CUDADeviceContext, int64_t>);

paddle/fluid/operators/sequence_pad_op.h

Lines changed: 21 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ See the License for the specific language governing permissions and
1313
limitations under the License. */
1414

1515
#pragma once
16+
17+
#include <vector>
1618
#include "paddle/fluid/framework/op_registry.h"
1719
#include "paddle/fluid/memory/memcpy.h"
1820
#include "paddle/fluid/operators/math/math_function.h"
@@ -24,95 +26,42 @@ namespace operators {
2426
using LoDTensor = framework::LoDTensor;
2527
using LoD = framework::LoD;
2628

27-
template <typename DeviceContext, typename T>
28-
struct CopyFunctor {
29-
LoDTensor* lod_tensor_;
30-
LoDTensor* pad_tensor_;
31-
const LoD& ref_lod_;
32-
const DeviceContext& ctx_;
33-
bool is_lod_to_pad_;
34-
35-
CopyFunctor(LoDTensor* lod_tensor, const LoD& ref_lod, LoDTensor* pad_tensor,
36-
const DeviceContext& ctx, bool is_lod_to_pad)
37-
: lod_tensor_(lod_tensor),
38-
pad_tensor_(pad_tensor),
39-
ref_lod_(ref_lod),
40-
ctx_(ctx),
41-
is_lod_to_pad_(is_lod_to_pad) {}
42-
43-
void operator()() const {
44-
/*
45-
auto seq_num = ref_lod_.size() - 1;
46-
auto max_len = pad_tensor_->dims()[0] / seq_num;
47-
48-
PADDLE_ENFORCE_EQ(max_len * seq_num, pad_tensor_->dims()[0],
49-
"First dimension of padded tensor should be equal to "
50-
"maximum sequence length mulplied by sequence number.");
51-
52-
for (size_t i = 1; i < ref_lod_.size(); ++i) {
53-
auto seq_start = ref_lod_[i - 1];
54-
auto seq_end = ref_lod_[i];
55-
auto pad_start = (i - 1) * max_len;
56-
auto pad_end = pad_start + (seq_end - seq_start);
57-
auto sub_lod_tensor = lod_tensor_->Slice(seq_start, seq_end);
58-
auto sub_pad_tensor = pad_tensor_->Slice(pad_start, pad_end);
59-
if (is_lod_to_pad_) {
60-
framework::TensorCopy(sub_lod_tensor, ctx.GetPlace(), &sub_pad_tensor);
61-
} else {
62-
framework::TensorCopy(sub_pad_tensor, ctx.GetPlace(), &sub_lod_tensor);
63-
}
64-
}
65-
*/
66-
}
67-
};
68-
6929
template <typename DeviceContext, typename T>
7030
class SequencePadOpKernel : public framework::OpKernel<T> {
7131
public:
7232
void Compute(const framework::ExecutionContext& ctx) const override {
73-
/*
74-
auto* x = ctx.Input<LoDTensor>("X");
75-
auto* out_ptr = ctx.Output<LoDTensor>("Out");
76-
77-
out_ptr->mutable_data<T>(ctx.GetPlace());
33+
const auto* x = ctx.Input<LoDTensor>("X");
34+
auto* out = ctx.Output<LoDTensor>("Out");
35+
out->mutable_data<T>(ctx.GetPlace());
7836

79-
// Resize();
37+
const auto* pad_value = ctx.Input<LoDTensor>("PadValue");
38+
const T* pad_value_data = pad_value->data<T>();
39+
std::vector<T> pad_value_vec(pad_value_data,
40+
pad_value_data + pad_value->numel());
8041

81-
T pad_value = static_cast<T>(ctx.Attr<float>("pad_value"));
42+
int padded_length = ctx.Attr<int>("padded_length");
8243

8344
math::PaddingLoDTensorFunctor<DeviceContext, T>()(
84-
ctx.template device_context<DeviceContext>(), *x, *, false);
85-
86-
math::SetConstant<DeviceContext, T> set_func;
87-
set_func(ctx.template device_context<DeviceContext>(), out_ptr, pad_value);
88-
*/
45+
ctx.template device_context<DeviceContext>(), *x, out, pad_value_vec,
46+
padded_length, 0, false, math::kBatchLengthWidth);
8947
}
9048
};
9149

9250
template <typename DeviceContext, typename T>
9351
class SequencePadGradOpKernel : public framework::OpKernel<T> {
9452
public:
9553
void Compute(const framework::ExecutionContext& ctx) const override {
96-
/*
97-
auto* x_ptr = ctx.Input<LoDTensor>("X");
98-
auto* g_out_ptr = ctx.Input<LoDTensor>(framework::GradVarName("Out"));
99-
auto* g_x_ptr = ctx.Output<LoDTensor>(framework::GradVarName("X"));
100-
101-
math::SetConstant<DeviceContext, T> set_func;
102-
set_func(ctx.template device_context<DeviceContext>(),
103-
g_x_ptr,
104-
static_cast<T>(0));
54+
auto* d_x = ctx.Output<LoDTensor>(framework::GradVarName("X"));
55+
if (d_x) {
56+
const auto* d_out = ctx.Input<LoDTensor>(framework::GradVarName("Out"));
57+
d_x->mutable_data<T>(ctx.GetPlace());
10558

106-
auto& x_lod = x_ptr->lod();
107-
auto& x_last_level_lod = x_lod[x_lod.size() - 1];
59+
int padded_length = ctx.Attr<int>("padded_length");
10860

109-
CopyFunctor copy_func<DeviceContext, T>(g_out_ptr,
110-
x_last_level_lod,
111-
g_x_ptr,
112-
ctx,
113-
false);
114-
copy_func();
115-
*/
61+
math::UnpaddingLoDTensorFunctor<DeviceContext, T>()(
62+
ctx.template device_context<DeviceContext>(), *d_out, d_x,
63+
padded_length, 0, false, math::kBatchLengthWidth);
64+
}
11665
}
11766
};
11867

0 commit comments

Comments
 (0)