From ce1f410100cb16e69c0f3826ef5fa80217047cbf Mon Sep 17 00:00:00 2001 From: xiongkun Date: Fri, 12 Aug 2022 06:07:44 +0000 Subject: [PATCH 1/2] while support for python container. It is convenient to convert more dynamic graph codes into static graphs. --- paddle/phi/core/dense_tensor_impl.cc | 2 +- .../fluid/dygraph/dygraph_to_static/convert_operators.py | 5 ++++- .../fluid/dygraph/dygraph_to_static/variable_trans_func.py | 6 +++++- python/paddle/fluid/layers/control_flow.py | 7 +++++-- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/paddle/phi/core/dense_tensor_impl.cc b/paddle/phi/core/dense_tensor_impl.cc index bc05ade76ea5d..9d7b369b3ecc5 100644 --- a/paddle/phi/core/dense_tensor_impl.cc +++ b/paddle/phi/core/dense_tensor_impl.cc @@ -53,7 +53,7 @@ void DenseTensor::check_memory_size() const { "Tensor's dimension is out of bound." "Tensor's dimension must be equal or less than the size of its " "memory." - "But received Tensor's dimension is d%, memory's size is %d.", + "But received Tensor's dimension is %d, memory's size is %d.", numel() * SizeOf(dtype()), memory_size())); } diff --git a/python/paddle/fluid/dygraph/dygraph_to_static/convert_operators.py b/python/paddle/fluid/dygraph/dygraph_to_static/convert_operators.py index b78b5957393a3..092e778a1e052 100644 --- a/python/paddle/fluid/dygraph/dygraph_to_static/convert_operators.py +++ b/python/paddle/fluid/dygraph/dygraph_to_static/convert_operators.py @@ -92,7 +92,10 @@ def _run_paddle_while(cond, body, getter, setter): # NOTE: loop_vars of Paddle op `control_flow.while_loop` must be Paddle Tensors. def new_body_fn(*args): """ wrap the body() and add return value for `while_loop` + the args may be differ from getter(). """ + mutable_loop_vars = args + setter(mutable_loop_vars) body() return getter() @@ -110,7 +113,7 @@ def new_cond_fn(*args): setter(loop_vars) # change the non-local var to variable # variable maybe modified to inner var. change it into loop_vars = control_flow.while_loop(new_cond_fn, new_body_fn, loop_vars) - setter(loop_vars) # change the non-local var to variable + setter(loop_vars) # change back to loop_vars return loop_vars diff --git a/python/paddle/fluid/dygraph/dygraph_to_static/variable_trans_func.py b/python/paddle/fluid/dygraph/dygraph_to_static/variable_trans_func.py index 5593658ee6232..fec231d548524 100644 --- a/python/paddle/fluid/dygraph/dygraph_to_static/variable_trans_func.py +++ b/python/paddle/fluid/dygraph/dygraph_to_static/variable_trans_func.py @@ -21,6 +21,7 @@ from paddle.fluid import unique_name from paddle.fluid.framework import Variable from paddle.fluid.dygraph.dygraph_to_static.utils import UndefinedVar, create_undefined_variable +from paddle.fluid.layers.utils import map_structure, is_sequence __all__ = [ 'create_bool_as_type', @@ -63,9 +64,12 @@ def to_static_variable(x): if isinstance(x, six.integer_types): return paddle.full(shape=[1], dtype='int64', fill_value=x) if isinstance(x, UndefinedVar) or x is None: - """ for early return case, we need a variable to represent None, current we use data_layer_not_check. + """ + for early return case, we need a variable to represent None, current we use data_layer_not_check. """ return create_undefined_variable() + if is_sequence(x): + return map_structure(to_static_variable, x) return x diff --git a/python/paddle/fluid/layers/control_flow.py b/python/paddle/fluid/layers/control_flow.py index d7b859612473f..e10fabacee044 100755 --- a/python/paddle/fluid/layers/control_flow.py +++ b/python/paddle/fluid/layers/control_flow.py @@ -1327,8 +1327,11 @@ def create_var_like(o_var): if isinstance(o_var, (Variable, ) + support_ret_buildin_type) or o_var is None: return create_undefined_variable() - if isinstance(o_var, (tuple, list)): - return [create_undefined_variable() for i in range(len(o_var))] + if is_sequence(o_var): + """ + Create a complex container class inside the body of while, including Python list and python Dict + """ + return map_structure(lambda x: create_undefined_variable(), o_var) if len(output_vars) != len(loop_vars): raise ValueError("The length of loop_vars should be the same.") From 29a31cadb00d1eb77c15820851b8c35f13c71024 Mon Sep 17 00:00:00 2001 From: xiongkun Date: Fri, 12 Aug 2022 15:44:59 +0000 Subject: [PATCH 2/2] cond support python container --- .../fluid/dygraph/dygraph_to_static/convert_operators.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/python/paddle/fluid/dygraph/dygraph_to_static/convert_operators.py b/python/paddle/fluid/dygraph/dygraph_to_static/convert_operators.py index 092e778a1e052..56babcec87a30 100644 --- a/python/paddle/fluid/dygraph/dygraph_to_static/convert_operators.py +++ b/python/paddle/fluid/dygraph/dygraph_to_static/convert_operators.py @@ -25,6 +25,7 @@ from paddle.fluid.layers.control_flow import cond, while_loop, less_than, increment from paddle.fluid.dygraph.dygraph_to_static.return_transformer import RETURN_NO_VALUE_VAR_NAME from paddle.fluid.dygraph.dygraph_to_static.utils import UndefinedVar, Dygraph2StaticException +from paddle.fluid.layers.utils import copy_mutable_vars def indexable(x, code=None): @@ -290,7 +291,8 @@ def _run_paddle_cond(pred, true_fn, false_fn, get_args, set_args, init_args = get_args() def new_true_fn(): - set_args(init_args) + #init args may contain mutable python container like [var, 2], we copy then like in while_loop + set_args(copy_mutable_vars(init_args)) ret = true_fn() # IfExpr will return a non-None return value, so we just return ret. # We assume normal return has no return value. @@ -298,7 +300,8 @@ def new_true_fn(): else: return ret def new_false_fn(): - set_args(init_args) + #init args may contain mutable python container like [var, 2], we copy then like in while_loop + set_args(copy_mutable_vars(init_args)) ret = false_fn() if ret is None: return get_args() else: return ret