Skip to content

Commit 869a6f9

Browse files
committed
Add python wrapper.
1 parent ea788fc commit 869a6f9

File tree

3 files changed

+155
-15
lines changed

3 files changed

+155
-15
lines changed

paddle/fluid/operators/lod_reset_op.cc

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class LoDResetOp : public framework::OperatorWithKernel {
3030
if (!ctx->HasInput("Y")) {
3131
auto level0 = ctx->Attrs().Get<std::vector<int>>("target_lod");
3232
PADDLE_ENFORCE_GT(level0.size(), 1,
33-
"If Input(Y) is not provided, the target lod should be "
33+
"If Input(Y) not provided, the target lod should be "
3434
"specified by attribute `target_lod`.");
3535
}
3636
ctx->SetOutputDim("Out", ctx->GetInputDim("X"));
@@ -54,9 +54,10 @@ class LoDResetOpMaker : public framework::OpProtoAndCheckerMaker {
5454
"could be a Tensor or LoDTensor, where the data of output "
5555
"variable inherits from.");
5656
AddInput("Y",
57-
"(Tensor, LoDTensor, optional) If provided, lod of Input(Y) would "
58-
"be considered as the target lod first, otherwise data of "
59-
"Input(Y) would be considered as the target lod.")
57+
"(Tensor, LoDTensor, optional) If provided and Y is LoDTensor, "
58+
"lod of Input(Y) would be considered as the target lod first, "
59+
"otherwise data of Input(Y) would be considered as the "
60+
"target lod.")
6061
.AsDispensable();
6162
AddOutput("Out",
6263
"(LoDTensor) Output variable of LoDResetOp which should be a "
@@ -67,25 +68,59 @@ class LoDResetOpMaker : public framework::OpProtoAndCheckerMaker {
6768
AddComment(R"DOC(LoDReset operator
6869
6970
Set LoD of `X` to a new one specified by `Y` or attribute `target_lod`. When `Y`
70-
provided, `Y.lod` would be considered as target LoD first, otherwise `Y.data`
71-
would be considered as target LoD. If `Y` is not provided, target LoD should be
72-
specified by attribute `target_lod`. If target LoD is specified by `Y.data` or
73-
`target_lod`, only one level LoD is supported.
71+
provided and `Y` is a LoDTensor, `Y.lod` would be considered as target LoD
72+
first, otherwise `Y.data` would be considered as target LoD. If `Y` is not
73+
provided, target LoD should be specified by attribute `target_lod`.
74+
If target LoD is specified by `Y.data` or `target_lod`, only one level LoD
75+
is supported.
7476
75-
An example:
77+
Example 1:
7678
77-
Given a 1-level LoDTensor input(X)
78-
X.lod = [[ 0, 2, 5 6 ]]
79+
Given a 1-level LoDTensor input(X):
80+
X.lod = [[ 0, 2, 5 6 ]]
7981
X.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]]
8082
X.dims = [6, 1]
8183
82-
target_lod: [0, 4, 6]
84+
attr(target_lod): [0, 4, 6]
8385
84-
then we get an 1-level LoDTensor
86+
then we get a 1-level LoDTensor:
8587
Out.lod = [[ 0, 4, 6 ]]
8688
Out.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]]
8789
Out.dims = [6, 1]
8890
91+
Example 2:
92+
93+
Given a 1-level LoDTensor input(X):
94+
X.lod = [[ 0, 2, 5 6 ]]
95+
X.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]]
96+
X.dims = [6, 1]
97+
98+
input(Y) is a Tensor:
99+
Y.data = [[0, 2, 6]]
100+
Y.dims = [1, 3]
101+
102+
then we get a 1-level LoDTensor:
103+
Out.lod = [[ 0, 2, 6 ]]
104+
Out.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]]
105+
Out.dims = [6, 1]
106+
107+
Example 3:
108+
109+
Given a 1-level LoDTensor input(X):
110+
X.lod = [[ 0, 2, 5 6 ]]
111+
X.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]]
112+
X.dims = [6, 1]
113+
114+
input(Y) is a 2-level LoDTensor:
115+
Y.lod = [[0, 2, 4], [0, 2, 5, 6]]
116+
Y.data = [[1.1], [2.1], [3.1], [4.1], [5.1], [6.1]]
117+
Y.dims = [6, 1]
118+
119+
then we get a 2-level LoDTensor:
120+
Out.lod = [[0, 2, 4], [0, 2, 5, 6]]
121+
Out.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]]
122+
Out.dims = [6, 1]
123+
89124
)DOC");
90125
}
91126
};

python/paddle/fluid/layers/nn.py

Lines changed: 98 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
'smooth_l1',
7474
'one_hot',
7575
'autoincreased_step_counter',
76+
'lod_reset',
7677
]
7778

7879

