Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
X2Paddle
提交
7bd948a1
X
X2Paddle
项目概览
PaddlePaddle
/
X2Paddle
大约 1 年 前同步成功
通知
328
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看板
未验证
提交
7bd948a1
编写于
8月 09, 2019
作者:
S
SunAhong1993
提交者:
GitHub
8月 09, 2019
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #2 from PaddlePaddle/develop
add onnx
上级
c39e8900
572f7472
变更
7
展开全部
隐藏空白更改
内联
并排
Showing
7 changed file
with
1374 addition
and
9 deletion
+1374
-9
README.md
README.md
+5
-4
x2paddle/convert.py
x2paddle/convert.py
+28
-5
x2paddle/decoder/onnx_decoder.py
x2paddle/decoder/onnx_decoder.py
+497
-0
x2paddle/op_mapper/onnx_directly_map.py
x2paddle/op_mapper/onnx_directly_map.py
+54
-0
x2paddle/op_mapper/onnx_op_mapper.py
x2paddle/op_mapper/onnx_op_mapper.py
+729
-0
x2paddle/optimizer/onnx_optimizer.py
x2paddle/optimizer/onnx_optimizer.py
+31
-0
x2paddle_model_zoo.md
x2paddle_model_zoo.md
+30
-0
未找到文件。
README.md
浏览文件 @
7bd948a1
...
...
@@ -12,7 +12,7 @@ paddlepaddle >= 1.5.0
**以下依赖只需对应安装自己需要的即可**
转换tensorflow模型 : tensorflow == 1.14.0
转换caffe模型 : caffe == 1.0.0
转换onnx模型 : onnx == 1.5.0 pytorch == 1.1.0
## 安装
```
pip install x2paddle
...
...
@@ -32,8 +32,9 @@ x2paddle --framework=tensorflow --model=tf_model.pb --save_dir=pd_model
x2paddle --framework=caffe --prototxt=deploy.proto --weight=deploy.caffemodel --save_dir=pd_model
```
### ONNX
即将release,目前仍可使用
[
onnx2fluid
](
https://github.com/PaddlePaddle/X2Paddle/tree/release-0.3/onnx2fluid
)
```
x2paddle --framework=onnx --model=onnx_model.onnx --save_dir=pd_model
```
### 参数选项
| 参数 | |
|----------|--------------|
...
...
@@ -42,7 +43,7 @@ x2paddle --framework=caffe --prototxt=deploy.proto --weight=deploy.caffemodel --
|--weight | 当framework为caffe时,该参数指定caffe模型的参数文件路径 |
|--save_dir | 指定转换后的模型保存目录路径 |
|--model | 当framework为tensorflow时,该参数指定tensorflow的pb模型文件路径 |
|--caffe_proto | [可选]由caffe.proto编译成caffe_pb2.py文件的存放路径,当
没有安装caffe或者使用
自定义Layer时使用,默认为None |
|--caffe_proto | [可选]由caffe.proto编译成caffe_pb2.py文件的存放路径,当
存在
自定义Layer时使用,默认为None |
## 使用转换后的模型
转换后的模型包括
`model_with_code`
和
`inference_model`
两个目录。
...
...
x2paddle/convert.py
浏览文件 @
7bd948a1
...
...
@@ -15,7 +15,6 @@
from
six
import
text_type
as
_text_type
import
argparse
import
sys
import
x2paddle
def
arg_parser
():
...
...
@@ -104,9 +103,32 @@ def caffe2paddle(proto, weight, save_dir, caffe_proto):
mapper
.
save_inference_model
(
save_dir
)
def
onnx2paddle
(
model_path
,
save_dir
):
# check onnx installation and version
try
:
import
onnx
version
=
onnx
.
version
.
version
if
version
!=
'1.5.0'
:
print
(
"onnx==1.5.0 is required"
)
return
except
:
print
(
"onnx is not installed, use
\"
pip install onnx==1.5.0
\"
."
)
return
from
x2paddle.decoder.onnx_decoder
import
ONNXDecoder
from
x2paddle.op_mapper.onnx_op_mapper
import
ONNXOpMapper
from
x2paddle.optimizer.onnx_optimizer
import
ONNXOptimizer
print
(
"Now translating model from onnx to paddle."
)
model
=
ONNXDecoder
(
model_path
)
mapper
=
ONNXOpMapper
(
model
)
optimizer
=
ONNXOptimizer
(
mapper
)
optimizer
.
delete_redundance_code
()
mapper
.
save_inference_model
(
save_dir
)
def
main
():
if
len
(
sys
.
argv
)
<
2
:
print
(
"Use
\"
x2paddle -h
\"
to print the help information
\n
"
)
print
(
"Use
\"
x2paddle -h
\"
to print the help information"
)
return
parser
=
arg_parser
()
...
...
@@ -124,7 +146,6 @@ def main():
return
except
:
print
(
"paddlepaddle not installed, use
\"
pip install paddlepaddle
\"
"
)
assert
args
.
framework
is
not
None
,
"--from is not defined(tensorflow/caffe)"
assert
args
.
save_dir
is
not
None
,
"--save_dir is not defined"
...
...
@@ -136,9 +157,11 @@ def main():
assert
args
.
prototxt
is
not
None
and
args
.
weight
is
not
None
,
"--prototxt and --weight should be defined while translating caffe model"
caffe2paddle
(
args
.
prototxt
,
args
.
weight
,
args
.
save_dir
,
args
.
caffe_proto
)
elif
args
.
framework
==
"onnx"
:
assert
args
.
model
is
not
None
,
"--model should be defined while translating onnx model"
onnx2paddle
(
args
.
model
,
args
.
save_dir
)
else
:
raise
Exception
(
"--framework only support tensorflow/caffe now"
)
raise
Exception
(
"--framework only support tensorflow/caffe
/onnx
now"
)
if
__name__
==
"__main__"
:
...
...
x2paddle/decoder/onnx_decoder.py
0 → 100644
浏览文件 @
7bd948a1
# 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.
from
x2paddle.core.graph
import
GraphNode
,
Graph
from
x2paddle.core.fluid_code
import
FluidCode
from
onnx.checker
import
ValidationError
from
onnx.checker
import
check_model
from
onnx.utils
import
polish_model
from
onnx.version_converter
import
convert_version
from
onnx
import
helper
from
onnx.helper
import
get_attribute_value
,
make_attribute
from
onnx.shape_inference
import
infer_shapes
from
onnx.mapping
import
TENSOR_TYPE_TO_NP_TYPE
from
onnx.numpy_helper
import
to_array
from
collections
import
OrderedDict
as
Dict
import
onnx
import
numpy
as
np
from
copy
import
deepcopy
import
logging
as
_logging
default_op_domain
=
'ai.onnx'
_logger
=
_logging
.
getLogger
(
__name__
)
class
ONNXGraphNode
(
GraphNode
):
def
__init__
(
self
,
layer
,
layer_name
=
None
):
if
layer_name
is
None
:
super
(
ONNXGraphNode
,
self
).
__init__
(
layer
,
layer
.
name
)
else
:
super
(
ONNXGraphNode
,
self
).
__init__
(
layer
,
layer_name
)
self
.
layer_type
=
layer
.
op_type
self
.
fluid_code
=
FluidCode
()
self
.
attr_map
=
self
.
get_attr_map
()
self
.
dtype_map
=
{
1
:
"float32"
,
3
:
"int32"
,
9
:
"int64"
}
self
.
weight_inputs
=
list
()
self
.
out_shapes
=
None
self
.
dtype
=
None
def
get_attr_map
(
self
):
"""
convert ONNX node attributes to dict
"""
return
{
attr
.
name
:
self
.
get_attribute_value2
(
attr
)
for
attr
in
self
.
layer
.
attribute
}
@
property
def
value
(
self
):
assert
'Constant'
in
self
.
layer_type
,
"Only Constant node has value."
attr
=
self
.
layer
.
attr
[
'value'
]
if
'value'
in
self
.
attr_map
:
return
default
return
self
.
attr_map
[
name
]
def
get_attribute_value2
(
self
,
attr
):
"""
get_attribute_value enhanced
"""
if
attr
.
type
==
onnx
.
AttributeProto
.
TENSOR
:
dtype
=
np
.
dtype
(
TENSOR_TYPE_TO_NP_TYPE
[
attr
.
t
.
data_type
])
data
=
attr
.
t
.
raw_data
value
=
np
.
frombuffer
(
data
,
dtype
=
dtype
,
count
=
(
len
(
data
)
//
dtype
.
itemsize
))
elif
attr
.
type
==
onnx
.
AttributeProto
.
STRING
:
value
=
attr
.
s
value
=
value
.
decode
()
if
isinstance
(
value
,
bytes
)
else
value
else
:
value
=
get_attribute_value
(
attr
)
return
value
def
get_attr
(
self
,
name
,
default
=
None
):
"""
get_attribute_value from attr_map
"""
if
name
not
in
self
.
attr_map
:
return
default
return
self
.
attr_map
[
name
]
class
ONNXGraphDataNode
(
GraphNode
):
def
__init__
(
self
,
layer
,
layer_name
=
None
,
is_global_input
=
False
):
if
layer_name
is
None
:
super
(
ONNXGraphDataNode
,
self
).
__init__
(
layer
,
layer
.
name
)
else
:
super
(
ONNXGraphDataNode
,
self
).
__init__
(
layer
,
layer_name
)
if
is_global_input
:
self
.
layer_type
=
'place_holder'
else
:
self
.
layer_type
=
'create_parameter'
self
.
layer_name
=
layer_name
self
.
fluid_code
=
FluidCode
()
self
.
weight
=
None
self
.
embeded_as
=
None
@
property
def
out_shapes
(
self
):
values
=
self
.
layer
.
type
.
tensor_type
.
shape
.
dim
out_shapes
=
list
()
out_shapes
=
[
dim
.
dim_value
for
dim
in
values
]
return
out_shapes
@
property
def
dtype
(
self
):
dtype
=
self
.
layer
.
type
.
tensor_type
.
elem_type
return
TENSOR_TYPE_TO_NP_TYPE
[
dtype
]
class
ONNXGraph
(
Graph
):
def
__init__
(
self
,
model
):
super
(
ONNXGraph
,
self
).
__init__
(
model
)
self
.
initializer
=
{}
self
.
place_holder_nodes
=
list
()
self
.
get_place_holder_nodes
()
def
get_inner_nodes
(
self
):
"""
generate inner node of ONNX model
"""
inner_nodes
=
[]
if
not
isinstance
(
self
.
model
,
onnx
.
GraphProto
):
logger
.
error
(
'graph is not a GraphProto instance'
)
return
for
initializer
in
self
.
model
.
initializer
:
name
=
initializer
.
name
inner_nodes
.
append
(
name
)
return
inner_nodes
def
get_place_holder_nodes
(
self
):
"""
generate place_holder node of ONNX model
"""
inner_nodes
=
self
.
get_inner_nodes
()
input_nodes
=
[
value
.
name
for
value
in
self
.
model
.
input
]
for
ipt_data
in
input_nodes
:
if
ipt_data
not
in
inner_nodes
:
self
.
place_holder_nodes
.
append
(
ipt_data
)
def
is_place_holder_nodes
(
self
,
layer
):
"""
return layer is or not place_holder node
"""
if
layer
in
self
.
place_holder_nodes
:
return
True
return
False
def
build
(
self
):
"""
build topo_sort of ONNX model
"""
for
layer
in
self
.
model
.
node
:
self
.
node_map
[
layer
.
name
]
=
ONNXGraphNode
(
layer
)
#set op node's dtype and out_shapes
for
item
in
self
.
model
.
value_info
:
if
item
.
name
in
self
.
node_map
:
self
.
node_map
[
item
.
name
].
dtype
=
TENSOR_TYPE_TO_NP_TYPE
[
item
.
type
.
tensor_type
.
elem_type
]
self
.
node_map
[
item
.
name
].
out_shapes
=
[
dim
.
dim_value
for
dim
in
item
.
type
.
tensor_type
.
shape
.
dim
]
for
layer
in
self
.
model
.
input
:
if
layer
.
name
not
in
self
.
node_map
:
is_place_holder
=
self
.
is_place_holder_nodes
(
layer
.
name
)
self
.
node_map
[
layer
.
name
]
=
ONNXGraphDataNode
(
layer
,
layer_name
=
layer
.
name
,
is_global_input
=
is_place_holder
)
#set data node's weight
for
name
,
weight
in
self
.
graph_weights
(
self
.
model
):
if
name
in
self
.
node_map
:
if
isinstance
(
self
.
node_map
[
name
],
ONNXGraphDataNode
):
self
.
node_map
[
name
].
weight
=
weight
self
.
node_map
[
name
].
embeded_as
=
[]
#generate connection between nodes for topo
for
layer_name
,
node
in
self
.
node_map
.
items
():
if
isinstance
(
node
,
ONNXGraphNode
):
for
idx
,
in_node
in
enumerate
(
node
.
layer
.
input
):
if
in_node
not
in
self
.
node_map
:
raise
Exception
(
'input[{}] of node[{}] does not exist in node_map'
.
format
(
in_node
,
layer_name
))
else
:
self
.
connect
(
in_node
,
layer_name
)
#generate topo
super
(
ONNXGraph
,
self
).
build
()
self
.
input_nodes
=
self
.
place_holder_nodes
def
get_nodes
(
self
,
names
,
copy
=
False
):
"""
get nodes by more than one name
"""
nodes
=
[]
for
name
in
names
:
nodes
.
add
(
self
.
get_node
(
name
,
copy
=
copy
))
def
graph_weights
(
self
,
graph
):
"""
generator for weights
"""
if
not
isinstance
(
graph
,
onnx
.
GraphProto
):
logger
.
error
(
'graph is not a GraphProto instance'
)
return
for
initializer
in
graph
.
initializer
:
name
=
initializer
.
name
weight
=
to_array
(
initializer
)
yield
name
,
weight
class
ONNXDecoder
(
object
):
def
__init__
(
self
,
onnx_model
):
model
=
onnx
.
load
(
onnx_model
)
print
(
'model ir_version: {}, op version: {}'
.
format
(
model
.
ir_version
,
model
.
opset_import
[
0
].
version
))
if
model
.
opset_import
[
0
].
version
<
9
:
_logger
.
warning
(
'Now, onnx2paddle main support convert onnx model opset_verison == 9,'
'opset_verison of your onnx model is %d < 9,'
'some operator may cannot convert.'
,
model
.
opset_import
[
0
].
version
)
check_model
(
model
)
model
=
polish_model
(
model
)
model
=
self
.
optimize_model_skip_op_for_inference
(
model
)
model
=
self
.
optimize_model_strip_initializer
(
model
)
self
.
standardize_variable_name
(
model
.
graph
)
self
.
model
=
model
graph_def
=
model
.
graph
self
.
onnx_graph
=
ONNXGraph
(
graph_def
)
self
.
onnx_graph
.
build
()
def
build_value_refs
(
self
,
nodes
):
"""
build op reference of inputs and outputs
"""
input_refs
=
Dict
()
output_refs
=
Dict
()
for
idx
,
node
in
enumerate
(
nodes
):
for
val_name
in
node
.
input
:
input_refs
.
setdefault
(
val_name
,
set
()).
add
(
idx
)
for
val_name
in
node
.
output
:
output_refs
.
setdefault
(
val_name
,
set
()).
add
(
idx
)
return
input_refs
,
output_refs
def
skip_node_forward
(
self
,
nodes
,
src_output_name
,
dst_input_name
,
input_refs
):
"""
skip nodes between src_output_name -> dst_input_name and connect this pair
"""
processed
=
0
for
next_idx
in
input_refs
[
src_output_name
]:
next_node
=
nodes
[
next_idx
]
for
val_idx
,
next_input_name
in
enumerate
(
next_node
.
input
):
if
next_input_name
==
src_output_name
:
next_node
.
input
[
val_idx
]
=
dst_input_name
processed
+=
1
return
processed
def
skip_node_backward
(
self
,
nodes
,
src_input_name
,
dst_output_name
,
output_refs
):
"""
skip nodes between dst_output_name -> src_input_name and connect this pair
"""
processed
=
0
for
prev_idx
in
output_refs
[
src_input_name
]:
prev_node
=
nodes
[
prev_idx
]
for
val_idx
,
prev_output_name
in
enumerate
(
prev_node
.
output
):
if
prev_output_name
==
src_input_name
:
prev_node
.
output
[
val_idx
]
=
dst_output_name
processed
+=
1
return
processed
def
optimize_model_skip_op_for_inference
(
self
,
model
,
op_list
=
None
):
"""
skip ops can be bypassed for inference
"""
if
op_list
is
None
:
op_list
=
[
'Dropout'
]
nodes
=
model
.
graph
.
node
input_refs
,
output_refs
=
self
.
build_value_refs
(
nodes
)
ret
=
type
(
model
)()
ret
.
CopyFrom
(
model
)
ret_nodes
=
ret
.
graph
.
node
nodes_to_remove
=
[]
for
node_idx
,
node
in
enumerate
(
nodes
):
if
not
(
node
.
domain
==
default_op_domain
or
node
.
domain
==
''
):
continue
op_type
=
node
.
op_type
if
not
(
op_type
in
op_list
):
continue
if
op_type
in
[
'Dropout'
]:
input_name
=
node
.
input
[
0
]
output_name
=
node
.
output
[
0
]
elif
not
(
len
(
node
.
input
)
==
1
and
len
(
node
.
output
)
==
1
):
print
(
'currently only 1-input-1-output op supported, skip required %d: %s'
,
node_idx
,
node
.
op_type
)
continue
else
:
input_name
=
node
.
input
[
0
]
output_name
=
node
.
output
[
0
]
if
output_name
in
input_refs
:
processed
=
self
.
skip_node_forward
(
ret_nodes
,
output_name
,
input_name
,
input_refs
)
elif
input_name
in
output_refs
:
processed
=
self
.
skip_node_backward
(
ret_nodes
,
input_name
,
output_name
,
output_refs
)
else
:
processed
=
-
1
if
processed
>
0
:
nodes_to_remove
.
append
(
node_idx
)
print
(
'skip op {}: {} -> {} -> {}'
.
format
(
node_idx
,
input_name
,
node
.
op_type
,
output_name
))
elif
processed
==
0
:
print
(
'weird, no node processed'
)
else
:
print
(
'standalone op {}: {} -> {} -> {} not skipped'
.
format
(
node_idx
,
input_name
,
node
.
op_type
,
output_name
))
nodes_to_remove
.
sort
(
reverse
=
True
)
for
node_idx
in
nodes_to_remove
:
ret_nodes
.
pop
(
node_idx
)
return
ret
def
optimize_model_strip_initializer
(
self
,
model
,
keep_input_only
=
True
):
"""
strip weights for inference
"""
nodes
=
model
.
graph
.
node
input_refs
,
output_refs
=
self
.
build_value_refs
(
nodes
)
out_names
=
[
val
.
name
for
val
in
model
.
graph
.
output
]
ret
=
type
(
model
)()
ret
.
CopyFrom
(
model
)
# strip initializers
ret
.
graph
.
ClearField
(
'initializer'
)
ret_initializers
=
ret
.
graph
.
initializer
for
initializer
in
model
.
graph
.
initializer
:
name
=
initializer
.
name
if
name
in
input_refs
:
ret_initializers
.
add
().
CopyFrom
(
initializer
)
elif
not
keep_input_only
and
name
in
output_refs
:
ret_initializers
.
add
().
CopyFrom
(
initializer
)
else
:
dtype
=
TENSOR_TYPE_TO_NP_TYPE
[
initializer
.
data_type
]
# strip inputs
ret
.
graph
.
ClearField
(
'input'
)
ret_inputs
=
ret
.
graph
.
input
for
item
in
model
.
graph
.
input
:
name
=
item
.
name
if
name
in
input_refs
or
name
in
out_names
:
ret_inputs
.
add
().
CopyFrom
(
item
)
return
ret
def
make_variable_name
(
self
,
name
):
"""
make a valid code name for ParamAttr
"""
if
name
==
''
:
raise
ValueError
(
'name should not be empty'
)
for
s
in
' .*?
\\
/-:'
:
#
name
=
name
.
replace
(
s
,
'_'
)
return
'_'
+
name
def
standardize_variable_name
(
self
,
graph
):
"""
standardize variable name for paddle's code
"""
for
initializer
in
graph
.
initializer
:
initializer
.
name
=
self
.
make_variable_name
(
initializer
.
name
)
for
ipt
in
graph
.
input
:
ipt
.
name
=
self
.
make_variable_name
(
ipt
.
name
)
for
output
in
graph
.
output
:
output
.
name
=
self
.
make_variable_name
(
output
.
name
)
for
item
in
graph
.
value_info
:
item
.
name
=
self
.
make_variable_name
(
item
.
name
)
for
node
in
graph
.
node
:
if
node
.
name
==
''
:
node
.
name
=
node
.
output
[
0
]
node
.
name
=
self
.
make_variable_name
(
node
.
name
)
for
i
in
range
(
len
(
node
.
input
)):
node
.
input
[
i
]
=
self
.
make_variable_name
(
node
.
input
[
i
])
for
i
in
range
(
len
(
node
.
output
)):
node
.
output
[
i
]
=
self
.
make_variable_name
(
node
.
output
[
i
])
def
split_model
(
self
,
model
,
outputs
=
None
):
"""
Takes a model and changes its outputs.
"""
if
outputs
is
None
:
raise
RuntimeError
(
"outputs is None"
)
if
outputs
==
model
.
graph
.
output
[
0
].
name
:
return
model
nodes
=
model
.
graph
.
node
keep_nodes
=
[]
# all the nodes we need to keep.
for
node
in
nodes
:
if
outputs
in
node
.
output
:
keep_nodes
.
append
(
node
)
break
keep_nodes
.
append
(
node
)
infer_shapes
=
onnx
.
shape_inference
.
infer_shapes
(
model
)
var_out
=
[]
for
value_info
in
infer_shapes
.
graph
.
value_info
:
if
value_info
.
name
==
outputs
:
var_out
.
append
(
value_info
)
break
graph
=
helper
.
make_graph
(
keep_nodes
,
model
.
graph
.
name
,
model
.
graph
.
input
,
var_out
,
model
.
graph
.
initializer
)
onnx_model
=
helper
.
make_model
(
graph
)
onnx_model
.
ir_version
=
model
.
ir_version
onnx_model
.
producer_name
=
model
.
producer_name
onnx_model
.
producer_version
=
model
.
producer_version
onnx_model
.
domain
=
model
.
domain
onnx_model
.
model_version
=
model
.
model_version
onnx_model
.
doc_string
=
model
.
doc_string
if
len
(
onnx_model
.
graph
.
input
)
!=
len
(
model
.
graph
.
input
):
raise
RuntimeError
(
"Input mismatch {} != {}"
.
format
(
len
(
onnx_model
.
input
),
len
(
model
.
input
)))
return
onnx_model
def
get_dynamic_shape_from_caffe2
(
self
,
layer
,
input_shapes
):
"""
get dynamic shape from caffe2.backend
"""
try
:
import
torch
version
=
torch
.
__version__
if
'1.1.0'
not
in
version
:
print
(
"your model have dynamic graph, torch==1.1.0 is required"
)
return
except
:
print
(
"your model have dynamic graph, we use caff2 to inference graph, please use
\"
pip install torch==1.1.0
\"
."
)
return
from
caffe2.python.onnx.backend
import
prepare
shape
=
input_shapes
[
0
]
np_images
=
np
.
random
.
rand
(
shape
[
0
],
shape
[
1
],
shape
[
2
],
shape
[
3
]).
astype
(
'float32'
)
num_onnx
=
self
.
split_model
(
self
.
model
,
layer
)
prepared_backend
=
prepare
(
num_onnx
,
device
=
'CPU'
)
output
=
prepared_backend
.
run
(
inputs
=
np_images
)
return
output
[
0
].
tolist
()
def
get_dynamic_shape_from_onnx
(
self
,
layer
,
input_shapes
):
"""
get dynamic shape from onnxruntime
"""
import
onnxruntime
as
rt
from
onnxruntime.backend
import
prepare
import
numpy
as
np
num_onnx
=
self
.
split_model
(
self
.
model
,
layer
)
sess
=
prepare
(
num_onnx
)
shape
=
input_shapes
[
0
]
print
(
shape
)
np_images
=
np
.
random
.
rand
(
shape
[
0
],
shape
[
1
],
shape
[
2
],
shape
[
3
]).
astype
(
'float32'
)
output
=
sess
.
run
(
model
=
sess
,
inputs
=
np_images
)
return
output
[
0
].
tolist
()
x2paddle/op_mapper/onnx_directly_map.py
0 → 100644
浏览文件 @
7bd948a1
# 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.
from
collections
import
OrderedDict
as
_dict
import
numpy
as
_np
default_op_mapping_field_values
=
_dict
()
default_op_mapping_field_values
[
'FLUID_OP'
]
=
''
default_op_mapping_field_values
[
'FLUID_INPUT_ARGS'
]
=
None
default_op_mapping_field_values
[
'FLUID_OUTPUT_ARGS'
]
=
None
default_op_mapping_field_values
[
'ATTR_MAPPING'
]
=
dict
()
default_op_mapping_field_values
[
'DEFAULTS'
]
=
dict
()
default_op_mapping_field_values
[
'INPUT_PERM'
]
=
None
default_op_mapping_field_values
[
'OUTPUT_PERM'
]
=
None
default_op_mapping_field_values
[
'FILL_NAME_FIELD'
]
=
True
default_op_mapping
=
{
'Gather'
:
[
'gather'
,
[
'X'
],
[
'Out'
],
dict
(
axis
=
''
)],
'Shape'
:
[
'shape'
,
[
'X'
],
[
'Out'
]],
'Mul'
:
[
'elementwise_mul'
,
[
'X'
,
'Y'
],
[
'Out'
],
dict
(),
dict
(
axis
=-
1
)],
'Clip'
:
[
'clip'
,
[
'X'
],
[
'Out'
],
dict
(),
dict
(
min
=
(
_np
.
asarray
([
255
,
255
,
127
,
255
],
dtype
=
_np
.
uint8
).
view
(
_np
.
float32
)),
max
=
(
_np
.
asarray
([
255
,
255
,
127
,
127
],
dtype
=
_np
.
uint8
).
view
(
_np
.
float32
)),
)
],
'ReduceMean'
:
[
'reduce_mean'
,
[
'X'
],
[
'Out'
],
dict
(
axes
=
'dim'
,
keepdims
=
'keep_dim'
),
dict
(
keep_dim
=
1
)
]
}
default_ioa_constraint
=
{
'Gather'
:
[(
lambda
i
,
o
,
a
:
a
.
get
(
'axis'
,
0
)
==
0
,
'only axis = 0 is supported'
)],
}
x2paddle/op_mapper/onnx_op_mapper.py
0 → 100644
浏览文件 @
7bd948a1
此差异已折叠。
点击以展开。
x2paddle/optimizer/onnx_optimizer.py
0 → 100644
浏览文件 @
7bd948a1
# 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.
# TODO useless node remove
from
x2paddle.op_mapper.onnx_op_mapper
import
ONNXOpMapper
from
x2paddle.core.util
import
*
class
ONNXOptimizer
(
object
):
def
__init__
(
self
,
op_mapper
):
self
.
op_mapper
=
op_mapper
self
.
graph
=
op_mapper
.
graph
def
delete_redundance_code
(
self
):
for
node_name
in
self
.
graph
.
topo_sort
:
if
node_name
in
self
.
op_mapper
.
omit_nodes
:
node
=
self
.
graph
.
get_node
(
node_name
)
omit_freq
=
self
.
op_mapper
.
omit_nodes
.
count
(
node_name
)
if
len
(
node
.
outputs
)
<=
omit_freq
:
node
.
fluid_code
.
clear
()
x2paddle_model_zoo.md
浏览文件 @
7bd948a1
...
...
@@ -26,3 +26,33 @@
| ShuffleNet |
[
code
](
https://github.com/miaow1988/ShuffleNet_V2_pytorch_caffe/releases/tag/v0.1.0
)
|
| mNASNet |
[
code
](
https://github.com/LiJianfei06/MnasNet-caffe
)
|
| MTCNN |
[
code
](
https://github.com/kpzhang93/MTCNN_face_detection_alignment/tree/master/code/codes/MTCNNv1/model
)
|
# ONNX
| 模型 | 来源 | operator version|
|-------|--------|---------|
| Resnet18 |
[
torchvison.model.resnet18
](
https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py
)
|9|
| Resnet34 |
[
torchvison.model.resnet34
](
https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py
)
|9|
| Resnet50 |
[
torchvison.model.resnet50
](
https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py
)
|9|
| Resnet101 |
[
torchvison.model.resnet101
](
https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py
)
|9|
| Vgg11 |
[
torchvison.model.vgg11
](
https://github.com/pytorch/vision/blob/master/torchvision/models/vgg.py
)
|9|
| Vgg11_bn |
[
torchvison.model.vgg11_bn
](
https://github.com/pytorch/vision/blob/master/torchvision/models/vgg.py
)
|9|
| Vgg19|
[
torchvison.model.vgg19
](
https://github.com/pytorch/vision/blob/master/torchvision/models/vgg.py
)
|9|
| Densenet121 |
[
torchvison.model.densenet121
](
https://github.com/pytorch/vision/blob/master/torchvision/models/densenet.py
)
|9|
| Alexnet |
[
torchvison.model.alexnet
](
https://github.com/pytorch/vision/blob/master/torchvision/models/alexnet.py
)
|9|
| Shufflenet |
[
onnx official
](
https://github.com/onnx/models/tree/master/vision/classification/shufflenet
)
|9|
| Inception_v2 |
[
onnx official
](
https://github.com/onnx/models/tree/master/vision/classification/inception_and_googlenet/inception_v2
)
|9|
目前onnx2paddle主要支持onnx operator version 9,关于如何使用torchvison的model:
```
import torch
import torchvision
#根据不同模型调整输入的shape
dummy_input = torch.randn(1, 3, 224, 224)
resnet18 = torchvision.models.resnet18(pretrained=True)
#"resnet18.onnx"为onnx model的存储路径
torch.onnx.export(resnet18, dummy_input, "resnet18.onnx",verbose=True)
```
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录