Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
wmsofts
Paddle
提交
dab5e5d8
P
Paddle
项目概览
wmsofts
/
Paddle
与 Fork 源项目一致
Fork自
PaddlePaddle / Paddle
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
P
Paddle
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
dab5e5d8
编写于
2月 24, 2020
作者:
A
Aurelius84
提交者:
GitHub
2月 24, 2020
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add IsControlFlowIfVisitor in ast_transformer (#22709)
* add is_control_flow_if test=develop
上级
cdf5f6fb
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
127 addition
and
36 deletion
+127
-36
python/paddle/fluid/dygraph/dygraph_to_static/ast_transformer.py
...paddle/fluid/dygraph/dygraph_to_static/ast_transformer.py
+2
-1
python/paddle/fluid/dygraph/dygraph_to_static/ast_utils.py
python/paddle/fluid/dygraph/dygraph_to_static/ast_utils.py
+54
-6
python/paddle/fluid/dygraph/dygraph_to_static/static_analysis.py
...paddle/fluid/dygraph/dygraph_to_static/static_analysis.py
+1
-1
python/paddle/fluid/tests/unittests/test_ast_util.py
python/paddle/fluid/tests/unittests/test_ast_util.py
+48
-21
python/paddle/fluid/tests/unittests/test_dygraph_to_static_basic.py
...dle/fluid/tests/unittests/test_dygraph_to_static_basic.py
+22
-7
未找到文件。
python/paddle/fluid/dygraph/dygraph_to_static/ast_transformer.py
浏览文件 @
dab5e5d8
...
...
@@ -52,8 +52,9 @@ class IfElseTransformer(gast.NodeTransformer):
def
visit_If
(
self
,
node
):
assert
isinstance
(
node
,
gast
.
If
)
need_transform
=
is_control_flow_if
(
node
.
test
)
self
.
generic_visit
(
node
)
if
is_control_flow_if
(
node
.
test
)
:
if
need_transform
:
pred_node
=
node
.
test
true_func_node
,
false_func_node
,
return_name_ids
=
transform_if_else
(
node
,
self
.
root
)
...
...
python/paddle/fluid/dygraph/dygraph_to_static/ast_utils.py
浏览文件 @
dab5e5d8
...
...
@@ -27,8 +27,53 @@ from collections import defaultdict
from
paddle.fluid
import
unique_name
TRUE_FUNC_PRFIX
=
'true_fn'
FALSE_FUNC_PRFIX
=
'false_fn'
TRUE_FUNC_PREFIX
=
'true_fn'
FALSE_FUNC_PREFIX
=
'false_fn'
class
IsControlFlowIfVisitor
(
gast
.
NodeTransformer
):
"""
Judge whether the node.test from Dygraph code dependent on paddle Tensor.
If does, it should satisfy:
1. must involve at least one var whose type is Tensor.
2. the Tensor var should call `.numpy()[]` interface or Tensor.shape is [1].
3. involve Tensor.shape[i] and the shape[i] is unknown in compile time.
The following examples should not be considered as control_flow_if:
1. `if Tensor_var` or `if Tensor_var is None`
2. if Tensor.shape[i] is determined with fixed value (not -1 or None)
Note: pred in ConditionalBlock require variable, which means all vars should be Tensor
or transformed into Tensor, like fill_constant(shape=[1], dtype='int32', value=Tensor.shape[i]).
TODO: 1. need to deal with `tensor.shape[i]` which need to eval the data of shape[i],
because reshape_op may be called before this statement.
"""
def
__init__
(
self
,
node
):
self
.
node
=
node
self
.
is_control_flow
=
False
def
ast_visit
(
self
):
self
.
visit
(
self
.
node
)
return
self
.
is_control_flow
def
visit_Compare
(
self
,
node
):
for
child
in
gast
.
walk
(
node
):
if
isinstance
(
child
,
gast
.
Subscript
):
self
.
_visit_Subscript
(
child
)
return
node
def
_visit_Subscript
(
self
,
node
):
self
.
generic_visit
(
node
)
if
isinstance
(
node
.
value
,
gast
.
Call
):
self
.
_visit_Call
(
node
.
value
)
return
node
def
_visit_Call
(
self
,
node
):
assert
isinstance
(
node
,
gast
.
Call
)
if
isinstance
(
node
.
func
,
gast
.
Attribute
):
attr_node
=
node
.
func
self
.
is_control_flow
=
(
attr_node
.
attr
==
'numpy'
)
def
is_control_flow_if
(
node
):
...
...
@@ -36,7 +81,10 @@ def is_control_flow_if(node):
Determine whether the node is a plain python `if statement` or
control flow in Paddle.
"""
return
True
assert
isinstance
(
node
,
gast
.
AST
),
"Type of input node should be gast.AST, but received %s."
%
type
(
node
)
return
IsControlFlowIfVisitor
(
node
).
ast_visit
()
def
get_name_ids
(
nodes
,
not_name_set
=
None
,
node_black_list
=
None
):
...
...
@@ -228,12 +276,12 @@ def transform_if_else(node, root):
true_func_node
=
create_funcDef_node
(
node
.
body
,
name
=
unique_name
.
generate
(
TRUE_FUNC_PRFIX
),
name
=
unique_name
.
generate
(
TRUE_FUNC_PR
E
FIX
),
input_args
=
parse_cond_args
(
if_name_ids
,
modified_name_ids
),
return_name_ids
=
return_name_ids
)
false_func_node
=
create_funcDef_node
(
node
.
orelse
,
name
=
unique_name
.
generate
(
FALSE_FUNC_PRFIX
),
name
=
unique_name
.
generate
(
FALSE_FUNC_PR
E
FIX
),
input_args
=
parse_cond_args
(
else_name_ids
,
modified_name_ids
),
return_name_ids
=
return_name_ids
)
...
...
@@ -309,7 +357,7 @@ def ast_to_func(ast_root, func_name, delete_on_exit=True):
f
=
tempfile
.
NamedTemporaryFile
(
mode
=
'w'
,
suffix
=
'.py'
,
delete
=
False
,
encoding
=
'utf-8'
)
# TODO(Aurelius84): more eleg
e
nt way to transform ast into callable object
# TODO(Aurelius84): more eleg
a
nt way to transform ast into callable object
import_str
=
"import paddle
\n
"
\
"import paddle.fluid as fluid
\n
"
\
"import paddle.fluid.layers as layers
\n
"
...
...
python/paddle/fluid/dygraph/dygraph_to_static/static_analysis.py
浏览文件 @
dab5e5d8
...
...
@@ -187,7 +187,7 @@ class AstVarEnv(object):
def
exit_scope
(
self
):
assert
self
.
cur_scope
.
parent_scope
is
not
None
,
"Call exit_scope in "
\
"AstVarEnv when current scope doe
ns
't have parent scope."
"AstVarEnv when current scope doe
sn
't have parent scope."
self
.
cur_scope
=
self
.
cur_scope
.
parent_scope
return
self
.
cur_scope
...
...
python/paddle/fluid/tests/unittests/test_ast_util.py
浏览文件 @
dab5e5d8
...
...
@@ -20,7 +20,9 @@ import gast
import
inspect
import
numpy
as
np
import
paddle.fluid
as
fluid
from
paddle.fluid.dygraph.dygraph_to_static.ast_utils
import
get_name_ids
,
ast_to_func
from
paddle.fluid.dygraph.dygraph_to_static.ast_utils
import
get_name_ids
,
ast_to_func
,
is_control_flow_if
from
test_dygraph_to_static_basic
import
dyfunc_with_if_else
,
dyfunc_with_if_else2
,
nested_if_else
class
TestGetNameIds
(
unittest
.
TestCase
):
...
...
@@ -92,22 +94,46 @@ class TestGetNameIds3(TestGetNameIds):
}
def
dyfunc_with_if_else
(
x_v
):
if
fluid
.
layers
.
mean
(
x_v
).
numpy
()[
0
]
>
5
:
x_v
=
x_v
-
1
else
:
x_v
=
x_v
+
1
return
x_v
class
TestIsControlFlowIf
(
unittest
.
TestCase
):
def
test_expr
(
self
):
# node is not ast.Compare
node
=
gast
.
parse
(
"a + b"
)
self
.
assertFalse
(
is_control_flow_if
(
node
))
def
test_expr2
(
self
):
node
=
gast
.
parse
(
"a + x.numpy()[1]"
)
self
.
assertFalse
(
is_control_flow_if
(
node
))
def
test_is_None
(
self
):
node
=
gast
.
parse
(
"x is None"
)
self
.
assertFalse
(
is_control_flow_if
(
node
))
def
test_is_None2
(
self
):
node
=
gast
.
parse
(
"fluid.layers.sum(x) is None"
)
self
.
assertFalse
(
is_control_flow_if
(
node
))
def
test_is_None3
(
self
):
node
=
gast
.
parse
(
"fluid.layers.sum(x).numpy() != None"
)
self
.
assertFalse
(
is_control_flow_if
(
node
))
def
dyfunc_with_if_else2
(
x
):
i
,
j
=
0
,
0
if
fluid
.
layers
.
reduce_mean
(
x
).
numpy
()[
0
]
>
x
.
numpy
()[
i
][
j
]:
y
=
fluid
.
layers
.
relu
(
x
)
else
:
x_pow
=
fluid
.
layers
.
pow
(
x
,
2
)
y
=
fluid
.
layers
.
tanh
(
x_pow
)
return
y
def
test_if
(
self
):
node
=
gast
.
parse
(
"x.numpy()[1] > 1"
)
self
.
assertTrue
(
is_control_flow_if
(
node
))
def
test_if_with_and
(
self
):
node
=
gast
.
parse
(
"x is not None and 1 < x.numpy()[1]"
)
self
.
assertTrue
(
is_control_flow_if
(
node
))
def
test_if_with_or
(
self
):
node
=
gast
.
parse
(
"1 < fluid.layers.sum(x).numpy()[2] or x+y < 0"
)
self
.
assertTrue
(
is_control_flow_if
(
node
))
def
test_raise_error
(
self
):
node
=
"a + b"
with
self
.
assertRaises
(
Exception
)
as
e
:
self
.
assertRaises
(
TypeError
,
is_control_flow_if
(
node
))
self
.
assertTrue
(
"Type of input node should be gast.AST"
in
str
(
e
.
exception
))
class
TestAST2Func
(
unittest
.
TestCase
):
...
...
@@ -130,13 +156,14 @@ class TestAST2Func(unittest.TestCase):
self
.
assertEqual
(
func
(
x
,
y
),
self
.
_ast2func
(
func
)(
x
,
y
))
def
test_ast2func_dygraph
(
self
):
func
=
dyfunc_with_if_else
func
s
=
[
dyfunc_with_if_else
,
dyfunc_with_if_else
,
nested_if_else
]
x_data
=
np
.
random
.
random
([
10
,
16
]).
astype
(
'float32'
)
with
fluid
.
dygraph
.
guard
():
x_v
=
fluid
.
dygraph
.
to_variable
(
x_data
)
true_ret
=
func
(
x_v
).
numpy
()
test_ret
=
self
.
_ast2func
(
func
)(
x_v
).
numpy
()
self
.
assertTrue
((
true_ret
==
test_ret
).
all
())
for
func
in
funcs
:
with
fluid
.
dygraph
.
guard
():
x_v
=
fluid
.
dygraph
.
to_variable
(
x_data
)
true_ret
=
func
(
x_v
).
numpy
()
test_ret
=
self
.
_ast2func
(
func
)(
x_v
).
numpy
()
self
.
assertTrue
((
true_ret
==
test_ret
).
all
())
def
test_ast2func_static
(
self
):
def
func
(
x
):
...
...
python/paddle/fluid/tests/unittests/test_dygraph_to_static_basic.py
浏览文件 @
dab5e5d8
...
...
@@ -22,18 +22,30 @@ from paddle.fluid.dygraph.jit import dygraph_to_static_output
np
.
random
.
seed
(
1
)
if
fluid
.
is_compiled_with_cuda
():
place
=
fluid
.
CUDAPlace
(
0
)
else
:
place
=
fluid
.
CPUPlace
()
def
dyfunc_with_if_else
(
x_v
):
def
dyfunc_with_if_else
(
x_v
,
label
=
None
):
if
fluid
.
layers
.
mean
(
x_v
).
numpy
()[
0
]
>
5
:
x_v
=
x_v
-
1
else
:
x_v
=
x_v
+
1
# plain if in python
if
label
is
not
None
:
loss
=
fluid
.
layers
.
cross_entropy
(
x_v
,
label
)
return
loss
return
x_v
def
dyfunc_with_if_else2
(
x
):
i
,
j
=
0
,
0
if
fluid
.
layers
.
reduce_mean
(
x
).
numpy
()[
0
]
>
x
.
numpy
()[
i
][
j
]:
def
dyfunc_with_if_else2
(
x
,
col
=
100
):
row
=
0
# plain if in python
if
abs
(
col
)
>
x
.
shape
[
-
1
]:
col
=
-
1
if
fluid
.
layers
.
reduce_mean
(
x
).
numpy
()[
0
]
>
x
.
numpy
()[
row
][
col
]:
y
=
fluid
.
layers
.
relu
(
x
)
else
:
x_pow
=
fluid
.
layers
.
pow
(
x
,
2
)
...
...
@@ -42,9 +54,12 @@ def dyfunc_with_if_else2(x):
def
nested_if_else
(
x_v
):
batch_size
=
x_v
.
shape
[
0
]
batch_size
=
16
feat_size
=
x_v
.
shape
[
-
1
]
bias
=
fluid
.
layers
.
fill_constant
([
feat_size
],
dtype
=
'float32'
,
value
=
1
)
# plain if in python
if
x_v
.
shape
[
0
]
!=
batch_size
:
batch_size
=
x_v
.
shape
[
0
]
if
fluid
.
layers
.
mean
(
x_v
).
numpy
()[
0
]
<
0
:
y
=
x_v
+
bias
w
=
fluid
.
layers
.
fill_constant
([
feat_size
],
dtype
=
'float32'
,
value
=
10
)
...
...
@@ -78,12 +93,12 @@ class TestDygraphIfElse(unittest.TestCase):
x_v
=
fluid
.
layers
.
assign
(
self
.
x
)
# Transform into static graph
out
=
dygraph_to_static_output
(
self
.
dyfunc
)(
x_v
)
exe
=
fluid
.
Executor
(
fluid
.
CPUPlace
()
)
exe
=
fluid
.
Executor
(
place
)
ret
=
exe
.
run
(
main_program
,
fetch_list
=
out
)
return
ret
def
_run_dygraph
(
self
):
with
fluid
.
dygraph
.
guard
():
with
fluid
.
dygraph
.
guard
(
place
):
x_v
=
fluid
.
dygraph
.
to_variable
(
self
.
x
)
ret
=
self
.
dyfunc
(
x_v
)
return
ret
.
numpy
()
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录