From bce84423fc7d7d308499e1192ad993da6490577e Mon Sep 17 00:00:00 2001 From: SigureMo Date: Fri, 2 Dec 2022 19:17:21 +0800 Subject: [PATCH 01/13] [Dy2St] refactor convert_print to display Tensor in compile time --- python/paddle/jit/dy2static/convert_operators.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python/paddle/jit/dy2static/convert_operators.py b/python/paddle/jit/dy2static/convert_operators.py index 02cafb77bbd30a..1b1f6398e57245 100644 --- a/python/paddle/jit/dy2static/convert_operators.py +++ b/python/paddle/jit/dy2static/convert_operators.py @@ -744,11 +744,10 @@ def convert_print(*args): python function so we haven't handle sep, end, file and flush parameters of python function. """ + print(*args) for var in args: if isinstance(var, Variable): var = Print(var) - else: - print(var) def convert_pop(target, *args): From 896c6d43fa048e19da3c9ee9438785e1ea754921 Mon Sep 17 00:00:00 2001 From: SigureMo Date: Fri, 2 Dec 2022 20:21:05 +0800 Subject: [PATCH 02/13] print Variable like a Tensor --- .../paddle/jit/dy2static/convert_operators.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/python/paddle/jit/dy2static/convert_operators.py b/python/paddle/jit/dy2static/convert_operators.py index 1b1f6398e57245..a81e9b77f939bb 100644 --- a/python/paddle/jit/dy2static/convert_operators.py +++ b/python/paddle/jit/dy2static/convert_operators.py @@ -738,16 +738,27 @@ def convert_assert(cond, message=""): assert cond, message +def _variable_to_tensor_like_string(var): + return ( + f"Tensor(shape={var.shape}, dtype={var.dtype}, place={var.place()}, stop_gradient={var.stop_gradient}," + + "\n The value of the tensor is unknown in compile time.)" + ) + + def convert_print(*args): """ A function representing Python ``print`` statement. Note: this is a basic python function so we haven't handle sep, end, file and flush parameters of python function. """ - print(*args) - for var in args: - if isinstance(var, Variable): - var = Print(var) + processed_args = [] + for arg in args: + if isinstance(arg, Variable): + processed_args.append(_variable_to_tensor_like_string(arg)) + Print(arg) + else: + processed_args.append(arg) + print(*processed_args) def convert_pop(target, *args): From abf3735ec4873ff75c22a5599be260536c99c8d4 Mon Sep 17 00:00:00 2001 From: SigureMo Date: Fri, 2 Dec 2022 20:24:01 +0800 Subject: [PATCH 03/13] remove python2 print statement handling --- python/paddle/jit/dy2static/print_transformer.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/python/paddle/jit/dy2static/print_transformer.py b/python/paddle/jit/dy2static/print_transformer.py index aa4bc2c219bbce..1e5286fab057ad 100644 --- a/python/paddle/jit/dy2static/print_transformer.py +++ b/python/paddle/jit/dy2static/print_transformer.py @@ -43,17 +43,11 @@ def __init__(self, wrapper_root): def transform(self): self.visit(self.root) - # NOTE: deal with print in PY3 def visit_Call(self, node): if isinstance(node.func, gast.Name) and node.func.id == 'print': node = self._create_print_node(node.args) return node - # NOTE: deal with print in PY2 - def visit_Print(self, node): - convert_print_node = self._create_print_node(node.values) - return gast.Expr(value=convert_print_node) - def _create_print_node(self, print_args): convert_print_func = gast.parse('_jst.Print').body[0].value return gast.Call(func=convert_print_func, args=print_args, keywords=[]) From d99717da95efcdd231b300478d928cfe61bf3251 Mon Sep 17 00:00:00 2001 From: SigureMo Date: Fri, 2 Dec 2022 20:34:42 +0800 Subject: [PATCH 04/13] remove PrintTransformer --- .../paddle/jit/dy2static/ast_transformer.py | 4 -- .../paddle/jit/dy2static/convert_call_func.py | 4 ++ .../paddle/jit/dy2static/print_transformer.py | 53 ------------------- 3 files changed, 4 insertions(+), 57 deletions(-) delete mode 100644 python/paddle/jit/dy2static/print_transformer.py diff --git a/python/paddle/jit/dy2static/ast_transformer.py b/python/paddle/jit/dy2static/ast_transformer.py index 2e244d6f341833..102ace16db6ece 100644 --- a/python/paddle/jit/dy2static/ast_transformer.py +++ b/python/paddle/jit/dy2static/ast_transformer.py @@ -52,9 +52,6 @@ from .loop_transformer import ( LoopTransformer, ) -from .print_transformer import ( - PrintTransformer, -) from .return_transformer import ( ReturnTransformer, ) @@ -135,7 +132,6 @@ def transfer_from_node_type(self, node_wrapper): LoopTransformer, # for/while -> while_op IfElseTransformer, # if/else -> cond_op AssertTransformer, # assert statement - PrintTransformer, # print statement CallTransformer, # transform call recursively CastTransformer, # type casting statement DecoratorTransformer, # transform decorators to function call diff --git a/python/paddle/jit/dy2static/convert_call_func.py b/python/paddle/jit/dy2static/convert_call_func.py index e0f393028cfac4..2f24bbf4cee7cd 100644 --- a/python/paddle/jit/dy2static/convert_call_func.py +++ b/python/paddle/jit/dy2static/convert_call_func.py @@ -30,6 +30,7 @@ convert_zip, convert_range, convert_enumerate, + convert_print, ) from paddle.jit.dy2static.logging_utils import ( @@ -215,6 +216,9 @@ def dyfunc(x): if is_builtin(func, "enumerate"): return convert_enumerate + if is_builtin(print, "print"): + return convert_print + if is_builtin(func) or is_unsupported(func): return func diff --git a/python/paddle/jit/dy2static/print_transformer.py b/python/paddle/jit/dy2static/print_transformer.py deleted file mode 100644 index 1e5286fab057ad..00000000000000 --- a/python/paddle/jit/dy2static/print_transformer.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from paddle.utils import gast - -from paddle.jit.dy2static.static_analysis import ( - AstNodeWrapper, - StaticAnalysisVisitor, -) -from .base_transformer import ( - BaseTransformer, -) - - -class PrintTransformer(BaseTransformer): - """ - This class transforms python print function to fluid.layers.Print. - """ - - def __init__(self, wrapper_root): - assert isinstance( - wrapper_root, AstNodeWrapper - ), "Input non-AstNodeWrapper node for the initialization of PrintTransformer." - self.wrapper_root = wrapper_root - self.root = wrapper_root.node - - self.static_analysis_visitor = StaticAnalysisVisitor(self.root) - self.node_to_wrapper_map = ( - self.static_analysis_visitor.get_node_to_wrapper_map() - ) - - def transform(self): - self.visit(self.root) - - def visit_Call(self, node): - if isinstance(node.func, gast.Name) and node.func.id == 'print': - node = self._create_print_node(node.args) - return node - - def _create_print_node(self, print_args): - convert_print_func = gast.parse('_jst.Print').body[0].value - return gast.Call(func=convert_print_func, args=print_args, keywords=[]) From 8a9a55b9fadaffe7ed6bf79023c24d526d175bb2 Mon Sep 17 00:00:00 2001 From: SigureMo Date: Fri, 2 Dec 2022 20:48:41 +0800 Subject: [PATCH 05/13] add print to need_convert_builtin_func_list --- python/paddle/jit/dy2static/call_transformer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python/paddle/jit/dy2static/call_transformer.py b/python/paddle/jit/dy2static/call_transformer.py index 11f0f6624e8fed..c5ae35ee3d4ac1 100644 --- a/python/paddle/jit/dy2static/call_transformer.py +++ b/python/paddle/jit/dy2static/call_transformer.py @@ -60,6 +60,7 @@ def _no_need_convert_call(self, node): 'zip', 'range', 'enumerate', + 'print', } is_builtin = eval("is_builtin({})".format(func_str)) need_convert = func_str in need_convert_builtin_func_list From 7e6d0d7c96582e6e28916a17e9ab5a5ceb4bcce3 Mon Sep 17 00:00:00 2001 From: SigureMo Date: Fri, 2 Dec 2022 21:04:55 +0800 Subject: [PATCH 06/13] add kwargs support --- python/paddle/jit/dy2static/convert_operators.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/python/paddle/jit/dy2static/convert_operators.py b/python/paddle/jit/dy2static/convert_operators.py index a81e9b77f939bb..c502f89fcb824c 100644 --- a/python/paddle/jit/dy2static/convert_operators.py +++ b/python/paddle/jit/dy2static/convert_operators.py @@ -745,20 +745,20 @@ def _variable_to_tensor_like_string(var): ) -def convert_print(*args): +def convert_print(*objects, sep=' ', end='\n', file=None, flush=False): """ A function representing Python ``print`` statement. Note: this is a basic python function so we haven't handle sep, end, file and flush parameters of python function. """ - processed_args = [] - for arg in args: - if isinstance(arg, Variable): - processed_args.append(_variable_to_tensor_like_string(arg)) - Print(arg) + processed_objects = [] + for obj in objects: + if isinstance(obj, Variable): + processed_objects.append(_variable_to_tensor_like_string(obj)) + Print(obj) else: - processed_args.append(arg) - print(*processed_args) + processed_objects.append(obj) + print(*processed_objects, sep=sep, end=end, file=file, flush=flush) def convert_pop(target, *args): From a4b872a75118e8101e8199da1022db13f87e38ad Mon Sep 17 00:00:00 2001 From: SigureMo Date: Fri, 2 Dec 2022 21:20:11 +0800 Subject: [PATCH 07/13] add kwargs unittest --- .../tests/unittests/dygraph_to_static/test_print.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/python/paddle/fluid/tests/unittests/dygraph_to_static/test_print.py b/python/paddle/fluid/tests/unittests/dygraph_to_static/test_print.py index a593bd37a9174c..736ab7aa3c4664 100644 --- a/python/paddle/fluid/tests/unittests/dygraph_to_static/test_print.py +++ b/python/paddle/fluid/tests/unittests/dygraph_to_static/test_print.py @@ -152,6 +152,13 @@ def dyfunc_print_continue_vars(x): print(x_v, y_v) +# 8. print with kwargs +@declarative +def dyfunc_print_with_kwargs(x): + x_v = fluid.dygraph.to_variable(x) + print("Tensor", x_v, end='\n\n', sep=':') + + class TestPrintBase(unittest.TestCase): def setUp(self): self.input = numpy.ones(5).astype("int32") @@ -217,5 +224,10 @@ def set_test_func(self): self.dygraph_func = dyfunc_print_continue_vars +class TestPrintWithKwargs(TestPrintVariable): + def set_test_func(self): + self.dygraph_func = dyfunc_print_with_kwargs + + if __name__ == '__main__': unittest.main() From 88f61deeb4a9d8488d155a1abc3f799933e9916f Mon Sep 17 00:00:00 2001 From: SigureMo Date: Fri, 2 Dec 2022 21:45:49 +0800 Subject: [PATCH 08/13] clean unittest --- .../unittests/dygraph_to_static/test_print.py | 164 +++++------------- 1 file changed, 45 insertions(+), 119 deletions(-) diff --git a/python/paddle/fluid/tests/unittests/dygraph_to_static/test_print.py b/python/paddle/fluid/tests/unittests/dygraph_to_static/test_print.py index 736ab7aa3c4664..ce1b0dec95156d 100644 --- a/python/paddle/fluid/tests/unittests/dygraph_to_static/test_print.py +++ b/python/paddle/fluid/tests/unittests/dygraph_to_static/test_print.py @@ -16,156 +16,82 @@ import numpy +import paddle import paddle.fluid as fluid -from paddle.jit import ProgramTranslator -from paddle.jit.api import declarative +from paddle.jit import ProgramTranslator, to_static program_translator = ProgramTranslator() -# 1. print VarBase -@declarative +# 1. print Tensor +@to_static def dyfunc_print_variable(x): - """ - PY2: - Print(dest=None, values=[Name(id='x_v', annotation=None, type_comment=None)], nl=True)], - PY3: - Expr( - value=Call(func=Name(id='print', annotation=None, type_comment=None), - args=[Name(id='x_v', annotation=None, type_comment=None)], - keywords=[])) - """ # NOTE: transform to static code, var name will be changed - x_v = fluid.dygraph.to_variable(x) - print(x_v) + x_t = paddle.to_tensor(x) + print(x_t) # 2. print ndarray -@declarative +@to_static def dyfunc_print_ndarray(x): - """ - PY2: - Print(dest=None, values=[Name(id='x', annotation=None, type_comment=None) - PY3: - Expr( - value=Call(func=Name(id='print', annotation=None, type_comment=None), - args=[Name(id='x', annotation=None, type_comment=None)], - keywords=[])) - """ print(x) -# 3. print VarBase with format -@declarative +# 3. print Tensor with format +@to_static def dyfunc_print_with_format(x): - """ - PY2: - Print(dest=None, - values=[ - Call( - func=Attribute(value=Constant(value='PrintVariable: {}', kind=None), attr='format'), - args=[Name(id='x_v', annotation=None, type_comment=None)], - keywords=[])], - nl=True) - PY3: - Expr( - value=Call(func=Name(id='print', annotation=None, type_comment=None), - args=[ - Call( - func=Attribute(value=Constant(value='PrintVariable: {}', kind=None), attr='format'), - args=[Name(id='x_v', annotation=None, type_comment=None)], - keywords=[])], - keywords=[])) - """ - x_v = fluid.dygraph.to_variable(x) - print("PrintVariable: {}".format(x_v)) - - -# 4. print VarBase with format 2 -@declarative + x_t = paddle.to_tensor(x) + print("PrintTensor: {}".format(x_t)) + + +# 4. print Tensor with format 2 +@to_static def dyfunc_print_with_format2(x): - """ - PY2: - Print(dest=None, - values=[ - BinOp(left=Constant(value='PrintVariable: %s', kind=None), - op=Mod, - right=Name(id='x_v', annotation=None, type_comment=None))], - nl=True) - PY3: - Expr( - value=Call(func=Name(id='print', annotation=None, type_comment=None), - args=[ - BinOp(left=Constant(value='PrintVariable: %s', kind=None), - op=Mod, - right=Name(id='x_v', annotation=None, type_comment=None))], - keywords=[])) - """ - x_v = fluid.dygraph.to_variable(x) - print("PrintVariable: %s" % (x_v)) - - -# 5. print VarBase in control flow1 -@declarative + x_t = paddle.to_tensor(x) + print("PrintTensor: %s" % (x_t)) + + +# 5. print Tensor in control flow1 +@to_static def dyfunc_print_with_ifelse(x): - x_v = fluid.dygraph.to_variable(x) - if len(x_v.shape) > 1: - print(x_v) + x_t = paddle.to_tensor(x) + if len(x_t.shape) > 1: + print(x_t) else: - print(x_v) + print(x_t) -# 6. print mutiple VarBases -@declarative -def dyfunc_print_multi_vars(x): - """ - # NOTE: y_v type is error before cur PR in this case - Assign(targets=[Name(id='y_v', annotation=None, type_comment=None)], - value=BinOp(left=Name(id='x_v', annotation=None, type_comment=None), op=Mult, right=Constant(value=2, kind=None))) - """ - x_v = fluid.dygraph.to_variable(x) - y_v = x_v * 2 - print(x_v) - print(y_v) +# 6. print mutiple Tensor +@to_static +def dyfunc_print_multi_tensor(x): + x_t = paddle.to_tensor(x) + y_t = x_t * 2 + print(x_t) + print(y_t) -# 7. print continue VarBase -@declarative +# 7. print continue Tensor +@to_static def dyfunc_print_continue_vars(x): - """ - PY3: - Expr( - value=Call(func=Name(id='print', annotation=None, type_comment=None), - args=[Name(id='x_v', annotation=None, type_comment=None), - Name(id='y_v', annotation=None, type_comment=None)], - keywords=[])) - PY2: - Print(dest=None, - values=[ - Tuple( - elts=[Name(id='x_v', annotation=None, type_comment=None), - Name(id='y_v', annotation=None, type_comment=None)])], - nl=True) - """ - x_v = fluid.dygraph.to_variable(x) - y_v = x_v * 2 - print(x_v, y_v) + x_t = paddle.to_tensor(x) + y_t = x_t * 2 + print(x_t, y_t) # 8. print with kwargs -@declarative +@to_static def dyfunc_print_with_kwargs(x): - x_v = fluid.dygraph.to_variable(x) - print("Tensor", x_v, end='\n\n', sep=':') + x_t = paddle.to_tensor(x) + print("Tensor", x_t, end='\n\n', sep=': ') class TestPrintBase(unittest.TestCase): def setUp(self): self.input = numpy.ones(5).astype("int32") self.place = ( - fluid.CUDAPlace(0) - if fluid.is_compiled_with_cuda() - else fluid.CPUPlace() + paddle.CUDAPlace(0) + if paddle.is_compiled_with_cuda() + else paddle.CPUPlace() ) self.set_test_func() @@ -214,9 +140,9 @@ def set_test_func(self): self.dygraph_func = dyfunc_print_with_ifelse -class TestPrintMultipleVar(TestPrintVariable): +class TestPrintMultipleTensor(TestPrintVariable): def set_test_func(self): - self.dygraph_func = dyfunc_print_multi_vars + self.dygraph_func = dyfunc_print_multi_tensor class TestPrintContinueVar(TestPrintVariable): From 18c8a16ff101026a35274c8105ab303c9474cb7b Mon Sep 17 00:00:00 2001 From: SigureMo Date: Sat, 3 Dec 2022 01:26:46 +0800 Subject: [PATCH 09/13] fix typo --- python/paddle/jit/dy2static/convert_call_func.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/paddle/jit/dy2static/convert_call_func.py b/python/paddle/jit/dy2static/convert_call_func.py index 2f24bbf4cee7cd..da0560cb346923 100644 --- a/python/paddle/jit/dy2static/convert_call_func.py +++ b/python/paddle/jit/dy2static/convert_call_func.py @@ -216,7 +216,7 @@ def dyfunc(x): if is_builtin(func, "enumerate"): return convert_enumerate - if is_builtin(print, "print"): + if is_builtin(func, "print"): return convert_print if is_builtin(func) or is_unsupported(func): From 36c8e5ebdafb94eed52c8bf6c822d44f88b4ced0 Mon Sep 17 00:00:00 2001 From: SigureMo Date: Sat, 3 Dec 2022 02:03:09 +0800 Subject: [PATCH 10/13] remove _variable_to_tensor_like_string --- python/paddle/jit/dy2static/convert_operators.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/python/paddle/jit/dy2static/convert_operators.py b/python/paddle/jit/dy2static/convert_operators.py index c502f89fcb824c..0330750026e52a 100644 --- a/python/paddle/jit/dy2static/convert_operators.py +++ b/python/paddle/jit/dy2static/convert_operators.py @@ -738,27 +738,16 @@ def convert_assert(cond, message=""): assert cond, message -def _variable_to_tensor_like_string(var): - return ( - f"Tensor(shape={var.shape}, dtype={var.dtype}, place={var.place()}, stop_gradient={var.stop_gradient}," - + "\n The value of the tensor is unknown in compile time.)" - ) - - def convert_print(*objects, sep=' ', end='\n', file=None, flush=False): """ A function representing Python ``print`` statement. Note: this is a basic python function so we haven't handle sep, end, file and flush parameters of python function. """ - processed_objects = [] for obj in objects: if isinstance(obj, Variable): - processed_objects.append(_variable_to_tensor_like_string(obj)) Print(obj) - else: - processed_objects.append(obj) - print(*processed_objects, sep=sep, end=end, file=file, flush=flush) + print(*objects, sep=sep, end=end, file=file, flush=flush) def convert_pop(target, *args): From 485c9f50af70405f433b65ea24052ead0e1cc491 Mon Sep 17 00:00:00 2001 From: SigureMo Date: Sat, 3 Dec 2022 02:15:12 +0800 Subject: [PATCH 11/13] update docstring for convert_print --- python/paddle/jit/dy2static/convert_operators.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/python/paddle/jit/dy2static/convert_operators.py b/python/paddle/jit/dy2static/convert_operators.py index 0330750026e52a..41a1a60b857b56 100644 --- a/python/paddle/jit/dy2static/convert_operators.py +++ b/python/paddle/jit/dy2static/convert_operators.py @@ -740,9 +740,8 @@ def convert_assert(cond, message=""): def convert_print(*objects, sep=' ', end='\n', file=None, flush=False): """ - A function representing Python ``print`` statement. Note: this is a basic - python function so we haven't handle sep, end, file and flush parameters of - python function. + A function representing Python ``print`` function. It will print all arguments + at compile time and only print the Tensor values at runtime. """ for obj in objects: if isinstance(obj, Variable): From 88b8ba7a8efeed53d33367e57fb7b79981545227 Mon Sep 17 00:00:00 2001 From: SigureMo Date: Sat, 3 Dec 2022 03:11:02 +0800 Subject: [PATCH 12/13] fix type mutiple --- .../fluid/tests/unittests/dygraph_to_static/test_print.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/paddle/fluid/tests/unittests/dygraph_to_static/test_print.py b/python/paddle/fluid/tests/unittests/dygraph_to_static/test_print.py index ce1b0dec95156d..21de18a9f531dd 100644 --- a/python/paddle/fluid/tests/unittests/dygraph_to_static/test_print.py +++ b/python/paddle/fluid/tests/unittests/dygraph_to_static/test_print.py @@ -61,7 +61,7 @@ def dyfunc_print_with_ifelse(x): print(x_t) -# 6. print mutiple Tensor +# 6. print multiple Tensor @to_static def dyfunc_print_multi_tensor(x): x_t = paddle.to_tensor(x) From e272e6cb0a3873fab2270dcf1f0beccced52957d Mon Sep 17 00:00:00 2001 From: SigureMo Date: Sat, 3 Dec 2022 05:39:56 +0800 Subject: [PATCH 13/13] remove _jst.Print --- python/paddle/jit/dy2static/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/python/paddle/jit/dy2static/__init__.py b/python/paddle/jit/dy2static/__init__.py index c42116c21065de..89204e62cee143 100644 --- a/python/paddle/jit/dy2static/__init__.py +++ b/python/paddle/jit/dy2static/__init__.py @@ -25,7 +25,6 @@ from .convert_operators import convert_logical_not as Not # noqa: F401 from .convert_operators import convert_logical_or as Or # noqa: F401 from .convert_operators import convert_pop as Pop # noqa: F401 -from .convert_operators import convert_print as Print # noqa: F401 from .convert_operators import convert_shape as Shape # noqa: F401 from .convert_operators import convert_while_loop as While # noqa: F401 from .convert_operators import unpack_by_structure as Unpack # noqa: F401