提交 ce960575 编写于 作者: C chengduoZH

fix doc format and unit test

上级 4c19f9f4
...@@ -27,10 +27,12 @@ class SequenceProjectOp : public framework::OperatorWithKernel { ...@@ -27,10 +27,12 @@ class SequenceProjectOp : public framework::OperatorWithKernel {
"Input(X) of SequenceProjectOp should not be null."); "Input(X) of SequenceProjectOp should not be null.");
PADDLE_ENFORCE(ctx->HasOutput("Out"), PADDLE_ENFORCE(ctx->HasOutput("Out"),
"Output(Out) of SequenceProjectOp should not be null."); "Output(Out) of SequenceProjectOp should not be null.");
// PaddingData mast be not empty. // PaddingData mast be not empty. Otherwise(EnforceNotMet: enforce numel() >
// 0 failed, 0 <= 0)
PADDLE_ENFORCE( PADDLE_ENFORCE(
ctx->HasInput("PaddingData"), ctx->HasInput("PaddingData"),
"Output(PaddingData) of SequenceProjectOp should not be null."); "Input(PaddingData) of SequenceProjectOp should not be null.");
auto in_dims = ctx->GetInputDim("X"); auto in_dims = ctx->GetInputDim("X");
PADDLE_ENFORCE(in_dims.size() == 2, "Input(X) should be 2-D tensor."); PADDLE_ENFORCE(in_dims.size() == 2, "Input(X) should be 2-D tensor.");
...@@ -47,7 +49,7 @@ class SequenceProjectOp : public framework::OperatorWithKernel { ...@@ -47,7 +49,7 @@ class SequenceProjectOp : public framework::OperatorWithKernel {
if (context_start == 0 && context_length == 1) { if (context_start == 0 && context_length == 1) {
PADDLE_THROW( PADDLE_THROW(
"if context_start == 0 && context_length == 1, padding_trainable " "If context_start is 0 and context_length is 1, padding_trainable "
"should be false."); "should be false.");
} }
PADDLE_ENFORCE(padding_dim.size() == 2, PADDLE_ENFORCE(padding_dim.size() == 2,
...@@ -70,8 +72,8 @@ class SequenceProjectGradOp : public framework::OperatorWithKernel { ...@@ -70,8 +72,8 @@ class SequenceProjectGradOp : public framework::OperatorWithKernel {
protected: protected:
void InferShape(framework::InferShapeContext* ctx) const override { void InferShape(framework::InferShapeContext* ctx) const override {
PADDLE_ENFORCE(ctx->HasInput(framework::GradVarName("Out")), PADDLE_ENFORCE(ctx->HasInput(framework::GradVarName("Out")),
"Gradient of Out should not be null."); "Gradient of output(Out) should not be null.");
PADDLE_ENFORCE(ctx->HasInput("X"), "The input X should not be null."); PADDLE_ENFORCE(ctx->HasInput("X"), "The input(X) should not be null.");
if (ctx->Attrs().Get<bool>("padding_trainable") && if (ctx->Attrs().Get<bool>("padding_trainable") &&
ctx->HasOutput(framework::GradVarName("PaddingData"))) { ctx->HasOutput(framework::GradVarName("PaddingData"))) {
...@@ -89,31 +91,35 @@ class SequenceProjectOpMaker : public framework::OpProtoAndCheckerMaker { ...@@ -89,31 +91,35 @@ class SequenceProjectOpMaker : public framework::OpProtoAndCheckerMaker {
SequenceProjectOpMaker(framework::OpProto* proto, SequenceProjectOpMaker(framework::OpProto* proto,
framework::OpAttrChecker* op_checker) framework::OpAttrChecker* op_checker)
: OpProtoAndCheckerMaker(proto, op_checker) { : OpProtoAndCheckerMaker(proto, op_checker) {
AddInput( AddInput("X",
"X", "(A float LoDTensor) the input of SequenceProjectOp, a vector of "
"A float LoDTensor, the variable-length input of SequenceProjectOp"); "2-D matrix of size (minibatch, number_of_input_features).");
AddOutput( AddOutput("Out",
"Out", "(A float LoDTensor) the output of SequenceProjectOp, a vector "
"A float LoDTensor, the variable-length output of SequenceProjectOp."); "of 2-D matrix of size (minibatch, number_of_input_features x "
AddInput("PaddingData", // PaddingData can be a float tensor "context_length).");
"A float LoDTensor, the padding data of SequenceProjectOp."); AddInput("PaddingData",
"(A float LoDTensor) the input of SequenceProjectOp, a vector of "
"2-D matrix of size (up_pad + down_pad, "
"number_of_input_features). ");
AddAttr<bool>("padding_trainable", AddAttr<bool>("padding_trainable",
"(bool, default false) the padding data of SequenceProjectOp " "(bool, default false) the padding data of SequenceProjectOp "
"is trainable or not.") "is trainable or not.")
.SetDefault(false); .SetDefault(false);
AddAttr<int>("context_length", AddAttr<int>("context_length",
"(int, default 3) the stride of SequenceProjectOp.") "(int, default 3) the context_length of SequenceProjectOp.")
.SetDefault(3) .SetDefault(3)
.GreaterThan(0); .GreaterThan(0);
AddAttr<int>("context_start", AddAttr<int>("context_start",
"(int, default 0) the xx of SequenceProjectOp.") "(int, default 0) the context_start of SequenceProjectOp.")
.SetDefault(0); .SetDefault(0);
AddAttr<int>("context_stride", AddAttr<int>("context_stride",
"(int, default 1) the xx of SequenceProjectOp.") "(int, default 1) the context_stride of SequenceProjectOp. "
"Currently, sequence_project_op only support "
"context_stride=1.")
.SetDefault(1) .SetDefault(1)
.GreaterThan( .GreaterThan(0);
0); // Currently, sequence_project_op only support context_stride=1
AddComment(R"DOC( AddComment(R"DOC(
SequenceProjectOp projects features of context_length time-steps of each instance. SequenceProjectOp projects features of context_length time-steps of each instance.
...@@ -132,22 +138,22 @@ class SequenceProjectOpMaker : public framework::OpProtoAndCheckerMaker { ...@@ -132,22 +138,22 @@ class SequenceProjectOpMaker : public framework::OpProtoAndCheckerMaker {
representation is 2. representation is 2.
- Case1: - Case1:
If we use zero to pad instead of learned weight to pad, 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: 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; a1, a2, b1, b2, c1, c2;
b1, b2, c1, c2, 0, 0; b1, b2, c1, c2, 0, 0;
0, 0, d1, d2, 0, 0] 0, 0, d1, d2, 0, 0]
- Case2: - Case2:
// If we use zero to pad instead of learned weight to pad, 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: and the context_lenth is 3, the output (Out) is:
//
// Out = [0, 0, a1, a2, b1, b2; Out = [w1, w2, a1, a2, b1, b2;
// a1, a2, b1, b2, c1, c2; a1, a2, b1, b2, c1, c2;
// b1, b2, c1, c2, 0, 0; b1, b2, c1, c2, w3, w4;
// 0, 0, d1, d2, 0, 0] w1, w2, d1, d2, w3, w4]
)DOC"); )DOC");
} }
......
...@@ -55,26 +55,17 @@ class SequenceProjectKernel : public framework::OpKernel<T> { ...@@ -55,26 +55,17 @@ class SequenceProjectKernel : public framework::OpKernel<T> {
PADDLE_ENFORCE_EQ(in->lod().size(), 1UL, PADDLE_ENFORCE_EQ(in->lod().size(), 1UL,
"Only support one level sequence now."); "Only support one level sequence now.");
auto lod_level_0 = in->lod()[0]; auto lod_level_0 = in->lod()[0];
int64_t input_width = in->dims()[1];
int64_t output_width = out->dims()[1];
int64_t padding_width = 0;
PADDLE_ENFORCE(input_width * context_length == output_width,
"Input size and pooling size should be consistent.");
const LoDTensor* padding_data = nullptr; const LoDTensor* padding_data = nullptr;
if (padding_trainable) { if (padding_trainable) {
padding_data = context.Input<LoDTensor>("PaddingData"); padding_data = context.Input<LoDTensor>("PaddingData");
PADDLE_ENFORCE_EQ(padding_data->dims().size(), 2UL,
"Only support one level sequence now.");
padding_width = padding_data->dims()[1];
PADDLE_ENFORCE(padding_width == input_width,
"Input size and pooling size should be consistent.");
} }
int up_pad = std::max(0, -context_start); int up_pad = std::max(0, -context_start);
int down_pad = std::max(0, context_start + context_length - 1); int down_pad = std::max(0, context_start + context_length - 1);
int sequence_height, sequence_width; int sequence_height, sequence_width;
int input_row_begin, input_row_end; int input_row_begin, input_row_end;
sequence_width = static_cast<int>(in->dims()[1]);
paddle::operators::math::Im2ColFunctor< paddle::operators::math::Im2ColFunctor<
paddle::operators::math::ColFormat::kOCF, Place, float> paddle::operators::math::ColFormat::kOCF, Place, float>
...@@ -90,7 +81,6 @@ class SequenceProjectKernel : public framework::OpKernel<T> { ...@@ -90,7 +81,6 @@ class SequenceProjectKernel : public framework::OpKernel<T> {
static_cast<int>(lod_level_0[i + 1])); static_cast<int>(lod_level_0[i + 1]));
sequence_height = static_cast<int>(out_t.dims()[0]); sequence_height = static_cast<int>(out_t.dims()[0]);
sequence_width = static_cast<int>(in->dims()[1]);
std::vector<int64_t> output_shape( std::vector<int64_t> output_shape(
{sequence_height, 1, 1, context_length, {sequence_height, 1, 1, context_length,
...@@ -190,13 +180,6 @@ class SequenceProjectGradKernel : public framework::OpKernel<T> { ...@@ -190,13 +180,6 @@ class SequenceProjectGradKernel : public framework::OpKernel<T> {
"Only support one level sequence now."); "Only support one level sequence now.");
auto lod_g_level_0 = in->lod()[0]; auto lod_g_level_0 = in->lod()[0];
int64_t input_width = in->dims()[1];
int64_t output_width = out_g->dims()[1];
int64_t padding_width = 0;
PADDLE_ENFORCE(input_width * context_length == output_width,
"Input size and pooling size should be consistent.");
int up_pad = std::max(0, -context_start); int up_pad = std::max(0, -context_start);
int down_pad = std::max(0, context_start + context_length - 1); int down_pad = std::max(0, context_start + context_length - 1);
int sequence_height, sequence_width; int sequence_height, sequence_width;
...@@ -250,11 +233,7 @@ class SequenceProjectGradKernel : public framework::OpKernel<T> { ...@@ -250,11 +233,7 @@ class SequenceProjectGradKernel : public framework::OpKernel<T> {
if (padding_trainable && padding_data_g) { if (padding_trainable && padding_data_g) {
padding_data_g->mutable_data<T>(context.GetPlace()); padding_data_g->mutable_data<T>(context.GetPlace());
PADDLE_ENFORCE_EQ(padding_data_g->dims().size(), 2UL,
"Only support one level sequence now.");
padding_width = padding_data_g->dims()[1];
PADDLE_ENFORCE(padding_width == input_width,
"Input size and pooling size should be consistent.");
math::SetConstant<Place, T> functor; math::SetConstant<Place, T> functor;
functor(context.device_context(), padding_data_g, 0); functor(context.device_context(), padding_data_g, 0);
......
...@@ -8,6 +8,10 @@ class TestSeqProject(OpTest): ...@@ -8,6 +8,10 @@ class TestSeqProject(OpTest):
def setUp(self): def setUp(self):
self.init_test_case() self.init_test_case()
self.op_type = 'sequence_project' 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 # one level, batch size
x = np.random.uniform( x = np.random.uniform(
0.1, 1, [self.input_size[0], self.input_size[1]]).astype('float32') 0.1, 1, [self.input_size[0], self.input_size[1]]).astype('float32')
...@@ -15,11 +19,15 @@ class TestSeqProject(OpTest): ...@@ -15,11 +19,15 @@ class TestSeqProject(OpTest):
self.begin_pad = np.max([0, -self.context_start]) self.begin_pad = np.max([0, -self.context_start])
self.end_pad = np.max([0, self.context_start + self.context_length - 1]) self.end_pad = np.max([0, self.context_start + self.context_length - 1])
self.total_pad = self.begin_pad + self.end_pad self.total_pad = self.begin_pad + self.end_pad
w = np.random.uniform( 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') 0.1, 1, [self.total_pad, self.input_size[1]]).astype('float32')
self.inputs = { self.inputs = {
'X': (x, self.lod), 'X': (x, self.lod),
'PaddingData': (w, [[0, self.total_pad]]) 'PaddingData': (padding_data, [[0, self.total_pad]])
} }
self.attrs = { self.attrs = {
'context_start': self.context_start, 'context_start': self.context_start,
...@@ -34,7 +42,7 @@ class TestSeqProject(OpTest): ...@@ -34,7 +42,7 @@ class TestSeqProject(OpTest):
def compute(self): def compute(self):
x, lod = self.inputs['X'] x, lod = self.inputs['X']
w, _ = self.inputs['PaddingData'] pading_data, _ = self.inputs['PaddingData']
out = self.outputs['Out'] out = self.outputs['Out']
lod = lod[0] lod = lod[0]
begin_pad = np.max([0, -self.context_start]) begin_pad = np.max([0, -self.context_start])
...@@ -48,7 +56,7 @@ class TestSeqProject(OpTest): ...@@ -48,7 +56,7 @@ class TestSeqProject(OpTest):
if in_begin < lod[i]: if in_begin < lod[i]:
pad_size = np.min([lod[i] - in_begin, lod[i + 1] - lod[i]]) pad_size = np.min([lod[i] - in_begin, lod[i + 1] - lod[i]])
if self.padding_trainable: if self.padding_trainable:
sub_w = w[j:j + pad_size, :] sub_w = pading_data[j:j + pad_size, :]
out[lod[i]:lod[i] + pad_size, j * self.input_size[1]:( out[lod[i]:lod[i] + pad_size, j * self.input_size[1]:(
j + 1) * self.input_size[1]] = sub_w j + 1) * self.input_size[1]] = sub_w
out_begin = lod[i] + pad_size out_begin = lod[i] + pad_size
...@@ -58,8 +66,9 @@ class TestSeqProject(OpTest): ...@@ -58,8 +66,9 @@ class TestSeqProject(OpTest):
pad_size = np.min( pad_size = np.min(
[in_end - lod[i + 1], lod[i + 1] - lod[i]]) [in_end - lod[i + 1], lod[i + 1] - lod[i]])
if self.padding_trainable: if self.padding_trainable:
sub_w = w[begin_pad + self.context_start + j - pad_size: sub_w = pading_data[begin_pad + self.context_start + j -
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. out[lod[i + 1] - pad_size:lod[i + 1], j * self.
input_size[1]:(j + 1) * self.input_size[1]] = sub_w input_size[1]:(j + 1) * self.input_size[1]] = sub_w
in_end = lod[i + 1] in_end = lod[i + 1]
...@@ -75,8 +84,9 @@ class TestSeqProject(OpTest): ...@@ -75,8 +84,9 @@ class TestSeqProject(OpTest):
self.check_output() self.check_output()
def test_check_grad(self): def test_check_grad(self):
self.check_grad( if self.padding_trainable:
set(['X', 'PaddingData']), 'Out', max_relative_error=0.05) self.check_grad(
set(['X', 'PaddingData']), 'Out', max_relative_error=0.05)
def test_check_grad_no_filter(self): def test_check_grad_no_filter(self):
self.check_grad( self.check_grad(
...@@ -86,12 +96,26 @@ class TestSeqProject(OpTest): ...@@ -86,12 +96,26 @@ class TestSeqProject(OpTest):
no_grad_set=set(['PaddingData'])) no_grad_set=set(['PaddingData']))
def test_check_grad_no_input(self): def test_check_grad_no_input(self):
self.check_grad( if self.padding_trainable:
['PaddingData'], self.check_grad(
'Out', ['PaddingData'],
max_relative_error=0.05, 'Out',
no_grad_set=set(['X'])) 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): def init_test_case(self):
self.op_type = "sequence_project" self.op_type = "sequence_project"
self.input_row = 11 self.input_row = 11
...@@ -104,7 +128,7 @@ class TestSeqProject(OpTest): ...@@ -104,7 +128,7 @@ class TestSeqProject(OpTest):
self.lod = [[0, 4, 5, 8, self.input_row]] self.lod = [[0, 4, 5, 8, self.input_row]]
class TestSeqProjectCase1(TestSeqProject): class TestSeqProjectCase2(TestSeqProject):
def init_test_case(self): def init_test_case(self):
self.op_type = "sequence_project" self.op_type = "sequence_project"
self.input_row = 25 self.input_row = 25
...@@ -151,21 +175,17 @@ class TestSeqProjectCases(TestSeqProject): ...@@ -151,21 +175,17 @@ class TestSeqProjectCases(TestSeqProject):
] ]
self.begin_pad = np.max([0, -self.context_start]) self.begin_pad = np.max([0, -self.context_start])
self.end_pad = np.max( self.end_pad = np.max([0, self.context_start + self.context_length - 1])
[0, self.context_start + self.context_length - 1])
self.total_pad = self.begin_pad + self.end_pad self.total_pad = self.begin_pad + self.end_pad
# w = np.ones((self.total_pad, self.input_size[1])) * 100 if self.total_pad == 0:
w = np.array(range(self.total_pad * self.input_size[1]))
w.shape = self.total_pad, self.input_size[1]
if self.total_pad * self.input_size[1] == 0:
w = np.random.uniform(
0.1, 1,
(1, self.input_size[1])).astype('float32')
self.total_pad = 1 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 = { self.inputs = {
'X': (x, self.lod), 'X': (x, self.lod),
'PaddingData': (w, [[0, self.total_pad]]) 'PaddingData': (padding_data, [[0, self.total_pad]])
} }
self.attrs = { self.attrs = {
'context_start': self.context_start, 'context_start': self.context_start,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册