@@ -2225,7 +2226,7 @@ def reduce_prod(input, dim=None, keep_dim=False, name=None):
22252226
keep_dim (bool|False): Whether to reserve the reduced dimension in the
22262227
output Tensor. The result tensor will have one fewer dimension
22272228
than the :attr:`input` unless :attr:`keep_dim` is true.
2228-
name(str|None): A name for this layer(optional). If set None, the
2229+
name(str|None): A name for this layer(optional). If set None, the
22292230
layer will be named automatically.
22302231
22312232
Returns:
@@ -2241,7 +2242,7 @@ def reduce_prod(input, dim=None, keep_dim=False, name=None):
22412242
fluid.layers.reduce_prod(x) # [0.0002268]
22422243
fluid.layers.reduce_prod(x, dim=0) # [0.02, 0.06, 0.3, 0.63]
22432244
fluid.layers.reduce_prod(x, dim=-1) # [0.027, 0.0084]
2244-
fluid.layers.reduce_prod(x, dim=1,
2245+
fluid.layers.reduce_prod(x, dim=1,
22452246
keep_dim=True) # [[0.027], [0.0084]]
22462247
"""
22472248
helper = LayerHelper('reduce_prod', **locals())
@@ -3292,3 +3293,98 @@ def autoincreased_step_counter(counter_name=None, begin=1, step=1):
32923293
counter.stop_gradient = True
32933294

32943295
return counter
3296+
3297+
3298+
def lod_reset(x, y, target_lod=None):
3299+
"""
3300+
LoD Reset Operator. Set LoD of **x** to a new one specified by **y** or
3301+
**target_lod**. When **y** provided, **y.lod** would be considered as target
3302+
LoD first, otherwise **y.data** would be considered as target LoD. If **y**
3303+
is not provided, target LoD should be specified by **target_lod**.
3304+
If target LoD is specified by **Y.data** or **target_lod**, only one level
3305+
LoD is supported.
3306+
3307+
.. code-block:: text
3308+
3309+
* Example 1:
3310+
3311+
Given a 1-level LoDTensor x:
3312+
x.lod = [[ 0, 2, 5 6 ]]
3313+
x.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]]
3314+
x.dims = [6, 1]
3315+
3316+
target_lod: [0, 4, 6]
3317+
3318+
then we get a 1-level LoDTensor:
3319+
out.lod = [[ 0, 4, 6 ]]
3320+
out.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]]
3321+
out.dims = [6, 1]
3322+
3323+
* Example 2:
3324+
3325+
Given a 1-level LoDTensor x:
3326+
x.lod = [[ 0, 2, 5 6 ]]
3327+
x.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]]
3328+
x.dims = [6, 1]
3329+
3330+
y is a Tensor:
3331+
y.data = [[0, 2, 6]]
3332+
y.dims = [1, 3]
3333+
3334+
then we get a 1-level LoDTensor:
3335+
out.lod = [[ 0, 2, 6 ]]
3336+
out.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]]
3337+
out.dims = [6, 1]
3338+
3339+
* Example 3:
3340+
3341+
Given a 1-level LoDTensor x:
3342+
x.lod = [[ 0, 2, 5 6 ]]
3343+
x.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]]
3344+
x.dims = [6, 1]
3345+
3346+
y is a 2-level LoDTensor:
3347+
y.lod = [[0, 2, 4], [0, 2, 5, 6]]
3348+
y.data = [[1.1], [2.1], [3.1], [4.1], [5.1], [6.1]]
3349+
y.dims = [6, 1]
3350+
3351+
then we get a 2-level LoDTensor:
3352+
out.lod = [[0, 2, 4], [0, 2, 5, 6]]
3353+
out.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]]
3354+
out.dims = [6, 1]
3355+
3356+
Args:
3357+
x (Variable): Input variable which could be a Tensor or LodTensor.
3358+
y (Variable|None): If provided, output's LoD would be derived from y.
3359+
target_lod (list|tuple|None): One level LoD which should be considered
3360+
as target LoD when y not provided.
3361+
3362+
Returns:
3363+
Variable: Output variable with LoD specified by this operator.
3364+
3365+
Raises:
3366+
ValueError: If y and target_lod are both None.
3367+
3368+
Examples:
3369+
.. code-block:: python
3370+
3371+
x = layers.data(name='x', shape=[10])
3372+
y = layers.data(name='y', shape=[10, 20], lod_level=2)
3373+
out = layers.lod_reset(x=x, y=y)
3374+
"""
3375+
helper = LayerHelper("lod_reset", **locals())
3376+
out = helper.create_tmp_variable(dtype=x.dtype)
3377+
if y is not None:
3378+
helper.append_op(
3379+
type="lod_reset", inputs={'X': x,
3380+
'Y': y}, outputs={'Out': out})
3381+
elif target_lod is not None:
3382+
helper.append_op(
3383+
type="lod_reset",
3384+
inputs={'X': x},
3385+
attrs={'target_lod': target_lod},
3386+
outputs={'Out': out})
3387+
else:
3388+
raise ValueError("y and target_lod should not be both None.")
3389+
3390+
return out

python/paddle/fluid/tests/unittests/test_layers.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,15 @@ def test_smooth_l1(self):
327327
self.assertIsNotNone(loss)
328328
print(str(program))
329329

330+
def test_lod_reset(self):
331+
program = Program()
332+
with program_guard(program):
333+
x = layers.data(name='x', shape=[10], dtype='float32')
334+
y = layers.data(
335+
name='y', shape=[10, 20], dtype='float32', lod_level=2)
336+
print(layers.lod_reset(x=x, y=y))
337+
print(str(program))
338+
330339

331340
if __name__ == '__main__':
332341
unittest.main()

0 commit comments

Comments
 (0)