Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
X2Paddle
提交
e8b8e410
X
X2Paddle
项目概览
PaddlePaddle
/
X2Paddle
大约 2 年 前同步成功
通知
329
Star
698
Fork
167
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
26
列表
看板
标记
里程碑
合并请求
4
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
X
X2Paddle
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
26
Issue
26
列表
看板
标记
里程碑
合并请求
4
合并请求
4
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
未验证
提交
e8b8e410
编写于
8月 26, 2020
作者:
J
Jason
提交者:
GitHub
8月 26, 2020
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #380 from SunAhong1993/me
add pytorch convertor
上级
23ba3b50
4fbb2c58
变更
15
显示空白变更内容
内联
并排
Showing
15 changed file
with
3099 addition
and
46 deletion
+3099
-46
x2paddle/__init__.py
x2paddle/__init__.py
+2
-2
x2paddle/core/program.py
x2paddle/core/program.py
+259
-44
x2paddle/decoder/pytorch_decoder.py
x2paddle/decoder/pytorch_decoder.py
+33
-0
x2paddle/op_mapper/pytorch2paddle/__init__.py
x2paddle/op_mapper/pytorch2paddle/__init__.py
+0
-0
x2paddle/op_mapper/pytorch2paddle/aten.py
x2paddle/op_mapper/pytorch2paddle/aten.py
+1381
-0
x2paddle/op_mapper/pytorch2paddle/prim.py
x2paddle/op_mapper/pytorch2paddle/prim.py
+397
-0
x2paddle/op_mapper/pytorch2paddle/prim2code.py
x2paddle/op_mapper/pytorch2paddle/prim2code.py
+257
-0
x2paddle/op_mapper/pytorch2paddle/pytorch_op_mapper.py
x2paddle/op_mapper/pytorch2paddle/pytorch_op_mapper.py
+237
-0
x2paddle/optimizer/fusion/__init__.py
x2paddle/optimizer/fusion/__init__.py
+24
-0
x2paddle/optimizer/fusion/fc_fuse_pass.py
x2paddle/optimizer/fusion/fc_fuse_pass.py
+33
-0
x2paddle/optimizer/fusion/fc_fuser.py
x2paddle/optimizer/fusion/fc_fuser.py
+186
-0
x2paddle/optimizer/optimizer.py
x2paddle/optimizer/optimizer.py
+34
-0
x2paddle/optimizer/pass_.py
x2paddle/optimizer/pass_.py
+27
-0
x2paddle/optimizer/pass_manager.py
x2paddle/optimizer/pass_manager.py
+42
-0
x2paddle/optimizer/pattern_matcher.py
x2paddle/optimizer/pattern_matcher.py
+187
-0
未找到文件。
x2paddle/__init__.py
浏览文件 @
e8b8e410
__version__
=
"0.7.4"
__version__
=
"0.7.4"
from
.core.program
import
Paddle
Program
from
.core.program
import
Paddle
Graph
program
=
Paddle
Program
()
program
=
Paddle
Graph
()
name_counter
=
dict
()
name_counter
=
dict
()
...
...
x2paddle/core/program.py
浏览文件 @
e8b8e410
...
@@ -18,15 +18,15 @@ import paddle.fluid as fluid
...
@@ -18,15 +18,15 @@ import paddle.fluid as fluid
from
paddle.fluid.proto
import
framework_pb2
from
paddle.fluid.proto
import
framework_pb2
from
collections
import
OrderedDict
from
collections
import
OrderedDict
import
numpy
import
numpy
import
time
import
collections
import
collections
import
sys
import
sys
import
os
import
os
import
six
import
six
import
pickle
class
PaddleLayer
(
object
):
class
PaddleLayer
(
object
):
def
__init__
(
self
,
kernel
,
inputs
,
outputs
,
**
kwargs
):
def
__init__
(
self
,
id
,
kernel
,
inputs
,
outputs
,
**
kwargs
):
assert
isinstance
(
assert
isinstance
(
inputs
,
inputs
,
dict
),
"parameter 'inputs' for PaddleLayer should be type of dict"
dict
),
"parameter 'inputs' for PaddleLayer should be type of dict"
...
@@ -51,22 +51,29 @@ class PaddleLayer(object):
...
@@ -51,22 +51,29 @@ class PaddleLayer(object):
self
.
inputs
=
inputs
self
.
inputs
=
inputs
self
.
outputs
=
outputs
self
.
outputs
=
outputs
self
.
attrs
=
kwargs
self
.
attrs
=
kwargs
self
.
id
=
str
(
time
.
time
())
self
.
id
=
id
self
.
blocks
=
list
()
def
add_block
(
self
,
block
):
def
add_block
(
self
,
block
):
block
.
father_layer
=
self
self
.
blocks
.
append
(
block
)
self
.
blocks
.
append
(
block
)
class
Paddle
Program
(
object
):
class
Paddle
Graph
(
object
):
def
__init__
(
self
):
def
__init__
(
self
,
parent_layer
=
None
,
graph_type
=
"static"
):
self
.
layers
=
OrderedDict
()
self
.
layers
=
OrderedDict
()
self
.
edges_out
=
dict
()
self
.
edges_out
=
dict
()
self
.
edges_in
=
dict
()
self
.
edges_in
=
dict
()
self
.
inputs
=
list
()
self
.
inputs
=
list
()
self
.
outputs
=
list
()
self
.
outputs
=
list
()
self
.
parameters
=
dict
()
self
.
parameters
=
dict
()
self
.
father_layer
=
None
self
.
parent_layer
=
parent_layer
self
.
graph_type
=
graph_type
def
set_name
(
self
,
name
):
self
.
name
=
name
def
set_parameters
(
self
,
parameters
):
self
.
parameters
=
parameters
def
clear
(
self
):
def
clear
(
self
):
self
.
layers
=
OrderedDict
()
self
.
layers
=
OrderedDict
()
...
@@ -76,25 +83,44 @@ class PaddleProgram(object):
...
@@ -76,25 +83,44 @@ class PaddleProgram(object):
self
.
outputs
=
list
()
self
.
outputs
=
list
()
self
.
parameters
=
dict
()
self
.
parameters
=
dict
()
def
clear_edges
(
self
):
self
.
edges_out
=
dict
()
self
.
edges_in
=
dict
()
def
add_layer
(
self
,
kernel
,
inputs
,
outputs
,
**
kwargs
):
def
add_layer
(
self
,
kernel
,
inputs
,
outputs
,
**
kwargs
):
layer
=
PaddleLayer
(
kernel
,
inputs
,
outputs
,
**
kwargs
)
layer_id
=
str
(
len
(
self
.
layers
))
layer_id
=
str
(
len
(
self
.
layers
))
if
self
.
father_layer
is
not
None
:
if
self
.
parent_layer
is
not
None
:
layer_id
=
"{}.{}.{}"
.
format
(
layer_id
,
len
(
self
.
father_layer
.
blocks
()),
self
.
father_layer
.
id
)
layer_id
=
"{}.{}.{}"
.
format
(
self
.
parent_layer
.
id
,
len
(
self
.
parent_layer
.
blocks
),
layer_id
)
layer
=
PaddleLayer
(
layer_id
,
kernel
,
inputs
,
outputs
,
**
kwargs
)
self
.
layers
[
layer_id
]
=
layer
self
.
layers
[
layer_id
]
=
layer
return
layer_id
return
layer_id
def
build
(
self
):
def
build
(
self
,
inputs
=
None
,
outputs
=
None
):
self
.
clear_edges
()
outputs_from_nodes
=
dict
()
outputs_from_nodes
=
dict
()
for
layer_id
,
layer
in
self
.
layers
.
items
():
for
layer_id
,
layer
in
self
.
layers
.
items
():
# if "x5109" in layer.outputs or "x5110" in layer.outputs:
# print(layer.kernel)
# print(layer.inputs)
# print(layer.outputs)
# print(layer.attrs)
for
input_key
,
input_var
in
layer
.
inputs
.
items
():
for
input_key
,
input_var
in
layer
.
inputs
.
items
():
vs
=
input_var
vs
=
input_var
if
not
isinstance
(
vs
,
list
):
if
not
isinstance
(
vs
,
list
):
vs
=
[
vs
]
vs
=
[
vs
]
for
v
in
vs
:
for
v
in
vs
:
assert
v
in
outputs_from_nodes
,
"Couldn't find {} in previous layers, the layers should be make by topological sort"
.
format
(
assert
v
in
outputs_from_nodes
or
(
inputs
is
not
None
and
v
in
list
(
inputs
.
values
())
)
or
(
outputs
is
not
None
and
v
in
outputs
),
"Couldn't find {} in previous layers, the layers should be make by topological sort"
.
format
(
v
)
v
)
if
v
in
outputs_from_nodes
:
in_layer_id
=
outputs_from_nodes
[
v
]
in_layer_id
=
outputs_from_nodes
[
v
]
else
:
in_layer_id
=
-
1
if
in_layer_id
not
in
self
.
edges_out
:
if
in_layer_id
not
in
self
.
edges_out
:
self
.
edges_out
[
in_layer_id
]
=
list
()
self
.
edges_out
[
in_layer_id
]
=
list
()
self
.
edges_out
[
in_layer_id
].
append
(
layer_id
)
self
.
edges_out
[
in_layer_id
].
append
(
layer_id
)
...
@@ -105,6 +131,27 @@ class PaddleProgram(object):
...
@@ -105,6 +131,27 @@ class PaddleProgram(object):
for
output
in
layer
.
outputs
:
for
output
in
layer
.
outputs
:
outputs_from_nodes
[
output
]
=
layer_id
outputs_from_nodes
[
output
]
=
layer_id
if
len
(
layer
.
blocks
)
>
0
:
for
block
in
layer
.
blocks
:
block
.
build
(
layer
.
inputs
,
layer
.
outputs
)
if
self
.
graph_type
==
"dygraph"
:
self
.
get_dygraph_inputs
()
self
.
get_dygraph_outputs
()
def
get_global_layers
(
self
):
# 该全局layers的信息是按照拓扑排序组成的
def
update
(
layers
):
global_layers
=
dict
()
for
layer_id
,
layer
in
layers
.
items
():
global_layers
[
layer_id
]
=
layer
for
block
in
layer
.
blocks
:
block_global_layers
=
update
(
block
.
layers
)
global_layers
.
update
(
block_global_layers
)
return
global_layers
return
update
(
self
.
layers
)
def
gen_code
(
self
,
code_dir
):
def
gen_code
(
self
,
code_dir
):
def
write_code
(
f
,
code_list
,
indent
=
0
):
def
write_code
(
f
,
code_list
,
indent
=
0
):
indent_blank
=
" "
*
indent
indent_blank
=
" "
*
indent
...
@@ -162,6 +209,7 @@ class PaddleProgram(object):
...
@@ -162,6 +209,7 @@ class PaddleProgram(object):
f
.
close
()
f
.
close
()
def
gen_model
(
self
,
save_dir
):
def
gen_model
(
self
,
save_dir
):
if
self
.
graph_type
==
"static"
:
code_dir
=
os
.
path
.
join
(
save_dir
,
'model_with_code'
)
code_dir
=
os
.
path
.
join
(
save_dir
,
'model_with_code'
)
infer_dir
=
os
.
path
.
join
(
save_dir
,
'inference_model'
)
infer_dir
=
os
.
path
.
join
(
save_dir
,
'inference_model'
)
self
.
gen_code
(
code_dir
)
self
.
gen_code
(
code_dir
)
...
@@ -193,6 +241,9 @@ class PaddleProgram(object):
...
@@ -193,6 +241,9 @@ class PaddleProgram(object):
feeded_var_names
=
[
i
.
name
for
i
in
inputs
],
feeded_var_names
=
[
i
.
name
for
i
in
inputs
],
target_vars
=
outputs
,
target_vars
=
outputs
,
executor
=
exe
)
executor
=
exe
)
else
:
self
.
gen_dygraph_code
(
save_dir
)
self
.
dump_dygraph_parameter
(
save_dir
)
def
dump_parameter
(
self
,
param_name
,
param
,
save_dir
):
def
dump_parameter
(
self
,
param_name
,
param
,
save_dir
):
if
not
os
.
path
.
exists
(
save_dir
):
if
not
os
.
path
.
exists
(
save_dir
):
...
@@ -227,3 +278,167 @@ class PaddleProgram(object):
...
@@ -227,3 +278,167 @@ class PaddleProgram(object):
fp
.
write
(
tensor_desc
.
SerializeToString
())
fp
.
write
(
tensor_desc
.
SerializeToString
())
param
.
tofile
(
fp
)
param
.
tofile
(
fp
)
fp
.
close
()
fp
.
close
()
def
get_dygraph_inputs
(
self
):
def
update
(
layers
):
for
layer_id
,
layer
in
layers
.
items
():
if
self
.
edges_in
.
get
(
layer_id
,
0
)
==
0
and
self
.
edges_out
.
get
(
layer_id
,
0
)
==
0
:
continue
if
layer
.
kernel
==
"fluid.dygraph.base.to_variable"
:
value
=
layer
.
attrs
[
"value"
]
if
not
value
.
startswith
(
"params["
):
self
.
inputs
.
append
(
value
)
if
len
(
layer
.
blocks
)
>
0
:
for
block
in
layer
.
blocks
:
block
.
get_dygraph_inputs
()
self
.
inputs
.
extend
(
block
.
inputs
)
update
(
self
.
layers
)
self
.
inputs
=
list
(
set
(
self
.
inputs
))
def
get_dygraph_outputs
(
self
):
for
layer_id
,
layer
in
self
.
layers
.
items
():
if
self
.
edges_in
.
get
(
layer_id
,
0
)
==
0
and
self
.
edges_out
.
get
(
layer_id
,
0
)
==
0
:
continue
if
self
.
edges_out
.
get
(
layer_id
,
0
)
==
0
:
for
output_name
in
layer
.
outputs
:
if
not
output_name
.
startswith
(
"x"
):
continue
self
.
outputs
.
append
(
output_name
)
self
.
outputs
=
list
(
set
(
self
.
outputs
))
def
gen_dygraph_code
(
self
,
code_dir
=
None
,
indent
=
2
):
def
gen_codes
(
code_list
,
indent
=
0
):
indent_blank
=
" "
*
indent
codes
=
[]
for
code_line
in
code_list
:
if
code_line
.
strip
()
==
""
:
codes
.
append
(
'
\n
'
)
else
:
codes
.
append
(
indent_blank
+
code_line
+
'
\n
'
)
return
codes
def
gen_head
():
self
.
head
=
gen_codes
(
[
"from paddle.fluid.initializer import Constant"
,
"from paddle.fluid.param_attr import ParamAttr"
,
"import paddle.fluid as fluid"
,
""
,
"class {}(fluid.dygraph.Layer):"
.
format
(
self
.
name
),
],
indent
=
0
)
input_data_name
=
', '
.
join
(
self
.
inputs
)
self
.
init_func
.
extend
(
gen_codes
(
[
"def __init__(self, params):"
],
indent
=
1
))
self
.
init_func
.
extend
(
gen_codes
(
[
"super({}, self).__init__()"
.
format
(
self
.
name
)],
indent
=
2
))
self
.
forward_func
.
extend
(
gen_codes
(
[
"def forward(self, {}):"
.
format
(
input_data_name
)],
indent
=
1
))
def
write_code
(
code_dir
):
f
=
open
(
os
.
path
.
join
(
code_dir
,
'code.py'
),
'w'
)
for
code_line
in
self
.
head
:
f
.
write
(
code_line
)
init_writen_codes
=
[]
for
code_line
in
self
.
init_func
:
if
code_line
in
init_writen_codes
:
continue
f
.
write
(
code_line
)
init_writen_codes
.
append
(
code_line
)
f
.
write
(
"
\n
"
)
return_code
=
"return {}"
.
format
(
", "
.
join
(
self
.
outputs
))
self
.
forward_func
.
extend
(
gen_codes
([
return_code
],
indent
=
2
))
for
code_line
in
self
.
forward_func
:
f
.
write
(
code_line
)
f
.
close
()
self
.
init_func
=
[]
self
.
forward_func
=
[]
if
indent
==
2
and
code_dir
is
not
None
:
gen_head
()
for
layer_id
,
layer
in
self
.
layers
.
items
():
if
len
(
self
.
layers
)
>
1
:
if
self
.
edges_in
.
get
(
layer_id
,
0
)
==
0
and
self
.
edges_out
.
get
(
layer_id
,
0
)
==
0
and
layer
.
kernel
!=
"prim.assert"
\
and
layer
.
kernel
!=
"prim.exception"
\
and
layer
.
kernel
!=
"prim.warnings"
:
continue
if
"dygraph"
in
layer
.
kernel
:
line
=
"{}"
.
format
(
layer
.
outputs
[
0
]
)
if
layer
.
kernel
==
"fluid.dygraph.base.to_variable"
and
not
layer
.
attrs
[
"value"
].
startswith
(
"params["
)
else
"self.{}"
.
format
(
layer
.
outputs
[
0
])
line
+=
" = {}("
.
format
(
layer
.
kernel
)
for
k
,
v
in
layer
.
attrs
.
items
():
line
+=
"{}={}, "
.
format
(
k
,
v
)
line
=
line
.
strip
(
", "
)
line
+=
")"
if
layer
.
kernel
==
"fluid.dygraph.base.to_variable"
and
not
layer
.
attrs
[
"value"
].
startswith
(
"params["
):
self
.
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
continue
else
:
self
.
init_func
.
extend
(
gen_codes
([
line
],
indent
=
2
))
if
len
(
layer
.
outputs
)
==
1
:
line
=
layer
.
outputs
[
0
]
elif
len
(
layer
.
outputs
)
==
2
:
line
=
layer
.
outputs
[
1
]
else
:
line
=
','
.
join
(
layer
.
outputs
[
1
:])
if
layer
.
kernel
==
"fluid.dygraph.base.to_variable"
and
layer
.
attrs
[
"value"
].
startswith
(
"params["
):
line
+=
" = self.{}"
.
format
(
layer
.
outputs
[
0
])
else
:
line
+=
" = self.{}("
.
format
(
layer
.
outputs
[
0
])
for
k
,
v
in
layer
.
inputs
.
items
():
line
+=
"{}, "
.
format
(
v
)
line
=
line
.
strip
(
", "
)
line
+=
")"
self
.
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
elif
"prim"
in
layer
.
kernel
:
func_name
=
layer
.
kernel
.
replace
(
"."
,
"_"
)
from
x2paddle.op_mapper.pytorch2paddle
import
prim2code
if
hasattr
(
prim2code
,
func_name
):
func
=
getattr
(
prim2code
,
func_name
)
func
(
layer
,
indent
=
indent
,
init_func
=
self
.
init_func
,
forward_func
=
self
.
forward_func
)
else
:
raise
Exception
(
"The kind {} in paddle model is not supported yet."
.
format
(
layer
.
kernel
))
else
:
if
len
(
layer
.
outputs
)
==
1
:
line
=
layer
.
outputs
[
0
]
else
:
line
=
','
.
join
(
layer
.
outputs
)
line
+=
" = {}("
.
format
(
layer
.
kernel
)
for
k
,
v
in
layer
.
inputs
.
items
():
line
+=
"{}={}, "
.
format
(
k
,
v
)
for
k
,
v
in
layer
.
attrs
.
items
():
line
+=
"{}={}, "
.
format
(
k
,
v
)
line
=
line
.
strip
(
", "
)
line
+=
")"
self
.
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
if
indent
==
2
:
write_code
(
code_dir
)
else
:
return
self
.
init_func
,
self
.
forward_func
def
dump_dygraph_parameter
(
self
,
code_dir
):
params_output
=
open
(
os
.
path
.
join
(
code_dir
,
'model.pdparams'
),
'wb'
)
pickle
.
dump
(
self
.
parameters
,
params_output
)
params_output
.
close
()
x2paddle/decoder/pytorch_decoder.py
0 → 100644
浏览文件 @
e8b8e410
# Copyright (c) 2019 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.
import
torch
class
PyTorchDecoder
(
object
):
def
__init__
(
self
,
script_path
):
self
.
script
=
torch
.
jit
.
load
(
script_path
)
self
.
graph
=
self
.
_optimize_graph
(
self
.
script
.
inlined_graph
)
def
_optimize_graph
(
self
,
graph
):
torch
.
_C
.
_jit_pass_constant_propagation
(
graph
)
torch
.
_C
.
_jit_pass_dce
(
graph
)
torch
.
_C
.
_jit_pass_lint
(
graph
)
torch
.
_C
.
_jit_pass_peephole
(
graph
)
torch
.
_C
.
_jit_pass_lint
(
graph
)
torch
.
_C
.
_jit_pass_dce
(
graph
)
torch
.
_C
.
_jit_pass_lint
(
graph
)
graph
=
torch
.
_C
.
_jit_pass_canonicalize
(
graph
)
torch
.
_C
.
_jit_pass_lint
(
graph
)
return
graph
x2paddle/op_mapper/pytorch2paddle/__init__.py
0 → 100644
浏览文件 @
e8b8e410
x2paddle/op_mapper/pytorch2paddle/aten.py
0 → 100644
浏览文件 @
e8b8e410
# 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
x2paddle.core.util
import
*
def
aten_adaptive_avg_pool2d
(
mapper
,
graph
,
node
):
""" 构造average adaptive pool2d的PaddleLayer。
TorchScript示例:
%x.5 : Tensor = aten::adaptive_avg_pool2d(%x.3, %_output_size.1)
参数含义:
%x.5 (Tensor): 池化后结果Tensor。
%x.3 (Tensor): 输入Tensor。
%_output_size.1 (list): 自适应池化后的Tensor的宽、高大小。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
layer_attrs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%x.3
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"input"
]
=
inputs_name
[
0
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
# 处理输入1,即%_output_size.1
if
inputs_name
[
1
]
in
mapper
.
attrs
:
layer_attrs
[
"pool_size"
]
=
mapper
.
attrs
[
inputs_name
[
1
]]
else
:
mapper
.
_check_input
(
graph
,
inputs_node
[
1
],
inputs_name
[
1
],
current_outputs
)
layer_attrs
[
"pool_size"
]
=
inputs_name
[
1
]
current_inputs
.
append
(
inputs_name
[
1
])
layer_attrs
[
"pool_type"
]
=
string
(
"avg"
)
graph
.
add_layer
(
"fluid.layers.adaptive_pool2d"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
,
**
layer_attrs
)
return
current_inputs
,
current_outputs
def
aten_addmm
(
mapper
,
graph
,
node
):
""" 构造addmm的PaddleLayer,该节点实现out = alpha ∗ x ∗ y + beta ∗ input。
TorchScript示例:
%ret.2 : Tensor = aten::addmm(%150, %input.3, %156, %151, %152)
参数含义:
%ret.2 (Tensor): addmm结果Tensor。
%150 (Tensor): 输入Tensor input。
%input.3 (Tensor): 输入Tensor x。
%156 (Tensor): 输入Tensor y。
%151 (int/float): 输入alpha。
%152 (int/float): 输入beta。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
layer_attrs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%150
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
,
add_dim
=
True
)
layer_inputs
[
"input"
]
=
inputs_name
[
0
]
# 处理输入1,即%input.3
mapper
.
_check_input
(
graph
,
inputs_node
[
1
],
inputs_name
[
1
],
current_outputs
)
layer_inputs
[
"x"
]
=
inputs_name
[
1
]
# 处理输入2,即%156
mapper
.
_check_input
(
graph
,
inputs_node
[
2
],
inputs_name
[
2
],
current_outputs
)
layer_inputs
[
"y"
]
=
inputs_name
[
2
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
# 处理输入3,即%152
if
inputs_name
[
3
]
in
mapper
.
attrs
:
layer_attrs
[
"beta"
]
=
mapper
.
attrs
[
inputs_name
[
3
]]
else
:
mapper
.
_check_input
(
graph
,
inputs_node
[
3
],
inputs_name
[
3
],
current_outputs
)
layer_attrs
[
"beta"
]
=
inputs_name
[
3
]
current_inputs
.
append
(
inputs_name
[
3
])
# 处理输入4,即%151
if
inputs_name
[
4
]
in
mapper
.
attrs
:
layer_attrs
[
"alpha"
]
=
mapper
.
attrs
[
inputs_name
[
4
]]
else
:
mapper
.
_check_input
(
graph
,
inputs_node
[
4
],
inputs_name
[
4
],
current_outputs
)
layer_attrs
[
"alpha"
]
=
inputs_name
[
4
]
current_inputs
.
append
(
inputs_name
[
4
])
graph
.
add_layer
(
"fluid.layers.addmm"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
,
**
layer_attrs
)
return
current_inputs
,
current_outputs
def
aten_add
(
mapper
,
graph
,
node
):
""" 构造数值相加的PaddleLayer,该节点实现out = x + y。
TorchScript示例:
%296 : int = aten::add(%i.12, %288)
参数含义:
%296 (-): 相加结果。
%i.12 (-): 输入数值 x。
%288 (-): 输入数值 y。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%i.12
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"x"
]
=
inputs_name
[
0
]
# 处理输入1,即%288
mapper
.
_check_input
(
graph
,
inputs_node
[
1
],
inputs_name
[
1
],
current_outputs
,
add_dim
=
True
)
layer_inputs
[
"y"
]
=
inputs_name
[
1
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"prim.add"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
aten_add_
(
mapper
,
graph
,
node
):
""" 构造数值相加的PaddleLayer,该节点实现out = x + alpha * y。
TorchScript示例:
%137 : Tensor = aten::add(%136, %130, %130)
参数含义:
%output.5 (Tensor): add结果Tensor。
%output.2 (Tensor): 输入Tensor x。
%150 (Tensor): 输入Tensor y。
%151 (int/float): 输入alpha。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
layer_attrs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%output.2
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"x"
]
=
inputs_name
[
0
]
# 处理输入1,即%150
mapper
.
_check_input
(
graph
,
inputs_node
[
1
],
inputs_name
[
1
],
current_outputs
,
add_dim
=
True
)
layer_inputs
[
"y"
]
=
inputs_name
[
1
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
# 处理输入2,即%151
if
inputs_name
[
2
]
in
mapper
.
attrs
:
layer_attrs
[
"alpha"
]
=
mapper
.
attrs
[
inputs_name
[
2
]]
else
:
mapper
.
_check_input
(
graph
,
inputs_node
[
2
],
inputs_name
[
2
],
current_outputs
)
layer_attrs
[
"alpha"
]
=
inputs_name
[
2
]
current_inputs
.
append
(
inputs_name
[
2
])
graph
.
add_layer
(
"prim.add_"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
,
**
layer_attrs
)
return
current_inputs
,
current_outputs
def
aten___and__
(
mapper
,
graph
,
node
):
""" 构造与计算的PaddleLayer。
TorchScript示例:
%361 : bool = aten::__and__(%360, %358)
参数含义:
%361 (bool): 输出,与计算结果。
%360 (-): 输入 x。
%358 (-): 输入 y。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%i.12
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"x"
]
=
inputs_name
[
0
]
# 处理输入1,即%288
mapper
.
_check_input
(
graph
,
inputs_node
[
1
],
inputs_name
[
1
],
current_outputs
,
add_dim
=
True
)
layer_inputs
[
"y"
]
=
inputs_name
[
1
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"prim.and"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
aten_append
(
mapper
,
graph
,
node
):
""" 构造对list进行append的PaddleLayer。
TorchScript示例:
%90 : int[] = aten::append(%_output_size.1, %v.1)
参数含义:
%90 (list): 输出,append后的list。
%_output_size.1 (list): 需要进行append的list。
%v.1 (-): append的元素。
"""
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
layer_outputs
=
[
inputs_name
[
0
]]
# 获取当前节点输出的list
current_outputs
=
[
inputs_name
[
0
]]
# 处理输入0,即_output_size.1
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"list"
]
=
inputs_name
[
0
]
# 处理输入1,即v.1
mapper
.
_check_input
(
graph
,
inputs_node
[
1
],
inputs_name
[
1
],
current_outputs
)
layer_inputs
[
"element"
]
=
inputs_name
[
1
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"prim.append"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
aten_avg_pool2d
(
mapper
,
graph
,
node
):
""" 构造最大池化的PaddleLayer。
TorchScript示例:
%branch_pool.2 : Tensor = aten::avg_pool2d(%x.43, %538, %539, %540, %273, %272, %271)
参数含义:
%branch_pool.2 (Tensor): 输出,池化后的结果。
%x.43 (Tensor): 需要池化的Tensor。
%538 (list): 池化kernel的大小。
%539 (list): 步长大小。
%540 (list): 填充大小。
%273 (bool): 是否用ceil函数计算输出高度和宽度。
%272 (bool): 是否在平均池化模式不忽略填充值,False为忽略。
%271 (int): 如果指定,它将用作除数,否则将使用池化区域的大小。
"""
if
"pool"
in
mapper
.
dygraph_name_id
:
mapper
.
dygraph_name_id
[
"pool"
]
+=
1
else
:
mapper
.
dygraph_name_id
[
"pool"
]
=
0
pool_name
=
"pool"
+
str
(
mapper
.
dygraph_name_id
[
"pool"
])
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
pool_name
,
output_name
]
layer_inputs
=
{}
layer_attrs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%x.34
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"input"
]
=
inputs_name
[
0
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
# 处理输入1,即%538
layer_attrs
[
"pool_size"
]
=
mapper
.
attrs
[
inputs_name
[
1
]]
# 处理输入2,即%539
layer_attrs
[
"pool_stride"
]
=
mapper
.
attrs
[
inputs_name
[
2
]]
# 处理输入3,即%540
layer_attrs
[
"pool_padding"
]
=
mapper
.
attrs
[
inputs_name
[
3
]]
# 处理输入4,即%273
layer_attrs
[
"ceil_mode"
]
=
mapper
.
attrs
[
inputs_name
[
4
]]
# 处理输入5,即%272
layer_attrs
[
"exclusive"
]
=
not
mapper
.
attrs
[
inputs_name
[
5
]]
# 处理输入6,即%271
graph
.
add_layer
(
"prim.assert"
,
inputs
=
{},
outputs
=
[
inputs_name
[
6
]],
type
=
"eq"
,
key
=
mapper
.
attrs
[
inputs_name
[
6
]],
value
=
None
)
layer_attrs
[
"pool_type"
]
=
string
(
"avg"
)
graph
.
add_layer
(
"fluid.dygraph.Pool2D"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
,
**
layer_attrs
)
return
current_inputs
,
current_outputs
def
aten_batch_norm
(
mapper
,
graph
,
node
):
""" 构造BatchNorm的PaddleLayer。
TorchScript示例:
%input.81 : Tensor = aten::batch_norm(%input.80, %778, %779, %776, %777, %780,
%exponential_average_factor.23, %766, %781)
参数含义:
%input.81 (Tensor): 输出,批处理后的结果。
%input.80 (Tensor): 需要进行批处理的特征层。
%778 (Tensor): weights。
%779 (Tensor): bias。
%776 (Tensor): 全局均值。
%777 (Tensor): 全局方差。
%780 (bool): 是否训练。
%exponential_average_factor.23 (float): 用于计算均值和方差的比例。
%766 (float): 为了数值稳定加在分母上的值。
%781 (bool): 是否启用cudnn。
"""
if
"batchnorm"
in
mapper
.
dygraph_name_id
:
mapper
.
dygraph_name_id
[
"batchnorm"
]
+=
1
else
:
mapper
.
dygraph_name_id
[
"batchnorm"
]
=
0
batchnorm_name
=
"batchnorm"
+
str
(
mapper
.
dygraph_name_id
[
"batchnorm"
])
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
batchnorm_name
,
output_name
]
layer_inputs
=
{}
layer_attrs
=
{}
layer_attrs
[
"is_test"
]
=
True
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%input.80
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"input"
]
=
inputs_name
[
0
]
# 获取当前节点输入、输出的list
current_inputs
=
list
(
layer_inputs
.
values
())
# 处理输入1,即%778
weights
=
mapper
.
pytorch_params
[
inputs_name
[
1
]]
mapper
.
paddle_params
[
batchnorm_name
+
".weight"
]
=
weights
layer_attrs
[
'num_channels'
]
=
weights
.
shape
[
0
]
# 处理输入2,即%779
if
inputs_name
[
2
]
in
mapper
.
pytorch_params
:
bias
=
mapper
.
pytorch_params
[
inputs_name
[
2
]]
if
bias
is
not
None
:
mapper
.
paddle_params
[
batchnorm_name
+
".bias"
]
=
bias
else
:
mapper
.
paddle_params
[
batchnorm_name
+
".bias"
]
=
False
# 处理输入3,即%776
mean
=
mapper
.
pytorch_params
[
inputs_name
[
3
]]
mapper
.
paddle_params
[
batchnorm_name
+
"._mean"
]
=
mean
# 处理输入4,即%777
var
=
mapper
.
pytorch_params
[
inputs_name
[
4
]]
mapper
.
paddle_params
[
batchnorm_name
+
"._variance"
]
=
var
# 处理输入6,即%exponential_average_factor.23
layer_attrs
[
"momentum"
]
=
mapper
.
attrs
[
inputs_name
[
6
]]
# 处理输入7,即%766
layer_attrs
[
"epsilon"
]
=
mapper
.
attrs
[
inputs_name
[
7
]]
graph
.
add_layer
(
"fluid.dygraph.BatchNorm"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
,
**
layer_attrs
)
return
current_inputs
,
current_outputs
def
aten_cat
(
mapper
,
graph
,
node
):
""" 构造连接Tensor的PaddleLayer。
TorchScript示例:
%x.222 : Tensor = aten::cat(%32, %7)
参数含义:
%x.222 (Tensor): 输出,连接后的结果。
%i.12 (list): 需要连接的Tensor组成的list。
%7 (int): 连接的轴。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
layer_attrs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%13
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"input"
]
=
inputs_name
[
0
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
# 处理输入1,即%12
if
inputs_name
[
1
]
in
mapper
.
attrs
:
layer_attrs
[
"axis"
]
=
mapper
.
attrs
[
inputs_name
[
1
]]
else
:
mapper
.
_check_input
(
graph
,
inputs_node
[
1
],
inputs_name
[
1
],
current_outputs
)
layer_attrs
[
"axis"
]
=
inputs_name
[
1
]
current_inputs
.
append
(
inputs_name
[
1
])
graph
.
add_layer
(
"fluid.layers.concat"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
,
**
layer_attrs
)
return
current_inputs
,
current_outputs
def
aten_conv2d
(
mapper
,
graph
,
node
):
""" 构造conv2d的PaddleLayer。
TorchScript示例:
%input.10 : Tensor = aten::conv2d(%input.8, %25, %27, %28, %29, %30, %26)
参数含义:
%input.10 (Tensor): 输出,卷积后的结果。
%input.8 (Tensor): 需要进行卷积的特征层。
%25 (Tensor): weights。
%27 (Tensor): bias。
%28 (int): 步长大小。
%29 (int): 填充大小。
%30 (int): 膨胀系数大小。
%26 (int): 卷积的组数。
"""
if
"conv"
in
mapper
.
dygraph_name_id
:
mapper
.
dygraph_name_id
[
"conv"
]
+=
1
else
:
mapper
.
dygraph_name_id
[
"conv"
]
=
0
conv2d_name
=
"conv"
+
str
(
mapper
.
dygraph_name_id
[
"conv"
])
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
conv2d_name
,
output_name
]
layer_inputs
=
{}
layer_attrs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%input.8
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"input"
]
=
inputs_name
[
0
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
# 处理输入1,即%25
weights
=
mapper
.
pytorch_params
[
inputs_name
[
1
]]
mapper
.
paddle_params
[
conv2d_name
+
".weight"
]
=
weights
layer_attrs
[
"num_filters"
]
=
weights
.
shape
[
0
]
layer_attrs
[
"filter_size"
]
=
weights
.
shape
[
2
:]
# 处理输入2,即%27
if
inputs_name
[
2
]
in
mapper
.
pytorch_params
:
bias
=
mapper
.
pytorch_params
[
inputs_name
[
2
]]
if
bias
is
not
None
:
mapper
.
paddle_params
[
conv2d_name
+
".bias"
]
=
bias
else
:
layer_attrs
[
"bias_attr"
]
=
False
else
:
layer_attrs
[
"bias_attr"
]
=
False
# 处理输入3,即%28
layer_attrs
[
"stride"
]
=
mapper
.
attrs
[
inputs_name
[
3
]]
# 处理输入4,即%29
layer_attrs
[
"padding"
]
=
mapper
.
attrs
[
inputs_name
[
4
]]
# 处理输入5,即%30
layer_attrs
[
"dilation"
]
=
mapper
.
attrs
[
inputs_name
[
5
]]
# 处理输入6,即%26
layer_attrs
[
"groups"
]
=
mapper
.
attrs
[
inputs_name
[
6
]]
layer_attrs
[
'num_channels'
]
=
weights
.
shape
[
1
]
*
mapper
.
attrs
[
inputs_name
[
6
]]
graph
.
add_layer
(
"fluid.dygraph.Conv2D"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
,
**
layer_attrs
)
return
current_inputs
,
current_outputs
def
aten_dim
(
mapper
,
graph
,
node
):
""" 构造获取维度的PaddleLayer。
TorchScript示例:
%106 : int = aten::dim(%101)
参数含义:
%106 (int): 输出,Tensor的维度。
%101 (Tensor): 输入的Tensor。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%input.8
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"input"
]
=
inputs_name
[
0
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"prim.shape"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
graph
.
add_layer
(
"prim.len"
,
inputs
=
{
"input"
:
output_name
},
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
aten_dropout
(
mapper
,
graph
,
node
):
""" 构造Dropout的PaddleLayer。
TorchScript示例:
%119 : Tensor = aten::dropout(%result.3, %117, %118)
参数含义:
%119 (Tensor): Dropout后的Tensor。
%result.3 (Tensor): 输入Tensor。
%118 (bool): 是否是训练阶段。
"""
if
"dropout"
in
mapper
.
dygraph_name_id
:
mapper
.
dygraph_name_id
[
"dropout"
]
+=
1
else
:
mapper
.
dygraph_name_id
[
"dropout"
]
=
0
dropout_name
=
"dropout"
+
str
(
mapper
.
dygraph_name_id
[
"dropout"
])
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
dropout_name
,
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%119
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"input"
]
=
inputs_name
[
0
]
# 获取当前节点输入、输出的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"fluid.dygraph.Dropout"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
,
p
=
0.0
)
return
current_inputs
,
current_outputs
def
aten_dropout_
(
mapper
,
graph
,
node
):
""" 构造Dropout的PaddleLayer。
TorchScript示例:
%119 : Tensor = aten::dropout_(%result.3, %117, %118)
参数含义:
%119 (Tensor): Dropout后的Tensor。
%result.3 (Tensor): 输入Tensor。
%118 (bool): 是否是训练阶段。
"""
if
"dropout"
in
mapper
.
dygraph_name_id
:
mapper
.
dygraph_name_id
[
"dropout"
]
+=
1
else
:
mapper
.
dygraph_name_id
[
"dropout"
]
=
0
dropout_name
=
"dropout"
+
str
(
mapper
.
dygraph_name_id
[
"dropout"
])
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
dropout_name
,
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%119
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"input"
]
=
inputs_name
[
0
]
# 获取当前节点输入、输出的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"fluid.dygraph.Dropout"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
,
p
=
0.0
)
return
current_inputs
,
current_outputs
def
aten_eq
(
mapper
,
graph
,
node
):
""" 构造判断数值是否相等的PaddleLayer。
TorchScript示例:
%125 : bool = aten::eq(%124, %123)
参数含义:
%125 (bool): 对比后结果。
%124 (-): 需对比的输入1。
%123 (-): 需对比的输入2。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%124
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"x"
]
=
inputs_name
[
0
]
# 处理输入1,即%123
mapper
.
_check_input
(
graph
,
inputs_node
[
1
],
inputs_name
[
1
],
current_outputs
)
layer_inputs
[
"y"
]
=
inputs_name
[
1
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"prim.eq"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
aten_flatten
(
mapper
,
graph
,
node
):
""" 构造flatten的PaddleLayer。
TorchScript示例:
%x.8 : Tensor = aten::flatten(%x, %4, %2)
参数含义:
%x.8 (Tensor): flatten后结果。
%x (Tensor): 输入Tensor。
%4 (int): flatten的开始维度。
%2 (int): flatten的结束维度。
注意:目前flatten只支持第一维的flatten
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入1,即%4
graph
.
add_layer
(
"prim.assert"
,
inputs
=
{},
outputs
=
[
inputs_name
[
1
]],
type
=
'eq'
,
key
=
mapper
.
attrs
[
inputs_name
[
1
]],
value
=
1
)
# 处理输入2,即%2
graph
.
add_layer
(
"prim.assert"
,
inputs
=
{},
outputs
=
[
inputs_name
[
2
]],
type
=
'eq'
,
key
=
mapper
.
attrs
[
inputs_name
[
2
]],
value
=-
1
)
# 处理输入0,即%x
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"x"
]
=
inputs_name
[
0
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"fluid.layers.flatten"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
,
axis
=
1
)
return
current_inputs
,
current_outputs
def
aten___getitem__
(
mapper
,
graph
,
node
):
""" 构造获取list中元素的PaddleLayer。
TorchScript示例:
%v.1 : int = aten::__getitem__(%72, %88)
参数含义:
%v.1 (-): 输出,list中的元素。
%72 (list): 需要获取元素的list。
%88 (int): 索引。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%72
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"list"
]
=
inputs_name
[
0
]
# 处理输入1,即%88
mapper
.
_check_input
(
graph
,
inputs_node
[
1
],
inputs_name
[
1
],
current_outputs
)
layer_inputs
[
"index"
]
=
inputs_name
[
1
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"prim.getitem"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
aten_gt
(
mapper
,
graph
,
node
):
""" 构造对比大小的PaddleLayer。
TorchScript示例:
%83 : bool = aten::gt(%82, %78)
参数含义:
%83 (bool): 输出,第一个元素是否大于第二个元素。
%82 (-): 需对比的输入1。
%78 (-): 需对比的输入2。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%82
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"x"
]
=
inputs_name
[
0
]
# 处理输入1,即%78
mapper
.
_check_input
(
graph
,
inputs_node
[
1
],
inputs_name
[
1
],
current_outputs
)
layer_inputs
[
"y"
]
=
inputs_name
[
1
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"prim.gt"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
aten_hardtanh_
(
mapper
,
graph
,
node
):
""" 构造hardtanh激活的PaddleLayer。
TorchScript示例:
%result.9 : Tensor = aten::hardtanh_(%input.20, %67, %66)
参数含义:
%result.9 (Tensor): 输出,hardtanh激活后的Tensor。
%input.20 (Tensor): 需要hardtanh激活的Tensor。
%67 (float): hardtanh激活的最小阈值。
%66 (float): hardtanh激活的最大阈值。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入1,即%67
graph
.
add_layer
(
"prim.assert"
,
inputs
=
{},
outputs
=
[
inputs_name
[
1
]],
type
=
'eq'
,
key
=
mapper
.
attrs
[
inputs_name
[
1
]],
value
=
0.0
)
# 处理输入2,即%66
graph
.
add_layer
(
"prim.assert"
,
inputs
=
{},
outputs
=
[
inputs_name
[
2
]],
type
=
'eq'
,
key
=
mapper
.
attrs
[
inputs_name
[
2
]],
value
=
6.0
)
# 处理输入0,即%input.20
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"x"
]
=
inputs_name
[
0
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
'fluid.layers.relu6'
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
,
threshold
=
6.0
)
return
current_inputs
,
current_outputs
def
aten_le
(
mapper
,
graph
,
node
):
""" 构造对比大小的PaddleLayer。
TorchScript示例:
%80 : bool = aten::le(%78, %79)
参数含义:
%80 (bool): 输出,第一个元素是否小于等于第二个元素。
%78 (-): 需对比的输入1。
%79 (-): 需对比的输入2。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%78
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"x"
]
=
inputs_name
[
0
]
# 处理输入1,即%79
mapper
.
_check_input
(
graph
,
inputs_node
[
1
],
inputs_name
[
1
],
current_outputs
)
layer_inputs
[
"y"
]
=
inputs_name
[
1
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"prim.le"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
aten_len
(
mapper
,
graph
,
node
):
""" 构造获取list长度的PaddleLayer。
TorchScript示例:
%85 : int = aten::len(%83)
参数含义:
%85 (int): 输出,list的长度。
%72 (list): 需要获取长度的list。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%72
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"input"
]
=
inputs_name
[
0
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"prim.len"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
aten_lt
(
mapper
,
graph
,
node
):
""" 构造对比大小的PaddleLayer。
TorchScript示例:
%80 : bool = aten::lt(%78, %79)
参数含义:
%80 (bool): 输出,第一个元素是否小于第二个元素。
%78 (-): 需对比的输入1。
%79 (-): 需对比的输入2。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%78
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"x"
]
=
inputs_name
[
0
]
# 处理输入1,即%79
mapper
.
_check_input
(
graph
,
inputs_node
[
1
],
inputs_name
[
1
],
current_outputs
)
layer_inputs
[
"y"
]
=
inputs_name
[
1
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"prim.lt"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
aten_max_pool2d
(
mapper
,
graph
,
node
):
""" 构造最大池化的PaddleLayer。
TorchScript示例:
%input.8 : Tensor = aten::max_pool2d(%result.11, %20, %23, %21, %22, %19)
参数含义:
%input.8 (Tensor): 输出,池化后的结果。
%result.11 (Tensor): 需要池化的Tensor。
%20 (list): 池化kernel的大小。
%23 (list): 步长大小。
%21 (list): 填充大小。
%22 (list): 膨胀系数大小。
%19 (bool): 是否用ceil函数计算输出高度和宽度。
"""
if
"pool"
in
mapper
.
dygraph_name_id
:
mapper
.
dygraph_name_id
[
"pool"
]
+=
1
else
:
mapper
.
dygraph_name_id
[
"pool"
]
=
0
pool_name
=
"pool"
+
str
(
mapper
.
dygraph_name_id
[
"pool"
])
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
pool_name
,
output_name
]
layer_inputs
=
{}
layer_attrs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%result.11
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"input"
]
=
inputs_name
[
0
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
# 处理输入1,即%20
layer_attrs
[
"pool_size"
]
=
mapper
.
attrs
[
inputs_name
[
1
]]
# 处理输入2,即%23
layer_attrs
[
"pool_stride"
]
=
mapper
.
attrs
[
inputs_name
[
2
]]
# 处理输入3,即%21
layer_attrs
[
"pool_padding"
]
=
mapper
.
attrs
[
inputs_name
[
3
]]
# 处理输入4,即%22
graph
.
add_layer
(
"prim.assert"
,
inputs
=
{},
outputs
=
[
inputs_name
[
4
]],
type
=
"eq"
,
key
=
mapper
.
attrs
[
inputs_name
[
4
]],
value
=
[
1
,
[
1
,
1
]])
# 处理输入5,即%19
layer_attrs
[
"ceil_mode"
]
=
mapper
.
attrs
[
inputs_name
[
5
]]
layer_attrs
[
"pool_type"
]
=
string
(
"max"
)
graph
.
add_layer
(
"fluid.dygraph.Pool2D"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
,
**
layer_attrs
)
return
current_inputs
,
current_outputs
def
aten_matmul
(
mapper
,
graph
,
node
):
""" 构造矩阵相乘的PaddleLayer。
TorchScript示例:
%output.2 : Tensor = aten::matmul(%101, %111)
参数含义:
%output.2 (Tensor): 输出,相乘后的结果。
%101 (Tensor): 矩阵1。
%102 (Tensor): 矩阵2。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%101
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"x"
]
=
inputs_name
[
0
]
# 处理输入1,即%102
mapper
.
_check_input
(
graph
,
inputs_node
[
1
],
inputs_name
[
1
],
current_outputs
)
layer_inputs
[
"y"
]
=
inputs_name
[
1
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"fluid.layers.matmul"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
aten_mul
(
mapper
,
graph
,
node
):
""" 构造数值相乘的PaddleLayer。
TorchScript示例:
%size_prods.39 : int = aten::mul(%size_prods.38, %114)
参数含义:
%size_prods.39 (Tensor): 输出,相乘后的结果。
%size_prods.38 (-): 数值1。
%114 (-): 数值2。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%size_prods.38
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"x"
]
=
inputs_name
[
0
]
# 处理输入1,即%114
mapper
.
_check_input
(
graph
,
inputs_node
[
1
],
inputs_name
[
1
],
current_outputs
)
layer_inputs
[
"y"
]
=
inputs_name
[
1
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
current_outputs
=
layer_outputs
graph
.
add_layer
(
"prim.mul"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
aten_ne
(
mapper
,
graph
,
node
):
""" 构造判断数值是否不相等的PaddleLayer。
TorchScript示例:
%134 : bool = aten::ne(%133, %132)
参数含义:
%134 (bool): 对比后结果。
%133 (-): 需对比的输入1。
%132 (-): 需对比的输入2。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%124
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"x"
]
=
inputs_name
[
0
]
# 处理输入1,即%123
mapper
.
_check_input
(
graph
,
inputs_node
[
1
],
inputs_name
[
1
],
current_outputs
)
layer_inputs
[
"y"
]
=
inputs_name
[
1
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"prim.ne"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
aten_neg
(
mapper
,
graph
,
node
):
""" 构造对数值取负的PaddleLayer。
TorchScript示例:
%909 : int = aten::neg(%908)
参数含义:
%909 (int): 取负后结果。
%908 (int): 需取负的输入。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%124
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"input"
]
=
inputs_name
[
0
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"prim.neg"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
aten___not__
(
mapper
,
graph
,
node
):
""" 构造对bool型取负的PaddleLayer。
TorchScript示例:
%4498 : bool = aten::__not__(%aux_defined.2)
参数含义:
%4498 (bool): 取负后结果。
%aux_defined.2 (bool): 需取负的输入。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%124
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"input"
]
=
inputs_name
[
0
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"prim.not"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
aten_relu
(
mapper
,
graph
,
node
):
""" 构造ReLU激活的PaddleLayer。
TorchScript示例:
%result.3 : Tensor = aten::relu(%input.5)
参数含义:
%result.3 (Tensor): 输出,ReLU后的结果。
%result.5 (Tensor): 需要ReLU的Tensor。
注意: inplace这个参数在paddle中未实现
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%result.5
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"x"
]
=
inputs_name
[
0
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"fluid.layers.relu"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
aten_relu_
(
mapper
,
graph
,
node
):
""" 构造ReLU激活的PaddleLayer。
TorchScript示例:
%result.3 : Tensor = aten::relu_(%input.5)
参数含义:
%result.3 (Tensor): 输出,ReLU后的结果。
%result.5 (Tensor): 需要ReLU的Tensor。
注意: inplace这个参数在paddle中未实现
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%result.5
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"x"
]
=
inputs_name
[
0
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"fluid.layers.relu"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
aten_relu6
(
mapper
,
graph
,
node
):
""" 构造ReLU6激活的PaddleLayer。
TorchScript示例:
%result.3 : Tensor = aten::relu6(%input.5)
参数含义:
%result.3 (Tensor): 输出,ReLU6后的结果。
%result.5 (Tensor): 需要ReLU6的Tensor。
注意: inplace这个参数在paddle中未实现
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%result.5
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"x"
]
=
inputs_name
[
0
]
# 获取当前节点输入、输出的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"fluid.layers.relu6"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
,
threshold
=
6.0
)
return
current_inputs
,
current_outputs
def
aten_reshape
(
mapper
,
graph
,
node
):
""" 构造调整大小的PaddleLayer。
TorchScript示例:
%x.6 : Tensor = aten::reshape(%4700, %4703)
参数含义:
%x.6 (Tensor): 输出,reshape后的Tensor。
%4700 (Tensor): 需要reshape的Tensor。
%4703 (list): 形状大小组成的list。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
layer_attrs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%4700
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"x"
]
=
inputs_name
[
0
]
# 处理输入1,即%4703
mapper
.
_check_input
(
graph
,
inputs_node
[
1
],
inputs_name
[
1
],
current_outputs
)
layer_inputs
[
"shape"
]
=
inputs_name
[
1
]
# 获取当前节点输入、输出的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"fluid.layers.reshape"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
aten_select
(
mapper
,
graph
,
node
):
""" 构造选取特定维度Variable的PaddleLayer。
TorchScript示例:
%19 : Tensor = aten::select(%18, %8, %7)
参数含义:
%19 (Tensor): 输出,选取的Tensor。
%18 (Tensor): 需要选取的Tensor。
%8 (int): select的维度。
%7 (int): select的第n个向量。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
layer_attrs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%18
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"input"
]
=
inputs_name
[
0
]
# 处理输入1,即%8
layer_attrs
[
"dim"
]
=
mapper
.
attrs
[
inputs_name
[
1
]]
# 处理输入2,即%75
mapper
.
_check_input
(
graph
,
inputs_node
[
2
],
inputs_name
[
2
],
current_outputs
)
layer_inputs
[
"index"
]
=
inputs_name
[
2
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"prim.select"
,
inputs
=
layer_inputs
,
outputs
=
current_outputs
,
**
layer_attrs
)
return
current_inputs
,
current_outputs
def
aten_size
(
mapper
,
graph
,
node
):
""" 构造获取shape的PaddleLayer。
TorchScript示例:
%73 : int[] = aten::size(%x.12)
参数含义:
%73 (list): 输出,shape的list。
%x.12 (Tensor): 需要获取shape的Tensor。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%x.12
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"input"
]
=
inputs_name
[
0
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"prim.shape"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
aten_slice
(
mapper
,
graph
,
node
):
""" 构造切分list或Variable的PaddleLayer。
TorchScript示例:
%83 : int[] = aten::slice(%73, %82, %75, %77)
参数含义:
%83 (list/Tensor): 输出,切分后的list。
%73 (list/Tensor): 需要切分的list。
%82 (int): 切分的开始索引。
%75 (int): 切分的结束索引。
%77 (int): 切分的步长。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%73
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"input"
]
=
inputs_name
[
0
]
# 处理输入1,即%82
mapper
.
_check_input
(
graph
,
inputs_node
[
1
],
inputs_name
[
1
],
current_outputs
)
layer_inputs
[
"start"
]
=
inputs_name
[
1
]
# 处理输入2,即%75
mapper
.
_check_input
(
graph
,
inputs_node
[
2
],
inputs_name
[
2
],
current_outputs
)
layer_inputs
[
"end"
]
=
inputs_name
[
2
]
# 处理输入3,即%77
mapper
.
_check_input
(
graph
,
inputs_node
[
3
],
inputs_name
[
3
],
current_outputs
)
layer_inputs
[
"step"
]
=
inputs_name
[
3
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"prim.slice"
,
inputs
=
layer_inputs
,
outputs
=
current_outputs
)
return
current_inputs
,
current_outputs
def
aten_sub
(
mapper
,
graph
,
node
):
""" 构造数值相减的PaddleLayer。
TorchScript示例:
%840 : int = aten::sub(%839, %836)
参数含义:
%840 (-): 相减结果。
%839 (-): 输入数值 x。
%836 (-): 输入数值 y。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%839
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"x"
]
=
inputs_name
[
0
]
# 处理输入1,即%836
mapper
.
_check_input
(
graph
,
inputs_node
[
1
],
inputs_name
[
1
],
current_outputs
,
add_dim
=
True
)
layer_inputs
[
"y"
]
=
inputs_name
[
1
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"prim.sub"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
aten_t
(
mapper
,
graph
,
node
):
""" 构造矩阵转置的PaddleLayer。
TorchScript示例:
%840 : int = aten::sub(%839, %836)
参数含义:
%109 (Tensor): 输出,转置后的矩阵。
%102 (Tensor): 需要转置的Tensor。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%x.12
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"x"
]
=
inputs_name
[
0
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"fluid.layers.transpose"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
,
perm
=
[
1
,
0
])
return
current_inputs
,
current_outputs
def
aten_unsqueeze
(
mapper
,
graph
,
node
):
""" 构造插入维度的PaddleLayer。
TorchScript示例:
%13 : Tensor = aten::unsqueeze(%12, %7)
参数含义:
%13 (Tensor): 输出,插入维度后的Tensor。
%12 (Tensor): 需要插入维度的Tensor。
%7 (int): 维度。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
layer_attrs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%13
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"input"
]
=
inputs_name
[
0
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
# 处理输入1,即%12
if
inputs_name
[
1
]
in
mapper
.
attrs
:
layer_attrs
[
"axes"
]
=
mapper
.
attrs
[
inputs_name
[
1
]]
else
:
mapper
.
_check_input
(
graph
,
inputs_node
[
1
],
inputs_name
[
1
],
current_outputs
)
layer_attrs
[
"axes"
]
=
inputs_name
[
1
]
current_inputs
.
append
(
inputs_name
[
1
])
graph
.
add_layer
(
"fluid.layers.unsqueeze"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
,
**
layer_attrs
)
return
current_inputs
,
current_outputs
def
aten_warn
(
mapper
,
graph
,
node
):
""" 构造warning的PaddleLayer。
TorchScript示例:
= aten::warn(%3, %2)
参数含义:
%3 (str): warning的提示字符串。
%2 (int): warning的stacklevel。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
layer_attrs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%3
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"input"
]
=
inputs_name
[
0
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
# 处理输入1,即%2
if
inputs_name
[
1
]
in
mapper
.
attrs
:
layer_attrs
[
"stacklevel"
]
=
mapper
.
attrs
[
inputs_name
[
1
]]
else
:
mapper
.
_check_input
(
graph
,
inputs_node
[
1
],
inputs_name
[
1
],
current_outputs
)
layer_attrs
[
"stacklevel"
]
=
inputs_name
[
1
]
current_inputs
.
append
(
inputs_name
[
1
])
graph
.
add_layer
(
"prim.warnings"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
,
**
layer_attrs
)
return
current_inputs
,
current_outputs
x2paddle/op_mapper/pytorch2paddle/prim.py
0 → 100644
浏览文件 @
e8b8e410
# 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.
import
torch
from
x2paddle.core.util
import
*
def
prim_Constant
(
mapper
,
graph
,
node
):
""" 构造constant的PaddleLayer,该节点实现常量赋值。
TorchScript示例:
%2 : int = prim::Constant[value=-1]()
参数含义:
%2 (常量类型由赋值类型定义,该示例中为int型): 常量赋值结果输出。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
output
=
list
(
node
.
outputs
())[
0
]
value
=
output
.
toIValue
()
mapper
.
attrs
[
output_name
]
=
value
if
isinstance
(
value
,
str
):
value
=
string
(
value
)
graph
.
add_layer
(
"prim.constant"
,
inputs
=
{},
outputs
=
[
output_name
],
value
=
value
)
return
[],
[
output_name
]
def
prim_GetAttr
(
mapper
,
graph
,
node
):
""" 获取attribute信息。
TorchScript示例:
%27 : Tensor? = prim::GetAttr[name="bias"](%7)
参数含义:
%7 (Tensor): 输入Tensor。
%27 (Tensor): 输入Tensor。
"""
current_node
=
node
field_name_list
=
[
node
.
s
(
'name'
)]
while
True
:
input_node
=
list
(
node
.
inputs
())[
0
].
node
()
try
:
field_name_list
.
insert
(
0
,
input_node
.
s
(
'name'
))
node
=
input_node
except
Exception
:
break
attr_name
=
"."
.
join
(
field_name_list
)
output_name
=
mapper
.
_get_outputs_name
(
current_node
,
attr_name
)[
0
]
part_script
=
mapper
.
script
for
field_name
in
field_name_list
:
if
hasattr
(
part_script
,
field_name
):
param
=
getattr
(
part_script
,
field_name
)
if
isinstance
(
param
,
torch
.
Tensor
):
param
=
param
.
detach
().
numpy
()
mapper
.
pytorch_params
[
output_name
]
=
param
part_script
=
param
return
[],
[
output_name
]
def
prim_ListConstruct
(
mapper
,
graph
,
node
):
""" 构造list的PaddleLayer。
TorchScript示例:
%86 : int[] = prim::ListConstruct(%84, %85)
参数含义:
%86 (list): list节点输出。
%84 (int/其他): list第一个元素信息。
%85 (int/其他): list第二个元素信息。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理每个输入
for
i
,
input_name
in
enumerate
(
inputs_name
):
layer_inputs
[
"input{}"
.
format
(
i
)]
=
input_name
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"prim.list"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
prim_RaiseException
(
mapper
,
graph
,
node
):
""" 构造抛出异常的PaddleLayer。
TorchScript示例:
= prim::RaiseException(%76)
参数含义:
%76 (str): 异常信息。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%76
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"input"
]
=
inputs_name
[
0
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"prim.exception"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
prim_Loop
(
mapper
,
graph
,
node
):
""" 构造loop循环的PaddleLayer。
TorchScript示例:
%x : Tensor = prim::Loop(%4, %3, %x.3)
block0(%i : int, %x.12 : Tensor):
%72 : int[] = prim::Constant[value=[6, 6]]()
...
%x.5 : Tensor = aten::adaptive_avg_pool2d(%x.12, %_output_size.1)
-> (%3, %x.5)
参数含义:
%4 (int): 循环次数。
%3 (bool): 是否进入退出。
%x.3 (Tensor): 循环中修改的Tensor。
%x (Tensor): loop循环的输出,与%x.5对应。
"""
node_outputs
=
mapper
.
_get_outputs_name
(
node
)
loop_inputs
=
{}
block
=
list
(
node
.
blocks
())[
0
]
loop_outputs
=
node_outputs
.
copy
()
for
i
,
block_input_ivalue
in
enumerate
(
block
.
inputs
()):
if
i
==
0
:
block_input_node_name
=
'_x'
+
str
(
mapper
.
output_index
)
else
:
block_input_node_name
=
'x'
+
str
(
mapper
.
output_index
)
unique_id
=
block_input_ivalue
.
unique
()
if
unique_id
not
in
mapper
.
outputs_info
:
mapper
.
outputs_info
[
unique_id
]
=
block_input_node_name
mapper
.
output_index
+=
1
if
i
==
0
:
loop_input_node
=
list
(
node
.
inputs
())[
0
].
node
()
script_loop_input_unique_id
=
list
(
node
.
inputs
())[
0
].
unique
()
loop_input_node_name
=
mapper
.
outputs_info
[
script_loop_input_unique_id
]
mapper
.
_check_input
(
graph
,
loop_input_node
,
loop_input_node_name
,
node_outputs
)
loop_inputs
[
'input'
]
=
loop_input_node_name
loop_outputs
.
append
(
block_input_node_name
)
node_outputs
.
append
(
block_input_node_name
)
else
:
loop_input_node
=
list
(
node
.
inputs
())[
i
+
1
].
node
()
script_loop_input_unique_id
=
list
(
node
.
inputs
())[
i
+
1
].
unique
()
loop_input_node_name
=
mapper
.
outputs_info
[
script_loop_input_unique_id
]
mapper
.
_check_input
(
graph
,
loop_input_node
,
loop_input_node_name
,
node_outputs
)
graph
.
add_layer
(
"prim.equal"
,
inputs
=
{
'input'
:
loop_input_node_name
},
outputs
=
[
block_input_node_name
])
node_outputs
.
append
(
block_input_node_name
)
graph
.
add_layer
(
"prim.loop"
,
inputs
=
loop_inputs
,
outputs
=
loop_outputs
)
current_layer
=
list
(
graph
.
layers
.
values
())[
-
1
]
block_graph
,
graph_inputs
=
mapper
.
traverse
(
block
,
current_layer
)
for
i
,
input_name
in
enumerate
(
graph_inputs
):
if
input_name
==
loop_outputs
[
1
]:
continue
current_layer
.
inputs
[
'input-{}'
.
format
(
i
)]
=
input_name
current_layer
.
add_block
(
block_graph
)
return
list
(
current_layer
.
inputs
.
values
()),
node_outputs
def
prim_If
(
mapper
,
graph
,
node
):
""" 构造if控制流的PaddleLayer。
TorchScript示例:
%input.5 : Tensor = prim::If(%107)
block0():
%109 : Tensor = aten::t(%102)
%ret.2 : Tensor = aten::addmm(%103, %101, %109, %104, %104)
-> (%ret.2)
block1():
%111 : Tensor = aten::t(%102)
...
-> (%output.4)
参数含义:
%107 (bool): if判断条件。
%input.5 (Tensor): if控制流的输出,与%output.4对应。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
node_outputs
=
[
output_name
]
input_node
=
list
(
node
.
inputs
())[
0
].
node
()
script_input_unique_id
=
list
(
node
.
inputs
())[
0
].
unique
()
input_node_name
=
mapper
.
outputs_info
[
script_input_unique_id
]
mapper
.
_check_input
(
graph
,
input_node
,
input_node_name
,
node_outputs
)
graph
.
add_layer
(
"prim.if"
,
{
'input'
:
input_node_name
},
[
output_name
])
current_layer
=
list
(
graph
.
layers
.
values
())[
-
1
]
block0
=
list
(
node
.
blocks
())[
0
]
block0_graph
,
graph_inputs0
=
mapper
.
traverse
(
block0
,
current_layer
)
len0
=
0
for
i
,
input_name
in
enumerate
(
graph_inputs0
):
current_layer
.
inputs
[
'input-{}'
.
format
(
i
)]
=
input_name
len0
=
i
current_layer
.
add_block
(
block0_graph
)
block1
=
list
(
node
.
blocks
())[
1
]
block1_graph
,
graph_inputs1
=
mapper
.
traverse
(
block1
,
current_layer
)
for
i
,
input_name
in
enumerate
(
graph_inputs1
):
current_layer
.
inputs
[
'input-{}'
.
format
(
len0
+
1
+
i
)]
=
input_name
current_layer
.
add_block
(
block1_graph
)
return
list
(
current_layer
.
inputs
.
values
()),
node_outputs
def
prim_min
(
mapper
,
graph
,
node
):
""" 构造min的PaddleLayer。
TorchScript示例:
%87 : int = prim::min(%86)
参数含义:
%86 (list): 输入。
%87 (int): 输出。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%86
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"input"
]
=
inputs_name
[
0
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"prim.min"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
prim_requires_grad
(
mapper
,
graph
,
node
):
""" 构造是否计算梯度的PaddleLayer。
TorchScript示例:
%356 : bool = prim::requires_grad(%tensor.31)
参数含义:
%356 (bool): 输出,当前Tensor是否计算梯度。
%tensor.31 (Tensor): 输入的Tensor。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%86
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"input"
]
=
inputs_name
[
0
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"prim.requires_grad"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
prim_SetAttr
(
mapper
,
graph
,
node
):
""" 设置attribute信息。
TorchScript示例:
= prim::SetAttr[name="num_batches_tracked"](%260, %277)
参数含义:
%260 (-): 属性名前缀。
%277 (-): 需要设置的值。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
field_name_list
=
[]
tmp_node
=
node
while
True
:
input_node
=
list
(
tmp_node
.
inputs
())[
0
].
node
()
try
:
field_name_list
.
insert
(
0
,
input_node
.
s
(
'name'
))
tmp_node
=
input_node
except
Exception
:
break
field_name_list
.
append
(
node
.
s
(
'name'
))
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
param
=
{
"Tensor"
:
"self."
+
"."
.
join
(
field_name_list
).
replace
(
"."
,
"_"
),
"parent_layer_id"
:
graph
.
parent_layer
.
id
}
mapper
.
pytorch_params
[
"."
.
join
(
field_name_list
)]
=
param
graph
.
add_layer
(
"prim.set_attr"
,
inputs
=
{
"input"
:
inputs_name
[
1
]},
outputs
=
[
"self."
+
"."
.
join
(
field_name_list
).
replace
(
"."
,
"_"
)])
return
[],
[
output_name
]
def
prim_shape
(
mapper
,
graph
,
node
):
""" 构造获取shape的PaddleLayer。
TorchScript示例:
%4701 : int[] = prim::shape(%result.1)
参数含义:
%4701 (list): 输出,shape信息。
%result.1 (Tensor): 需要获取shape的值。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理输入0,即%input.8
mapper
.
_check_input
(
graph
,
inputs_node
[
0
],
inputs_name
[
0
],
current_outputs
)
layer_inputs
[
"input"
]
=
inputs_name
[
0
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"prim.shape"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
prim_TupleConstruct
(
mapper
,
graph
,
node
):
""" 构造tuple的PaddleLayer。
TorchScript示例:
%4492 : (Tensor, Tensor?) = prim::TupleConstruct(%x.46, %aux)
参数含义:
%4492 (tuple): 输出,tuple。
%x.46 (Tensor/其他): tuple第一个元素信息。
%aux (Tensor/其他): tuple第二个元素信息。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
layer_outputs
=
[
output_name
]
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
[
output_name
]
# 处理每个输入
for
i
,
input_name
in
enumerate
(
inputs_name
):
layer_inputs
[
"input{}"
.
format
(
i
)]
=
input_name
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"prim.tuple"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
prim_TupleUnpack
(
mapper
,
graph
,
node
):
""" 构造获取tuple元素的PaddleLayer。
TorchScript示例:
%x.223 : Tensor, %aux.3 : Tensor? = prim::TupleUnpack(%4492)
参数含义:
%x.223 (Tensor/其他): 输出,tuple第一个元素信息。
%aux.3 (Tensor/其他): 输出,tuple第二个元素信息。
%4492 (tuple): 需要获取元素的tuple。
"""
outputs_name
=
mapper
.
_get_outputs_name
(
node
)
layer_outputs
=
outputs_name
layer_inputs
=
{}
inputs_name
,
inputs_node
=
mapper
.
_get_inputs_name
(
node
)
# 获取当前节点输出的list
current_outputs
=
outputs_name
layer_inputs
[
"input"
]
=
inputs_name
[
0
]
# 获取当前节点输入的list
current_inputs
=
list
(
layer_inputs
.
values
())
graph
.
add_layer
(
"prim.tuple_unpack"
,
inputs
=
layer_inputs
,
outputs
=
layer_outputs
)
return
current_inputs
,
current_outputs
def
prim_Uninitialized
(
mapper
,
graph
,
node
):
""" 构造表示编译器永远不会使用的值的PaddleLayer,该节点转换为None。
TorchScript示例:
%345 : bool = prim::Uninitialized()
参数含义:
%345 (bool): 输出,为赋值的bool。
"""
output_name
=
mapper
.
_get_outputs_name
(
node
)[
0
]
output
=
list
(
node
.
outputs
())[
0
]
mapper
.
attrs
[
output_name
]
=
None
graph
.
add_layer
(
"prim.constant"
,
inputs
=
{},
outputs
=
[
output_name
],
value
=
None
)
return
[],
[
output_name
]
x2paddle/op_mapper/pytorch2paddle/prim2code.py
0 → 100644
浏览文件 @
e8b8e410
# Copyright (c) 2019 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.
def
gen_codes
(
code_list
,
indent
=
0
):
indent_blank
=
" "
*
indent
codes
=
[]
for
code_line
in
code_list
:
if
code_line
.
strip
()
==
""
:
codes
.
append
(
'
\n
'
)
else
:
codes
.
append
(
indent_blank
+
code_line
+
'
\n
'
)
return
codes
def
get_value
(
layer
,
key
):
""" 进行optimizer后可能把inputs的value直接用数值代替(ConstantFuser),
会把input换成attr,所以需要此处的操作。
"""
if
key
in
layer
.
inputs
:
return
layer
.
inputs
[
key
]
else
:
return
str
(
layer
.
attrs
[
key
])
def
prim_add
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"{} = {} + {}"
.
format
(
layer
.
outputs
[
0
],
get_value
(
layer
,
"x"
),
get_value
(
layer
,
"y"
))
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_add_
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"{} = {} + {} * {}"
.
format
(
layer
.
outputs
[
0
],
get_value
(
layer
,
"x"
),
layer
.
attrs
[
"alpha"
],
get_value
(
layer
,
"y"
))
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_and
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"{} = {} and {}"
.
format
(
layer
.
outputs
[
0
],
get_value
(
layer
,
"x"
),
get_value
(
layer
,
"y"
))
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_append
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"{}.append({})"
.
format
(
get_value
(
layer
,
"list"
),
get_value
(
layer
,
"element"
))
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_assert
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
if
layer
.
attrs
[
"type"
]
==
"eq"
:
if
isinstance
(
layer
.
attrs
[
"value"
],
list
):
s
=
""
for
v
in
layer
.
attrs
[
"value"
]:
s
+=
"{} == {} or "
.
format
(
layer
.
attrs
[
"key"
],
v
)
if
len
(
s
)
>
0
:
s
=
s
[:
-
4
]
line
=
"assert {},
\'
The {} must be {}!
\'
"
.
format
(
s
,
layer
.
attrs
[
"key"
],
layer
.
attrs
[
"value"
])
else
:
line
=
"assert {} == {},
\'
The {} must be {}!
\'
"
.
format
(
layer
.
attrs
[
"key"
],
layer
.
attrs
[
"value"
],
layer
.
attrs
[
"key"
],
layer
.
attrs
[
"value"
])
else
:
raise
Exception
(
"Not implement yet!"
)
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_constant
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"{} = {}"
.
format
(
layer
.
outputs
[
0
],
layer
.
attrs
[
"value"
])
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_eq
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"{} = {} == {}"
.
format
(
layer
.
outputs
[
0
],
get_value
(
layer
,
"x"
),
get_value
(
layer
,
"y"
))
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_equal
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"{} = {}"
.
format
(
layer
.
outputs
[
0
],
get_value
(
layer
,
"input"
))
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_exception
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"raise RaiseException({})"
.
format
(
get_value
(
layer
,
"input"
))
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_if
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"if {} :"
.
format
(
get_value
(
layer
,
"input"
))
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
block
=
layer
.
blocks
[
0
]
b_init_lines
,
b_forward_lines
=
block
.
gen_dygraph_code
(
indent
=
indent
+
1
)
init_func
.
extend
(
b_init_lines
)
forward_func
.
extend
(
b_forward_lines
)
block
=
layer
.
blocks
[
1
]
if
len
(
block
.
layers
)
>
0
:
line
=
"else:"
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
b_init_lines
,
b_forward_lines
=
block
.
gen_dygraph_code
(
indent
=
indent
+
1
)
init_func
.
extend
(
b_init_lines
)
forward_func
.
extend
(
b_forward_lines
)
def
prim_getitem
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"{} = {}[{}]"
.
format
(
layer
.
outputs
[
0
],
get_value
(
layer
,
"list"
),
get_value
(
layer
,
"index"
))
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_gt
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"{} = {} > {}"
.
format
(
layer
.
outputs
[
0
],
get_value
(
layer
,
"x"
),
get_value
(
layer
,
"y"
))
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_le
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"{} = {} <= {}"
.
format
(
layer
.
outputs
[
0
],
get_value
(
layer
,
"x"
),
get_value
(
layer
,
"y"
))
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_len
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"{} = len({})"
.
format
(
layer
.
outputs
[
0
],
get_value
(
layer
,
"input"
))
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_lt
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"{} = {} < {}"
.
format
(
layer
.
outputs
[
0
],
get_value
(
layer
,
"x"
),
get_value
(
layer
,
"y"
))
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_list
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
input_len
=
len
(
layer
.
inputs
)
+
len
(
layer
.
attrs
)
inputs_list
=
list
()
for
i
in
range
(
input_len
):
inputs_list
.
append
(
get_value
(
layer
,
"input{}"
.
format
(
i
)))
inputs_str
=
', '
.
join
(
inputs_list
)
line
=
"{} = [{}]"
.
format
(
layer
.
outputs
[
0
],
inputs_str
)
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_loop
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
loop_range
=
get_value
(
layer
,
"input"
)
line
=
"for {} in range({}):"
.
format
(
layer
.
outputs
[
1
],
loop_range
)
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
block
=
layer
.
blocks
[
0
]
b_init_lines
,
b_forward_lines
=
block
.
gen_dygraph_code
(
indent
=
indent
+
1
)
init_func
.
extend
(
b_init_lines
)
forward_func
.
extend
(
b_forward_lines
)
def
prim_min
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"{} = min({})"
.
format
(
layer
.
outputs
[
0
],
get_value
(
layer
,
"input"
))
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_mul
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"{} = {} * {}"
.
format
(
layer
.
outputs
[
0
],
get_value
(
layer
,
"x"
),
get_value
(
layer
,
"y"
))
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_ne
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"{} = {} != {}"
.
format
(
layer
.
outputs
[
0
],
get_value
(
layer
,
"x"
),
get_value
(
layer
,
"y"
))
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_neg
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"{} = -{}"
.
format
(
layer
.
outputs
[
0
],
get_value
(
layer
,
"input"
))
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_not
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"{} = not {}"
.
format
(
layer
.
outputs
[
0
],
get_value
(
layer
,
"input"
))
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_requires_grad
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"{} = not {}.stop_gradient"
.
format
(
layer
.
outputs
[
0
],
get_value
(
layer
,
"input"
))
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_select
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"{} = {}["
.
format
(
layer
.
outputs
[
0
],
get_value
(
layer
,
"input"
))
for
dim
in
range
(
layer
.
attrs
[
"dim"
]):
line
+=
":, "
line
+=
(
get_value
(
layer
,
"index"
)
+
"]"
)
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_set_attr
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"{} = {}"
.
format
(
layer
.
outputs
[
0
],
get_value
(
layer
,
"input"
))
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_shape
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"{} = {}.shape"
.
format
(
layer
.
outputs
[
0
],
get_value
(
layer
,
"input"
))
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_slice
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"{} = {}[{}: {}: {}]"
.
format
(
layer
.
outputs
[
0
],
get_value
(
layer
,
"input"
),
get_value
(
layer
,
"start"
),
get_value
(
layer
,
"end"
),
get_value
(
layer
,
"step"
))
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_sub
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
line
=
"{} = {} - {}"
.
format
(
layer
.
outputs
[
0
],
get_value
(
layer
,
"x"
),
get_value
(
layer
,
"y"
))
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_tuple
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
input_len
=
len
(
layer
.
inputs
)
+
len
(
layer
.
attrs
)
inputs_list
=
list
()
for
i
in
range
(
input_len
):
inputs_list
.
append
(
get_value
(
layer
,
"input{}"
.
format
(
i
)))
inputs_str
=
', '
.
join
(
inputs_list
)
line
=
"{} = ({})"
.
format
(
layer
.
outputs
[
0
],
inputs_str
)
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_tuple_unpack
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
outputs_str
=
', '
.
join
(
layer
.
outputs
)
line
=
"{} = {}"
.
format
(
outputs_str
,
get_value
(
layer
,
"input"
))
forward_func
.
extend
(
gen_codes
([
line
],
indent
=
indent
))
def
prim_warnings
(
layer
,
indent
=
1
,
init_func
=
[],
forward_func
=
[]):
lines
=
[
"import warnings"
]
line
=
"warnings.warn({}, stacklevel={})"
.
format
(
get_value
(
layer
,
"input"
),
layer
.
attrs
[
"stacklevel"
])
lines
.
append
(
line
)
forward_func
.
extend
(
gen_codes
(
lines
,
indent
=
indent
))
x2paddle/op_mapper/pytorch2paddle/pytorch_op_mapper.py
0 → 100644
浏览文件 @
e8b8e410
# Copyright (c) 2019 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.
import
torch
import
numpy
as
np
from
x2paddle.core.op_mapper
import
OpMapper
from
x2paddle.core.util
import
*
from
x2paddle.core.program
import
PaddleGraph
from
x2paddle.op_mapper.pytorch2paddle
import
prim
from
x2paddle.op_mapper.pytorch2paddle
import
aten
class
PyTorchOpMapper
(
OpMapper
):
def
__init__
(
self
,
decoder
):
super
(
PyTorchOpMapper
,
self
).
__init__
()
self
.
script
=
decoder
.
script
self
.
paddle_params
=
dict
()
self
.
outputs_info
=
{}
# key为output unique id,value为当前节点的输出名字
self
.
pytorch_params
=
{}
# key为节点名,value为参数
self
.
attrs
=
{}
# key为节点名,value为属性值
self
.
output_index
=
0
self
.
dygraph_name_id
=
{}
# 动态图__init__输出名字中的id,key为kernel类型,value为id
# 转换
self
.
check_op
(
decoder
.
graph
)
self
.
graph
,
_
=
self
.
traverse
(
decoder
.
graph
)
def
check_op
(
self
,
script_graph
):
def
_update_op_list
(
graph
):
for
node
in
graph
.
nodes
():
op_list
.
append
(
node
.
kind
())
for
block
in
node
.
blocks
():
_update_op_list
(
block
)
op_list
=
list
()
_update_op_list
(
script_graph
)
op_list
=
list
(
set
(
op_list
))
unsupported_op_list
=
[]
for
op
in
op_list
:
func_name
=
op
.
replace
(
'::'
,
'_'
)
if
not
(
hasattr
(
prim
,
func_name
)
or
hasattr
(
aten
,
func_name
)):
unsupported_op_list
.
append
(
op
)
if
len
(
unsupported_op_list
)
>
0
:
raise
Exception
(
"The kind {} in model is not supported yet."
.
format
(
unsupported_op_list
))
def
traverse
(
self
,
script_graph
,
parent_layer
=
None
):
# 用于获取graph的输入
def
_update_graph_inputs
(
kind
,
inputs
,
outputs
):
# extend只能放更新graph_inputs之前的情况:
# 1. loop的输出i也是输入;i是输入的原因是:子图中为父图得到的。
# 2. 在_check_input中需要使用to_variable。
# extend只能放更新graph_inputs之后的情况:
# 使用了append。
if
kind
!=
"aten::append"
:
current_node_outputs
.
extend
(
outputs
)
for
name
in
inputs
:
if
name
not
in
current_node_outputs
:
graph_inputs
.
append
(
name
)
if
kind
==
"aten::append"
:
current_node_outputs
.
extend
(
outputs
)
# 初始化
graph
=
PaddleGraph
(
parent_layer
,
graph_type
=
"dygraph"
)
current_node_outputs
=
[]
graph_inputs
=
[]
# 转换输入节点
if
isinstance
(
script_graph
,
torch
.
_C
.
Graph
):
for
i
,
ivalue
in
enumerate
(
script_graph
.
inputs
()):
node
=
ivalue
.
node
()
if
str
(
ivalue
.
type
())
!=
"Tensor"
:
graph
.
set_name
(
str
(
ivalue
.
type
()).
split
(
"."
)[
-
1
])
inputs
,
outputs
=
self
.
data
(
graph
,
node
,
ivalue
.
unique
())
# 转换中间节点
for
node
in
script_graph
.
nodes
():
kind
=
node
.
kind
()
func_name
=
kind
.
replace
(
'::'
,
'_'
)
if
hasattr
(
prim
,
func_name
):
func
=
getattr
(
prim
,
func_name
)
inputs
,
outputs
=
func
(
self
,
graph
,
node
)
_update_graph_inputs
(
kind
,
inputs
,
outputs
)
elif
hasattr
(
aten
,
func_name
):
func
=
getattr
(
aten
,
func_name
)
inputs
,
outputs
=
func
(
self
,
graph
,
node
)
_update_graph_inputs
(
kind
,
inputs
,
outputs
)
# 转换输出节点
if
hasattr
(
script_graph
,
'returnNode'
):
for
i
,
ivalue
in
enumerate
(
script_graph
.
returnNode
().
inputs
()):
if
parent_layer
.
kernel
==
"prim.loop"
and
i
==
0
:
continue
node
=
ivalue
.
node
()
script_unique_id
=
ivalue
.
unique
()
inputs
,
outputs
=
self
.
equal
(
graph
,
node
,
uid
=
script_unique_id
,
parent_layer
=
parent_layer
,
index
=
i
)
_update_graph_inputs
(
"equal"
,
inputs
,
outputs
)
# 设置graph的参数
if
isinstance
(
script_graph
,
torch
.
_C
.
Graph
):
graph
.
set_parameters
(
self
.
paddle_params
)
return
graph
,
graph_inputs
def
_get_outputs_name
(
self
,
node
,
attr_name
=
None
):
outputs_name
=
[]
for
output_ivalue
in
node
.
outputs
():
script_unique_id
=
output_ivalue
.
unique
()
if
attr_name
is
None
:
output_name
=
'x'
+
str
(
self
.
output_index
)
if
script_unique_id
in
self
.
outputs_info
:
output_name
=
self
.
outputs_info
[
script_unique_id
]
else
:
output_name
=
attr_name
.
replace
(
"."
,
"_"
)
self
.
outputs_info
[
script_unique_id
]
=
output_name
self
.
output_index
+=
1
outputs_name
.
append
(
output_name
)
# if或loop节点没有输出的情况
if
len
(
list
(
node
.
outputs
()))
==
0
:
output_name
=
'_x'
+
str
(
self
.
output_index
)
self
.
output_index
+=
1
outputs_name
.
append
(
output_name
)
return
outputs_name
def
_check_input
(
self
,
graph
,
node
,
output_name
,
node_outputs
,
add_dim
=
False
):
if
node
.
kind
()
==
"prim::GetAttr"
:
param
=
self
.
pytorch_params
[
output_name
]
if
isinstance
(
param
,
np
.
ndarray
):
if
add_dim
:
param
=
param
[
np
.
newaxis
,
:]
self
.
paddle_params
[
output_name
]
=
param
graph
.
add_layer
(
"fluid.dygraph.base.to_variable"
,
inputs
=
{},
outputs
=
[
output_name
],
value
=
"params[{}]"
.
format
(
string
(
output_name
)))
else
:
if
isinstance
(
param
,
dict
)
and
"Tensor"
in
param
and
\
"parent_layer_id"
in
param
:
if
graph
.
parent_layer
is
not
None
:
# 当某个param被2个控制流(if-else)赋值时,else不可以引用if中的赋值结果
id1
=
param
[
"parent_layer_id"
]
id2
=
graph
.
parent_layer
.
id
id1_part
=
id1
.
split
(
"."
)
id2_part
=
id2
.
split
(
"."
)
if
len
(
id1_part
)
>=
len
(
id2_part
):
for
i
in
range
(
len
(
id1_part
)):
if
id1_part
[
i
]
==
id2_part
[
i
]:
continue
else
:
if
id1_part
[
i
]
==
"0"
and
id2_part
[
i
]
==
"1"
:
if
add_dim
:
param
=
param
[
np
.
newaxis
,
:]
self
.
paddle_params
[
output_name
]
=
param
graph
.
add_layer
(
"fluid.dygraph.base.to_variable"
,
inputs
=
{},
outputs
=
[
output_name
],
value
=
"params[{}]"
.
format
(
string
(
output_name
)))
node_outputs
.
append
(
output_name
)
return
# 若if-else外,则可直接引用if-else中的赋值结果
graph
.
add_layer
(
"prim.constant"
,
inputs
=
{},
outputs
=
[
output_name
],
value
=
param
[
"Tensor"
])
else
:
graph
.
add_layer
(
"prim.constant"
,
inputs
=
{},
outputs
=
[
output_name
],
value
=
string
(
param
)
if
isinstance
(
param
,
str
)
else
param
)
node_outputs
.
append
(
output_name
)
def
_get_inputs_name
(
self
,
node
):
inputs_name
=
[]
inputs_node
=
[]
for
script_input_ivalue
in
node
.
inputs
():
script_input_node
=
script_input_ivalue
.
node
()
script_input_unique_id
=
script_input_ivalue
.
unique
()
input_name
=
self
.
outputs_info
[
script_input_unique_id
]
inputs_node
.
append
(
script_input_node
)
inputs_name
.
append
(
input_name
)
return
inputs_name
,
inputs_node
def
data
(
self
,
graph
,
node
,
uid
):
for
output_ivalue
in
node
.
outputs
():
script_unique_id
=
output_ivalue
.
unique
()
if
script_unique_id
in
self
.
outputs_info
or
script_unique_id
!=
uid
:
continue
node_name
=
'x'
+
str
(
self
.
output_index
)
self
.
outputs_info
[
script_unique_id
]
=
node_name
self
.
output_index
+=
1
output_name
=
self
.
outputs_info
[
uid
]
graph
.
add_layer
(
"fluid.dygraph.base.to_variable"
,
inputs
=
{},
outputs
=
[
node_name
],
value
=
output_name
)
return
[],
[
output_name
]
def
equal
(
self
,
graph
,
node
,
uid
=
None
,
parent_layer
=
None
,
index
=
None
):
if
parent_layer
is
not
None
and
index
is
not
None
:
# block的输出
input_node_name
=
self
.
outputs_info
[
uid
]
control_output_id
=
index
if
parent_layer
.
kernel
==
"prim.loop"
:
control_output_id
=
index
-
1
output_node_name
=
parent_layer
.
outputs
[
control_output_id
]
current_outputs
=
[
output_node_name
]
self
.
_check_input
(
graph
,
node
,
input_node_name
,
current_outputs
)
graph
.
add_layer
(
"prim.equal"
,
inputs
=
{
'input'
:
input_node_name
},
outputs
=
[
output_node_name
])
return
[
input_node_name
],
current_outputs
x2paddle/optimizer/fusion/__init__.py
0 → 100644
浏览文件 @
e8b8e410
# 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
.fc_fuser
import
FcFuser
from
.fc_fuse_pass
import
FcFusePass
from
.nn_adaptive_pool2d_fuser
import
NnAdaptivePool2dFuser
from
.nn_adaptive_pool2d_fuse_pass
import
NnAdaptivePool2dFusePass
from
.functional_adaptive_pool2d_fuser
import
FunctionalAdaptivePool2dFuser
from
.functional_adaptive_pool2d_fuse_pass
import
FunctionalAdaptivePool2dFusePass
from
.constant_fuser
import
ConstantFuser
from
.constant_fuse_pass
import
ConstantFusePass
from
.batchnorm2d_fuser
import
BatchNorm2dFuser
from
.batchnorm2d_fuse_pass
import
BatchNorm2dFusePass
x2paddle/optimizer/fusion/fc_fuse_pass.py
0 → 100644
浏览文件 @
e8b8e410
# 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
x2paddle.optimizer.pass_
import
Pass
from
x2paddle.optimizer.fusion
import
FcFuser
from
x2paddle.optimizer.pass_manager
import
pass_register
@
pass_register
class
FcFusePass
(
Pass
):
name
=
"fc_fuse_pass"
def
__init__
(
self
):
Pass
.
__init__
(
self
)
def
apply
(
self
,
graph
):
fuser
=
FcFuser
()
fuser
.
operate
(
graph
,
match_kind
=
"topo"
)
# 用于注册
fc_fuse_pass
=
FcFusePass
()
x2paddle/optimizer/fusion/fc_fuser.py
0 → 100644
浏览文件 @
e8b8e410
# 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.
import
numpy
as
np
from
x2paddle.optimizer.pattern_matcher
import
FuseBase
from
x2paddle.core.program
import
PaddleGraph
,
PaddleLayer
from
x2paddle.core.util
import
*
class
FcFuser
(
FuseBase
):
def
__init__
(
self
):
self
.
linear_index
=
0
super
(
FcFuser
,
self
).
__init__
(
graph_type
=
"dygraph"
)
def
build_pattern
(
self
):
""" 描述需要替换的fc图结构。
fc层模式python实现代码示例:
x149 = 2
x151 = x146.shape
x151 = len(x151)
x152 = x151 == x149
if x152 :
x147 = self.x147
x154 = fluid.layers.transpose(x=x147, perm=[1, 0])
x148 = self.x148
x155 = fluid.layers.addmm(input=x148, x=x146, y=x154, beta=1, alpha=1)
x153 = x155
else:
x147 = self.x147
x157 = fluid.layers.transpose(x=x147, perm=[1, 0])
x158 = fluid.layers.matmul(x=x146, y=x157)
x159 = True
if x159 :
x148 = self.x148
x161 = x158 + 1 * x148
x160 = x161
else:
x160 = x158
x153 = x160
"""
def
gen_name
(
id
):
return
"x"
+
str
(
id
)
self
.
pattern
.
add_layer
(
"prim.constant"
,
inputs
=
{},
outputs
=
[
gen_name
(
0
)],
value
=
2
)
self
.
pattern
.
add_layer
(
"prim.constant"
,
inputs
=
{},
outputs
=
[
gen_name
(
1
)],
value
=
1
)
self
.
pattern
.
add_layer
(
"prim.shape"
,
inputs
=
{
'input'
:
"fc-input-0"
},
outputs
=
[
gen_name
(
2
)])
self
.
pattern
.
add_layer
(
"prim.len"
,
inputs
=
{
'input'
:
gen_name
(
2
)},
outputs
=
[
gen_name
(
2
)])
self
.
pattern
.
add_layer
(
"prim.eq"
,
inputs
=
{
"eq0"
:
gen_name
(
2
),
"eq1"
:
gen_name
(
0
)},
outputs
=
[
gen_name
(
3
)])
self
.
pattern
.
add_layer
(
"prim.if"
,
{
'input'
:
gen_name
(
3
)},
[
gen_name
(
4
)])
self
.
pattern
.
outputs
.
append
(
gen_name
(
4
))
if_layer1
=
self
.
pattern
.
layers
[
list
(
self
.
pattern
.
layers
.
keys
())[
-
1
]]
pattern_block0
=
PaddleGraph
(
if_layer1
,
graph_type
=
"dygraph"
)
pattern_block0
.
add_layer
(
"fluid.dygraph.base.to_variable"
,
inputs
=
{},
outputs
=
[
gen_name
(
5
)],
value
=
"params[{}]"
.
format
(
string
(
gen_name
(
5
))))
pattern_block0
.
add_layer
(
"fluid.layers.transpose"
,
inputs
=
{
"x"
:
gen_name
(
5
)},
outputs
=
[
gen_name
(
6
)],
perm
=
[
1
,
0
])
pattern_block0
.
add_layer
(
"fluid.dygraph.base.to_variable"
,
inputs
=
{},
outputs
=
[
gen_name
(
7
)],
value
=
"params[{}]"
.
format
(
string
(
gen_name
(
7
))))
pattern_block0
.
add_layer
(
"fluid.layers.addmm"
,
inputs
=
{
"input"
:
gen_name
(
7
),
"x"
:
"fc-input-0"
,
"y"
:
gen_name
(
6
)},
outputs
=
[
gen_name
(
8
)],
beta
=
1
,
alpha
=
1
)
if_layer1
.
inputs
[
"input-0"
]
=
"fc-input-0"
self
.
pattern
.
inputs
.
append
(
"fc-input-0"
)
pattern_block0
.
add_layer
(
"prim.equal"
,
inputs
=
{
'input'
:
gen_name
(
8
)},
outputs
=
[
gen_name
(
4
)])
if_layer1
.
add_block
(
pattern_block0
)
pattern_block1
=
PaddleGraph
(
if_layer1
,
graph_type
=
"dygraph"
)
pattern_block1
.
add_layer
(
"fluid.dygraph.base.to_variable"
,
inputs
=
{},
outputs
=
[
gen_name
(
5
)],
value
=
"params[{}]"
.
format
(
string
(
gen_name
(
5
))))
pattern_block1
.
add_layer
(
"fluid.layers.transpose"
,
inputs
=
{
"x"
:
gen_name
(
5
)},
outputs
=
[
gen_name
(
6
)],
perm
=
[
1
,
0
])
pattern_block1
.
add_layer
(
"fluid.layers.matmul"
,
inputs
=
{
"x"
:
"fc-input-0"
,
"y"
:
gen_name
(
6
)},
outputs
=
[
gen_name
(
9
)])
if_layer1
.
inputs
[
"input-1"
]
=
"fc-input-0"
pattern_block1
.
add_layer
(
"prim.constant"
,
inputs
=
{},
outputs
=
[
gen_name
(
10
)],
value
=
True
)
pattern_block1
.
add_layer
(
"prim.if"
,
{
'input'
:
gen_name
(
10
)},
[
gen_name
(
11
)])
if_layer2
=
pattern_block1
.
layers
[
list
(
pattern_block1
.
layers
.
keys
())[
-
1
]]
pattern_block1_block0
=
PaddleGraph
(
if_layer2
,
graph_type
=
"dygraph"
)
pattern_block1_block0
.
add_layer
(
"fluid.dygraph.base.to_variable"
,
inputs
=
{},
outputs
=
[
gen_name
(
12
)],
value
=
"params[{}]"
.
format
(
string
(
gen_name
(
12
))))
pattern_block1_block0
.
add_layer
(
"prim.add_"
,
inputs
=
{
"x"
:
gen_name
(
9
),
"y"
:
gen_name
(
12
)},
outputs
=
[
gen_name
(
13
)],
alpha
=
1
)
if_layer2
.
inputs
[
"input-0"
]
=
gen_name
(
9
)
pattern_block1_block0
.
add_layer
(
"prim.equal"
,
inputs
=
{
'input'
:
gen_name
(
13
)},
outputs
=
[
gen_name
(
11
)])
if_layer2
.
add_block
(
pattern_block1_block0
)
pattern_block1_block1
=
PaddleGraph
(
if_layer2
,
graph_type
=
"dygraph"
)
pattern_block1_block1
.
add_layer
(
"prim.equal"
,
inputs
=
{
'input'
:
gen_name
(
9
)},
outputs
=
[
gen_name
(
11
)])
if_layer2
.
inputs
[
"input-1"
]
=
gen_name
(
9
)
pattern_block1
.
add_layer
(
"prim.equal"
,
inputs
=
{
'input'
:
gen_name
(
11
)},
outputs
=
[
gen_name
(
4
)])
if_layer2
.
add_block
(
pattern_block1_block1
)
if_layer1
.
add_block
(
pattern_block1
)
self
.
pattern
.
build
(
inputs
=
{
"input-0"
:
"fc-input-0"
})
def
insert_new_layer
(
self
,
graph
,
parameters
,
matches
):
new_layer
=
self
.
gen_new_layer
(
parameters
,
matches
)
new_layer_id
=
list
(
matches
.
keys
())[
0
]
graph
.
layers
[
new_layer_id
]
=
new_layer
matches
.
pop
(
new_layer_id
)
def
gen_new_layer
(
self
,
parameters
,
matches
):
layers_id
=
list
(
matches
.
keys
())
layer
=
matches
[
layers_id
[
2
]]
input_name
=
layer
.
inputs
[
"input"
]
layer
=
matches
[
layers_id
[
5
]]
output_name
=
layer
.
outputs
[
0
]
layer
=
matches
[
layers_id
[
6
]]
weight_name
=
layer
.
attrs
[
"value"
][
8
:
-
2
]
layer
=
matches
[
layers_id
[
8
]]
bias_name
=
layer
.
attrs
[
"value"
][
8
:
-
2
]
attrs
=
dict
()
attrs
[
"input_dim"
]
=
parameters
[
weight_name
].
shape
[
1
]
attrs
[
"output_dim"
]
=
parameters
[
weight_name
].
shape
[
0
]
linear_name
=
"linear{}"
.
format
(
self
.
linear_index
)
self
.
linear_index
+=
1
parameters
[
"{}.weight"
.
format
(
linear_name
)]
=
parameters
[
weight_name
].
transpose
((
1
,
0
))
parameters
[
"{}.bias"
.
format
(
linear_name
)]
=
np
.
squeeze
(
parameters
[
bias_name
])
new_layer
=
PaddleLayer
(
layers_id
[
0
],
"fluid.dygraph.Linear"
,
inputs
=
{
"input"
:
input_name
},
outputs
=
[
linear_name
,
output_name
],
**
attrs
)
return
new_layer
x2paddle/optimizer/optimizer.py
0 → 100644
浏览文件 @
e8b8e410
# 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
x2paddle.optimizer.fusion
import
*
from
x2paddle.optimizer.pass_manager
import
PassManager
class
GraphOptimizer
(
object
):
def
__init__
(
self
):
self
.
passes
=
[
"fc_fuse_pass"
,
# "nn_adaptive_pool2d_fuse_pass",
# "functional_adaptive_pool2d_fuse_pass",
# "batchnorm2d_fuse_pass",
"constant_fuse_pass"
]
def
optimize
(
self
,
graph
):
for
pass_name
in
self
.
passes
:
pass_
=
PassManager
.
lookup
(
pass_name
)()
pass_
.
apply
(
graph
)
print
(
"{} done!"
.
format
(
pass_name
))
return
graph
x2paddle/optimizer/pass_.py
0 → 100644
浏览文件 @
e8b8e410
# 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.
class
Pass
(
object
):
name
=
"pass"
def
__init__
(
self
):
pass
def
apply
(
self
,
graph
):
raise
NotImplementedError
(
"The apply function must be implemented!"
)
@
classmethod
def
get_name
(
cls
):
return
cls
.
name
x2paddle/optimizer/pass_manager.py
0 → 100644
浏览文件 @
e8b8e410
# 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.
class
PassManager
(
object
):
""" pass管理器。
"""
# pass_map存储name与其对应的pass
pass_map
=
dict
()
def
__init__
(
self
):
pass
@
staticmethod
def
add_new_pass
(
name
,
pass_
):
if
name
not
in
PassManager
.
pass_map
:
PassManager
.
pass_map
[
name
]
=
pass_
@
staticmethod
def
clear
():
PassManager
.
passes
=
list
()
@
staticmethod
def
lookup
(
name
):
return
PassManager
.
pass_map
[
name
]
def
pass_register
(
cls
):
name
=
cls
.
get_name
()
PassManager
.
add_new_pass
(
name
,
cls
)
return
cls
x2paddle/optimizer/pattern_matcher.py
0 → 100644
浏览文件 @
e8b8e410
# 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
x2paddle.core.program
import
PaddleGraph
class
PatternMatcher
(
object
):
def
__init__
(
self
,
pattern
):
self
.
pattern
=
pattern
# matches的每个match是按照拓扑排序组成layer的dict
self
.
matches
=
list
()
def
operate
(
self
,
graph
,
match_kind
=
"topo"
):
if
match_kind
==
"topo"
:
self
.
detect_patterns_by_topo
(
graph
)
elif
match_kind
==
"edge"
:
self
.
detect_patterns_by_edge
(
graph
)
self
.
remove_overlapped_match
()
return
self
.
matches
def
detect_patterns_by_topo
(
self
,
graph
):
""" 找到与模式匹配的子图,
并将子图的id以拓扑排序存放到subgraph_id2layers。
"""
def
get_subgraph
(
pattern
,
graph
,
start_index
):
pattern_index
=
0
pattern_id2layers
=
pattern
.
get_global_layers
()
pattern_ids
=
list
(
pattern_id2layers
.
keys
())
subgraph_id2layers
=
dict
()
graph_layers
=
dict
(
list
(
graph
.
layers
.
items
())[
start_index
:])
for
layer_id
,
layer
in
graph_layers
.
items
():
pattern_layer
=
pattern
.
layers
[
list
(
pattern
.
layers
.
keys
())[
pattern_index
]]
if
layer
.
kernel
==
pattern_layer
.
kernel
:
subgraph_id2layers
[
layer_id
]
=
layer
pattern_layer_id
=
pattern_layer
.
id
# 判断输入连接是否一致
if
layer_id
in
graph
.
edges_in
:
if
pattern_layer_id
not
in
pattern
.
edges_in
:
return
False
else
:
if
len
(
graph
.
edges_in
[
layer_id
])
!=
len
(
pattern
.
edges_in
[
pattern_layer_id
]):
return
False
layer_in
=
graph
.
edges_in
[
layer_id
]
pattern_layer_in
=
pattern
.
edges_in
[
pattern_layer_id
]
for
i
in
range
(
len
(
layer_in
)):
layer_id_in
=
layer_in
[
i
]
pattern_layer_id_in
=
pattern_layer_in
[
i
]
if
pattern_layer_id_in
!=
-
1
:
subgraph_ids
=
list
(
subgraph_id2layers
.
keys
())
if
pattern_ids
.
index
(
pattern_layer_id_in
)
==
\
subgraph_ids
.
index
(
layer_id_in
):
# 判断pattern输入在pattern_ids的索引
# 和graph输入在subgraph_ids的索引一致
continue
return
False
# 判断subgraph中的节点是否被外部图使用到(如若被使用到则无效)
if
layer_id
in
graph
.
edges_out
:
if
pattern_layer_id
not
in
pattern
.
edges_out
:
if
not
set
(
pattern_layer
.
outputs
).
issubset
(
pattern
.
outputs
):
# 若pattern当前layer的输出是pattern的输出,则是正确的
return
False
else
:
if
len
(
graph
.
edges_out
[
layer_id
])
!=
len
(
pattern
.
edges_out
[
pattern_layer_id
]):
# 如果在每个节点edges_in相同的情况下,edges_out数目相同则说明无节点在subgraph外被用到
if
not
set
(
pattern_layer
.
outputs
).
issubset
(
pattern
.
outputs
):
# 若pattern当前layer的输出是pattern的输出,则是正确的
return
False
# 当为控制流时的处理
if
layer
.
kernel
==
"prim.if"
or
layer
.
kernel
==
"prim.loop"
:
if
len
(
pattern_layer
.
blocks
)
!=
len
(
layer
.
blocks
):
return
False
for
i
,
b
in
enumerate
(
pattern_layer
.
blocks
):
match_info
=
get_subgraph
(
pattern_layer
.
blocks
[
i
],
layer
.
blocks
[
i
],
0
)
if
match_info
is
not
False
:
subgraph_id2layers
.
update
(
match_info
)
else
:
return
False
pattern_index
+=
1
if
pattern_index
==
len
(
pattern
.
layers
):
return
subgraph_id2layers
else
:
return
False
return
subgraph_id2layers
for
i
,
(
layer_id
,
layer
)
in
enumerate
(
graph
.
layers
.
items
()):
match_info
=
get_subgraph
(
self
.
pattern
,
graph
,
i
)
if
match_info
:
self
.
matches
.
append
(
match_info
)
for
j
,
block
in
enumerate
(
layer
.
blocks
):
if
len
(
block
.
layers
)
>
0
:
self
.
detect_patterns_by_topo
(
layer
.
blocks
[
j
])
def
detect_patterns_by_edge
(
self
,
graph
):
"""当遇见顺序没有强制规定的pattern时使用该方式
"""
pass
def
remove_overlapped_match
(
self
):
""" 如果2个子图有重叠,只取前一个子图。
"""
match_ids
=
[]
for
i
,
match
in
enumerate
(
self
.
matches
):
is_overlapped
=
False
for
id
in
match
.
keys
():
if
id
in
match_ids
:
self
.
matches
.
pop
(
i
)
is_overlapped
=
True
break
if
not
is_overlapped
:
match_ids
.
extend
(
list
(
match
.
keys
()))
def
get_subgraph
(
prefix_layer_id
,
suffix_layer_id
,
graph
):
""" 根据prefix_layer_id和suffix_layer_id获取需要子图。
Args:
prefix_layer_id (str): 起初为一个空字符串,之后为suffix_layer_id分割出来的前缀。
suffix_layer_id (str): 起初为以一个layer的id,之后将分割部分给prefix_layer_id;例如”57.0.1“;
graph (x2paddle.core.program.PaddleGraph): 需要进行pass的子图。
"""
id_part
=
suffix_layer_id
.
split
(
"."
)
if
len
(
id_part
)
==
1
:
return
graph
if
prefix_layer_id
==
""
:
layer_id
=
id_part
[
0
]
prefix_layer_id
+=
"."
.
join
(
id_part
[:
2
])
else
:
layer_id
=
prefix_layer_id
+
"."
+
id_part
[
0
]
prefix_layer_id
+=
(
"."
+
"."
.
join
(
id_part
[:
2
]))
subgraph
=
graph
.
layers
[
layer_id
].
blocks
[
int
(
id_part
[
1
])]
suffix_layer_id
=
"."
.
join
(
id_part
[
2
:])
return
get_subgraph
(
prefix_layer_id
,
suffix_layer_id
,
subgraph
)
class
FuseBase
(
object
):
def
__init__
(
self
,
graph_type
):
self
.
pattern
=
PaddleGraph
(
graph_type
=
graph_type
)
def
operate
(
self
,
graph
,
match_kind
=
"topo"
):
parameters
=
graph
.
parameters
self
.
build_pattern
()
self
.
perform_pattern_matcher
(
graph
,
match_kind
)
for
match
in
self
.
matches
:
first_layer_id
=
list
(
match
.
keys
())[
0
]
subgraph
=
get_subgraph
(
""
,
first_layer_id
,
graph
)
self
.
insert_new_layer
(
subgraph
,
parameters
,
match
)
self
.
delete_inter_layer
(
graph
)
graph
.
build
()
def
perform_pattern_matcher
(
self
,
graph
,
match_kind
=
"topo"
):
""" 执行模式匹配,找到匹配的子图。
"""
pattern_matcher
=
PatternMatcher
(
self
.
pattern
)
self
.
matches
=
pattern_matcher
.
operate
(
graph
,
match_kind
)
def
delete_inter_layer
(
self
,
graph
):
""" 删除不需要的中间layer及其对应参数。
"""
for
match
in
self
.
matches
:
first_layer_id
=
list
(
match
.
keys
())[
0
]
subgraph
=
get_subgraph
(
""
,
first_layer_id
,
graph
)
for
layer_id
,
layer
in
match
.
items
():
if
layer
.
kernel
==
"fluid.dygraph.base.to_variable"
and
\
layer
.
attrs
[
"value"
].
startswith
(
"params["
):
param_name
=
layer
.
attrs
[
"value"
][
8
:
-
2
]
if
param_name
in
graph
.
parameters
:
graph
.
parameters
.
pop
(
param_name
)
if
layer_id
in
subgraph
.
layers
:
# layer_id可能是属于子图的,此时删除父layer,即删除整个子图
subgraph
.
layers
.
pop
(
layer_id
)
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录