Skip to content

Commit a656801

Browse files
authored
Merge pull request #13122 from JiayiFeng/cherrypick_seq_pad
Cherrypick seq pad
2 parents ec2aed2 + 2315dae commit a656801

File tree

12 files changed

+743
-271
lines changed

12 files changed

+743
-271
lines changed

paddle/fluid/API.spec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ paddle.fluid.layers.beam_search_decode ArgSpec(args=['ids', 'scores', 'beam_size
114114
paddle.fluid.layers.conv2d_transpose ArgSpec(args=['input', 'num_filters', 'output_size', 'filter_size', 'padding', 'stride', 'dilation', 'groups', 'param_attr', 'bias_attr', 'use_cudnn', 'act', 'name'], varargs=None, keywords=None, defaults=(None, None, 0, 1, 1, None, None, None, True, None, None))
115115
paddle.fluid.layers.conv3d_transpose ArgSpec(args=['input', 'num_filters', 'output_size', 'filter_size', 'padding', 'stride', 'dilation', 'groups', 'param_attr', 'bias_attr', 'use_cudnn', 'act', 'name'], varargs=None, keywords=None, defaults=(None, None, 0, 1, 1, None, None, None, True, None, None))
116116
paddle.fluid.layers.sequence_expand ArgSpec(args=['x', 'y', 'ref_level', 'name'], varargs=None, keywords=None, defaults=(-1, None))
117+
paddle.fluid.layers.sequence_pad ArgSpec(args=['x', 'pad_value', 'maxlen'], varargs=None, keywords=None, defaults=(None,))
117118
paddle.fluid.layers.lstm_unit ArgSpec(args=['x_t', 'hidden_t_prev', 'cell_t_prev', 'forget_bias', 'param_attr', 'bias_attr', 'name'], varargs=None, keywords=None, defaults=(0.0, None, None, None))
118119
paddle.fluid.layers.reduce_sum ArgSpec(args=['input', 'dim', 'keep_dim', 'name'], varargs=None, keywords=None, defaults=(None, False, None))
119120
paddle.fluid.layers.reduce_mean ArgSpec(args=['input', 'dim', 'keep_dim', 'name'], varargs=None, keywords=None, defaults=(None, False, None))

paddle/fluid/operators/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ op_library(unsqueeze_op DEPS reshape_op)
282282
op_library(squeeze_op DEPS reshape_op)
283283
op_library(extract_rows_op DEPS memory)
284284
op_library(flatten_op DEPS reshape_op)
285+
op_library(sequence_pad_op DEPS sequence_padding)
285286

286287
if (WITH_GPU)
287288
op_library(conv_op DEPS vol2col depthwise_conv im2col)

paddle/fluid/operators/math/sequence_padding.cc

Lines changed: 97 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -18,128 +18,122 @@ namespace paddle {
1818
namespace operators {
1919
namespace math {
2020

21+
template <typename T>
22+
void CopyValidData(framework::Tensor* dst_tensor,
23+
const framework::Tensor* src_tensor,
24+
const framework::Vector<size_t>& seq_offsets,
25+
int pad_seq_len, int step_width, bool norm_by_len,
26+
CopyType type, PadLayout layout) {
27+
int seq_num = seq_offsets.size() - 1;
28+
const T* src_data = src_tensor->data<T>();
29+
T* dst_data = dst_tensor->data<T>();
30+
31+
int seq_cpy_gap = step_width;
32+
int pad_cpy_gap =
33+
layout == kBatchLengthWidth ? step_width : seq_num * step_width;
34+
for (int seq_idx = 0; seq_idx < seq_num; ++seq_idx) {
35+
int valid_seq_len = seq_offsets[seq_idx + 1] - seq_offsets[seq_idx];
36+
PADDLE_ENFORCE_GE(
37+
pad_seq_len, valid_seq_len,
38+
"The padded sequence length can not be less than its original length.");
39+
int seq_data_offset = seq_offsets[seq_idx] * step_width;
40+
int pad_data_offset = layout == kBatchLengthWidth
41+
? seq_idx * pad_seq_len * step_width
42+
: seq_idx * step_width;
43+
float scale = 1.0f / static_cast<float>(valid_seq_len);
44+
45+
for (int step_idx = 0; step_idx < valid_seq_len; ++step_idx) {
46+
const T* src =
47+
src_data + (type == kSeqToPad ? seq_data_offset : pad_data_offset);
48+
T* dst =
49+
dst_data + (type == kSeqToPad ? pad_data_offset : seq_data_offset);
50+
memcpy(dst, src, step_width * sizeof(T));
51+
if (norm_by_len) {
52+
for (int i = 0; i < step_width; ++i) {
53+
*(dst + i) *= scale;
54+
}
55+
}
56+
seq_data_offset += seq_cpy_gap;
57+
pad_data_offset += pad_cpy_gap;
58+
}
59+
}
60+
}
61+
2162
template <typename T>
2263
class PaddingLoDTensorFunctor<platform::CPUDeviceContext, T> {
2364
public:
2465
void operator()(const platform::CPUDeviceContext& context,
25-
const framework::LoDTensor& seq, framework::Tensor* padding,
26-
bool norm_by_times) {
27-
auto lod = seq.lod();
28-
PADDLE_ENFORCE_GT(lod.size(), 0UL,
29-
"The LoD of LoDTensor seq should not be null.");
30-
31-
const size_t level = 0;
32-
framework::LoD abs_offset_lod = framework::ToAbsOffset(lod);
33-
34-
auto seq_dims = seq.dims();
35-
PADDLE_ENFORCE_EQ(seq_dims[0],
36-
static_cast<int64_t>(abs_offset_lod[level].back()),
37-
"The first dimension of LoDTensor seq should be "
38-
"equal to the sum of all sequences's length.");
39-
40-
auto padding_dims = padding->dims();
41-
PADDLE_ENFORCE_EQ(padding_dims.size(), 3UL,
42-
"The input padding should be a 3-D Tensor of shape "
43-
"[max_sequence_length, num_sequences, sequence_width].");
44-
45-
const int64_t max_sequence_length = MaximumSequenceLength(lod, level);
46-
PADDLE_ENFORCE_EQ(padding_dims[0], max_sequence_length,
47-
"The first dimension of Tensor padding should be the "
48-
"maximum length of all sequences in LoDTensor seq.");
49-
50-
const int64_t num_sequences = abs_offset_lod[level].size() - 1;
51-
PADDLE_ENFORCE_EQ(padding_dims[1], num_sequences,
52-
"The second dimension of Tensor padding should be the "
53-
"number of sequences in LoDTensor seq.");
54-
55-
const int64_t sequence_width = seq.numel() / seq_dims[0];
56-
PADDLE_ENFORCE_EQ(padding_dims[2], sequence_width,
57-
"The third dimension of Tensor padding should be the "
58-
"width of sequence in LoDTensor seq.");
59-
60-
const T* seq_data = seq.data<T>();
61-
T* padding_data = padding->data<T>();
62-
for (int64_t i = 0; i < max_sequence_length; ++i) {
63-
for (int64_t j = 0; j < num_sequences; ++j) {
64-
int64_t start_pos = abs_offset_lod[level][j];
65-
int64_t sequence_length = abs_offset_lod[level][j + 1] - start_pos;
66-
if (i < sequence_length) {
67-
// i > 0 => sequence_length > 0
68-
T scale =
69-
norm_by_times ? (1.0f / static_cast<T>(sequence_length)) : 1.0f;
70-
for (int64_t k = 0; k < sequence_width; ++k) {
71-
padding_data[(i * num_sequences + j) * sequence_width + k] =
72-
seq_data[(start_pos + i) * sequence_width + k] * scale;
73-
}
74-
} else {
75-
memset(padding_data + (i * num_sequences + j) * sequence_width, 0,
76-
sequence_width * sizeof(T));
77-
}
66+
const framework::LoDTensor& seq_tensor,
67+
framework::LoDTensor* pad_tensor,
68+
const framework::LoDTensor& pad_value, int pad_seq_len = -1,
69+
int lod_level = 0, bool norm_by_times = false,
70+
const PadLayout layout = kBatchLengthWidth) {
71+
auto seq_lod = seq_tensor.lod();
72+
const auto seq_offsets = framework::ToAbsOffset(seq_lod)[lod_level];
73+
const auto& seq_tensor_dims = seq_tensor.dims();
74+
const auto& pad_tensor_dims = pad_tensor->dims();
75+
if (pad_seq_len == -1) {
76+
pad_seq_len = MaximumSequenceLength(seq_offsets);
77+
}
78+
int step_width = seq_tensor.numel() / seq_tensor_dims[0];
79+
80+
CheckDims(seq_tensor_dims, pad_tensor_dims, seq_offsets, pad_seq_len,
81+
step_width, layout);
82+
PADDLE_ENFORCE(pad_value.numel() == 1 || pad_value.numel() == step_width,
83+
"The numel of 'pad_value' can only be 1 or be equal to the "
84+
"'step_width'.");
85+
86+
// fill padding value
87+
T* pad_data = pad_tensor->data<T>();
88+
const T* pad_value_data = pad_value.data<T>();
89+
if (pad_value.numel() == 1) {
90+
for (int i = 0; i < pad_tensor->numel(); ++i) {
91+
pad_data[i] = *pad_value_data;
92+
}
93+
} else {
94+
for (int i = 0; i < pad_tensor->numel(); i += step_width) {
95+
memcpy(pad_data + i, pad_value_data, step_width * sizeof(T));
7896
}
7997
}
98+
99+
CopyValidData<T>(pad_tensor, &seq_tensor, seq_offsets, pad_seq_len,
100+
step_width, norm_by_times, kSeqToPad, layout);
80101
}
81102
};
82103

83104
template <typename T>
84105
class UnpaddingLoDTensorFunctor<platform::CPUDeviceContext, T> {
85106
public:
86107
void operator()(const platform::CPUDeviceContext& context,
87-
framework::LoDTensor* seq, const framework::Tensor& padding,
88-
bool norm_by_times) {
89-
auto lod = seq->lod();
90-
PADDLE_ENFORCE_GT(lod.size(), 0UL,
91-
"The LoD of LoDTensor seq should not be null.");
92-
93-
const size_t level = 0;
94-
framework::LoD abs_offset_lod = framework::ToAbsOffset(lod);
95-
96-
auto seq_dims = seq->dims();
97-
PADDLE_ENFORCE_EQ(seq_dims[0],
98-
static_cast<int64_t>(abs_offset_lod[level].back()),
99-
"The first dimension of LoDTensor seq should be "
100-
"equal to the sum of all sequences's length.");
101-
102-
auto padding_dims = padding.dims();
103-
PADDLE_ENFORCE_EQ(padding_dims.size(), 3UL,
104-
"The input padding should be a 3-D Tensor of shape "
105-
"[max_sequnece_length, num_sequences, sequence_width].");
106-
107-
const int64_t max_sequence_length = MaximumSequenceLength(lod, level);
108-
PADDLE_ENFORCE_EQ(padding_dims[0], max_sequence_length,
109-
"The first dimension of Tensor padding should be "
110-
"the maximum length of all sequences in LoDTensor seq.");
111-
112-
const int64_t num_sequences = abs_offset_lod[level].size() - 1;
113-
PADDLE_ENFORCE_EQ(padding_dims[1], num_sequences,
114-
"The second dimension of Tensor padding should be "
115-
"the number of sequences in LoDTensor seq.");
116-
117-
const int64_t sequence_width = seq->numel() / seq_dims[0];
118-
PADDLE_ENFORCE_EQ(padding_dims[2], sequence_width,
119-
"The third dimension of Tensor padding should be the "
120-
"width of sequence in LoDTensor seq.");
121-
122-
const T* padding_data = padding.data<T>();
123-
T* seq_data = seq->data<T>();
124-
for (int64_t i = 0; i < num_sequences; ++i) {
125-
int64_t start_pos = abs_offset_lod[level][i];
126-
int64_t sequence_length = abs_offset_lod[level][i + 1] - start_pos;
127-
for (int64_t j = 0; j < sequence_length; ++j) {
128-
// sequence_width > j > 0
129-
T scale =
130-
norm_by_times ? (1.0f / static_cast<T>(sequence_length)) : 1.0f;
131-
for (int64_t k = 0; k < sequence_width; ++k) {
132-
seq_data[(start_pos + j) * sequence_width + k] =
133-
padding_data[(j * num_sequences + i) * sequence_width + k] *
134-
scale;
135-
}
136-
}
108+
const framework::LoDTensor& pad_tensor,
109+
framework::LoDTensor* seq_tensor, int pad_seq_len = -1,
110+
int lod_level = 0, bool norm_by_times = false,
111+
const PadLayout layout = kBatchLengthWidth) {
112+
auto seq_offsets = framework::ToAbsOffset(seq_tensor->lod())[lod_level];
113+
const auto& seq_tensor_dims = seq_tensor->dims();
114+
const auto& pad_tensor_dims = pad_tensor.dims();
115+
if (pad_seq_len == -1) {
116+
pad_seq_len = MaximumSequenceLength(seq_offsets);
137117
}
118+
int step_width = seq_tensor->numel() / seq_tensor_dims[0];
119+
120+
CheckDims(seq_tensor_dims, pad_tensor_dims, seq_offsets, pad_seq_len,
121+
step_width, layout);
122+
123+
CopyValidData<T>(seq_tensor, &pad_tensor, seq_offsets, pad_seq_len,
124+
step_width, norm_by_times, kPadToSeq, layout);
138125
}
139126
};
140127

128+
template class PaddingLoDTensorFunctor<platform::CPUDeviceContext, int>;
129+
template class PaddingLoDTensorFunctor<platform::CPUDeviceContext, int64_t>;
141130
template class PaddingLoDTensorFunctor<platform::CPUDeviceContext, float>;
131+
template class PaddingLoDTensorFunctor<platform::CPUDeviceContext, double>;
132+
133+
template class UnpaddingLoDTensorFunctor<platform::CPUDeviceContext, int>;
134+
template class UnpaddingLoDTensorFunctor<platform::CPUDeviceContext, int64_t>;
142135
template class UnpaddingLoDTensorFunctor<platform::CPUDeviceContext, float>;
136+
template class UnpaddingLoDTensorFunctor<platform::CPUDeviceContext, double>;
143137

144138
} // namespace math
145139
} // namespace operators

0 commit comments

Comments
 (0)