提交 869a6f9c 编写于 作者: Y yangyaming

Add python wrapper.

上级 ea788fc5
...@@ -30,7 +30,7 @@ class LoDResetOp : public framework::OperatorWithKernel { ...@@ -30,7 +30,7 @@ class LoDResetOp : public framework::OperatorWithKernel {
if (!ctx->HasInput("Y")) { if (!ctx->HasInput("Y")) {
auto level0 = ctx->Attrs().Get<std::vector<int>>("target_lod"); auto level0 = ctx->Attrs().Get<std::vector<int>>("target_lod");
PADDLE_ENFORCE_GT(level0.size(), 1, PADDLE_ENFORCE_GT(level0.size(), 1,
"If Input(Y) is not provided, the target lod should be " "If Input(Y) not provided, the target lod should be "
"specified by attribute `target_lod`."); "specified by attribute `target_lod`.");
} }
ctx->SetOutputDim("Out", ctx->GetInputDim("X")); ctx->SetOutputDim("Out", ctx->GetInputDim("X"));
...@@ -54,9 +54,10 @@ class LoDResetOpMaker : public framework::OpProtoAndCheckerMaker { ...@@ -54,9 +54,10 @@ class LoDResetOpMaker : public framework::OpProtoAndCheckerMaker {
"could be a Tensor or LoDTensor, where the data of output " "could be a Tensor or LoDTensor, where the data of output "
"variable inherits from."); "variable inherits from.");
AddInput("Y", AddInput("Y",
"(Tensor, LoDTensor, optional) If provided, lod of Input(Y) would " "(Tensor, LoDTensor, optional) If provided and Y is LoDTensor, "
"be considered as the target lod first, otherwise data of " "lod of Input(Y) would be considered as the target lod first, "
"Input(Y) would be considered as the target lod.") "otherwise data of Input(Y) would be considered as the "
"target lod.")
.AsDispensable(); .AsDispensable();
AddOutput("Out", AddOutput("Out",
"(LoDTensor) Output variable of LoDResetOp which should be a " "(LoDTensor) Output variable of LoDResetOp which should be a "
...@@ -67,25 +68,59 @@ class LoDResetOpMaker : public framework::OpProtoAndCheckerMaker { ...@@ -67,25 +68,59 @@ class LoDResetOpMaker : public framework::OpProtoAndCheckerMaker {
AddComment(R"DOC(LoDReset operator AddComment(R"DOC(LoDReset operator
Set LoD of `X` to a new one specified by `Y` or attribute `target_lod`. When `Y` Set LoD of `X` to a new one specified by `Y` or attribute `target_lod`. When `Y`
provided, `Y.lod` would be considered as target LoD first, otherwise `Y.data` provided and `Y` is a LoDTensor, `Y.lod` would be considered as target LoD
would be considered as target LoD. If `Y` is not provided, target LoD should be first, otherwise `Y.data` would be considered as target LoD. If `Y` is not
specified by attribute `target_lod`. If target LoD is specified by `Y.data` or provided, target LoD should be specified by attribute `target_lod`.
`target_lod`, only one level LoD is supported. If target LoD is specified by `Y.data` or `target_lod`, only one level LoD
is supported.
An example: Example 1:
Given a 1-level LoDTensor input(X) Given a 1-level LoDTensor input(X):
X.lod = [[ 0, 2, 5 6 ]] X.lod = [[ 0, 2, 5 6 ]]
X.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]] X.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]]
X.dims = [6, 1] X.dims = [6, 1]
target_lod: [0, 4, 6] attr(target_lod): [0, 4, 6]
then we get an 1-level LoDTensor then we get a 1-level LoDTensor:
Out.lod = [[ 0, 4, 6 ]] Out.lod = [[ 0, 4, 6 ]]
Out.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]] Out.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]]
Out.dims = [6, 1] Out.dims = [6, 1]
Example 2:
Given a 1-level LoDTensor input(X):
X.lod = [[ 0, 2, 5 6 ]]
X.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]]
X.dims = [6, 1]
input(Y) is a Tensor:
Y.data = [[0, 2, 6]]
Y.dims = [1, 3]
then we get a 1-level LoDTensor:
Out.lod = [[ 0, 2, 6 ]]
Out.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]]
Out.dims = [6, 1]
Example 3:
Given a 1-level LoDTensor input(X):
X.lod = [[ 0, 2, 5 6 ]]
X.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]]
X.dims = [6, 1]
input(Y) is a 2-level LoDTensor:
Y.lod = [[0, 2, 4], [0, 2, 5, 6]]
Y.data = [[1.1], [2.1], [3.1], [4.1], [5.1], [6.1]]
Y.dims = [6, 1]
then we get a 2-level LoDTensor:
Out.lod = [[0, 2, 4], [0, 2, 5, 6]]
Out.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]]
Out.dims = [6, 1]
)DOC"); )DOC");
} }
}; };
......
...@@ -73,6 +73,7 @@ __all__ = [ ...@@ -73,6 +73,7 @@ __all__ = [
'smooth_l1', 'smooth_l1',
'one_hot', 'one_hot',
'autoincreased_step_counter', 'autoincreased_step_counter',
'lod_reset',
] ]
...@@ -2225,7 +2226,7 @@ def reduce_prod(input, dim=None, keep_dim=False, name=None): ...@@ -2225,7 +2226,7 @@ def reduce_prod(input, dim=None, keep_dim=False, name=None):
keep_dim (bool|False): Whether to reserve the reduced dimension in the keep_dim (bool|False): Whether to reserve the reduced dimension in the
output Tensor. The result tensor will have one fewer dimension output Tensor. The result tensor will have one fewer dimension
than the :attr:`input` unless :attr:`keep_dim` is true. than the :attr:`input` unless :attr:`keep_dim` is true.
name(str|None): A name for this layer(optional). If set None, the name(str|None): A name for this layer(optional). If set None, the
layer will be named automatically. layer will be named automatically.
Returns: Returns:
...@@ -2241,7 +2242,7 @@ def reduce_prod(input, dim=None, keep_dim=False, name=None): ...@@ -2241,7 +2242,7 @@ def reduce_prod(input, dim=None, keep_dim=False, name=None):
fluid.layers.reduce_prod(x) # [0.0002268] fluid.layers.reduce_prod(x) # [0.0002268]
fluid.layers.reduce_prod(x, dim=0) # [0.02, 0.06, 0.3, 0.63] fluid.layers.reduce_prod(x, dim=0) # [0.02, 0.06, 0.3, 0.63]
fluid.layers.reduce_prod(x, dim=-1) # [0.027, 0.0084] fluid.layers.reduce_prod(x, dim=-1) # [0.027, 0.0084]
fluid.layers.reduce_prod(x, dim=1, fluid.layers.reduce_prod(x, dim=1,
keep_dim=True) # [[0.027], [0.0084]] keep_dim=True) # [[0.027], [0.0084]]
""" """
helper = LayerHelper('reduce_prod', **locals()) helper = LayerHelper('reduce_prod', **locals())
...@@ -3292,3 +3293,98 @@ def autoincreased_step_counter(counter_name=None, begin=1, step=1): ...@@ -3292,3 +3293,98 @@ def autoincreased_step_counter(counter_name=None, begin=1, step=1):
counter.stop_gradient = True counter.stop_gradient = True
return counter return counter
def lod_reset(x, y, target_lod=None):
"""
LoD Reset Operator. Set LoD of **x** to a new one specified by **y** or
**target_lod**. When **y** provided, **y.lod** would be considered as target
LoD first, otherwise **y.data** would be considered as target LoD. If **y**
is not provided, target LoD should be specified by **target_lod**.
If target LoD is specified by **Y.data** or **target_lod**, only one level
LoD is supported.
.. code-block:: text
* Example 1:
Given a 1-level LoDTensor x:
x.lod = [[ 0, 2, 5 6 ]]
x.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]]
x.dims = [6, 1]
target_lod: [0, 4, 6]
then we get a 1-level LoDTensor:
out.lod = [[ 0, 4, 6 ]]
out.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]]
out.dims = [6, 1]
* Example 2:
Given a 1-level LoDTensor x:
x.lod = [[ 0, 2, 5 6 ]]
x.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]]
x.dims = [6, 1]
y is a Tensor:
y.data = [[0, 2, 6]]
y.dims = [1, 3]
then we get a 1-level LoDTensor:
out.lod = [[ 0, 2, 6 ]]
out.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]]
out.dims = [6, 1]
* Example 3:
Given a 1-level LoDTensor x:
x.lod = [[ 0, 2, 5 6 ]]
x.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]]
x.dims = [6, 1]
y is a 2-level LoDTensor:
y.lod = [[0, 2, 4], [0, 2, 5, 6]]
y.data = [[1.1], [2.1], [3.1], [4.1], [5.1], [6.1]]
y.dims = [6, 1]
then we get a 2-level LoDTensor:
out.lod = [[0, 2, 4], [0, 2, 5, 6]]
out.data = [[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]]
out.dims = [6, 1]
Args:
x (Variable): Input variable which could be a Tensor or LodTensor.
y (Variable|None): If provided, output's LoD would be derived from y.
target_lod (list|tuple|None): One level LoD which should be considered
as target LoD when y not provided.
Returns:
Variable: Output variable with LoD specified by this operator.
Raises:
ValueError: If y and target_lod are both None.
Examples:
.. code-block:: python
x = layers.data(name='x', shape=[10])
y = layers.data(name='y', shape=[10, 20], lod_level=2)
out = layers.lod_reset(x=x, y=y)
"""
helper = LayerHelper("lod_reset", **locals())
out = helper.create_tmp_variable(dtype=x.dtype)
if y is not None:
helper.append_op(
type="lod_reset", inputs={'X': x,
'Y': y}, outputs={'Out': out})
elif target_lod is not None:
helper.append_op(
type="lod_reset",
inputs={'X': x},
attrs={'target_lod': target_lod},
outputs={'Out': out})
else:
raise ValueError("y and target_lod should not be both None.")
return out
...@@ -327,6 +327,15 @@ class TestBook(unittest.TestCase): ...@@ -327,6 +327,15 @@ class TestBook(unittest.TestCase):
self.assertIsNotNone(loss) self.assertIsNotNone(loss)
print(str(program)) print(str(program))
def test_lod_reset(self):
program = Program()
with program_guard(program):
x = layers.data(name='x', shape=[10], dtype='float32')
y = layers.data(
name='y', shape=[10, 20], dtype='float32', lod_level=2)
print(layers.lod_reset(x=x, y=y))
print(str(program))
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册