|
|
|
@ -16,34 +16,36 @@ limitations under the License. */
|
|
|
|
|
|
|
|
|
|
#include "paddle/framework/eigen.h"
|
|
|
|
|
#include "paddle/framework/lod_tensor.h"
|
|
|
|
|
#include "paddle/framework/tensor.h"
|
|
|
|
|
#include "paddle/operators/math/im2col.h"
|
|
|
|
|
|
|
|
|
|
namespace paddle {
|
|
|
|
|
namespace operators {
|
|
|
|
|
namespace math {
|
|
|
|
|
|
|
|
|
|
using Tensor = framework::Tensor;
|
|
|
|
|
using LoDTensor = framework::LoDTensor;
|
|
|
|
|
template <typename T, int MajorType = Eigen::RowMajor,
|
|
|
|
|
typename IndexType = Eigen::DenseIndex>
|
|
|
|
|
using EigenMatrix = framework::EigenMatrix<T, MajorType, IndexType>;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* \brief Context projection concatenate features in adjacent time steps in
|
|
|
|
|
* \brief Context projection concatenates features in adjacent time-steps in
|
|
|
|
|
* a sequence. The i-th row of the output is the concatenation of
|
|
|
|
|
* context_length rows of the input. The context_length rows are the
|
|
|
|
|
* consecutive rows from the i+shift_start row.
|
|
|
|
|
* ContextProjectGradFunctor is the inverse process of ContextProjectFunctor.
|
|
|
|
|
|
|
|
|
|
*
|
|
|
|
|
* \param in Input data.
|
|
|
|
|
* \param Shape The shape of Input data,
|
|
|
|
|
* [minibatch, input_hidden_size].
|
|
|
|
|
* \param Shape The shape of Input data:
|
|
|
|
|
* [mini-batch, input_hidden_size].
|
|
|
|
|
*
|
|
|
|
|
* \param padding_data Padding data.
|
|
|
|
|
* \param Shape The shape of Padding data,
|
|
|
|
|
* [up_pad + down_pad, input_hidden_size].
|
|
|
|
|
* \param Shape The shape of Padding data:
|
|
|
|
|
* [up_pad + down_pad, input_hidden_size].
|
|
|
|
|
*
|
|
|
|
|
* \param col Col data.
|
|
|
|
|
* \param Shape The shape of Col data,
|
|
|
|
|
* [minibatch, context_length * input_hidden_size].
|
|
|
|
|
* \param Shape The shape of Col data:
|
|
|
|
|
* [mini-batch, context_length * input_hidden_size].
|
|
|
|
|
*
|
|
|
|
|
* For a mini-batch of 2 variable lengths sentences, containing 3, and 1
|
|
|
|
|
* time-steps:
|
|
|
|
@ -61,40 +63,37 @@ using EigenMatrix = framework::EigenMatrix<T, MajorType, IndexType>;
|
|
|
|
|
* representation is 2.
|
|
|
|
|
*
|
|
|
|
|
* - Case1:
|
|
|
|
|
* If context_start is -1 and padding_trainable is false, we use zero to pad
|
|
|
|
|
* instead of learned weight to pad,
|
|
|
|
|
* and the context_lenth is 3, the output (Out) is:
|
|
|
|
|
* If context_start is -1 and padding_trainable is false, we use zero to pad
|
|
|
|
|
* instead of learned weight to pad,
|
|
|
|
|
* and the context_length is 3, the output (Out) is:
|
|
|
|
|
*
|
|
|
|
|
* Out =[[0, 0, a1, a2, b1, b2;
|
|
|
|
|
* a1, a2, b1, b2, c1, c2;
|
|
|
|
|
* b1, b2, c1, c2, 0, 0 ]
|
|
|
|
|
* [0, 0, d1, d2, 0, 0 ]]
|
|
|
|
|
* Out =[[0, 0, a1, a2, b1, b2;
|
|
|
|
|
* a1, a2, b1, b2, c1, c2;
|
|
|
|
|
* b1, b2, c1, c2, 0, 0 ]
|
|
|
|
|
* [0, 0, d1, d2, 0, 0 ]]
|
|
|
|
|
*
|
|
|
|
|
* - Case2:
|
|
|
|
|
* If context_start is -1 and padding_trainable is true, we use learned weight
|
|
|
|
|
* to pad,
|
|
|
|
|
* and the context_lenth is 3, the output (Out) is:
|
|
|
|
|
* If context_start is -1 and padding_trainable is true, we use learned weight
|
|
|
|
|
* to pad,
|
|
|
|
|
* and the context_length is 3, the output (Out) is:
|
|
|
|
|
*
|
|
|
|
|
* Out = [[w1, w2, a1, a2, b1, b2;
|
|
|
|
|
* a1, a2, b1, b2, c1, c2;
|
|
|
|
|
* b1, b2, c1, c2, w3, w4]
|
|
|
|
|
* [w1, w2, d1, d2, w3, w4]]
|
|
|
|
|
* Out = [[w1, w2, a1, a2, b1, b2;
|
|
|
|
|
* a1, a2, b1, b2, c1, c2;
|
|
|
|
|
* b1, b2, c1, c2, w3, w4]
|
|
|
|
|
* [w1, w2, d1, d2, w3, w4]]
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
template <typename Place, typename T>
|
|
|
|
|
class ContextProjectFunctor {
|
|
|
|
|
public:
|
|
|
|
|
void operator()(const platform::DeviceContext& context,
|
|
|
|
|
const framework::LoDTensor& in,
|
|
|
|
|
const framework::Tensor& padding_data, framework::Tensor& col,
|
|
|
|
|
void operator()(const platform::DeviceContext& context, const LoDTensor& in,
|
|
|
|
|
const Tensor& padding_data, Tensor& col,
|
|
|
|
|
bool padding_trainable, int context_start, int context_length,
|
|
|
|
|
int context_stride, int up_pad, int down_pad) {
|
|
|
|
|
auto lod_level_0 = in.lod()[0];
|
|
|
|
|
|
|
|
|
|
paddle::operators::math::Im2ColFunctor<
|
|
|
|
|
paddle::operators::math::ColFormat::kOCF, Place, float>
|
|
|
|
|
im2col_ocf;
|
|
|
|
|
math::Im2ColFunctor<math::ColFormat::kOCF, Place, float> im2col_ocf;
|
|
|
|
|
|
|
|
|
|
int input_row_begin, input_row_end;
|
|
|
|
|
int sequence_height, sequence_width;
|
|
|
|
@ -106,19 +105,18 @@ class ContextProjectFunctor {
|
|
|
|
|
: static_cast<int>(lod_level_0[i]);
|
|
|
|
|
input_row_end = static_cast<int>(lod_level_0[i + 1]);
|
|
|
|
|
|
|
|
|
|
framework::Tensor out_t = col.Slice(static_cast<int>(lod_level_0[i]),
|
|
|
|
|
static_cast<int>(lod_level_0[i + 1]));
|
|
|
|
|
Tensor out_t = col.Slice(static_cast<int>(lod_level_0[i]),
|
|
|
|
|
static_cast<int>(lod_level_0[i + 1]));
|
|
|
|
|
|
|
|
|
|
sequence_height = static_cast<int>(out_t.dims()[0]);
|
|
|
|
|
|
|
|
|
|
if (input_row_begin < input_row_end) {
|
|
|
|
|
framework::Tensor in_t = in.Slice(input_row_begin, input_row_end);
|
|
|
|
|
Tensor in_t = in.Slice(input_row_begin, input_row_end);
|
|
|
|
|
|
|
|
|
|
std::vector<int64_t> output_shape(
|
|
|
|
|
{sequence_height, 1, 1, context_length,
|
|
|
|
|
sequence_width}); // output_height, output_width,
|
|
|
|
|
// input_channels, filter_height, filter_width
|
|
|
|
|
|
|
|
|
|
out_t.Resize(framework::make_ddim(output_shape));
|
|
|
|
|
|
|
|
|
|
std::vector<int64_t> input_shape(
|
|
|
|
@ -134,9 +132,8 @@ class ContextProjectFunctor {
|
|
|
|
|
}
|
|
|
|
|
if (padding_trainable) {
|
|
|
|
|
for (int i = 0; i < static_cast<int>(lod_level_0.size()) - 1; ++i) {
|
|
|
|
|
framework::Tensor out_t =
|
|
|
|
|
col.Slice(static_cast<int>(lod_level_0[i]),
|
|
|
|
|
static_cast<int>(lod_level_0[i + 1]));
|
|
|
|
|
Tensor out_t = col.Slice(static_cast<int>(lod_level_0[i]),
|
|
|
|
|
static_cast<int>(lod_level_0[i + 1]));
|
|
|
|
|
|
|
|
|
|
sequence_height = static_cast<int>(out_t.dims()[0]);
|
|
|
|
|
|
|
|
|
@ -150,10 +147,9 @@ class ContextProjectFunctor {
|
|
|
|
|
for (int k = 0; k < padding_rows; ++k) {
|
|
|
|
|
int padding_size =
|
|
|
|
|
k + context_length < up_pad ? context_length : up_pad - k;
|
|
|
|
|
framework::Tensor out_t_sub = out_t.Slice(
|
|
|
|
|
k * context_length, k * context_length + padding_size);
|
|
|
|
|
framework::Tensor w_sub = padding_data.Slice(k, k + padding_size);
|
|
|
|
|
// in this block, using EigenVector<T>::Flatten is ok too.
|
|
|
|
|
Tensor out_t_sub = out_t.Slice(k * context_length,
|
|
|
|
|
k * context_length + padding_size);
|
|
|
|
|
Tensor w_sub = padding_data.Slice(k, k + padding_size);
|
|
|
|
|
auto out_t_sub_e = EigenMatrix<T>::From(out_t_sub);
|
|
|
|
|
auto w_sub_e = EigenMatrix<T>::From(w_sub);
|
|
|
|
|
out_t_sub_e.device(*context.GetEigenDevice<Place>()) = w_sub_e;
|
|
|
|
@ -180,10 +176,11 @@ class ContextProjectFunctor {
|
|
|
|
|
}
|
|
|
|
|
if (padding_begin > 0 || sequence_height == context_start)
|
|
|
|
|
padding_idx = padding_begin + t;
|
|
|
|
|
framework::Tensor out_t_sub = out_t.Slice(
|
|
|
|
|
|
|
|
|
|
Tensor out_t_sub = out_t.Slice(
|
|
|
|
|
(down_pad_begin_row + t) * context_length - padding_size,
|
|
|
|
|
(down_pad_begin_row + t) * context_length);
|
|
|
|
|
framework::Tensor w_sub = padding_data.Slice(
|
|
|
|
|
Tensor w_sub = padding_data.Slice(
|
|
|
|
|
up_pad + padding_idx, up_pad + padding_idx + padding_size);
|
|
|
|
|
auto out_t_sub_e = EigenMatrix<T>::From(out_t_sub);
|
|
|
|
|
auto w_sub_e = EigenMatrix<T>::From(w_sub);
|
|
|
|
@ -199,16 +196,13 @@ class ContextProjectFunctor {
|
|
|
|
|
template <typename Place, typename T>
|
|
|
|
|
class ContextProjectGradFunctor {
|
|
|
|
|
public:
|
|
|
|
|
void operator()(const platform::DeviceContext& context,
|
|
|
|
|
framework::LoDTensor& in, framework::Tensor& padding_data,
|
|
|
|
|
framework::Tensor& col, bool padding_trainable,
|
|
|
|
|
void operator()(const platform::DeviceContext& context, LoDTensor& in,
|
|
|
|
|
Tensor& padding_data, Tensor& col, bool padding_trainable,
|
|
|
|
|
int context_start, int context_length, int context_stride,
|
|
|
|
|
int up_pad, int down_pad, bool input_grad, bool pad_grad) {
|
|
|
|
|
auto lod_level_0 = in.lod()[0];
|
|
|
|
|
|
|
|
|
|
paddle::operators::math::Col2ImFunctor<
|
|
|
|
|
paddle::operators::math::ColFormat::kOCF, Place, float>
|
|
|
|
|
col2im_ocf;
|
|
|
|
|
math::Col2ImFunctor<math::ColFormat::kOCF, Place, float> col2im_ocf;
|
|
|
|
|
|
|
|
|
|
int input_row_begin, input_row_end;
|
|
|
|
|
int sequence_height, sequence_width;
|
|
|
|
@ -221,20 +215,18 @@ class ContextProjectGradFunctor {
|
|
|
|
|
: static_cast<int>(lod_level_0[i]);
|
|
|
|
|
input_row_end = static_cast<int>(lod_level_0[i + 1]);
|
|
|
|
|
|
|
|
|
|
framework::Tensor out_t =
|
|
|
|
|
col.Slice(static_cast<int>(lod_level_0[i]),
|
|
|
|
|
static_cast<int>(lod_level_0[i + 1]));
|
|
|
|
|
Tensor out_t = col.Slice(static_cast<int>(lod_level_0[i]),
|
|
|
|
|
static_cast<int>(lod_level_0[i + 1]));
|
|
|
|
|
|
|
|
|
|
sequence_height = static_cast<int>(out_t.dims()[0]);
|
|
|
|
|
|
|
|
|
|
if (input_row_begin < input_row_end) {
|
|
|
|
|
framework::Tensor in_t = in.Slice(input_row_begin, input_row_end);
|
|
|
|
|
Tensor in_t = in.Slice(input_row_begin, input_row_end);
|
|
|
|
|
|
|
|
|
|
std::vector<int64_t> output_shape(
|
|
|
|
|
{sequence_height, 1, 1, context_length,
|
|
|
|
|
sequence_width}); // output_height, output_width,
|
|
|
|
|
// input_channels, filter_height, filter_width
|
|
|
|
|
|
|
|
|
|
out_t.Resize(framework::make_ddim(output_shape));
|
|
|
|
|
|
|
|
|
|
std::vector<int64_t> input_shape(
|
|
|
|
@ -252,9 +244,8 @@ class ContextProjectGradFunctor {
|
|
|
|
|
if (pad_grad) {
|
|
|
|
|
if (padding_trainable) {
|
|
|
|
|
for (int i = 0; i < static_cast<int>(lod_level_0.size()) - 1; ++i) {
|
|
|
|
|
framework::Tensor out_t =
|
|
|
|
|
col.Slice(static_cast<int>(lod_level_0[i]),
|
|
|
|
|
static_cast<int>(lod_level_0[i + 1]));
|
|
|
|
|
Tensor out_t = col.Slice(static_cast<int>(lod_level_0[i]),
|
|
|
|
|
static_cast<int>(lod_level_0[i + 1]));
|
|
|
|
|
|
|
|
|
|
sequence_height = static_cast<int>(out_t.dims()[0]);
|
|
|
|
|
out_t.Resize({sequence_height * context_length, sequence_width});
|
|
|
|
@ -266,10 +257,9 @@ class ContextProjectGradFunctor {
|
|
|
|
|
for (int k = 0; k < padding_rows; ++k) {
|
|
|
|
|
int padding_size =
|
|
|
|
|
k + context_length < up_pad ? context_length : up_pad - k;
|
|
|
|
|
framework::Tensor out_t_sub = out_t.Slice(
|
|
|
|
|
k * context_length, k * context_length + padding_size);
|
|
|
|
|
framework::Tensor w_sub = padding_data.Slice(k, k + padding_size);
|
|
|
|
|
// in this block, using EigenVector<T>::Flatten is ok too.
|
|
|
|
|
Tensor out_t_sub = out_t.Slice(k * context_length,
|
|
|
|
|
k * context_length + padding_size);
|
|
|
|
|
Tensor w_sub = padding_data.Slice(k, k + padding_size);
|
|
|
|
|
auto out_t_sub_e = EigenMatrix<T>::From(out_t_sub);
|
|
|
|
|
auto w_sub_e = EigenMatrix<T>::From(w_sub);
|
|
|
|
|
w_sub_e.device(*context.GetEigenDevice<Place>()) =
|
|
|
|
@ -298,10 +288,11 @@ class ContextProjectGradFunctor {
|
|
|
|
|
}
|
|
|
|
|
if (padding_begin > 0 || sequence_height == context_start)
|
|
|
|
|
padding_idx = padding_begin + t;
|
|
|
|
|
framework::Tensor out_t_sub = out_t.Slice(
|
|
|
|
|
|
|
|
|
|
Tensor out_t_sub = out_t.Slice(
|
|
|
|
|
(down_pad_begin_row + t) * context_length - padding_size,
|
|
|
|
|
(down_pad_begin_row + t) * context_length);
|
|
|
|
|
framework::Tensor w_sub = padding_data.Slice(
|
|
|
|
|
Tensor w_sub = padding_data.Slice(
|
|
|
|
|
up_pad + padding_idx, up_pad + padding_idx + padding_size);
|
|
|
|
|
auto out_t_sub_e = EigenMatrix<T>::From(out_t_sub);
|
|
|
|
|
auto w_sub_e = EigenMatrix<T>::From(w_sub);
|
|
|
|
|