Skip to content

Commit b698d19

Browse files
authored
Add grad for lodtensor array ops (#5461)
* Add LoDRankTable LoD Rank Table stores the `level` of `lod` which is ordered by sequence length in descending order. It is useful when implement dynamic RNN and is shared by dynamic RNN memory, dynamic RNN slice input and dynamic RNN slice output operators. * Add skeleton for array_to_lod_tensor and lod_tensor_to_array * Add VarType::LoDTensorArray * Add PyBind of LoDTensorArray * Add InferVarType * Add first unittest * Add ut * Add unittest * Add unittest * Add unittests * update * init * add infershape for lod_tensor_to_array_op * compelete array_to_lod_tensor_op * copy data * clean code * clean code * Fix unittest data * fix bugs * fix compile error * Refine TensorToArrayOp * refactor array_to_lod_tensor * Unittest * fix bugs * Fix unittest * Fix unittest * debug * Debug * Fix unittest * Add grad for ops * Debug * Fix a bug * fix a bug * fix a bug
1 parent b266f50 commit b698d19

File tree

5 files changed

+85
-5
lines changed

5 files changed

+85
-5
lines changed

paddle/operators/array_to_lod_tensor_op.cc

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,23 @@ class ArrayToLoDTensorInferShape : public framework::InferShapeBase {
140140
"ArrayToLoDTensorOp must has input X.");
141141
PADDLE_ENFORCE(context->HasInput("RankTable"),
142142
"ArrayToLoDTensorOp must has input RankTable.");
143+
context->SetOutputDim("Out", context->GetInputDim("X"));
144+
}
145+
};
146+
147+
class ArrayToLoDTensorGradMaker : public framework::SingleGradOpDescMaker {
148+
public:
149+
using framework::SingleGradOpDescMaker::SingleGradOpDescMaker;
150+
151+
protected:
152+
std::unique_ptr<framework::OpDescBind> Apply() const override {
153+
auto *grad_op = new framework::OpDescBind();
154+
grad_op->SetType("lod_tensor_to_array");
155+
grad_op->SetInput("X", OutputGrad("Out"));
156+
grad_op->SetInput("RankTable", Input("RankTable"));
157+
grad_op->SetOutput("Out", InputGrad("X"));
158+
grad_op->SetAttrMap(Attrs());
159+
return std::unique_ptr<framework::OpDescBind>(grad_op);
143160
}
144161
};
145162

@@ -149,4 +166,5 @@ class ArrayToLoDTensorInferShape : public framework::InferShapeBase {
149166
namespace ops = paddle::operators;
150167
REGISTER_OPERATOR(array_to_lod_tensor, ops::ArrayToLoDTensorOp,
151168
ops::ArrayToLoDTensorOpProtoMaker,
152-
ops::ArrayToLoDTensorInferShape);
169+
ops::ArrayToLoDTensorInferShape,
170+
ops::ArrayToLoDTensorGradMaker);

paddle/operators/lod_tensor_to_array_op.cc

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,28 @@ class LoDTensorToArrayInferVarType : public framework::VarTypeInference {
133133
}
134134
};
135135

136+
class LoDTensorToArrayGradMaker : public framework::SingleGradOpDescMaker {
137+
public:
138+
using framework::SingleGradOpDescMaker::SingleGradOpDescMaker;
139+
140+
protected:
141+
std::unique_ptr<framework::OpDescBind> Apply() const override {
142+
auto *grad_op = new framework::OpDescBind();
143+
grad_op->SetType("array_to_lod_tensor");
144+
grad_op->SetInput("X", OutputGrad("Out"));
145+
grad_op->SetInput("RankTable", Input("RankTable"));
146+
grad_op->SetOutput("Out", InputGrad("X"));
147+
grad_op->SetAttrMap(Attrs());
148+
return std::unique_ptr<framework::OpDescBind>(grad_op);
149+
}
150+
};
151+
136152
} // namespace operators
137153
} // namespace paddle
138154

