Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
X2Paddle
提交
538a95dd
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看板
未验证
提交
538a95dd
编写于
7月 31, 2019
作者:
J
Jason
提交者:
GitHub
7月 31, 2019
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #3 from PaddlePaddle/develop
Develop
上级
68d82cf7
2424f4a7
变更
10
隐藏空白更改
内联
并排
Showing
10 changed file
with
497 addition
and
156 deletion
+497
-156
Q&A.md
Q&A.md
+4
-0
README.md
README.md
+1
-1
x2paddle/convert.py
x2paddle/convert.py
+12
-6
x2paddle/core/fluid_code.py
x2paddle/core/fluid_code.py
+58
-28
x2paddle/decoder/caffe_decoder.py
x2paddle/decoder/caffe_decoder.py
+24
-31
x2paddle/op_mapper/caffe_custom_layer/__init__.py
x2paddle/op_mapper/caffe_custom_layer/__init__.py
+82
-0
x2paddle/op_mapper/caffe_custom_layer/convolutiondepthwise.py
...ddle/op_mapper/caffe_custom_layer/convolutiondepthwise.py
+129
-0
x2paddle/op_mapper/caffe_custom_layer/register.py
x2paddle/op_mapper/caffe_custom_layer/register.py
+43
-0
x2paddle/op_mapper/caffe_op_mapper.py
x2paddle/op_mapper/caffe_op_mapper.py
+135
-90
x2paddle/op_mapper/caffe_shape.py
x2paddle/op_mapper/caffe_shape.py
+9
-0
未找到文件。
Q&A.md
0 → 100644
浏览文件 @
538a95dd
## 常见问题
**Q1. TensorFlow模型转换过程中,提示『Unknown shape for input tensor[tensor name: "input"], Please define shape of input here』?**
A:该提示信息表示无法从TensorFlow的pb模型中获取到输入tensor(tensor名为"input:)的shape信息,所以需要用户手动在提示后输入详细的shape信息,如None,224,224,3 其中None表示Batch
README.md
浏览文件 @
538a95dd
...
...
@@ -33,4 +33,4 @@ x2paddle --framework=caffe --proto=deploy.proto --weight=deploy.caffemodel --sav
## Related Docs
1.
[
X2Paddle使用过程中常见问题
](
Q&A.md
)
2.
[
如何导出TensorFlow的pb模型
](
export_tf_model.md
)
2.
[
如何导出TensorFlow的pb模型
](
export_tf_model.md
)
\ No newline at end of file
x2paddle/convert.py
浏览文件 @
538a95dd
...
...
@@ -23,11 +23,11 @@ def arg_parser():
type
=
_text_type
,
default
=
None
,
help
=
"model file path"
)
parser
.
add_argument
(
"--proto"
,
parser
.
add_argument
(
"--proto
txt
"
,
"-p"
,
type
=
_text_type
,
default
=
None
,
help
=
"proto file of caffe model"
)
help
=
"proto
txt
file of caffe model"
)
parser
.
add_argument
(
"--weight"
,
"-w"
,
type
=
_text_type
,
...
...
@@ -43,6 +43,11 @@ def arg_parser():
type
=
_text_type
,
default
=
None
,
help
=
"define which deeplearning framework"
)
parser
.
add_argument
(
"--caffe_proto"
,
"-c"
,
type
=
_text_type
,
default
=
None
,
help
=
"caffe proto file of caffe model"
)
return
parser
...
...
@@ -57,12 +62,12 @@ def tf2paddle(model_path, save_dir):
mapper
.
save_python_model
(
save_dir
)
def
caffe2paddle
(
proto
,
weight
,
save_dir
):
def
caffe2paddle
(
proto
,
weight
,
save_dir
,
caffe_proto
):
from
x2paddle.decoder.caffe_decoder
import
CaffeDecoder
from
x2paddle.op_mapper.caffe_op_mapper
import
CaffeOpMapper
print
(
"Now translating model from caffe to paddle."
)
model
=
CaffeDecoder
(
proto
,
weight
)
model
=
CaffeDecoder
(
proto
,
weight
,
caffe_proto
)
mapper
=
CaffeOpMapper
(
model
)
mapper
.
run
()
mapper
.
save_python_model
(
save_dir
)
...
...
@@ -80,8 +85,9 @@ def main():
tf2paddle
(
args
.
model
,
args
.
save_dir
)
elif
args
.
framework
==
"caffe"
:
assert
args
.
proto
is
not
None
,
"--proto and --weight should be defined while translating caffe model"
caffe2paddle
(
args
.
proto
,
args
.
weight
,
args
.
save_dir
)
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
)
else
:
raise
Exception
(
"--framework only support tensorflow/caffe now"
)
...
...
x2paddle/core/fluid_code.py
浏览文件 @
538a95dd
...
...
@@ -13,7 +13,6 @@
# limitations under the License.
from
x2paddle.core.graph
import
GraphNode
import
collections
class
Layer
(
object
):
...
...
@@ -22,6 +21,7 @@ class Layer(object):
self
.
param_attr
=
dict
()
self
.
inputs
=
dict
()
self
.
output
=
None
self
.
is_new
=
False
def
get_code
(
self
):
layer_code
=
""
...
...
@@ -36,34 +36,25 @@ class Layer(object):
if
isinstance
(
self
.
inputs
,
list
):
in_list
=
"["
for
input
in
self
.
inputs
:
if
isinstance
(
input
,
GraphNode
):
if
hasattr
(
input
,
"index"
):
in_list
+=
(
input
.
layer_name
+
"[{}]"
.
format
(
input
.
index
)
+
", "
)
else
:
in_list
+=
(
input
.
layer_name
+
", "
)
elif
isinstance
(
input
,
str
):
in_list
+=
(
input
+
", "
)
assert
isinstance
(
input
,
GraphNode
),
"Type of input should be GraphNode"
if
hasattr
(
input
,
"index"
):
in_list
+=
(
input
.
layer_name
+
"[{}]"
.
format
(
input
.
index
)
+
", "
)
else
:
raise
Exception
(
"Element of inputs should GraphNode or String"
)
in_list
+=
(
input
.
layer_name
+
", "
)
in_list
=
in_list
.
strip
(
", "
)
+
"], "
layer_code
+=
in_list
elif
isinstance
(
self
.
inputs
,
dict
):
inputs
=
collections
.
OrderedDict
(
self
.
inputs
)
for
key
,
input
in
inputs
.
items
():
if
isinstance
(
input
,
GraphNode
):
if
hasattr
(
input
,
"index"
):
layer_code
=
layer_code
+
key
+
"={}, "
.
format
(
input
.
layer_name
+
"[{}]"
.
format
(
input
.
index
))
else
:
layer_code
=
layer_code
+
key
+
"={}, "
.
format
(
input
.
layer_name
)
elif
isinstance
(
input
,
str
):
layer_code
=
layer_code
+
key
+
"={}, "
.
format
(
input
)
for
key
,
input
in
self
.
inputs
.
items
():
assert
isinstance
(
input
,
GraphNode
),
"Type of input should be GraphNode"
if
hasattr
(
input
,
"index"
):
layer_code
=
layer_code
+
key
+
"={}, "
.
format
(
input
.
layer_name
+
"[{}]"
.
format
(
input
.
index
))
else
:
raise
Exception
(
"Element of inputs should GraphNode or String"
)
layer_code
=
layer_code
+
key
+
"={}, "
.
format
(
input
.
layer_name
)
elif
isinstance
(
self
.
inputs
,
GraphNode
):
if
hasattr
(
self
.
inputs
,
"index"
):
layer_code
+=
(
self
.
inputs
.
layer_name
+
...
...
@@ -75,8 +66,38 @@ class Layer(object):
else
:
raise
Exception
(
"Unknown type of inputs."
)
param_attr
=
collections
.
OrderedDict
(
self
.
param_attr
)
for
key
,
value
in
param_attr
.
items
():
for
key
,
value
in
self
.
param_attr
.
items
():
layer_code
=
layer_code
+
key
+
"={}, "
.
format
(
value
)
layer_code
=
layer_code
.
strip
(
", "
)
return
layer_code
+
")"
def
get_custom_code
(
self
):
layer_code
=
""
if
self
.
output
is
not
None
:
if
isinstance
(
self
.
output
,
str
):
layer_code
=
self
.
output
+
" = "
else
:
layer_code
=
self
.
output
.
layer_name
+
" = "
layer_code
=
layer_code
+
self
.
op
+
"("
if
isinstance
(
self
.
inputs
,
list
):
in_list
=
"["
for
input
in
self
.
inputs
:
assert
isinstance
(
input
,
GraphNode
),
"Type of input should be GraphNode"
if
hasattr
(
input
,
"index"
):
in_list
+=
(
input
.
layer_name
+
"[{}]"
.
format
(
input
.
index
)
+
", "
)
else
:
in_list
+=
(
input
.
layer_name
+
", "
)
in_list
=
in_list
.
strip
(
", "
)
+
"], "
layer_code
+=
in_list
else
:
raise
Exception
(
"Unknown type of inputs."
)
for
key
,
value
in
self
.
param_attr
.
items
():
layer_code
=
layer_code
+
key
+
"={}, "
.
format
(
value
)
layer_code
=
layer_code
.
strip
(
", "
)
...
...
@@ -87,9 +108,15 @@ class FluidCode(object):
def
__init__
(
self
):
self
.
layers
=
list
()
def
add_layer
(
self
,
op
,
inputs
,
output
,
param_attr
=
None
):
def
add_layer
(
self
,
op
,
inputs
,
output
,
param_attr
=
None
,
is_custom_layer
=
False
):
layer
=
Layer
()
layer
.
op
=
op
layer
.
is_custom_layer
=
is_custom_layer
if
inputs
is
not
None
:
layer
.
inputs
=
inputs
layer
.
output
=
output
...
...
@@ -108,7 +135,10 @@ class FluidCode(object):
codes
=
list
()
for
layer
in
self
.
layers
:
if
isinstance
(
layer
,
Layer
):
codes
.
append
(
layer
.
get_code
())
if
layer
.
is_custom_layer
:
codes
.
append
(
layer
.
get_custom_code
())
else
:
codes
.
append
(
layer
.
get_code
())
elif
isinstance
(
layer
,
str
):
codes
.
append
(
layer
)
return
codes
x2paddle/decoder/caffe_decoder.py
浏览文件 @
538a95dd
...
...
@@ -18,19 +18,20 @@ from google.protobuf import text_format
import
numpy
as
np
from
x2paddle.core.graph
import
GraphNode
,
Graph
from
x2paddle.core.fluid_code
import
FluidCode
from
x2paddle.
decod
er
import
caffe_shape
from
x2paddle.
op_mapp
er
import
caffe_shape
class
CaffeResolver
(
object
):
def
__init__
(
self
,
use_default
=
True
):
self
.
use_default
=
use_default
def
__init__
(
self
,
caffe_proto_folder
=
None
):
self
.
proto_path
=
caffe_proto_folder
if
self
.
proto_path
==
None
:
self
.
use_default
=
True
else
:
self
.
use_default
=
False
self
.
import_caffe
()
def
import_caffepb
(
self
):
p
=
os
.
path
.
realpath
(
__file__
)
p
=
os
.
path
.
dirname
(
p
)
p
=
os
.
path
.
join
(
p
,
'./proto'
)
sys
.
path
.
insert
(
0
,
p
)
sys
.
path
.
append
(
self
.
proto_path
)
import
caffe_pb2
return
caffe_pb2
...
...
@@ -60,11 +61,13 @@ class CaffeResolver(object):
class
CaffeGraphNode
(
GraphNode
):
def
__init__
(
self
,
layer
,
layer_name
=
None
):
if
layer_name
is
None
:
super
(
CaffeGraphNode
,
self
).
__init__
(
layer
,
layer
.
name
.
replace
(
'/'
,
'_'
))
super
(
CaffeGraphNode
,
self
).
__init__
(
layer
,
layer
.
name
.
replace
(
'/'
,
'_'
).
replace
(
'-'
,
'_'
))
else
:
super
(
CaffeGraphNode
,
self
).
__init__
(
layer
,
layer_name
.
replace
(
'/'
,
'_'
))
super
(
CaffeGraphNode
,
self
).
__init__
(
layer
,
layer_name
.
replace
(
'/'
,
'_'
).
replace
(
'-'
,
'_'
))
self
.
layer_type
=
layer
.
type
self
.
fluid_code
=
FluidCode
()
self
.
data
=
None
...
...
@@ -72,10 +75,13 @@ class CaffeGraphNode(GraphNode):
def
set_params
(
self
,
params
):
self
.
data
=
params
def
set_output_shape
(
self
,
input_shape
):
def
set_output_shape
(
self
,
input_shape
,
is_input
=
True
):
func_name
=
'shape_'
+
self
.
layer_type
.
lower
()
self
.
output_shape
=
getattr
(
caffe_shape
,
func_name
)(
self
.
layer
,
input_shape
)
if
is_input
:
self
.
output_shape
=
getattr
(
caffe_shape
,
func_name
)(
self
.
layer
,
input_shape
)
else
:
self
.
output_shape
=
input_shape
def
set_input_shape
(
self
,
input_shape
):
self
.
input_shape
=
input_shape
...
...
@@ -135,7 +141,7 @@ class CaffeGraph(Graph):
]))).
to_proto
().
layer
[
0
])
except
:
raise
ImportError
(
'
You must install the caffe first when you use old style prototxt
.'
'
The .proto file does not work for the old style prototxt. You must install the caffe or modify the old style to new style in .protottx file
.'
)
data
.
name
=
self
.
model
.
input
[
i
]
data
.
top
[
0
]
=
self
.
model
.
input
[
i
]
...
...
@@ -151,7 +157,7 @@ class CaffeGraph(Graph):
]))).
to_proto
().
layer
[
0
])
except
:
raise
ImportError
(
'
You must install the caffe first when you use old style prototxt
.'
'
The .proto file does not work for the old style prototxt. You must install the caffe or modify the old style to new style in .protottx file
.'
)
data
.
name
=
self
.
model
.
input
[
i
]
data
.
top
[
0
]
=
self
.
model
.
input
[
i
]
...
...
@@ -180,19 +186,6 @@ class CaffeGraph(Graph):
else
:
notice
(
'Ignoring parameters for non-existent layer: %s'
%
\
layer_name
)
for
layer_name
in
self
.
node_map
:
node
=
self
.
node_map
[
layer_name
]
inputs
=
node
.
inputs
i
=
0
input_shape
=
[]
for
nm
in
inputs
:
last_node
=
self
.
get_node
(
nm
)
tmp
=
node
.
layer
.
bottom
[
i
]
i
=
i
+
1
idx
=
list
(
last_node
.
layer
.
top
).
index
(
tmp
)
input_shape
.
append
(
last_node
.
output_shape
[
idx
])
node
.
set_output_shape
(
input_shape
)
node
.
set_input_shape
(
input_shape
)
super
(
CaffeGraph
,
self
).
build
()
...
...
@@ -210,11 +203,11 @@ class CaffeGraph(Graph):
class
CaffeDecoder
(
object
):
def
__init__
(
self
,
proto_path
,
model_path
,
use_caffe
=
Tru
e
):
def
__init__
(
self
,
proto_path
,
model_path
,
caffe_proto_folder
=
Non
e
):
self
.
proto_path
=
proto_path
self
.
model_path
=
model_path
self
.
resolver
=
CaffeResolver
(
use_default
=
use_caffe
)
self
.
resolver
=
CaffeResolver
(
caffe_proto_folder
=
caffe_proto_folder
)
self
.
net
=
self
.
resolver
.
NetParameter
()
with
open
(
proto_path
,
'rb'
)
as
proto_file
:
proto_str
=
proto_file
.
read
()
...
...
x2paddle/op_mapper/caffe_custom_layer/__init__.py
0 → 100644
浏览文件 @
538a95dd
from
.register
import
get_registered_layers
#custom layer import begins
# from . import roipooling
# from . import priorbox
# from . import permute
# from . import detection_out
# from . import normalize
# from . import select
from
.
import
convolutiondepthwise
#custom layer import ends
custom_layers
=
get_registered_layers
()
def
set_args
(
f
,
params
):
""" set args for function 'f' using the parameters in node.layer.param
Args:
f (function): a python function object
params (object): a object contains attributes needed by f's arguments
Returns:
arg_names (list): a list of argument names
kwargs (dict): a dict contains needed arguments
"""
argc
=
f
.
__code__
.
co_argcount
arg_list
=
f
.
__code__
.
co_varnames
[
0
:
argc
]
kwargs
=
{}
for
arg_name
in
arg_list
:
if
hasattr
(
params
,
arg_name
)
and
params
is
not
None
:
kwargs
[
arg_name
]
=
getattr
(
params
,
arg_name
)
return
arg_list
,
kwargs
def
has_layer
(
layer_type
):
""" test whether this layer exists in custom layer
"""
return
layer_type
in
custom_layers
def
get_params
(
layer
,
layer_type
):
if
layer_type
.
lower
()
==
"deconvolution"
or
layer_type
.
lower
(
)
==
"convolutiondepthwise"
:
param_name
=
'_'
.
join
((
'convolution'
,
'param'
))
elif
layer_type
.
lower
()
==
"normalize"
:
param_name
=
'_'
.
join
((
'norm'
,
'param'
))
else
:
param_name
=
'_'
.
join
((
layer_type
.
lower
(),
'param'
))
return
getattr
(
layer
,
param_name
,
None
)
def
compute_output_shape
(
node
):
""" compute the output shape of custom layer
"""
layer_type
=
node
.
layer_type
assert
layer_type
in
custom_layers
,
"layer[%s] not exist in custom layers"
%
(
layer_type
)
shape_func
=
custom_layers
[
layer_type
][
'shape'
]
layer
=
node
.
layer
params
=
get_params
(
layer
,
layer_type
)
arg_names
,
kwargs
=
set_args
(
shape_func
,
params
)
input_shape
=
node
.
input_shape
return
shape_func
(
input_shape
,
**
kwargs
)
def
make_custom_layer
(
node
):
""" get the code which implement the custom layer function
"""
layer_type
=
node
.
layer_type
assert
layer_type
in
custom_layers
,
"layer[%s] not exist in custom layers"
%
(
layer_type
)
layer_func
=
custom_layers
[
layer_type
][
'layer'
]
import
inspect
return
inspect
.
getsource
(
layer_func
),
layer_func
def
deal_weights
(
node
,
data
=
None
):
""" deal the weights of the custom layer
"""
layer_type
=
node
.
layer_type
weights_func
=
custom_layers
[
layer_type
][
'weights'
]
name
=
node
.
layer_name
return
weights_func
(
name
,
data
)
x2paddle/op_mapper/caffe_custom_layer/convolutiondepthwise.py
0 → 100644
浏览文件 @
538a95dd
from
.register
import
register
from
x2paddle.core.util
import
*
import
numbers
def
convolutiondepthwise_shape
(
input_shape
,
num_output
=
None
,
pad
=
None
,
kernel_size
=
None
,
stride
=
None
,
dilation
=
None
,
pad_h
=
None
,
pad_w
=
None
,
kernel_h
=
None
,
kernel_w
=
None
,
stride_h
=
None
,
stride_w
=
None
):
[
k_h
,
k_w
]
=
[
1
,
1
]
if
isinstance
(
kernel_size
,
numbers
.
Number
):
[
k_h
,
k_w
]
=
[
kernel_size
]
*
2
elif
isinstance
(
kernel_size
,
list
):
k_h
=
kernel_h
if
kernel_h
else
kernel_size
[
0
]
k_w
=
kernel_w
if
kernel_w
else
kernel_size
[
len
(
kernel_size
)
-
1
]
[
s_h
,
s_w
]
=
[
1
,
1
]
if
isinstance
(
stride
,
numbers
.
Number
):
[
s_h
,
s_w
]
=
[
stride
]
*
2
elif
isinstance
(
stride
,
list
):
s_h
=
stride_h
if
stride_h
else
stride
[
0
]
s_w
=
stride_w
if
stride_w
else
stride
[
len
(
stride
)
-
1
]
[
p_h
,
p_w
]
=
[
0
,
0
]
if
isinstance
(
pad
,
numbers
.
Number
):
[
p_h
,
p_w
]
=
[
pad
]
*
2
elif
isinstance
(
pad
,
list
):
p_h
=
pad_h
if
pad_h
else
pad
[
0
]
p_w
=
pad_w
if
pad_w
else
pad
[
len
(
pad
)
-
1
]
dila_len
=
len
(
dilation
)
dila_h
=
1
dila_w
=
1
if
dila_len
==
2
:
dila_h
=
dilation
[
0
]
dila_w
=
dilation
[
1
]
elif
dila_len
==
1
:
dila_h
=
dila_w
=
dilation
[
0
]
else
:
assert
dila_len
==
0
,
"invalid length[%s] of dilation in convolution"
%
(
dila_len
)
i_w
=
input_shape
[
0
][
2
]
i_h
=
input_shape
[
0
][
3
]
o_h
=
(
i_h
+
2
*
p_h
-
(
dila_h
*
(
k_h
-
1
)
+
1
))
/
float
(
s_h
)
+
1
o_w
=
(
i_w
+
2
*
p_w
-
(
dila_w
*
(
k_w
-
1
)
+
1
))
/
float
(
s_w
)
+
1
import
math
o_h
=
int
(
math
.
floor
(
o_h
))
o_w
=
int
(
math
.
floor
(
o_w
))
c
=
num_output
if
num_output
is
not
None
else
input_shape
[
0
][
1
]
return
[[
input_shape
[
0
][
0
],
c
,
o_h
,
o_w
]]
def
convolutiondepthwise_layer
(
inputs
,
num_output
=
None
,
pad
=
None
,
kernel_size
=
None
,
stride
=
None
,
dilation
=
None
,
pad_h
=
None
,
pad_w
=
None
,
kernel_h
=
None
,
kernel_w
=
None
,
stride_h
=
None
,
stride_w
=
None
,
input_shape
=
[],
name
=
None
):
[
k_h
,
k_w
]
=
[
1
,
1
]
if
isinstance
(
kernel_size
,
numbers
.
Number
):
[
k_h
,
k_w
]
=
[
kernel_size
]
*
2
elif
isinstance
(
kernel_size
,
list
):
k_h
=
kernel_h
if
kernel_h
else
kernel_size
[
0
]
k_w
=
kernel_w
if
kernel_w
else
kernel_size
[
len
(
kernel_size
)
-
1
]
[
s_h
,
s_w
]
=
[
1
,
1
]
if
isinstance
(
stride
,
numbers
.
Number
):
[
s_h
,
s_w
]
=
[
stride
]
*
2
elif
isinstance
(
stride
,
list
):
s_h
=
stride_h
if
stride_h
else
stride
[
0
]
s_w
=
stride_w
if
stride_w
else
stride
[
len
(
stride
)
-
1
]
[
p_h
,
p_w
]
=
[
0
,
0
]
if
isinstance
(
pad
,
numbers
.
Number
):
[
p_h
,
p_w
]
=
[
pad
]
*
2
elif
isinstance
(
pad
,
list
):
p_h
=
pad_h
if
pad_h
else
pad
[
0
]
p_w
=
pad_w
if
pad_w
else
pad
[
len
(
pad
)
-
1
]
input
=
inputs
[
0
]
dila_len
=
len
(
dilation
)
dila_h
=
1
dila_w
=
1
if
dila_len
==
2
:
dila_h
=
dilation
[
0
]
dila_w
=
dilation
[
1
]
elif
dila_len
==
1
:
dila_h
=
dila_w
=
dilation
[
0
]
else
:
assert
dila_len
==
0
,
"invalid length[%s] of dilation in convolution"
%
(
dila_len
)
c_in
=
input_shape
[
0
][
1
]
c_out
=
num_output
if
num_output
is
not
None
else
input_shape
[
0
][
1
]
group
=
int
(
c_in
/
(
c_in
/
c_out
))
if
c_in
>
c_out
else
int
(
c_in
/
(
c_out
/
c_in
))
out
=
fluid
.
layers
.
conv2d
(
input
,
dilation
=
[
dila_h
,
dila_w
],
filter_size
=
[
k_h
,
k_w
],
stride
=
[
s_h
,
s_w
],
padding
=
[
p_h
,
p_w
],
groups
=
group
,
num_filters
=
c_out
,
param_attr
=
name
+
'_weights'
,
bias_attr
=
name
+
'_bias'
,
name
=
name
)
return
out
def
convolutiondepthwise_weights
(
name
,
data
=
None
):
weights_name
=
[]
weights_name
.
append
(
name
+
'_weights'
)
weights_name
.
append
(
name
+
'_bias'
)
return
weights_name
register
(
kind
=
'ConvolutionDepthwise'
,
shape
=
convolutiondepthwise_shape
,
layer
=
convolutiondepthwise_layer
,
weights
=
convolutiondepthwise_weights
)
x2paddle/op_mapper/caffe_custom_layer/register.py
0 → 100644
浏览文件 @
538a95dd
""" this module provides 'register' for registering customized layers
"""
g_custom_layers
=
{}
def
register
(
kind
,
shape
,
layer
,
weights
):
""" register a custom layer or a list of custom layers
Args:
@kind (str or list): type name of the layer
@shape (function): a function to generate the shape of layer's output
@layer (function): a function to generate the paddle code of layer
@weights (function): a function to deal with weights data
Returns:
None
"""
assert
type
(
shape
).
__name__
==
'function'
,
'shape should be a function'
assert
type
(
layer
).
__name__
==
'function'
,
'layer should be a function'
if
type
(
kind
)
is
str
:
kind
=
[
kind
]
else
:
assert
type
(
kind
)
is
list
,
'invalid param "kind" for register, not a list or str'
for
k
in
kind
:
assert
type
(
k
)
is
str
,
'invalid param "kind" for register, not a list of str'
assert
k
not
in
g_custom_layers
,
'this type[%s] has already been registered'
%
(
k
)
print
(
'register layer[%s]'
%
(
k
))
g_custom_layers
[
k
]
=
{
'shape'
:
shape
,
'layer'
:
layer
,
'weights'
:
weights
}
def
get_registered_layers
():
return
g_custom_layers
x2paddle/op_mapper/caffe_op_mapper.py
浏览文件 @
538a95dd
...
...
@@ -17,6 +17,7 @@ import numpy as np
from
x2paddle.decoder.caffe_decoder
import
CaffeGraph
from
x2paddle.core.op_mapper
import
OpMapper
from
x2paddle.core.util
import
*
from
x2paddle.op_mapper.caffe_custom_layer
import
*
class
CaffeOpMapper
(
OpMapper
):
...
...
@@ -25,34 +26,72 @@ class CaffeOpMapper(OpMapper):
self
.
graph
=
decoder
.
caffe_graph
self
.
weights
=
dict
()
resolver
=
decoder
.
resolver
self
.
mylayers
=
{}
if
resolver
.
has_pycaffe
():
self
.
did_use_pb
=
False
else
:
self
.
did_use_pb
=
True
def
op_checker
(
self
):
unsupported_ops
=
set
()
for
node_name
in
self
.
graph
.
topo_sort
:
node
=
self
.
graph
.
get_node
(
node_name
)
op
=
node
.
layer_type
if
not
hasattr
(
self
,
op
)
and
op
not
in
custom_layers
:
unsupported_ops
.
add
(
op
)
if
len
(
unsupported_ops
)
==
0
:
return
True
else
:
print
(
"There are {} ops not supported yet, list as below"
.
format
(
len
(
unsupported_ops
)))
for
op
in
unsupported_ops
:
print
(
op
)
return
False
def
run
(
self
):
print
(
"Total nodes: {}"
.
format
(
len
(
self
.
graph
.
topo_sort
)))
# check if ops in model are all supported
if
not
self
.
op_checker
():
raise
Exception
(
"Model are not supported yet."
)
for
node_name
in
self
.
graph
.
topo_sort
:
node
=
self
.
graph
.
get_node
(
node_name
)
op
=
node
.
layer_type
if
hasattr
(
self
,
op
):
self
.
set_shape
(
node
)
func
=
getattr
(
self
,
op
)
func
(
node
)
elif
op
in
custom_layers
:
self
.
set_shape
(
node
,
is_fluid_op
=
False
)
self
.
deal_custom_layer
(
node
)
else
:
raise
Exception
(
"Model are not supported yet."
)
for
key
in
self
.
mylayers
:
self
.
net_code
.
append
(
self
.
mylayers
[
key
])
for
i
in
range
(
len
(
self
.
graph
.
topo_sort
)):
node_name
=
self
.
graph
.
topo_sort
[
i
]
node
=
self
.
graph
.
get_node
(
node_name
)
self
.
net_code
+=
node
.
fluid_code
.
gen_codes
()
def
adjust_parameters
(
self
,
node
,
data
):
def
set_shape
(
self
,
node
,
is_fluid_op
=
True
):
inputs
=
node
.
inputs
input_shape
=
[]
for
i
,
nm
in
enumerate
(
inputs
):
last_node
=
self
.
graph
.
get_node
(
nm
)
tmp
=
node
.
layer
.
bottom
[
i
]
idx
=
list
(
last_node
.
layer
.
top
).
index
(
tmp
)
input_shape
.
append
(
last_node
.
output_shape
[
idx
])
node
.
set_input_shape
(
input_shape
)
if
is_fluid_op
:
node
.
set_output_shape
(
input_shape
)
else
:
node
.
set_output_shape
(
compute_output_shape
(
node
),
is_input
=
is_fluid_op
)
def
adjust_parameters
(
self
,
node
):
data
=
node
.
data
if
not
self
.
did_use_pb
:
return
data
# When using the protobuf-backend, each parameter initially has four dimensions.
# In certain cases (like FC layers), we want to eliminate the singleton dimensions.
# This implementation takes care of the common cases. However, it does leave the
...
...
@@ -61,7 +100,7 @@ class CaffeOpMapper(OpMapper):
data
=
list
(
data
)
squeeze_indices
=
[
1
]
# Squeeze biases.
if
node
.
kind
==
NodeKind
.
InnerProduct
:
if
node
.
layer_type
==
'InnerProduct'
:
squeeze_indices
.
append
(
0
)
# Squeeze FC.
for
idx
in
squeeze_indices
:
...
...
@@ -85,55 +124,44 @@ class CaffeOpMapper(OpMapper):
data
[
idx
]
=
np
.
squeeze
(
d
,
axis
=
sq_axis
)
shape_new
=
data
[
idx
].
shape
print
(
'shape-old'
+
str
(
shape_old
))
print
(
'shape-new'
+
str
(
shape_new
))
if
len
(
shape_old
)
!=
shape_new
:
debug
(
'squeeze idx:%d, with kind:%s,name:%s'
%
\
(
idx
,
node
.
kind
,
node
.
name
))
print
(
'squeeze idx:%d, with kind:%s,name:%s'
%
\
(
idx
,
node
.
layer_type
,
node
.
layer
.
name
))
return
data
@
staticmethod
def
get_kernel_value
(
scalar
,
repeated
,
idx
,
default
=
None
):
if
scalar
:
return
scalar
if
repeated
:
if
isinstance
(
repeated
,
numbers
.
Number
):
return
repeated
if
len
(
repeated
)
==
1
:
# Same value applies to all spatial dimensions
return
int
(
repeated
[
0
])
assert
idx
<
len
(
repeated
)
# Extract the value for the given spatial dimension
return
repeated
[
idx
]
if
default
is
None
:
raise
ValueError
(
'Unable to determine kernel parameter!'
)
return
default
def
get_kernel_parameters
(
self
,
kind
,
params
):
assert
kind
in
[
'Convolution'
,
'Pooling'
,
'Deconvolution'
]
k_h
=
self
.
get_kernel_value
(
params
.
kernel_h
,
params
.
kernel_size
,
0
,
default
=
1
)
k_w
=
self
.
get_kernel_value
(
params
.
kernel_w
,
params
.
kernel_size
,
1
,
default
=
1
)
s_h
=
self
.
get_kernel_value
(
params
.
stride_h
,
params
.
stride
,
0
,
default
=
1
)
s_w
=
self
.
get_kernel_value
(
params
.
stride_w
,
params
.
stride
,
1
,
default
=
1
)
p_h
=
self
.
get_kernel_value
(
params
.
pad_h
,
params
.
pad
,
0
,
default
=
0
)
p_w
=
self
.
get_kernel_value
(
params
.
pad_w
,
params
.
pad
,
1
,
default
=
0
)
assert
kind
in
[
'Convolution'
,
'Pooling'
,
'Deconvolution'
,
'ConvolutionDepthwise'
]
[
k_h
,
k_w
]
=
[
1
,
1
]
print
(
params
.
kernel_size
)
if
isinstance
(
params
.
kernel_size
,
numbers
.
Number
):
[
k_h
,
k_w
]
=
[
params
.
kernel_size
]
*
2
else
:
k_h
=
params
.
kernel_h
if
params
.
kernel_h
else
params
.
kernel_size
[
0
]
k_w
=
params
.
kernel_w
if
params
.
kernel_w
else
params
.
kernel_size
[
len
(
params
.
kernel_size
)
-
1
]
[
s_h
,
s_w
]
=
[
1
,
1
]
if
isinstance
(
params
.
stride
,
numbers
.
Number
):
[
s_h
,
s_w
]
=
[
params
.
stride
]
*
2
else
:
s_h
=
params
.
stride_h
if
params
.
stride_h
else
params
.
stride
[
0
]
s_w
=
params
.
stride_w
if
params
.
stride_w
else
params
.
stride
[
len
(
params
.
stride
)
-
1
]
[
p_h
,
p_w
]
=
[
0
,
0
]
if
isinstance
(
params
.
pad
,
numbers
.
Number
):
[
p_h
,
p_w
]
=
[
params
.
pad
]
*
2
else
:
p_h
=
params
.
pad_h
if
params
.
pad_h
else
params
.
pad
[
0
]
p_w
=
params
.
pad_w
if
params
.
pad_w
else
params
.
pad
[
len
(
params
.
pad
)
-
1
]
dila_h
=
dila_w
=
1
group
=
1
c_o
=
1
if
kind
in
[
'Convolution'
,
'Deconvolution'
]:
if
kind
in
[
'Convolution'
,
'Deconvolution'
,
'ConvolutionDepthwise'
]:
c_o
=
params
.
num_output
group
=
params
.
group
dila_len
=
len
(
params
.
dilation
)
if
dila_len
==
2
:
dila_h
=
params
.
dilation
[
0
]
...
...
@@ -143,12 +171,12 @@ class CaffeOpMapper(OpMapper):
else
:
assert
dila_len
==
0
,
"invalid length[%s] of dilation in convolution"
%
(
dila_len
)
if
kind
in
[
'Convolution'
,
'Deconvolution'
]:
group
=
params
.
group
kernel
=
[
k_h
,
k_w
]
stride
=
[
s_h
,
s_w
]
pad
=
[
p_h
,
p_w
]
dilation
=
[
dila_h
,
dila_w
]
return
c_o
,
kernel
,
stride
,
pad
,
dilation
,
group
def
get_input_name
(
self
,
node
):
...
...
@@ -180,7 +208,7 @@ class CaffeOpMapper(OpMapper):
data
=
node
.
data
assert
data
is
not
None
,
'The parameter of {} (type is {}) is not set. You need to use python package of caffe to set the default value.'
.
format
(
node
.
layer_name
,
node
.
layer_type
)
data
=
self
.
adjust_parameters
(
node
,
data
)
data
=
self
.
adjust_parameters
(
node
)
self
.
weights
[
node
.
layer_name
+
'_weights'
]
=
data
[
0
]
if
len
(
data
)
==
2
:
self
.
weights
[
node
.
layer_name
+
'_bias'
]
=
data
[
1
]
...
...
@@ -224,7 +252,7 @@ class CaffeOpMapper(OpMapper):
data
=
node
.
data
assert
data
is
not
None
,
'The parameter of {} (type is {}) is not set. You need to use python package of caffe to set the default value.'
.
format
(
node
.
layer_name
,
node
.
layer_type
)
data
=
self
.
adjust_parameters
(
node
,
data
)
data
=
self
.
adjust_parameters
(
node
)
self
.
weights
[
node
.
layer_name
+
'_weights'
]
=
data
[
0
]
if
len
(
data
)
==
2
:
self
.
weights
[
node
.
layer_name
+
'_bias'
]
=
data
[
1
]
...
...
@@ -343,7 +371,7 @@ class CaffeOpMapper(OpMapper):
data
=
node
.
data
assert
data
is
not
None
,
'The parameter of {} (type is {}) is not set. You need to use python package of caffe to set the default value.'
.
format
(
node
.
layer_name
,
node
.
layer_type
)
data
=
self
.
adjust_parameters
(
node
,
data
)
data
=
self
.
adjust_parameters
(
node
)
# Reshape the parameters to Paddle's ordering
transpose_order
=
(
1
,
0
)
w
=
data
[
0
]
...
...
@@ -396,40 +424,11 @@ class CaffeOpMapper(OpMapper):
shape
=
node
.
input_shape
[
0
]
dims
=
len
(
shape
)
axis
=
axis
+
dims
if
axis
<
0
else
axis
need_transpose
=
False
if
axis
+
1
!=
dims
:
need_transpose
=
True
if
need_transpose
:
in_order
=
list
(
range
(
dims
))
in_order
.
remove
(
axis
)
in_order
.
append
(
axis
)
attr
=
{
'perm'
:
in_order
,
'name'
:
string
(
node
.
layer_name
+
'_transpose_in'
)
}
node
.
fluid_code
.
add_layer
(
"transpose"
,
inputs
=
input
,
output
=
node
,
param_attr
=
attr
)
attr
=
{
'name'
:
string
(
node
.
layer_name
+
'_softmax'
)}
attr
=
{
'axis'
:
axis
,
'name'
:
string
(
node
.
layer_name
+
'_softmax'
)}
node
.
fluid_code
.
add_layer
(
"softmax"
,
inputs
=
node
if
need_transpose
else
input
,
inputs
=
input
,
output
=
node
,
param_attr
=
attr
)
if
need_transpose
:
out_order
=
[
0
,
]
*
dims
for
id
,
v
in
enumerate
(
in_order
):
out_order
[
v
]
=
id
attr
=
{
'perm'
:
out_order
,
'name'
:
string
(
node
.
layer_name
+
'_transpose_out'
)
}
node
.
fluid_code
.
add_layer
(
"transpose"
,
inputs
=
node
,
output
=
node
,
param_attr
=
attr
)
def
Slice
(
self
,
node
):
assert
len
(
...
...
@@ -451,13 +450,11 @@ class CaffeOpMapper(OpMapper):
attr
=
{
'axes'
:
[
axis
],
'starts'
:
[
points
[
i
]],
'ends'
:
[
points
[
i
+
1
]],
'name'
:
string
(
node
.
layer_name
+
'_'
+
str
(
i
))
'ends'
:
[
points
[
i
+
1
]]
}
node
.
fluid_code
.
add_layer
(
"slice"
,
inputs
=
input
,
output
=
string
(
node
.
layer_name
+
'_'
+
str
(
i
)),
output
=
node
.
layer_name
+
'_'
+
str
(
i
),
param_attr
=
attr
)
node
.
fluid_code
.
add_note
(
'{}.append({})'
.
format
(
node
.
layer_name
,
node
.
layer_name
+
'_'
+
str
(
i
)))
...
...
@@ -503,7 +500,7 @@ class CaffeOpMapper(OpMapper):
node
.
layer_name
,
node
.
layer_type
)
self
.
weights
[
node
.
layer_name
+
'_weights'
]
=
data
[
0
]
attr
=
{
'mode'
:
mode
,
'mode'
:
string
(
mode
)
,
'param_attr'
:
string
(
node
.
layer_name
+
'_weights'
),
'name'
:
string
(
node
.
layer_name
)
}
...
...
@@ -731,7 +728,7 @@ class CaffeOpMapper(OpMapper):
def
Scale
(
self
,
node
):
assert
len
(
node
.
outputs
)
==
1
,
'The count of Scale node
\'
s out
put is not 1.'
node
.
inputs
)
==
1
,
'The count of Scale node
\'
s in
put is not 1.'
if
len
(
node
.
inputs
)
==
1
and
self
.
graph
.
get_node
(
node
.
inputs
[
0
]).
layer_type
==
'BatchNorm'
:
return
...
...
@@ -1058,7 +1055,9 @@ class CaffeOpMapper(OpMapper):
param_attr
=
attr
)
input_name
=
self
.
get_input_name
(
input
)
data
=
node
.
data
data
=
self
.
adjust_parameters
(
node
,
data
)
assert
data
is
not
None
,
'The parameter of {} (type is {}) is not set. You need to use python package of caffe to set the default value.'
.
format
(
node
.
layer_name
,
node
.
layer_type
)
data
=
self
.
adjust_parameters
(
node
)
self
.
weights
[
node
.
layer_name
+
'_scale'
]
=
data
[
0
]
node
.
fluid_code
.
add_note
(
'{}_scale_attr = ParamAttr(name=
\'
{}
\'
)'
.
format
(
...
...
@@ -1297,7 +1296,7 @@ class CaffeOpMapper(OpMapper):
def
Select
(
self
,
node
):
assert
len
(
node
.
inputs
)
==
1
,
'The count of Select node
\'
s input is not
2
.'
node
.
inputs
)
==
1
,
'The count of Select node
\'
s input is not
1
.'
input
=
self
.
graph
.
get_bottom_node
(
node
,
idx
=
0
,
copy
=
True
)
if
self
.
is_Scale
(
input
):
tmp
=
self
.
graph
.
get_bottom_node
(
input
,
idx
=
0
,
copy
=
True
)
...
...
@@ -1327,3 +1326,49 @@ class CaffeOpMapper(OpMapper):
node
.
layer_name
,
node
.
layer_name
+
'_'
+
str
(
i
)))
if
i
==
len
(
slice_point
)
-
2
:
break
def
ShuffleChannel
(
self
,
node
):
assert
len
(
node
.
inputs
)
==
1
,
'The count of ShuffleChannel node
\'
s input is not 1.'
params
=
node
.
layer
.
shuffle_channel_param
group
=
params
.
group
input
=
self
.
graph
.
get_bottom_node
(
node
,
idx
=
0
,
copy
=
True
)
if
self
.
is_Scale
(
input
):
tmp
=
self
.
graph
.
get_bottom_node
(
input
,
idx
=
0
,
copy
=
True
)
if
self
.
is_BN
(
tmp
):
input
=
tmp
attr
=
{
'group'
:
group
,
'name'
:
string
(
node
.
layer_name
)}
node
.
fluid_code
.
add_layer
(
"shuffle_channel"
,
inputs
=
input
,
output
=
node
,
param_attr
=
attr
)
def
deal_custom_layer
(
self
,
node
):
op
=
node
.
layer_type
custom_code
,
func
=
make_custom_layer
(
node
)
params
=
get_params
(
node
.
layer
,
node
.
layer_type
)
arg_names
,
kwargs
=
set_args
(
func
,
params
)
kwargs
[
'name'
]
=
string
(
node
.
layer_name
)
kwargs
[
'input_shape'
]
=
node
.
input_shape
data
=
node
.
data
assert
data
is
not
None
,
'The parameter of {} (type is {}) is not set. You need to use python package of caffe to set the default value.'
.
format
(
node
.
layer_name
,
node
.
layer_type
)
data
=
self
.
adjust_parameters
(
node
)
weights_name
=
deal_weights
(
node
)
for
i
in
range
(
len
(
data
)):
self
.
weights
[
weights_name
[
i
]]
=
data
[
i
]
inputs_node
=
[]
for
i
in
range
(
len
(
node
.
inputs
)):
input
=
self
.
graph
.
get_bottom_node
(
node
,
idx
=
i
,
copy
=
True
)
if
self
.
is_Scale
(
input
):
tmp
=
self
.
graph
.
get_bottom_node
(
input
,
idx
=
0
,
copy
=
True
)
if
self
.
is_BN
(
tmp
):
input
=
tmp
inputs_node
.
append
(
input
)
node
.
fluid_code
.
add_layer
(
func
.
__code__
.
co_name
,
inputs
=
inputs_node
,
output
=
node
,
param_attr
=
kwargs
,
is_custom_layer
=
True
)
if
op
not
in
self
.
mylayers
:
self
.
mylayers
[
op
]
=
custom_code
x2paddle/
decod
er/caffe_shape.py
→
x2paddle/
op_mapp
er/caffe_shape.py
浏览文件 @
538a95dd
...
...
@@ -453,3 +453,12 @@ def shape_select(layer, input_shape):
output_shape
=
input_shape
output_shape
[
axis
]
=
end
-
start
return
[
output_shape
]
def
shape_shufflechannel
(
layer
,
input_shape
):
return
input_shape
# def shape_convolutiondepthwise(layer, input_shape):
# params = layer.convolution_param
# return get_strided_kernel_output_shape(params, input_shape[0], math.floor)
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录