Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
Paddle
提交
f2ccef26
P
Paddle
项目概览
PaddlePaddle
/
Paddle
大约 1 年 前同步成功
通知
2298
Star
20931
Fork
5422
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
1423
列表
看板
标记
里程碑
合并请求
543
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
P
Paddle
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
1,423
Issue
1,423
列表
看板
标记
里程碑
合并请求
543
合并请求
543
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
f2ccef26
编写于
10月 23, 2017
作者:
C
chengduoZH
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add sequence_conv_op
上级
0ab2c436
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
158 addition
and
384 deletion
+158
-384
paddle/operators/CMakeLists.txt
paddle/operators/CMakeLists.txt
+4
-1
paddle/operators/sequence_conv_op.cc
paddle/operators/sequence_conv_op.cc
+54
-43
paddle/operators/sequence_conv_op.cu
paddle/operators/sequence_conv_op.cu
+4
-5
paddle/operators/sequence_conv_op.h
paddle/operators/sequence_conv_op.h
+96
-123
python/paddle/v2/framework/tests/test_seq_project.py
python/paddle/v2/framework/tests/test_seq_project.py
+0
-212
未找到文件。
paddle/operators/CMakeLists.txt
浏览文件 @
f2ccef26
...
...
@@ -115,7 +115,8 @@ set(DEPS_OPS
softmax_with_cross_entropy_op
sum_op
pool_op
pool_with_index_op
)
pool_with_index_op
sequence_conv_op
)
op_library
(
recurrent_op SRCS recurrent_op.cc rnn/recurrent_op_utils.cc
...
...
@@ -126,6 +127,8 @@ op_library(softmax_with_cross_entropy_op DEPS cross_entropy softmax)
op_library
(
sum_op DEPS net_op
)
op_library
(
pool_op DEPS pooling
)
op_library
(
pool_with_index_op DEPS pooling
)
op_library
(
sequence_conv_op DEPS sequence_project
)
list
(
REMOVE_ITEM GENERAL_OPS
${
DEPS_OPS
}
)
foreach
(
src
${
GENERAL_OPS
}
)
...
...
paddle/operators/sequence_
project
_op.cc
→
paddle/operators/sequence_
conv
_op.cc
浏览文件 @
f2ccef26
...
...
@@ -12,34 +12,41 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
#include "paddle/operators/sequence_
project
_op.h"
#include "paddle/operators/sequence_
conv
_op.h"
namespace
paddle
{
namespace
operators
{
class
Sequence
Project
Op
:
public
framework
::
OperatorWithKernel
{
class
Sequence
Conv
Op
:
public
framework
::
OperatorWithKernel
{
public:
using
framework
::
OperatorWithKernel
::
OperatorWithKernel
;
protected:
void
InferShape
(
framework
::
InferShapeContext
*
ctx
)
const
override
{
PADDLE_ENFORCE
(
ctx
->
HasInput
(
"X"
),
"Input(X) of SequenceProjectOp should not be null."
);
"Input(X) of SequenceConvOp should not be null."
);
PADDLE_ENFORCE
(
ctx
->
HasInput
(
"Filter"
),
"Input(Filter) of SequenceConvOp should not be null."
);
PADDLE_ENFORCE
(
ctx
->
HasOutput
(
"Out"
),
"Output(Out) of Sequence
Project
Op should not be null."
);
"Output(Out) of Sequence
Conv
Op should not be null."
);
// PaddingData mast be not empty. Otherwise(EnforceNotMet: enforce numel() >
// 0 failed, 0 <= 0)
PADDLE_ENFORCE
(
ctx
->
HasInput
(
"PaddingData"
),
"Input(PaddingData) of SequenceProjectOp should not be null."
);
auto
in_dims
=
ctx
->
GetInputDim
(
"X"
);
PADDLE_ENFORCE
(
in_dims
.
size
()
==
2
,
"Input(X) should be 2-D tensor."
);
PADDLE_ENFORCE
(
ctx
->
HasInput
(
"PaddingData"
),
"Input(PaddingData) of SequenceConvOp should not be null."
);
int
context_length
=
ctx
->
Attrs
().
Get
<
int
>
(
"context_length"
);
bool
padding_trainable
=
ctx
->
Attrs
().
Get
<
bool
>
(
"padding_trainable"
);
int
context_start
=
ctx
->
Attrs
().
Get
<
int
>
(
"context_start"
);
auto
in_dims
=
ctx
->
GetInputDim
(
"X"
);
auto
filter_dims
=
ctx
->
GetInputDim
(
"Filter"
);
PADDLE_ENFORCE
(
in_dims
.
size
()
==
2
&&
filter_dims
.
size
()
==
2
,
"Input(X, Filter) should be 2-D tensor."
);
PADDLE_ENFORCE
(
filter_dims
[
0
]
==
context_length
&&
filter_dims
[
1
]
==
in_dims
[
1
],
"Filter's shape should be (context_length x "
"number_of_input_features)."
);
if
(
padding_trainable
)
{
framework
::
DDim
padding_dim
=
ctx
->
GetInputDim
(
"PaddingData"
);
int
up_pad
=
std
::
max
(
0
,
-
context_start
);
...
...
@@ -60,12 +67,12 @@ class SequenceProjectOp : public framework::OperatorWithKernel {
"and 'context_length'."
);
}
in_dims
[
1
]
=
in_dims
[
1
]
*
context_length
;
in_dims
[
1
]
=
1
;
ctx
->
SetOutputDim
(
"Out"
,
in_dims
);
}
};
class
Sequence
Project
GradOp
:
public
framework
::
OperatorWithKernel
{
class
Sequence
Conv
GradOp
:
public
framework
::
OperatorWithKernel
{
public:
using
framework
::
OperatorWithKernel
::
OperatorWithKernel
;
...
...
@@ -77,60 +84,66 @@ class SequenceProjectGradOp : public framework::OperatorWithKernel {
if
(
ctx
->
Attrs
().
Get
<
bool
>
(
"padding_trainable"
)
&&
ctx
->
HasOutput
(
framework
::
GradVarName
(
"PaddingData"
)))
{
auto
padding_dims
=
ctx
->
GetInputDim
(
"PaddingData"
);
ctx
->
SetOutputDim
(
framework
::
GradVarName
(
"PaddingData"
),
padding_dims
);
ctx
->
SetOutputDim
(
framework
::
GradVarName
(
"PaddingData"
),
ctx
->
GetInputDim
(
"PaddingData"
)
);
}
if
(
ctx
->
HasOutput
(
framework
::
GradVarName
(
"X"
)))
{
ctx
->
SetOutputDim
(
framework
::
GradVarName
(
"X"
),
ctx
->
GetInputDim
(
"X"
));
}
if
(
ctx
->
HasOutput
(
framework
::
GradVarName
(
"Filter"
)))
{
ctx
->
SetOutputDim
(
framework
::
GradVarName
(
"Filter"
),
ctx
->
GetInputDim
(
"Filter"
));
}
}
};
class
Sequence
Project
OpMaker
:
public
framework
::
OpProtoAndCheckerMaker
{
class
Sequence
Conv
OpMaker
:
public
framework
::
OpProtoAndCheckerMaker
{
public:
Sequence
Project
OpMaker
(
framework
::
OpProto
*
proto
,
framework
::
OpAttrChecker
*
op_checker
)
Sequence
Conv
OpMaker
(
framework
::
OpProto
*
proto
,
framework
::
OpAttrChecker
*
op_checker
)
:
OpProtoAndCheckerMaker
(
proto
,
op_checker
)
{
AddInput
(
"X"
,
"(A float LoDTensor) the input of Sequence
Project
Op, a vector of "
"(A float LoDTensor) the input of Sequence
Conv
Op, a vector of "
"2-D matrix of size (minibatch, number_of_input_features)."
);
AddOutput
(
"Out"
,
"(A float LoDTensor) the output of SequenceProjectOp, a vector "
"of 2-D matrix of size (minibatch, number_of_input_features x "
"context_length)."
);
AddInput
(
"PaddingData"
,
"(A float LoDTensor) the input of Sequence
Project
Op, a vector of "
"(A float LoDTensor) the input of Sequence
Conv
Op, a vector of "
"2-D matrix of size (up_pad + down_pad, "
"number_of_input_features). "
);
AddInput
(
"Filter"
,
"(A float LoDTensor) the input of SequenceConvOp, a vector of "
"2-D matrix of size (context_length x number_of_input_features)."
);
AddOutput
(
"Out"
,
"(A float LoDTensor) the output of SequenceConvOp, a vector "
"of 2-D matrix of size (minibatch, 1)."
);
AddAttr
<
bool
>
(
"padding_trainable"
,
"(bool, default false) the padding data of Sequence
Project
Op "
"(bool, default false) the padding data of Sequence
Conv
Op "
"is trainable or not."
)
.
SetDefault
(
false
);
AddAttr
<
int
>
(
"context_length"
,
"(int, default 3) the context_length of Sequence
Project
Op."
)
"(int, default 3) the context_length of Sequence
Conv
Op."
)
.
SetDefault
(
3
)
.
GreaterThan
(
0
);
AddAttr
<
int
>
(
"context_start"
,
"(int, default 0) the context_start of Sequence
Project
Op."
)
"(int, default 0) the context_start of Sequence
Conv
Op."
)
.
SetDefault
(
0
);
AddAttr
<
int
>
(
"context_stride"
,
"(int, default 1) the context_stride of Sequence
Project
Op. "
"(int, default 1) the context_stride of Sequence
Conv
Op. "
"Currently, sequence_project_op only support "
"context_stride=1."
)
.
SetDefault
(
1
)
.
GreaterThan
(
0
);
AddComment
(
R"DOC(
Sequence
Project
Op projects features of context_length time-steps of each instance.
Sequence
Conv
Op projects features of context_length time-steps of each instance.
For a mini-batch of 2 variable lengths sentences, containing 3, and 1 time-steps:
Assumed input (X) is a [4, M, N] float LoDTensor, and X->lod()[0] = [0, 3, 4].
Besides, for the sake of simplicity, we assume M=1 and N=2.
X = [[a1, a2
,
b1, b2
.
X = [[a1, a2
;
b1, b2
;
c1, c2]
[d1, d2]]
...
...
@@ -141,19 +154,19 @@ class SequenceProjectOpMaker : public framework::OpProtoAndCheckerMaker {
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:
Out =
[0, 0, a1, a2, b1, b2;
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
]
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:
Out = [w1, w2, a1, a2, b1, b2;
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
]
b1, b2, c1, c2, w3, w4
]
[w1, w2, d1, d2, w3, w4]
]
)DOC"
);
}
...
...
@@ -163,13 +176,11 @@ class SequenceProjectOpMaker : public framework::OpProtoAndCheckerMaker {
}
// namespace paddle
namespace
ops
=
paddle
::
operators
;
REGISTER_OP
(
sequence_project
,
ops
::
SequenceProjectOp
,
ops
::
SequenceProjectOpMaker
,
sequence_project_grad
,
ops
::
SequenceProjectGradOp
);
REGISTER_OP
(
sequence_conv
,
ops
::
SequenceConvOp
,
ops
::
SequenceConvOpMaker
,
sequence_conv_grad
,
ops
::
SequenceConvGradOp
);
REGISTER_OP_CPU_KERNEL
(
sequence_project
,
ops
::
SequenceProjectKernel
<
paddle
::
platform
::
CPUPlace
,
float
>
);
sequence_conv
,
ops
::
SequenceConvKernel
<
paddle
::
platform
::
CPUPlace
,
float
>
);
REGISTER_OP_CPU_KERNEL
(
sequence_
project
_grad
,
ops
::
Sequence
Project
GradKernel
<
paddle
::
platform
::
CPUPlace
,
float
>
);
sequence_
conv
_grad
,
ops
::
Sequence
Conv
GradKernel
<
paddle
::
platform
::
CPUPlace
,
float
>
);
paddle/operators/sequence_
project
_op.cu
→
paddle/operators/sequence_
conv
_op.cu
浏览文件 @
f2ccef26
...
...
@@ -14,12 +14,11 @@
#define EIGEN_USE_GPU
#include "paddle/operators/sequence_
project
_op.h"
#include "paddle/operators/sequence_
conv
_op.h"
namespace
ops
=
paddle
::
operators
;
REGISTER_OP_GPU_KERNEL
(
sequence_project
,
ops
::
SequenceProjectKernel
<
paddle
::
platform
::
GPUPlace
,
float
>
);
sequence_conv
,
ops
::
SequenceConvKernel
<
paddle
::
platform
::
GPUPlace
,
float
>
);
REGISTER_OP_GPU_KERNEL
(
sequence_
project
_grad
,
ops
::
Sequence
Project
GradKernel
<
paddle
::
platform
::
GPUPlace
,
float
>
);
sequence_
conv
_grad
,
ops
::
Sequence
Conv
GradKernel
<
paddle
::
platform
::
GPUPlace
,
float
>
);
paddle/operators/sequence_
project
_op.h
→
paddle/operators/sequence_
conv
_op.h
浏览文件 @
f2ccef26
...
...
@@ -15,46 +15,39 @@ limitations under the License. */
#pragma once
#include "paddle/framework/eigen.h"
#include "paddle/framework/op_registry.h"
#include "paddle/operators/math/im2col.h"
#include "paddle/operators/math/math_function.h"
#include "paddle/operators/
strided_memcpy
.h"
#include "paddle/operators/
math/sequence_project
.h"
namespace
paddle
{
namespace
operators
{
using
Tensor
=
framework
::
Tensor
;
using
LoDTensor
=
framework
::
LoDTensor
;
template
<
typename
T
,
int
MajorType
=
Eigen
::
RowMajor
,
typename
IndexType
=
Eigen
::
DenseIndex
>
using
EigenVector
=
framework
::
EigenVector
<
T
,
MajorType
,
IndexType
>
;
//
template <typename T, int MajorType = Eigen::RowMajor,
//
typename IndexType = Eigen::DenseIndex>
//
using EigenVector = framework::EigenVector<T, MajorType, IndexType>;
template
<
typename
T
,
int
MajorType
=
Eigen
::
RowMajor
,
typename
IndexType
=
Eigen
::
DenseIndex
>
using
EigenMatrix
=
framework
::
EigenMatrix
<
T
,
MajorType
,
IndexType
>
;
template
<
typename
Place
,
typename
T
>
class
Sequence
Project
Kernel
:
public
framework
::
OpKernel
<
T
>
{
class
Sequence
Conv
Kernel
:
public
framework
::
OpKernel
<
T
>
{
public:
void
Compute
(
const
framework
::
ExecutionContext
&
context
)
const
override
{
auto
*
in
=
context
.
Input
<
LoDTensor
>
(
"X"
);
auto
*
out
=
context
.
Output
<
LoDTensor
>
(
"Out"
);
out
->
mutable_data
<
T
>
(
context
.
GetPlace
());
// Because if padding_trainable is false, padding data should be zeros.
auto
temp
=
framework
::
EigenVector
<
T
>::
Flatten
(
*
out
);
temp
.
device
(
context
.
GetEigenDevice
<
Place
>
())
=
temp
.
constant
(
static_cast
<
T
>
(
0
));
auto
filter
=
*
context
.
Input
<
LoDTensor
>
(
"Filter"
);
auto
place
=
context
.
GetEigenDevice
<
Place
>
(
);
out
->
mutable_data
<
T
>
(
context
.
GetPlace
()
);
int
context_start
=
context
.
Attr
<
int
>
(
"context_start"
);
int
context_length
=
context
.
Attr
<
int
>
(
"context_length"
);
bool
padding_trainable
=
context
.
Attr
<
bool
>
(
"padding_trainable"
);
int
context_stride
=
context
.
Attr
<
int
>
(
"context_stride"
);
bool
padding_trainable
=
context
.
Attr
<
bool
>
(
"padding_trainable"
);
// InferShape by in_lod
PADDLE_ENFORCE_EQ
(
in
->
lod
().
size
(),
1UL
,
"Only support one level sequence now."
);
auto
lod_level_0
=
in
->
lod
()[
0
];
const
LoDTensor
*
padding_data
=
nullptr
;
if
(
padding_trainable
)
{
...
...
@@ -63,117 +56,51 @@ class SequenceProjectKernel : public framework::OpKernel<T> {
int
up_pad
=
std
::
max
(
0
,
-
context_start
);
int
down_pad
=
std
::
max
(
0
,
context_start
+
context_length
-
1
);
int
sequence_height
,
sequence_width
;
int
input_row_begin
,
input_row_end
;
int
sequence_width
;
sequence_width
=
static_cast
<
int
>
(
in
->
dims
()[
1
]);
paddle
::
operators
::
math
::
Im2ColFunctor
<
paddle
::
operators
::
math
::
ColFormat
::
kOCF
,
Place
,
float
>
im2col_ocf
;
for
(
int
i
=
0
;
i
<
static_cast
<
int
>
(
lod_level_0
.
size
())
-
1
;
++
i
)
{
input_row_begin
=
(
context_start
>
0
)
?
static_cast
<
int
>
(
lod_level_0
[
i
])
+
context_start
:
static_cast
<
int
>
(
lod_level_0
[
i
]);
input_row_end
=
static_cast
<
int
>
(
lod_level_0
[
i
+
1
]);
Tensor
out_t
=
out
->
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
]);
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
));
if
(
input_row_begin
<
input_row_end
)
{
Tensor
in_t
=
in
->
Slice
(
input_row_begin
,
input_row_end
);
std
::
vector
<
int64_t
>
input_shape
(
{
1
,
input_row_end
-
input_row_begin
,
sequence_width
});
// input_channels, input_height, input_width
in_t
.
Resize
(
framework
::
make_ddim
(
input_shape
));
im2col_ocf
(
context
.
device_context
(),
in_t
,
out_t
,
/*stride_height*/
context_stride
,
/*stride_width*/
0
,
up_pad
,
down_pad
);
}
// use col_shape in the im2col calculation
framework
::
DDim
col_shape
=
{
in
->
dims
()[
0
],
sequence_width
*
context_length
};
LoDTensor
col
;
col
.
mutable_data
<
T
>
(
col_shape
,
context
.
GetPlace
());
// Because if padding_trainable is false, padding data should be zeros.
auto
temp
=
framework
::
EigenVector
<
T
>::
Flatten
(
col
);
temp
.
device
(
context
.
GetEigenDevice
<
Place
>
())
=
temp
.
constant
(
static_cast
<
T
>
(
0
));
if
(
padding_trainable
)
{
// add up trainable data
out_t
.
Resize
(
framework
::
make_ddim
(
{
sequence_height
*
context_length
,
sequence_width
}));
paddle
::
operators
::
math
::
SequenceProjectFunctor
<
Place
,
T
>
seq_project_functor
;
if
(
up_pad
>
0
)
{
// add up pad
int
padding_rows
=
std
::
min
(
up_pad
,
static_cast
<
int
>
(
lod_level_0
[
i
+
1
]
-
lod_level_0
[
i
])
);
seq_project_functor
(
context
.
device_context
(),
in
,
padding_data
,
&
col
,
padding_trainable
,
context_start
,
context_length
,
context_stride
,
up_pad
,
down_pad
);
for
(
int
k
=
0
;
k
<
padding_rows
;
++
k
)
{
int
padding_size
=
k
+
context_length
<
up_pad
?
context_length
:
up_pad
-
k
;
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
);
// in this block, using EigenVector<T>::Flatten is ok too.
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
(
place
)
=
w_sub_e
;
}
}
if
(
down_pad
>
0
)
{
// add down pad
int
down_pad_begin_row
=
std
::
max
(
0
,
(
sequence_height
-
context_start
-
context_length
)
+
1
)
+
1
;
int
padding_begin
=
std
::
max
(
0
,
context_start
-
sequence_height
);
int
padding_size
=
sequence_height
-
context_start
>=
context_length
?
1
:
context_length
-
(
sequence_height
-
context_start
);
if
(
context_start
>=
sequence_height
)
padding_size
=
context_length
;
int
padding_idx
=
padding_begin
;
for
(
int
t
=
0
;
t
+
down_pad_begin_row
<=
sequence_height
;
++
t
,
++
padding_size
)
{
if
(
context_start
>=
sequence_height
)
padding_size
=
context_length
;
if
(
padding_size
>
context_length
)
{
padding_size
=
context_length
;
padding_idx
++
;
}
if
(
padding_begin
>
0
||
sequence_height
==
context_start
)
padding_idx
=
padding_begin
+
t
;
Tensor
out_t_sub
=
out_t
.
Slice
(
(
down_pad_begin_row
+
t
)
*
context_length
-
padding_size
,
(
down_pad_begin_row
+
t
)
*
context_length
);
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
);
out_t_sub_e
.
device
(
place
)
=
w_sub_e
;
}
}
}
out_t
.
Resize
(
framework
::
make_ddim
(
{
sequence_height
,
context_length
*
sequence_width
}));
}
filter
.
Resize
(
framework
::
make_ddim
({
context_length
*
sequence_width
,
1
}));
math
::
matmul
<
Place
,
T
>
(
context
.
device_context
(),
col
,
false
,
filter
,
false
,
T
(
1.0
),
out
,
T
(
0.0
));
}
};
template
<
typename
Place
,
typename
T
>
class
Sequence
Project
GradKernel
:
public
framework
::
OpKernel
<
T
>
{
class
Sequence
Conv
GradKernel
:
public
framework
::
OpKernel
<
T
>
{
public:
void
Compute
(
const
framework
::
ExecutionContext
&
context
)
const
override
{
auto
*
out_g
=
context
.
Input
<
LoDTensor
>
(
framework
::
GradVarName
(
"Out"
));
auto
*
in_g
=
context
.
Output
<
LoDTensor
>
(
framework
::
GradVarName
(
"X"
));
auto
*
filter_g
=
context
.
Output
<
LoDTensor
>
(
framework
::
GradVarName
(
"Filter"
));
auto
*
padding_data_g
=
context
.
Output
<
LoDTensor
>
(
framework
::
GradVarName
(
"PaddingData"
));
auto
*
in
=
context
.
Input
<
LoDTensor
>
(
"X"
);
auto
*
filter
=
context
.
Input
<
LoDTensor
>
(
"Filter"
);
auto
place
=
context
.
GetEigenDevice
<
Place
>
();
int
context_start
=
context
.
Attr
<
int
>
(
"context_start"
);
int
context_length
=
context
.
Attr
<
int
>
(
"context_length"
);
bool
padding_trainable
=
context
.
Attr
<
bool
>
(
"padding_trainable"
);
int
context_stride
=
context
.
Attr
<
int
>
(
"context_stride"
);
bool
padding_trainable
=
context
.
Attr
<
bool
>
(
"padding_trainable"
);
// InferShape by in_lod
PADDLE_ENFORCE_EQ
(
in
->
lod
().
size
(),
1UL
,
...
...
@@ -187,15 +114,31 @@ class SequenceProjectGradKernel : public framework::OpKernel<T> {
sequence_width
=
static_cast
<
int
>
(
in
->
dims
()[
1
]);
paddle
::
operators
::
math
::
Col2ImFunctor
<
paddle
::
operators
::
math
::
ColFormat
::
kOCF
,
Place
,
float
>
col2im_ocf
;
// use col_shape in the im2col calculation
framework
::
DDim
col_shape
=
{
in
->
dims
()[
0
],
sequence_width
*
context_length
};
LoDTensor
col
;
if
(
in_g
||
filter_g
||
(
padding_trainable
&&
padding_data_g
))
{
col
.
mutable_data
<
T
>
(
col_shape
,
context
.
GetPlace
());
// Because if padding_trainable is false, padding data should be zeros.
auto
temp
=
framework
::
EigenVector
<
T
>::
Flatten
(
col
);
temp
.
device
(
context
.
GetEigenDevice
<
Place
>
())
=
temp
.
constant
(
static_cast
<
T
>
(
0
));
math
::
matmul
<
Place
,
T
>
(
context
.
device_context
(),
*
out_g
,
false
,
*
filter
,
true
,
T
(
1.0
),
&
col
,
T
(
1.0
));
}
if
(
in_g
)
{
in_g
->
mutable_data
<
T
>
(
context
.
GetPlace
());
math
::
SetConstant
<
Place
,
T
>
functor
;
functor
(
context
.
device_context
(),
in_g
,
0
);
paddle
::
operators
::
math
::
Col2ImFunctor
<
paddle
::
operators
::
math
::
ColFormat
::
kOCF
,
Place
,
float
>
col2im_ocf
;
for
(
int
i
=
0
;
i
<
static_cast
<
int
>
(
lod_g_level_0
.
size
())
-
1
;
++
i
)
{
input_row_begin
=
(
context_start
>
0
)
...
...
@@ -203,10 +146,10 @@ class SequenceProjectGradKernel : public framework::OpKernel<T> {
:
static_cast
<
int
>
(
lod_g_level_0
[
i
]);
input_row_end
=
static_cast
<
int
>
(
lod_g_level_0
[
i
+
1
]);
Tensor
out_g_t
=
out_g
->
Slice
(
static_cast
<
int
>
(
lod_g_level_0
[
i
]),
static_cast
<
int
>
(
lod_g_level_0
[
i
+
1
]));
Tensor
col_t
=
col
.
Slice
(
static_cast
<
int
>
(
lod_g_level_0
[
i
]),
static_cast
<
int
>
(
lod_g_level_0
[
i
+
1
]));
sequence_height
=
static_cast
<
int
>
(
out_g
_t
.
dims
()[
0
]);
sequence_height
=
static_cast
<
int
>
(
col
_t
.
dims
()[
0
]);
if
(
input_row_begin
<
input_row_end
)
{
Tensor
in_t
=
in_g
->
Slice
(
input_row_begin
,
input_row_end
);
...
...
@@ -214,19 +157,19 @@ class SequenceProjectGradKernel : public framework::OpKernel<T> {
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_g
_t
.
Resize
(
framework
::
make_ddim
(
output_shape
));
// input_channels, filter_height, filter_width
col
_t
.
Resize
(
framework
::
make_ddim
(
output_shape
));
std
::
vector
<
int64_t
>
input_shape
(
{
1
,
input_row_end
-
input_row_begin
,
sequence_width
});
// input_channels, input_height, input_width
in_t
.
Resize
(
framework
::
make_ddim
(
input_shape
));
col2im_ocf
(
context
.
device_context
(),
in_t
,
out_g
_t
,
col2im_ocf
(
context
.
device_context
(),
in_t
,
col
_t
,
/*stride_height*/
context_stride
,
/*stride_width*/
0
,
up_pad
,
down_pad
);
}
out_g
_t
.
Resize
(
framework
::
make_ddim
(
col
_t
.
Resize
(
framework
::
make_ddim
(
{
sequence_height
,
context_length
*
sequence_width
}));
}
}
...
...
@@ -244,12 +187,12 @@ class SequenceProjectGradKernel : public framework::OpKernel<T> {
:
static_cast
<
int
>
(
lod_g_level_0
[
i
]);
input_row_end
=
static_cast
<
int
>
(
lod_g_level_0
[
i
+
1
]);
Tensor
out_g_t
=
out_g
->
Slice
(
static_cast
<
int
>
(
lod_g_level_0
[
i
]),
static_cast
<
int
>
(
lod_g_level_0
[
i
+
1
]));
Tensor
col_t
=
col
.
Slice
(
static_cast
<
int
>
(
lod_g_level_0
[
i
]),
static_cast
<
int
>
(
lod_g_level_0
[
i
+
1
]));
sequence_height
=
static_cast
<
int
>
(
out_g
_t
.
dims
()[
0
]);
sequence_height
=
static_cast
<
int
>
(
col
_t
.
dims
()[
0
]);
out_g
_t
.
Resize
(
framework
::
make_ddim
(
col
_t
.
Resize
(
framework
::
make_ddim
(
{
sequence_height
*
context_length
,
sequence_width
}));
if
(
up_pad
>
0
)
{
// add up pad
...
...
@@ -260,8 +203,8 @@ class SequenceProjectGradKernel : public framework::OpKernel<T> {
for
(
int
k
=
0
;
k
<
padding_rows
;
++
k
)
{
int
padding_size
=
k
+
context_length
<
up_pad
?
context_length
:
up_pad
-
k
;
Tensor
out_t_sub
=
out_g
_t
.
Slice
(
k
*
context_length
,
k
*
context_length
+
padding_size
);
Tensor
out_t_sub
=
col
_t
.
Slice
(
k
*
context_length
,
k
*
context_length
+
padding_size
);
Tensor
w_sub
=
padding_data_g
->
Slice
(
k
,
k
+
padding_size
);
// in this block, using EigenVector<T>::Flatten is ok too.
auto
out_t_sub_e
=
EigenMatrix
<
T
>::
From
(
out_t_sub
);
...
...
@@ -290,7 +233,7 @@ class SequenceProjectGradKernel : public framework::OpKernel<T> {
}
if
(
padding_begin
>
0
||
sequence_height
==
context_start
)
padding_idx
=
padding_begin
+
t
;
Tensor
out_t_sub
=
out_g
_t
.
Slice
(
Tensor
out_t_sub
=
col
_t
.
Slice
(
(
down_pad_begin_row
+
t
)
*
context_length
-
padding_size
,
(
down_pad_begin_row
+
t
)
*
context_length
);
Tensor
w_sub
=
padding_data_g
->
Slice
(
...
...
@@ -300,10 +243,40 @@ class SequenceProjectGradKernel : public framework::OpKernel<T> {
w_sub_e
.
device
(
place
)
=
w_sub_e
+
out_t_sub_e
;
}
}
out_g
_t
.
Resize
(
framework
::
make_ddim
(
col
_t
.
Resize
(
framework
::
make_ddim
(
{
sequence_height
,
context_length
*
sequence_width
}));
}
}
if
(
filter_g
)
{
filter_g
->
mutable_data
<
T
>
(
context
.
GetPlace
());
math
::
SetConstant
<
Place
,
T
>
functor
;
functor
(
context
.
device_context
(),
filter_g
,
0
);
Tensor
filter_grad_
=
*
filter_g
;
Tensor
out_grad_
=
*
out_g
;
const
LoDTensor
*
padding_data
=
nullptr
;
if
(
padding_trainable
)
{
padding_data
=
context
.
Input
<
LoDTensor
>
(
"PaddingData"
);
}
sequence_width
=
static_cast
<
int
>
(
in
->
dims
()[
1
]);
paddle
::
operators
::
math
::
SequenceProjectFunctor
<
Place
,
T
>
seq_project_functor
;
seq_project_functor
(
context
.
device_context
(),
in
,
padding_data
,
&
col
,
padding_trainable
,
context_start
,
context_length
,
context_stride
,
up_pad
,
down_pad
);
filter_grad_
.
Resize
(
framework
::
make_ddim
({
context_length
*
sequence_width
,
1
}));
math
::
matmul
<
Place
,
T
>
(
context
.
device_context
(),
col
,
true
,
out_grad_
,
false
,
T
(
1.0
),
&
filter_grad_
,
T
(
1.0
));
}
}
};
...
...
python/paddle/v2/framework/tests/test_seq_project.py
已删除
100644 → 0
浏览文件 @
0ab2c436
import
unittest
import
numpy
as
np
import
random
from
op_test
import
OpTest
class
TestSeqProject
(
OpTest
):
def
setUp
(
self
):
self
.
init_test_case
()
self
.
op_type
=
'sequence_project'
if
self
.
context_length
==
1
and
self
.
context_start
==
0
and
self
.
padding_trainable
:
print
"If context_start is 0 and context_length is 1, padding_trainable should be false."
return
# one level, batch size
x
=
np
.
random
.
uniform
(
0.1
,
1
,
[
self
.
input_size
[
0
],
self
.
input_size
[
1
]]).
astype
(
'float32'
)
self
.
begin_pad
=
np
.
max
([
0
,
-
self
.
context_start
])
self
.
end_pad
=
np
.
max
([
0
,
self
.
context_start
+
self
.
context_length
-
1
])
self
.
total_pad
=
self
.
begin_pad
+
self
.
end_pad
if
self
.
total_pad
==
0
:
self
.
total_pad
=
1
# PaddingData mast be not empty. Otherwise(EnforceNotMet: enforce numel() > 0 failed, 0 <= 0)
padding_data
=
np
.
random
.
uniform
(
0.1
,
1
,
[
self
.
total_pad
,
self
.
input_size
[
1
]]).
astype
(
'float32'
)
self
.
inputs
=
{
'X'
:
(
x
,
self
.
lod
),
'PaddingData'
:
(
padding_data
,
[[
0
,
self
.
total_pad
]])
}
self
.
attrs
=
{
'context_start'
:
self
.
context_start
,
'context_length'
:
self
.
context_length
,
'padding_trainable'
:
self
.
padding_trainable
,
'context_stride'
:
self
.
context_stride
}
out
=
np
.
zeros
((
self
.
input_size
[
0
],
self
.
input_size
[
1
]
*
self
.
context_length
)).
astype
(
'float32'
)
self
.
outputs
=
{
'Out'
:
out
}
self
.
compute
()
def
compute
(
self
):
x
,
lod
=
self
.
inputs
[
'X'
]
pading_data
,
_
=
self
.
inputs
[
'PaddingData'
]
out
=
self
.
outputs
[
'Out'
]
lod
=
lod
[
0
]
begin_pad
=
np
.
max
([
0
,
-
self
.
context_start
])
for
i
in
range
(
len
(
lod
)
-
1
):
for
j
in
range
(
self
.
context_length
):
in_begin
=
lod
[
i
]
+
self
.
context_start
+
j
in_end
=
lod
[
i
+
1
]
+
self
.
context_start
+
j
out_begin
=
lod
[
i
]
out_end
=
lod
[
i
+
1
]
if
in_begin
<
lod
[
i
]:
pad_size
=
np
.
min
([
lod
[
i
]
-
in_begin
,
lod
[
i
+
1
]
-
lod
[
i
]])
if
self
.
padding_trainable
:
sub_w
=
pading_data
[
j
:
j
+
pad_size
,
:]
out
[
lod
[
i
]:
lod
[
i
]
+
pad_size
,
j
*
self
.
input_size
[
1
]:(
j
+
1
)
*
self
.
input_size
[
1
]]
=
sub_w
out_begin
=
lod
[
i
]
+
pad_size
in_begin
=
lod
[
i
]
if
in_end
>
lod
[
i
+
1
]:
pad_size
=
np
.
min
(
[
in_end
-
lod
[
i
+
1
],
lod
[
i
+
1
]
-
lod
[
i
]])
if
self
.
padding_trainable
:
sub_w
=
pading_data
[
begin_pad
+
self
.
context_start
+
j
-
pad_size
:
begin_pad
+
self
.
context_start
+
j
,
:]
out
[
lod
[
i
+
1
]
-
pad_size
:
lod
[
i
+
1
],
j
*
self
.
input_size
[
1
]:(
j
+
1
)
*
self
.
input_size
[
1
]]
=
sub_w
in_end
=
lod
[
i
+
1
]
out_end
=
lod
[
i
+
1
]
-
pad_size
if
in_end
<=
in_begin
:
continue
in_sub
=
x
[
in_begin
:
in_end
,
:]
out
[
out_begin
:
out_end
,
j
*
self
.
input_size
[
1
]:(
j
+
1
)
*
self
.
input_size
[
1
]]
+=
in_sub
def
test_check_output
(
self
):
self
.
check_output
()
def
test_check_grad
(
self
):
if
self
.
padding_trainable
:
self
.
check_grad
(
set
([
'X'
,
'PaddingData'
]),
'Out'
,
max_relative_error
=
0.05
)
def
test_check_grad_no_filter
(
self
):
self
.
check_grad
(
[
'X'
],
'Out'
,
max_relative_error
=
0.05
,
no_grad_set
=
set
([
'PaddingData'
]))
def
test_check_grad_no_input
(
self
):
if
self
.
padding_trainable
:
self
.
check_grad
(
[
'PaddingData'
],
'Out'
,
max_relative_error
=
0.05
,
no_grad_set
=
set
([
'X'
]))
def
init_test_case
(
self
):
self
.
op_type
=
"sequence_project"
self
.
input_row
=
11
self
.
context_start
=
0
self
.
context_length
=
1
self
.
padding_trainable
=
False
self
.
context_stride
=
1
self
.
input_size
=
[
self
.
input_row
,
23
]
self
.
lod
=
[[
0
,
4
,
5
,
8
,
self
.
input_row
]]
class
TestSeqProjectCase1
(
TestSeqProject
):
def
init_test_case
(
self
):
self
.
op_type
=
"sequence_project"
self
.
input_row
=
11
self
.
context_start
=
-
1
self
.
context_length
=
3
self
.
padding_trainable
=
True
self
.
context_stride
=
1
self
.
input_size
=
[
self
.
input_row
,
23
]
self
.
lod
=
[[
0
,
4
,
5
,
8
,
self
.
input_row
]]
class
TestSeqProjectCase2
(
TestSeqProject
):
def
init_test_case
(
self
):
self
.
op_type
=
"sequence_project"
self
.
input_row
=
25
self
.
context_start
=
2
self
.
context_length
=
3
self
.
padding_trainable
=
True
self
.
context_stride
=
1
self
.
input_size
=
[
self
.
input_row
,
23
]
idx
=
range
(
self
.
input_size
[
0
])
del
idx
[
0
]
self
.
lod
=
[[
0
]
+
np
.
sort
(
random
.
sample
(
idx
,
8
)).
tolist
()
+
[
self
.
input_size
[
0
]]]
'''
class TestSeqProjectCases(TestSeqProject):
def setUp(self):
self.init_test_case()
self.op_type = 'sequence_project'
num = 0
for context_start in [-5, -3, -1, 0, 3]:
for context_length in [1, 2, 5, 7]:
for batch_size in [1, 2, 5, 7]:
for padding_trainable in [False, True]:
if context_length == 1 and context_start == 0 and padding_trainable:
continue
self.context_start = context_start
self.context_length = context_length
self.padding_trainable = padding_trainable
self.input_size = [batch_size, 23]
x = np.random.uniform(0.1, 1,
self.input_size).astype('float32')
self.lod = [[0, self.input_size[0]]]
if self.input_size[0] > 2:
idx = range(self.input_size[0])
del idx[0]
self.lod = [
[0] + np.sort(random.sample(idx, 2)).tolist() +
[self.input_size[0]]
]
self.begin_pad = np.max([0, -self.context_start])
self.end_pad = np.max([0, self.context_start + self.context_length - 1])
self.total_pad = self.begin_pad + self.end_pad
if self.total_pad == 0:
self.total_pad = 1
# PaddingData mast be not empty. Otherwise(EnforceNotMet: enforce numel() > 0 failed, 0 <= 0)
padding_data = np.random.uniform(
0.1, 1, [self.total_pad, self.input_size[1]]).astype('float32')
self.inputs = {
'X': (x, self.lod),
'PaddingData': (padding_data, [[0, self.total_pad]])
}
self.attrs = {
'context_start': self.context_start,
'context_length': self.context_length,
'padding_trainable': self.padding_trainable,
'context_stride': self.context_stride
}
out = np.zeros((self.input_size[0], self.input_size[1] *
self.context_length)).astype('float32')
self.outputs = {'Out': out}
print num
print self.attrs
print batch_size
print padding_trainable
print "$$$$$$$$$$$$$"
self.compute()
self.test_check_output()
num += 1
'''
if
__name__
==
'__main__'
:
unittest
.
main
()
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录