139155
namespace ops = paddle::operators;
140156
REGISTER_OPERATOR(lod_tensor_to_array, ops::LoDTensorToArrayOp,
141157
ops::LoDTensorToArrayOpProtoMaker,
142158
ops::LoDTensorToArrayInferShape,
143-
ops::LoDTensorToArrayInferVarType);
159+
ops::LoDTensorToArrayInferVarType,
160+
ops::LoDTensorToArrayGradMaker);

paddle/operators/mean_op.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class MeanGradOp : public framework::OperatorWithKernel {
5151

5252
void InferShape(framework::InferShapeContext* ctx) const override {
5353
ctx->SetOutputDim(framework::GradVarName("X"), ctx->GetInputDim("X"));
54+
ctx->ShareLoD("X", framework::GradVarName("X"));
5455
}
5556
};
5657

python/paddle/v2/framework/layers.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ def data(name,
8787
type=core.VarDesc.VarType.LOD_TENSOR,
8888
append_batch_size=True,
8989
main_program=None,
90-
startup_program=None):
90+
startup_program=None,
91+
stop_gradient=True):
9192
helper = LayerHelper('data', **locals())
9293
shape = list(shape)
9394
for i in xrange(len(shape)):
@@ -101,7 +102,11 @@ def data(name,
101102
shape = [-1] + shape # append batch size as -1
102103

103104
return helper.create_global_variable(
104-
name=name, shape=shape, dtype=data_type, type=type, stop_gradient=True)
105+
name=name,
106+
shape=shape,
107+
dtype=data_type,
108+
type=type,
109+
stop_gradient=stop_gradient)
105110

106111

107112
def _convert_(name):
@@ -845,7 +850,8 @@ def lod_tensor_to_array(x, table, main_program=None):
845850
helper = LayerHelper("lod_tensor_to_array", **locals())
846851
array = helper.create_variable(
847852
name=unique_name("lod_tensor_to_array"),
848-
type=core.VarDesc.VarType.LOD_TENSOR_ARRAY)
853+
type=core.VarDesc.VarType.LOD_TENSOR_ARRAY,
854+
dtype=x.data_type)
849855
helper.append_op(
850856
type='lod_tensor_to_array',
851857
inputs={'X': x,

python/paddle/v2/framework/tests/test_lod_tensor_array_ops.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import paddle.v2.framework.layers as layers
55
from paddle.v2.framework.framework import Program
66
from paddle.v2.framework.executor import Executor
7+
from paddle.v2.framework.backward import append_backward_ops
78

89

910
class TestCPULoDTensorArrayOps(unittest.TestCase):
@@ -123,5 +124,42 @@ def check_tensor_same(self, actual, expect):
123124
self.assertEqual(actual.lod(), expect.lod())
124125

125126

127+
class TestCPULoDTensorArrayOpGrad(unittest.TestCase):
128+
def test_grad(self):
129+
place = core.CPUPlace()
130+
program = Program()
131+
132+
x = layers.data(
133+
name='x',
134+
shape=[1],
135+
data_type='float32',
136+
main_program=program,
137+
stop_gradient=False)
138+
table = layers.lod_rank_table(x, level=0, main_program=program)
139+
array = layers.lod_tensor_to_array(x, table, main_program=program)
140+
result = layers.array_to_lod_tensor(array, table, main_program=program)
141+
142+
mean = layers.mean(x=result, main_program=program)
143+
144+
append_backward_ops(mean)
145+
146+
tensor = core.LoDTensor()
147+
tensor.set(numpy.arange(10).reshape(10, 1).astype('float32'), place)
148+
tensor.set_lod([[0, 3, 9, 10]])
149+
150+
g_vars = program.global_block().var(x.name + "@GRAD")
151+
152+
exe = Executor(place)
153+
g_out = [
154+
item.sum()
155+
for item in map(
156+
numpy.array,
157+
exe.run(program, feed={'x': tensor}, fetch_list=[g_vars]))
158+
]
159+
g_out_sum = numpy.array(g_out).sum()
160+
161+
self.assertAlmostEqual(1.0, g_out_sum, delta=0.1)
162+
163+
126164
if __name__ == '__main__':
127165
unittest.main()

0 commit comments

Comments
 (0)