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"
from
.core.program
import
Paddle
Program
from
.core.program
import
Paddle
Graph
program
=
Paddle
Program
()
program
=
Paddle
Graph
()
name_counter
=
dict
()
...
...
x2paddle/core/program.py
浏览文件 @
e8b8e410
...
...
@@ -18,15 +18,15 @@ import paddle.fluid as fluid
from
paddle.fluid.proto
import
framework_pb2
from
collections
import
OrderedDict
import
numpy
import
time
import
collections
import
sys
import
os
import
six
import
pickle
class
PaddleLayer
(
object
):
def
__init__
(
self
,
kernel
,
inputs
,
outputs
,
**
kwargs
):
def
__init__
(
self
,
id
,
kernel
,
inputs
,
outputs
,
**
kwargs
):
assert
isinstance
(
inputs
,
dict
),
"parameter 'inputs' for PaddleLayer should be type of dict"
...
...
@@ -51,22 +51,29 @@ class PaddleLayer(object):
self
.
inputs
=
inputs
self
.
outputs
=
outputs
self
.
attrs
=
kwargs
self
.
id
=
str
(
time
.
time
())
self
.
id
=
id
self
.
blocks
=
list
()
def
add_block
(
self
,
block
):
block
.
father_layer
=
self
self
.
blocks
.
append
(
block
)
class
Paddle
Program
(
object
):
def
__init__
(
self
):
class
Paddle
Graph
(
object
):
def
__init__
(
self
,
parent_layer
=
None
,
graph_type
=
"static"
):
self
.
layers
=
OrderedDict
()
self
.
edges_out
=
dict
()
self
.
edges_in
=
dict
()
self
.
inputs
=
list
()
self
.
outputs
=
list
()
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
):
self
.
layers
=
OrderedDict
()
...
...
@@ -76,25 +83,44 @@ class PaddleProgram(object):
self
.
outputs
=
list
()
self
.
parameters
=
dict
()
def
clear_edges
(
self
):
self
.
edges_out
=
dict
()
self
.
edges_in
=
dict
()
def
add_layer
(
self
,
kernel
,
inputs
,
outputs
,
**
kwargs
):
layer
=
PaddleLayer
(
kernel
,
inputs
,
outputs
,
**
kwargs
)
layer_id
=
str
(
len
(
self
.
layers
))
if
self
.
father_layer
is
not
None
:
layer_id
=
"{}.{}.{}"
.
format
(
layer_id
,
len
(
self
.
father_layer
.
blocks
()),
self
.
father_layer
.
id
)
if
self
.
parent_layer
is
not
None
:
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
return
layer_id
def
build
(
self
):
def
build
(
self
,
inputs
=
None
,
outputs
=
None
):
self
.
clear_edges
()
outputs_from_nodes
=
dict
()
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
():
vs
=
input_var
if
not
isinstance
(
vs
,
list
):
vs
=
[
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
)
in_layer_id
=
outputs_from_nodes
[
v
]
if
v
in
outputs_from_nodes
:
in_layer_id
=
outputs_from_nodes
[
v
]
else
:
in_layer_id
=
-
1
if
in_layer_id
not
in
self
.
edges_out
:
self
.
edges_out
[
in_layer_id
]
=
list
()
self
.
edges_out
[
in_layer_id
].
append
(
layer_id
)
...
...
@@ -105,6 +131,27 @@ class PaddleProgram(object):
for
output
in
layer
.
outputs
:
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
write_code
(
f
,
code_list
,
indent
=
0
):
indent_blank
=
" "
*
indent
...
...
@@ -162,37 +209,41 @@ class PaddleProgram(object):
f
.
close
()
def
gen_model
(
self
,
save_dir
):
code_dir
=
os
.
path
.
join
(
save_dir
,
'model_with_code'
)
infer_dir
=
os
.
path
.
join
(
save_dir
,
'inference_model'
)
self
.
gen_code
(
code_dir
)
sys
.
path
.
append
(
code_dir
)
import
x2paddle_model
scope
=
fluid
.
Scope
()
startup_program
=
fluid
.
Program
()
main_program
=
fluid
.
Program
()
with
fluid
.
scope_guard
(
scope
):
with
fluid
.
program_guard
(
main_program
,
startup_program
):
inputs
,
outputs
=
x2paddle_model
.
x2paddle_net
()
exe
=
fluid
.
Executor
(
fluid
.
CPUPlace
())
exe
.
run
(
startup_program
)
param_dir
=
os
.
path
.
join
(
code_dir
,
'weights'
)
for
k
,
v
in
self
.
parameters
.
items
():
if
scope
.
find_var
(
k
):
self
.
dump_parameter
(
k
,
v
,
param_dir
)
def
if_exist
(
var
):
b
=
os
.
path
.
exists
(
os
.
path
.
join
(
os
.
path
.
join
(
param_dir
,
var
.
name
)))
return
b
fluid
.
io
.
load_vars
(
exe
,
param_dir
,
main_program
,
predicate
=
if_exist
)
fluid
.
io
.
save_inference_model
(
dirname
=
infer_dir
,
feeded_var_names
=
[
i
.
name
for
i
in
inputs
],
target_vars
=
outputs
,
executor
=
exe
)
if
self
.
graph_type
==
"static"
:
code_dir
=
os
.
path
.
join
(
save_dir
,
'model_with_code'
)
infer_dir
=
os
.
path
.
join
(
save_dir
,
'inference_model'
)
self
.
gen_code
(
code_dir
)
sys
.
path
.
append
(
code_dir
)
import
x2paddle_model
scope
=
fluid
.
Scope
()
startup_program
=
fluid
.
Program
()
main_program
=
fluid
.
Program
()
with
fluid
.
scope_guard
(
scope
):
with
fluid
.
program_guard
(
main_program
,
startup_program
):
inputs
,
outputs
=
x2paddle_model
.
x2paddle_net
()
exe
=
fluid
.
Executor
(
fluid
.
CPUPlace
())
exe
.
run
(
startup_program
)
param_dir
=
os
.
path
.
join
(
code_dir
,
'weights'
)
for
k
,
v
in
self
.
parameters
.
items
():
if
scope
.
find_var
(
k
):
self
.
dump_parameter
(
k
,
v
,
param_dir
)
def
if_exist
(
var
):
b
=
os
.
path
.
exists
(
os
.
path
.
join
(
os
.
path
.
join
(
param_dir
,
var
.
name
)))
return
b
fluid
.
io
.
load_vars
(
exe
,
param_dir
,
main_program
,
predicate
=
if_exist
)
fluid
.
io
.
save_inference_model
(
dirname
=
infer_dir
,
feeded_var_names
=
[
i
.
name
for
i
in
inputs
],
target_vars
=
outputs
,
executor
=
exe
)
else
:
self
.
gen_dygraph_code
(
save_dir
)
self
.
dump_dygraph_parameter
(
save_dir
)
def
dump_parameter
(
self
,
param_name
,
param
,
save_dir
):
if
not
os
.
path
.
exists
(
save_dir
):
...
...
@@ -227,3 +278,167 @@ class PaddleProgram(object):
fp
.
write
(
tensor_desc
.
SerializeToString
())
param
.
tofile
(
fp
)
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.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录