debugging_cn.md 5.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
# 调试方法

本节内容将介绍动态图转静态图(下文简称动转静)推荐的几种调试方法。

注意:请确保转换前的动态图代码能够成功运行,建议使用[paddle.jit.ProgramTranslator().enable(False)](../../api_cn/dygraph_cn/ProgramTranslator_cn.html#enable)关闭动转静功能,直接运行动态图,如下:
```python
import paddle
import numpy as np
paddle.disable_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]))
```

## 断点调试
使用动转静功能时,您可以使用断点调试代码。
例如,在代码中,调用`pdb.set_trace()`
```Python
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
```
执行以下代码,将会在转化后的静态图代码中使用调试器:
```Python
func(np.ones([3, 2]))
```

运行结果:
```bash
> /tmp/tmpR809hf.py(6)func()
-> def true_fn_0(x):
(Pdb) n
> /tmp/tmpR809hf.py(6)func()
-> def false_fn_0(x):
...
```

如果您想在原始的动态图代码中使用调试器,请先调用[`paddle.jit.ProgramTranslator().enable(False)`](../../api_cn/dygraph_cn/ProgramTranslator_cn.html#enable),如下:
```python
paddle.jit.ProgramTranslator().enable(False)
func(np.ones([3, 2]))
```
运行结果:
```bash
> <ipython-input-22-0bd4eab35cd5>(10)func()
-> if x > 3:
...

```

## 打印转换后的代码
您可以打印转换后的静态图代码,有2种方法:

1. 使用被装饰函数的`code` 属性
    ```Python
    @paddle.jit.to_static
    def func(x):
    x = paddle.to_tensor(x)
        if x > 3:
            x = x - 1
        return x

    print(func.code)
    ```
    运行结果:

    ```bash

    def func(x):
        x = fluid.layers.assign(x)

        def true_fn_0(x):
            x = x - 1
            return x

        def false_fn_0(x):
            return x
        x = fluid.dygraph.dygraph_to_static.convert_operators.convert_ifelse(x >
            3, true_fn_0, false_fn_0, (x,), (x,), (x,))
        return x
    ```

2. 使用`set_code_level(level)`或环境变量`TRANSLATOR_CODE_LEVEL=level`

    通过调用`set_code_level`或设置环境变量`TRANSLATOR_CODE_LEVEL`,可以在log中查看转换后的代码
```python
@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() # 也可设置 os.environ["TRANSLATOR_CODE_LEVEL"] = '100',效果相同
func(np.ones([1]))
```
    运行结果:

```bash
2020-XX-XX 00:00:00,980-INFO: After the level 100 ast transformer: 'All Transformers', the transformed code:
def func(x):
    x = fluid.layers.assign(x)

    def true_fn_0(x):
        x = x - 1
        return x

    def false_fn_0(x):
        return x
    x = fluid.dygraph.dygraph_to_static.convert_operators.convert_ifelse(x >
        3, true_fn_0, false_fn_0, (x,), (x,), (x,))
    return x
```
    `set_code_level` 函数可以设置查看不同的AST Transformer转化后的代码,详情请见[set_code_level]()<!--TODO:补充set_code_level文档链接-->。

## 使用 `print`
`print` 函数可以用来查看变量,该函数在动转静中会被转化。当仅打印Paddle Tensor时,实际运行时会被转换为Paddle算子[Print](../../api_cn/layers_cn/Print_cn.html),否则仍然运行`print`
```python
@paddle.jit.to_static
def func(x):
    x = paddle.to_tensor(x)
    # 打印x,x是Paddle Tensor,实际运行时会运行Paddle Print(x)
    print(x)
    # 打印注释,非Paddle Tensor,实际运行时仍运行print
    print("Here call print function.")
    if len(x) > 3:
        x = x - 1
    else:
        x = paddle.ones(shape=[1])
    return x
func(np.ones([1]))
```

运行结果:
```bash
Variable: assign_0.tmp_0
  - lod: {}
  - place: CPUPlace
  - shape: [1]
  - layout: NCHW
  - dtype: double
  - data: [1]
Here call print function.  
```

## 日志打印
ProgramTranslator在日志中记录了额外的调试信息,以帮助您了解动转静过程中函数是否被成功转换。
您可以调用`paddle.jit.set_verbosity(level)` 或设置环境变量`TRANSLATOR_VERBOSITY=level`来设置日志详细等级,并查看不同等级的日志信息。目前,`level`可以取值0-3:
- 0: 无日志
- 1: 包括了动转静转化流程的信息,如转换前的源码、转换的可调用对象
- 2: 包括以上信息,还包括更详细函数转化日志
- 3: 包括以上信息,以及更详细的动转静日志


可以在代码运行前调用`paddle.jit.set_verbosity()`
```python
paddle.jit.set_verbosity(3)
```
或者设置环境变量`TRANSLATOR_VERBOSITY`
```python
import os
os.environ["TRANSLATOR_VERBOSITY"] = '3'
```

运行结果:
```bash
2020-XX-XX 00:00:00,123-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-Level 1: Convert callable object: convert <built-in function len>.
```