未验证 提交 7b69a251 编写于 作者: H Huihuang Zheng 提交者: GitHub

[Dy2stat] Add Supported and Unsupported Grammar List (#2574)

As the title
上级 e4539a63
...@@ -10,7 +10,7 @@ ProgramTranslator本质是把Python运行语法转写为PaddlePaddle静态图代 ...@@ -10,7 +10,7 @@ ProgramTranslator本质是把Python运行语法转写为PaddlePaddle静态图代
控制流相关关键词 控制流相关关键词
------------------ ------------------
控制流指if-elif-else,while等能够控制程序语句执行顺序的关键字。PaddlePaddle静态图通过cond,while_loop API来实现条件判断和循环,如果动态图Python控制流的判断条件/循环条件依赖 Paddle Tensor,动转静后会被转化为等价的Paddle控制流接口,否则仍然使用Python控制流逻辑运行。在动转静过程中这些关键字的转化情况为: 控制流指if-elif-else,while等能够控制程序语句执行顺序的关键字。PaddlePaddle静态图通过cond,while_loop API来实现条件判断和循环,如果动态图Python控制流的判断条件或循环条件依赖 PaddlePaddle Tensor,动转静后会被转化为等价的PaddlePaddle控制流接口,否则仍然使用Python控制流逻辑运行。在动转静过程中这些关键字的转化情况为:
1. if-elif-else 条件 1. if-elif-else 条件
...@@ -47,7 +47,7 @@ ProgramTranslator 支持在循环,条件判断中return结果而不需要一 ...@@ -47,7 +47,7 @@ ProgramTranslator 支持在循环,条件判断中return结果而不需要一
一些需要转化的运算类型 一些需要转化的运算类型
------------------------ ------------------------
1. +,-,*,/,** 等Python内置运算 1. +,-,*,/,**, >, <, >= , <=, == 等Python内置运算
由于静态图有重载这些基本运算符,所以这些被ProgramTranslator转化后都适用相应重载的运算符,动转静支持此类运算。 由于静态图有重载这些基本运算符,所以这些被ProgramTranslator转化后都适用相应重载的运算符,动转静支持此类运算。
...@@ -76,7 +76,7 @@ Python 函数相关 ...@@ -76,7 +76,7 @@ Python 函数相关
4. 函数内再调用函数 4. 函数内再调用函数
对于函数内调用其他函数的情况,ProgramTranslator也会对内部的函数递归地进行动转静,这样做的好处是可以在最外层函数加一次装饰器就能进行动转静,而不需要每个函数都加装饰器 对于函数内调用其他函数的情况,ProgramTranslator也会对内部的函数递归地进行动转静,这样做的好处是可以在最外层函数只需加一次装饰器即可,而不需要每个函数都加装饰器。但需要注意,动转静还不支持函数递归调用自己,详细原因请查看下文动转静无法正确运行的情况
报错异常相关 报错异常相关
-------------- --------------
...@@ -96,7 +96,7 @@ Python基本容器 ...@@ -96,7 +96,7 @@ Python基本容器
动转静无法正确运行的情况 动转静无法正确运行的情况
-------------------------- --------------------------
1. Reshape后的变量调用其shape作为Paddle API参数。 1. Reshape后的变量调用其shape作为PaddlePaddle API参数。
具体表现比如 ``x = reshape(x, shape=shape_tensor)`` ,再使用 ``x.shape[0]`` 的值进行其他操作。这种情况会由于动态图和静态图的本质不同而使得动态图能够运行,但静态图运行失败。其原因是动态图情况下,API是直接返回运行结果,因此 ``x.shape`` 在经过reshape运算后是确定的。但是在转化为静态图后,因为静态图API只是组网,``shape_tensor`` 的值在组网时是不知道的,所以 ``reshape`` 接口组网完,静态图并不知道 ``x.shape`` 的值。PaddlePaddle静态图用-1表示未知的shape值,此时 ``x`` 的shape每个维度会被设为-1,而不是期望的值。 具体表现比如 ``x = reshape(x, shape=shape_tensor)`` ,再使用 ``x.shape[0]`` 的值进行其他操作。这种情况会由于动态图和静态图的本质不同而使得动态图能够运行,但静态图运行失败。其原因是动态图情况下,API是直接返回运行结果,因此 ``x.shape`` 在经过reshape运算后是确定的。但是在转化为静态图后,因为静态图API只是组网,``shape_tensor`` 的值在组网时是不知道的,所以 ``reshape`` 接口组网完,静态图并不知道 ``x.shape`` 的值。PaddlePaddle静态图用-1表示未知的shape值,此时 ``x`` 的shape每个维度会被设为-1,而不是期望的值。
...@@ -104,7 +104,7 @@ Python基本容器 ...@@ -104,7 +104,7 @@ Python基本容器
2. 多重list嵌套读写Tensor 2. 多重list嵌套读写Tensor
具体表现如 ``l = [[tensor1, tensor2], [tensor3, tensor4]]`` ,因为现在静态图将元素全是Tensor的list转化为TensorArray,而Paddle的TensorArray还不支持多维数组,因此这种情况无法动转静正确运行。 具体表现如 ``l = [[tensor1, tensor2], [tensor3, tensor4]]`` ,因为现在动转静将元素全是Tensor的list转化为TensorArray,而PaddlePaddle的TensorArray还不支持多维数组,因此这种情况下,动转静无法正确运行。
遇到这类情况我们建议尽量用一维list,或者自己使用PaddlePaddle的create_array,array_read,array_write接口编写为TensorArray。 遇到这类情况我们建议尽量用一维list,或者自己使用PaddlePaddle的create_array,array_read,array_write接口编写为TensorArray。
...@@ -114,3 +114,9 @@ Python基本容器 ...@@ -114,3 +114,9 @@ Python基本容器
遇到这种情况我们建议在动转静的函数中尽量使用PaddlePaddle接口替代numpy接口进行运算。 遇到这种情况我们建议在动转静的函数中尽量使用PaddlePaddle接口替代numpy接口进行运算。
4. 一个函数递归调用自己
ProgramTranslator还无法支持一个函数递归调用自己,原因是递归常常会用 ``if-else`` 构造停止递归的条件。然而这样的停止条件在静态图下只是一个 ``cond`` 组网,组网并不能在编译阶段决定自己组多少次,会导致函数运行时一直组网递归直至栈溢出,因此ProgramTranslator还无法支持一个函数递归调用自己。
遇到这种情况我们建议将代码改为非递归写法。
Supported Grammars
==================
The key part of ProgramTranslator is transforming Python grammar into PaddlePaddle static graph code, but there exists difference between Python and PaddlePaddle static graph which causes some limitation of the code transformation.
In this section we will talk about the supported grammars and unsupported grammars, also give some suggestions when the grammar is unsupported.
There are several kinds of supported grammars:
Control flow keywords
---------------------
Control flow means those keywords that controls the execution order of program statements, for example ``if-elif-else, while`` . Conditional operation and loop were implemented as ``cond, while_loop`` APIs in PaddlePaddle static graph. If the condition of a Python dygraph control flow depends on PaddlePaddle Tensor, the ProgramTranslator will convert the control flow into equivalent PaddlePaddle control flow APIs, else it will still be executed as Python control flow. The transformations of those control flow keywords are listed below:
1. ``if-elif-else`` statements
If the condition of ``if <condition>`` is Tensor, ProgramTranslator will turn this ``if-elif-else`` statement to equivalent PaddlePaddle static graph ``cond`` statements, otherwise the ``if-elif-else`` statement is executed as normal Python conditional statement. Note that ``cond`` API only accepts input conditional Tensor with numel equals to 1, so please use this kind of Tensor to write dygraph conditional statement, other Tensors will cause error.
2. ``while`` loop
If the condition of ``while`` is Tensor, ProgramTranslator will turn this ``while`` statement to equivalent PaddlePaddle static graph ``while_loop`` statements, otherwise the ``while`` statement is executed as normal Python ``while`` loop statement. Note that ``while_loop`` API only accepts input conditional Tensor with numel equals to 1, so please use this kind of Tensor to write dygraph loop condition statement, other Tensors will cause error.
3. ``for`` loop
3.1 ``for _ in range(__)`` loop
Firstly, ProgramTranslator will transform it into equivalent Python while loop, then convert dygraph to static graph by same logic of ``while`` loop.
3.2 ``for _ in x`` loop
If ``x`` is a Python container, iterator, or generator, it will be executed as original Python statement. Otherwise ``x`` is a Tensor, ProgramTranslator will transform the loop into PaddlePaddle static graph loop and fetches ``x[0], x[1], ...`` as loop iteration variable in each loop iteration.
3.3 ``for idx, val in enumerate(x)`` loop
If ``x`` is a Python container, iterator, or generator, it will be executed as original Python statement. Otherwise ``x`` is a Tensor, Program
Translator will transform the loop into PaddlePaddle static graph loop. The ``idx`` will be transformed to 1-D tensor with value ``0, 1, ...`` and the ``val`` will be transformed to ``x[0], x[1], ...`` in each loop iteration.
4. ``break, continue``
ProgramTranslator supports ``break, continue`` statements in loop. ProgramTranslator will add some PaddlePaddle static graph ``cond`` statements to skip execution of corresponding part when ``break, continue`` condition is meet.
5. ``return``
ProgramTranslator supports ``return`` in a conditonal block or loop body, not necessary to be at the end of a function. It also supports returning tuple with various length of Tensors with different dtype. The implementation is adding some PaddlePaddle static graph ``cond`` statement to skipparts of code when ``return`` is triggered.
Some Python basic operators
---------------------------
1. ``+, -, *, /, **, >, <, >= , <=, ==`` etc.
Because PaddlePaddle static graph overrides those Python basic arithmetic operators and comparison operators, ProgramTranslator can support those operators.
2. ``and, or, not`` logical operators
Python has ``and, or, not`` keywards as basic logical operators, ProgramTranslator will check whether the variables of the logical operators are Tensors, if they are Tensors, ProgramTranslator replaces the ``and, or, not`` statements into corresponding PaddlePaddle static graph logical operator and run it.
3. Type casting
In dygraph mode, users can use Python type casting grammar. For instance, if ``x`` is a Tensor, ``float(x)`` casts the data type of ``x`` to float. ProgramTranslator will check whether ``x`` is a Tensor during run time, if it is, the casting sentence will be modified to PaddlePaddle static graph ``cast`` API so that its dtype can be changed in the dygraph to static transformation.
Python functions
------------------------------
1. ``print``
In dygraph mode, ``print(x)`` will print Tensor value if ``x`` is a Tensor. ProgramTranslator converts the built-in ``print`` to PaddlePaddle static graph ``Print`` API during dygraph to static graph transformation if the arguments are Tensors, otherwise ProgramTranslator won't convert the ``print``.
2. ``len``
If ``x`` is a Tensor, ``len(x)`` can get the length at 0-dimension of ``x`` in dygraph mode. ProgramTranslator turns it to PaddlePaddle static graph ``shape`` API and returns the 0-dimension of the ``shape``, else if ``x`` is a TensorArray, then ``len(x)`` will be transformed to static graph API ``control_flow.array_length`` to return the length of TensorArray. In other cases, the ``len`` function will be executed as Python built-in ``len``
3. lambda expression
ProgramTranslator supports Python lambda expression and it modifies code to return the expected result.
4. Calling function
If the transformed function calls another function, ProgramTranslator also transform the called function. The benefit is that users can add one decorator at the outside function to do transformation, no need to add the decorator for each function. Note that ProgramTranslator doesn't support
that a function calls itself recursively, the details is in the unsupported grammars section below.
Errors and Exceptions
---------------------
1. ``assert``
If ``x`` is a Tensor, ``assert x`` statement can assert ``x`` to be ``True`` or non-zero value in dygraph mode. ProgramTranslator converts the statement into PaddlePaddle static graph ``Assert`` API to support this grammar.
Python containers
-----------------
1. ``list``: if all elements in a list are Tensors, then ProgramTranslator converts it to TensorArray. PaddlePaddle static graph TensorArray supports append, pop, and modify, other list operations such as sort cannot be supported. When not all elements in a list are Tensors, ProgramTranslator will treat it as normal Python list.
2. ``dict``: ProgramTranslator will add the Tensors in a dict into PaddlePaddle static graph ``Program``, so ``dict`` is supported by ProgramTranslator.
Unsupported grammars
--------------------
1. Use the shape of output tensor of ``reshape``
For example, ``x = reshape(x, shape=shape_tensor)`` , then use ``x.shape[0]`` to do other operation. Due to the difference between dygraph and static graph, it is okay in dygraph but it will fail in static graph. The reason is that APIs return computation result in dygraph mode, so ``x.shape`` has deterministic value after calling ``reshape`` . However, static graph doesn't have the value ``shape_tensor`` during building network, so PaddlePaddle doesn't know the value of ``x.shape`` after calling ``reshape``. PaddlePaddle static graph will set -1 to represent unknown shape value for each dimension of ``x.shape`` in this case, not the expected value.
We suggest to set fixed shape value as much as possible, reduce the reshape operation.
2. List of list of Tensor
For example: ``l = [[tensor1, tensor2], [tensor3, tensor4]]``, because ProgramTranslator transformed a list whose elements are all Tensors into PaddlePaddle static graph TensorArray, but TensorArray doesn't support multi-dimensions, ProgramTranslator cannot run this case.
We suggest to use 1-D list at most time, or use PaddlePaddle API ``create_array, array_read, array_write`` to control TensorArray.
3. Convert Tensor to numpy array and do operation
For example, user doesn't return Tensor in the decorated function but call ``numpy.array(tensor)`` to convert Tensor to numpy array and then use numpy API to compute on it. In dygraph mode, it is okey because Tensor has value, but Tensor is variable for building network in static graph mode, it doesn't contain value if not in static graph running time, so we cannot do numpy calculation on it.
We suggest to use PaddlePaddle APIs to replace numpy API in this case.
4. A function calls itself recursively
ProgramTranslator doesn't support a function calls itself recursively, the reason is that recursive function usually uses ``if-else`` for a condition to stop the recursion, the stop condition will be transformed to a ``cond`` in static graph mode. Since ``cond`` just builds network, it cannot determine how many times it recursively builds network during network built stage, so the function will recursively call itself and build network until stack overflow. Due to above reason, ProgramTranslator cannot support a function calls itself recursively now.
We suggest to write non-recursive function in this case.
...@@ -2,10 +2,13 @@ ...@@ -2,10 +2,13 @@
Dygraph to Static Graph Dygraph to Static Graph
####################### #######################
- `Dygraph to Static Graph <program_translator_en.html>`_ :Introduce the basic usage for transforming dygraph code into static code and the architecture of ProgramTranslator. - `Dygraph to Static Graph <program_translator_cn.html>`_ :Introduce the basic usage for transforming dygraph code into static code and the architecture of ProgramTranslator.
- `Supported Grammars <grammar_list_en.html>`_ :Introduce the grammars supported by ProgramTranslator and list unsupport grammars.
.. toctree:: .. toctree::
:hidden: :hidden:
grammar_list_en.rst
program_translator_en.rst program_translator_en.rst
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册