Skip to content

Commit 8e3ecf5

Browse files
author
chengduo
authored
Merge pull request #4814 from chengduoZH/Add_sequence_project_op
Add sequence_conv_op and sequence_projection functor
2 parents 9d142d5 + 99c6f44 commit 8e3ecf5

File tree

9 files changed

+858
-0
lines changed

9 files changed

+858
-0
lines changed

paddle/operators/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ set(DEPS_OPS
123123
sum_op
124124
pool_op
125125
pool_with_index_op
126+
sequence_conv_op
126127
lstm_op)
127128

128129

@@ -134,6 +135,7 @@ op_library(softmax_with_cross_entropy_op DEPS cross_entropy softmax)
134135
op_library(sum_op DEPS net_op)
135136
op_library(pool_op DEPS pooling)
136137
op_library(pool_with_index_op DEPS pooling)
138+
op_library(sequence_conv_op DEPS context_project)
137139
op_library(lstm_op DEPS sequence2batch lstm_compute)
138140

139141
list(REMOVE_ITEM GENERAL_OPS ${DEPS_OPS})

paddle/operators/math/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ if(WITH_GPU)
99
nv_library(cross_entropy SRCS cross_entropy.cc cross_entropy.cu DEPS operator)
1010
nv_library(pooling SRCS pooling.cc pooling.cu DEPS device_context)
1111
nv_library(vol2col SRCS vol2col.cc vol2col.cu DEPS device_context)
12+
nv_library(context_project SRCS context_project.cc context_project.cu DEPS device_context)
1213
nv_library(sequence2batch SRCS sequence2batch.cc sequence2batch.cu DEPS device_context)
1314
nv_library(lstm_compute SRCS lstm_compute.cc lstm_compute.cu DEPS device_context activation_functions)
1415
else()
@@ -18,6 +19,7 @@ else()
1819
cc_library(cross_entropy SRCS cross_entropy.cc DEPS operator)
1920
cc_library(pooling SRCS pooling.cc DEPS device_context)
2021
cc_library(vol2col SRCS vol2col.cc DEPS device_context)
22+
cc_library(context_project SRCS context_project.cc DEPS device_context)
2123
cc_library(sequence2batch SRCS sequence2batch.cc DEPS device_context)
2224
cc_library(lstm_compute SRCS lstm_compute.cc DEPS device_context activation_functions)
2325
endif()
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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/math/context_project.h"
16+
17+
namespace paddle {
18+
namespace operators {
19+
namespace math {
20+
21+
template class ContextProjectFunctor<platform::CPUPlace, float>;
22+
template class ContextProjectFunctor<platform::CPUPlace, double>;
23+
24+
} // namespace math
25+
} // namespace operators
26+
} // namespace paddle
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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+
17+
#include "paddle/operators/math/context_project.h"
18+
19+
namespace paddle {
20+
namespace operators {
21+
namespace math {
22+
23+
template class ContextProjectFunctor<platform::GPUPlace, float>;
24+
template class ContextProjectFunctor<platform::GPUPlace, double>;
25+
26+
} // namespace math
27+
} // namespace operators
28+
} // namespace paddle
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
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+
#pragma once
16+
17+
#include "paddle/framework/eigen.h"
18+
#include "paddle/framework/lod_tensor.h"
19+
#include "paddle/framework/tensor.h"
20+
#include "paddle/operators/math/im2col.h"
21+
22+
namespace paddle {
23+
namespace operators {
24+
namespace math {
25+
26+
template <typename T, int MajorType = Eigen::RowMajor,
27+
typename IndexType = Eigen::DenseIndex>
28+
using EigenMatrix = framework::EigenMatrix<T, MajorType, IndexType>;
29+
/*
30+
* \brief Context projection concatenate features in adjacent time steps in
31+
* a sequence. The i-th row of the output is the concatenation of
32+
* context_length rows of the input. The context_length rows are the
33+
* consecutive rows from the i+shift_start row.
34+
35+
* \param in Input data.
36+
* \param Shape The shape of Input data,
37+
* [minibatch, number_of_input_features].
38+
* \param type A float LoDTensor.
39+
*
40+
* \param padding_data Padding data.
41+
* \param Shape The shape of Padding data,
42+
* [up_pad + down_pad, number_of_input_features].
43+
* \param type A float Tensor.
44+
*
45+
* \param col Col data.
46+
* \param Shape The shape of Col data,
47+
* [minibatch, context_length * number_of_input_features].
48+
* \param type A float Tensor.
49+
*
50+
* For a mini-batch of 2 variable lengths sentences, containing 3, and 1
51+
* time-steps:
52+
*
53+
* Assumed input (X) is a [4, M, N] float LoDTensor, and X->lod()[0] = [0, 3,
54+
* 4].
55+
* Besides, for the sake of simplicity, we assume M=1 and N=2.
56+
*
57+
* X = [[a1, a2;
58+
* b1, b2;
59+
* c1, c2]
60+
* [d1, d2]]
61+
*
62+
* This is to say that input (X) has 4 words and the dimension of each word
63+
* representation is 2.
64+
*
65+
* - Case1:
66+
* If context_start is -1 and padding_trainable is false, we use zero to pad
67+
* instead of learned weight to pad,
68+
* and the context_lenth is 3, the output (Out) is:
69+
*
70+
* Out =[[0, 0, a1, a2, b1, b2;
71+
* a1, a2, b1, b2, c1, c2;
72+
* b1, b2, c1, c2, 0, 0 ]
73+
* [0, 0, d1, d2, 0, 0 ]]
74+
*
75+
* - Case2:
76+
* If context_start is -1 and padding_trainable is true, we use learned weight
77+
* to pad,
78+
* and the context_lenth is 3, the output (Out) is:
79+
*
80+
* Out = [[w1, w2, a1, a2, b1, b2;
81+
* a1, a2, b1, b2, c1, c2;
82+
* b1, b2, c1, c2, w3, w4]
83+
* [w1, w2, d1, d2, w3, w4]]
84+
*
85+
*/
86+
87+
template <typename Place, typename T>
88+
class ContextProjectFunctor {
89+
public:
90+
void operator()(const platform::DeviceContext& context,
91+
framework::LoDTensor& in, framework::Tensor& padding_data,
92+
framework::Tensor& col, bool padding_trainable,
93+
int context_start, int context_length, int context_stride,
94+
int up_pad, int down_pad, bool gradient, bool input_grad,
95+
bool pad_grad) {
96+
auto lod_level_0 = in.lod()[0];
97+
98+
paddle::operators::math::Im2ColFunctor<
99+
paddle::operators::math::ColFormat::kOCF, Place, float>
100+
im2col_ocf;
101+
paddle::operators::math::Col2ImFunctor<
102+
paddle::operators::math::ColFormat::kOCF, Place, float>
103+
col2im_ocf;
104+
105+
int input_row_begin, input_row_end;
106+
int sequence_height, sequence_width;
107+
sequence_width = in.dims()[1];
108+
input_grad = gradient && input_grad;
109+
pad_grad = gradient && pad_grad;
110+
111+
if (!gradient || input_grad) {
112+
for (int i = 0; i < static_cast<int>(lod_level_0.size()) - 1; ++i) {
113+
input_row_begin = (context_start > 0)
114+
? static_cast<int>(lod_level_0[i]) + context_start
115+
: static_cast<int>(lod_level_0[i]);
116+
input_row_end = static_cast<int>(lod_level_0[i + 1]);
117+
118+
framework::Tensor out_t =
119+
col.Slice(static_cast<int>(lod_level_0[i]),
120+
static_cast<int>(lod_level_0[i + 1]));
121+
122+
sequence_height = static_cast<int>(out_t.dims()[0]);
123+
124+
if (input_row_begin < input_row_end) {
125+
framework::Tensor in_t = in.Slice(input_row_begin, input_row_end);
126+
127+
std::vector<int64_t> output_shape(
128+
{sequence_height, 1, 1, context_length,
129+
sequence_width}); // output_height, output_width,
130+
// input_channels, filter_height, filter_width
131+
132+
out_t.Resize(framework::make_ddim(output_shape));
133+
134+
std::vector<int64_t> input_shape(
135+
{1, input_row_end - input_row_begin,
136+
sequence_width}); // input_channels, input_height, input_width
137+
in_t.Resize(framework::make_ddim(input_shape));
138+
139+
if (gradient) {
140+
col2im_ocf(context, in_t, out_t,
141+
/*stride_height*/ context_stride, /*stride_width*/ 1,
142+
up_pad, down_pad, 0, 0);
143+
} else {
144+
im2col_ocf(context, in_t, out_t,
145+
/*stride_height*/ context_stride, /*stride_width*/ 1,
146+
up_pad, down_pad, 0, 0);
147+
}
148+
out_t.Resize({sequence_height, context_length * sequence_width});
149+
}
150+
}
151+
}
152+
if (!gradient || pad_grad) {
153+
if (padding_trainable) {
154+
for (int i = 0; i < static_cast<int>(lod_level_0.size()) - 1; ++i) {
155+
framework::Tensor out_t =
156+
col.Slice(static_cast<int>(lod_level_0[i]),
157+
static_cast<int>(lod_level_0[i + 1]));
158+
159+
sequence_height = static_cast<int>(out_t.dims()[0]);
160+
161+
// add up trainable data
162+
out_t.Resize({sequence_height * context_length, sequence_width});
163+
164+
if (up_pad > 0) { // add up pad
165+
int padding_rows = std::min(
166+
up_pad, static_cast<int>(lod_level_0[i + 1] - lod_level_0[i]));
167+
168+
for (int k = 0; k < padding_rows; ++k) {
169+
int padding_size =
170+
k + context_length < up_pad ? context_length : up_pad - k;
171+
framework::Tensor out_t_sub = out_t.Slice(
172+
k * context_length, k * context_length + padding_size);
173+
framework::Tensor w_sub = padding_data.Slice(k, k + padding_size);
174+
// in this block, using EigenVector<T>::Flatten is ok too.
175+
auto out_t_sub_e = EigenMatrix<T>::From(out_t_sub);
176+
auto w_sub_e = EigenMatrix<T>::From(w_sub);
177+
if (gradient) {
178+
w_sub_e.device(*context.GetEigenDevice<Place>()) =
179+
w_sub_e + out_t_sub_e;
180+
} else {
181+
out_t_sub_e.device(*context.GetEigenDevice<Place>()) = w_sub_e;
182+
}
183+
}
184+
}
185+
if (down_pad > 0) { // add down pad
186+
int down_pad_begin_row =
187+
std::max(
188+
0, (sequence_height - context_start - context_length) + 1) +
189+
1;
190+
int padding_begin = std::max(0, context_start - sequence_height);
191+
int padding_size =
192+
sequence_height - context_start >= context_length
193+
? 1
194+
: context_length - (sequence_height - context_start);
195+
if (context_start >= sequence_height) padding_size = context_length;
196+
int padding_idx = padding_begin;
197+
for (int t = 0; t + down_pad_begin_row <= sequence_height;
198+
++t, ++padding_size) {
199+
if (context_start >= sequence_height)
200+
padding_size = context_length;
201+
if (padding_size > context_length) {
202+
padding_size = context_length;
203+
padding_idx++;
204+
}
205+
if (padding_begin > 0 || sequence_height == context_start)
206+
padding_idx = padding_begin + t;
207+
framework::Tensor out_t_sub = out_t.Slice(
208+
(down_pad_begin_row + t) * context_length - padding_size,
209+
(down_pad_begin_row + t) * context_length);
210+
framework::Tensor w_sub = padding_data.Slice(
211+
up_pad + padding_idx, up_pad + padding_idx + padding_size);
212+
auto out_t_sub_e = EigenMatrix<T>::From(out_t_sub);
213+
auto w_sub_e = EigenMatrix<T>::From(w_sub);
214+
if (gradient) {
215+
w_sub_e.device(*context.GetEigenDevice<Place>()) =
216+
w_sub_e + out_t_sub_e;
217+
} else {
218+
out_t_sub_e.device(*context.GetEigenDevice<Place>()) = w_sub_e;
219+
}
220+
}
221+
}
222+
out_t.Resize({sequence_height, context_length * sequence_width});
223+
}
224+
}
225+
}
226+
}
227+
};
228+
229+
} // namespace math
230+
} // namespace operators
231+
} // namespace paddle

0 commit comments

Comments
 (0)