This section will introduce several debugging methods recommended by Dynamic Graph to Static Graph (hereafter called Dynamic-to-Staic).
NOTE:
Please ensure that the dynamic graph code before transformation can run successfully. It is recommended to call paddle.jit.ProgramTranslator().enable(False) to disable Dynamic-to-Static, and run dynamic graph code as follows:
import paddle
import numpy as np
# Disable Dynamic-to-Static
paddle.jit.ProgramTranslator().enable(False)
@paddle.jit.to_static
def func(x):
x = paddle.to_tensor(x)
if x > 3:
x = x - 1
return x
func(np.ones([3, 2]))
When using Dynamic-to-Static, you can use breakpoints to debug.
For example, call pdb.set_trace()
in your code:
import pdb
@paddle.jit.to_static
def func(x):
x = paddle.to_tensor(x)
pdb.set_trace()
if x > 3:
x = x - 1
return x
Executing the following code will land the debugger in the transformed static graph code:
func(np.ones([3, 2]))
> /tmp/tmpR809hf.py(6)func()
-> def true_fn_0(x):
(Pdb) n
> /tmp/tmpR809hf.py(6)func()
-> def false_fn_0(x):
...
Calling paddle.jit.ProgramTranslator().enable(False)
before executing the code will land the debugger in the original dynamic graph code:
paddle.jit.ProgramTranslator().enable(False)
func(np.ones([3, 2]))
> <ipython-input-22-0bd4eab35cd5>(10)func()
-> if x > 3:
...
There are two ways to print the transformed static graph code:
-
Use the attribute
code
of the decorated functionIn the following code, the decorator
paddle.jit.to_static
transformsfunc
into a class objectStaticLayer
. You can use thecode
attribute ofStaticLayer
to get the transformed code.@paddle.jit.to_static def func(x): x = paddle.to_tensor(x) if x > 3: x = x - 1 return x print(func.code)
def func(x): x = paddle.nn.functional.assign(x) def true_fn_0(x): x = x - 1 return x def false_fn_0(x): return x x = paddle.jit.dy2static.convert_ifelse(x > 3, true_fn_0, false_fn_0, (x,), (x,), (x,)) return x
-
Call
set_code_level(level=100, also_to_stdout=False)
or set environment variableTRANSLATOR_CODE_LEVEL=level
You can view the transformed code in the log by calling
set_code_level
or set environment variableTRANSLATOR_CODE_LEVEL
.@paddle.jit.to_static def func(x): x = paddle.to_tensor(x) if x > 3: x = x - 1 return x paddle.jit.set_code_level() # the same effect to set os.environ["TRANSLATOR_CODE_LEVEL"] = '100' func(np.ones([1]))
2020-XX-XX 00:00:00,980 Dynamic-to-Static INFO: After the level 100 ast transformer: 'All Transformers', the transformed code: def func(x): x = paddle.nn.functional.assign(x) def true_fn_0(x): x = x - 1 return x def false_fn_0(x): return x x = paddle.jit.dy2static.convert_ifelse(x > 3, true_fn_0, false_fn_0, (x,), (x,), (x,)) return x
In addition, if you want to output the transformed code to
sys.stdout
, you can set the argumentalso_to_stdout
to True, otherwise the transformed code is only output tosys.stderr
.set_code_level
can set different levels to view the code transformed by different ast transformers. For details, please refer to set_code_level.
You can call print
to view variables. print
will be transformed when using Dynamic-to-Static. When only Paddle Tensor is printed, print
will be transformed and call Paddle operator Print in runtime. Otherwise, call python print
.
@paddle.jit.to_static
def func(x):
x = paddle.to_tensor(x)
# x is a Paddle Tensor, so it will run Paddle Print(x) actually.
print(x)
# The string is not a Paddle Tensor, so it will run print as-is.
print("Here call print function.")
if len(x) > 3:
x = x - 1
else:
x = paddle.ones(shape=[1])
return x
func(np.ones([1]))
Variable: assign_0.tmp_0
- lod: {}
- place: CPUPlace
- shape: [1]
- layout: NCHW
- dtype: double
- data: [1]
Here call print function.
ProgramTranslator can log additional debugging information to help you know whether the function was successfully transformed or not.
You can call paddle.jit.set_verbosity(level=0, also_to_stdout=False)
or set environment variable TRANSLATOR_VERBOSITY=level
to enable logging and view logs of different levels. The argument level
varies from 0 to 3:
- 0: no logging
- 1: includes the information in Dynamic-to-Static tranformation process, such as the source code not transformed, the callable object to transform and so on
- 2: includes above and more detailed function transformation logs
- 3: includes above and extremely verbose logging
WARNING:
The logs includes information such as source code. Please make sure logs don't contain any sensitive information before sharing them.
You can call paddle.jit.set_verbosity
to control the verbosity level of logs:
paddle.jit.set_verbosity(3)
or use the environment variable TRANSLATOR_VERBOSITY
:
import os
os.environ["TRANSLATOR_VERBOSITY"] = '3'
2020-XX-XX 00:00:00,123 Dynamic-to-Static INFO: (Level 1) Source code:
@paddle.jit.to_static
def func(x):
x = paddle.to_tensor(x)
if len(x) > 3:
x = x - 1
else:
x = paddle.ones(shape=[1])
return x
2020-XX-XX 00:00:00,152 Dynamic-to-Static INFO: (Level 1) Convert callable object: convert <built-in function len>.
In addition, if you want to output the logs to sys.stdout
, you can set the argument also_to_stdout
to True, otherwise the logs are only output to sys.stderr
. For details, please refer to set_verbosity.