未验证 提交 a1af51d3 编写于 作者: S SunAhong1993 提交者: GitHub

Merge pull request #15 from PaddlePaddle/develop

Merge
...@@ -38,50 +38,6 @@ bash ./toos/compile.sh /home/root/caffe/src/caffe/proto ...@@ -38,50 +38,6 @@ bash ./toos/compile.sh /home/root/caffe/src/caffe/proto
``` ```
***步骤三 添加自定义Layer的实现代码*** ***步骤三 添加自定义Layer的实现代码***
**静态图方式:**
- 进入./x2paddle/op_mapper/static/caffe2paddle/caffe_custom_layer,创建.py文件,例如mylayer.py
- 仿照./x2paddle/op_mapper/static/caffe2paddle/caffe_custom_layer中的其他文件,在mylayer.py中主要需要实现3个函数,下面以roipooling.py为例分析代码:
1. `def roipooling_shape(input_shape, pooled_w=None, pooled_h=None)`
参数:
1. input_shape(list):其中每个元素代表该层每个输入数据的shape,为必须传入的参数
2. pooled_w(int):代表ROI Pooling的kernel的宽,其命名与.prototxt中roi_pooling_param中的key一致
3. pooled_h(int):代表ROI Pooling的kernel的高,其命名与.prototxt中roi_pooling_param中的key一致
功能:计算出进行ROI Pooling后的shape
返回:一个list,其中每个元素代表每个输出数据的shape,由于ROI Pooling的输出数据只有一个,所以其list长度为1
2. `def roipooling_layer(inputs, input_shape=None, name=None, pooled_w=None, pooled_h=None, spatial_scale=None)`
参数:
1. inputs(list):其中每个元素代表该层每个输入数据,为必须传入的参数
2. input_shape(list):其中每个元素代表该层每个输入数据的shape,为必须传入的参数
3. name(str):ROI Pooling层的名字,为必须传入的参数
4. pooled_w(int):代表ROI Pooling的kernel的宽,其命名与.prototxt中roi_pooling_param中的key一致
5. pooled_h(int):代表ROI Pooling的kernel的高,其命名与.prototxt中roi_pooling_param中的key一致
6. spatial_scale(float):用于将ROI坐标从输入比例转换为池化时使用的比例,其命名与.prototxt中roi_pooling_param中的key一致
功能:运用PaddlePaddle完成组网来实现`roipooling_layer`的功能
返回:一个Variable,为组网后的结果
3. `def roipooling_weights(name, data=None)`
参数:
1. name(str):ROI Pooling层的名字,为必须传入的参数
2. data(list):由Caffe模型.caffemodel获得的关于roipooling的参数,roipooling的参数为None
功能:为每个参数(例如kernel、bias等)命名;同时,若Caffe中该层参数与PaddlePaddle中参数的格式不一致,则变换操作也在该函数中实现。
返回:一个list,包含每个参数的名字。
- 在roipooling.py中注册`roipooling`,主要运用下述代码实现:
```
register(kind='ROIPooling', shape=roipooling_shape, layer=roipooling_layer, weights=roipooling_weights)
# kind为在model.prototxt中roipooling的type
```
- 在./x2paddle/op_mapper/caffe_custom_layer/\_\_init\_\_.py中引入该层的使用
```
from . import roipooling
```
**动态图方式:**
> 【注意】若Caffe自定义layer与Paddle的op一一对应,使用方式一,否则使用方式二。 > 【注意】若Caffe自定义layer与Paddle的op一一对应,使用方式一,否则使用方式二。
- 方式一: - 方式一:
......
...@@ -310,11 +310,18 @@ class PaddleGraph(object): ...@@ -310,11 +310,18 @@ class PaddleGraph(object):
os.makedirs(code_dir) os.makedirs(code_dir)
f = open(osp.join(code_dir, 'x2paddle_model.py'), 'w') f = open(osp.join(code_dir, 'x2paddle_model.py'), 'w')
if self.source_type == "caffe":
custom_import = "from x2paddle.op_mapper.static.caffe2paddle " + \
"import caffe_custom_layer as x2paddle_nn"
else:
custom_import = ""
write_code( write_code(
f, [ f, [
"from paddle.fluid.initializer import Constant", "from paddle.fluid.initializer import Constant",
"from paddle.fluid.param_attr import ParamAttr", "from paddle.fluid.param_attr import ParamAttr",
"import paddle.fluid as fluid", "import paddle.fluid as fluid",
custom_import,
"import paddle", "import math", "", "import paddle", "import math", "",
], ],
...@@ -347,7 +354,7 @@ class PaddleGraph(object): ...@@ -347,7 +354,7 @@ class PaddleGraph(object):
line += "{}, ".format(output) line += "{}, ".format(output)
line = line.strip(", ") line = line.strip(", ")
if layer.kernel.startswith("custom_layer"): if layer.kernel.startswith("custom_layer"):
line += " = {}(".format(layer.kernel.split(":")[-1].lower() + "_layer") line += "= x2paddle_nn.{}(".format(layer.kernel.split(":")[-1])
else: else:
line += " = {}(".format(layer.kernel) line += " = {}(".format(layer.kernel)
for k, v in layer.inputs.items(): for k, v in layer.inputs.items():
......
...@@ -1092,11 +1092,7 @@ class CaffeOpMapper(OpMapper): ...@@ -1092,11 +1092,7 @@ class CaffeOpMapper(OpMapper):
**layer_attrs) **layer_attrs)
def ReLU6(self, node): def ReLU6(self, node):
if "relu6" in self.nn_name2id: relu6_name = name_generator("relu6", self.nn_name2id)
self.nn_name2id["relu6"] += 1
else:
self.nn_name2id["relu6"] = 0
relu6_name = "relu6" + str(self.nn_name2id["relu6"])
output_name = node.layer_name output_name = node.layer_name
layer_outputs = [relu6_name, output_name] layer_outputs = [relu6_name, output_name]
assert len( assert len(
......
from .register import get_registered_layers # Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
#
#custom layer import begins # Licensed under the Apache License, Version 2.0 (the "License"
from . import roipooling # you may not use this file except in compliance with the License.
from . import priorbox # You may obtain a copy of the License at
from . import permute #
from . import detectionoutput # http://www.apache.org/licenses/LICENSE-2.0
from . import normalize #
from . import select # Unless required by applicable law or agreed to in writing, software
from . import shufflechannel # distributed under the License is distributed on an "AS IS" BASIS,
from . import convolutiondepthwise # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
from . import axpy # See the License for the specific language governing permissions and
from . import upsample # limitations under the License.
from . import relu6
#custom layer import ends
from .detectionoutput import detectionoutput
custom_layers = get_registered_layers() from .normalize import normalize
from .priorbox import priorbox
from .roipooling import roipooling
def set_args(f, params): from .select import select
""" set args for function 'f' using the parameters in node.layer.param \ No newline at end of file
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):
import re
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'))
elif len(layer_type) - len(re.sub("[A-Z]", "", layer_type)) >= 2:
s = ''
tmp_name = ''
for i, ch in enumerate(layer_type):
if i == 0:
s += ch.lower()
continue
elif ch.isupper() and layer_type[i - 1].islower():
tmp_name += (s + '_')
s = ''
s += ch.lower()
tmp_name += s
param_name = '_'.join((tmp_name, '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)
from .register import register
from x2paddle.core.util import *
def axpy_shape(input_shapes):
assert len(input_shapes) == 3, "not valid input shape for axpy layer"
assert len(input_shapes[0]) == len(input_shapes[1]), 'should have same dims'
output_shape = input_shapes[1]
assert (input_shapes[2] == output_shape),\
"shape not consistent for axpy[%s <--> %s]" \
% (str(output_shape), str(input_shapes[2]))
return [output_shape]
def axpy_layer(inputs, input_shape=None, name=None):
alpha = inputs[0]
x = inputs[1]
y = inputs[2]
out = fluid.layers.elementwise_mul(x, alpha, axis=0)
out = fluid.layers.elementwise_add(out, y, name=name)
return out
def axpy_weights(name, data=None):
weights_name = []
return weights_name
register(kind='Axpy', shape=axpy_shape, layer=axpy_layer, weights=axpy_weights)
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 len(kernel_size) > 0:
k_h = kernel_h if kernel_h > 0 else kernel_size[0]
k_w = kernel_w if kernel_w > 0 else kernel_size[len(kernel_size) - 1]
elif kernel_h > 0 or kernel_w > 0:
k_h = kernel_h
k_w = kernel_w
[s_h, s_w] = [1, 1]
if isinstance(stride, numbers.Number):
[s_h, s_w] = [stride] * 2
elif len(stride) > 0:
s_h = stride_h if stride_h > 0 else stride[0]
s_w = stride_w if stride_w > 0 else stride[len(stride) - 1]
elif stride_h > 0 or stride_w > 0:
s_h = stride_h
s_w = stride_w
[p_h, p_w] = [0, 0]
if isinstance(pad, numbers.Number):
[p_h, p_w] = [pad] * 2
elif len(pad) > 0:
p_h = pad_h if pad_h > 0 else pad[0]
p_w = pad_w if pad_w > 0 else pad[len(pad) - 1]
elif pad_h > 0 or pad_w > 0:
p_h = pad_h
p_w = pad_w
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=None,
name=None):
import numbers
[k_h, k_w] = [1, 1]
if isinstance(kernel_size, numbers.Number):
[k_h, k_w] = [kernel_size] * 2
elif len(kernel_size) > 0:
k_h = kernel_h if kernel_h > 0 else kernel_size[0]
k_w = kernel_w if kernel_w > 0 else kernel_size[len(kernel_size) - 1]
elif kernel_h > 0 or kernel_w > 0:
k_h = kernel_h
k_w = kernel_w
[s_h, s_w] = [1, 1]
if isinstance(stride, numbers.Number):
[s_h, s_w] = [stride] * 2
elif len(stride) > 0:
s_h = stride_h if stride_h > 0 else stride[0]
s_w = stride_w if stride_w > 0 else stride[len(stride) - 1]
elif stride_h > 0 or stride_w > 0:
s_h = stride_h
s_w = stride_w
[p_h, p_w] = [0, 0]
if isinstance(pad, numbers.Number):
[p_h, p_w] = [pad] * 2
elif len(pad) > 0:
p_h = pad_h if pad_h > 0 else pad[0]
p_w = pad_w if pad_w > 0 else pad[len(pad) - 1]
elif pad_h > 0 or pad_w > 0:
p_h = pad_h
p_w = pad_w
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)
from .register import register # Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
from x2paddle.core.util import * #
# Licensed under the Apache License, Version 2.0 (the "License"
# you may not use this file except in compliance with the License.
def detectionoutput_shape(input_shape): # You may obtain a copy of the License at
return [[-1, 6]] #
# http://www.apache.org/licenses/LICENSE-2.0
#
def detectionoutput_layer(inputs, # Unless required by applicable law or agreed to in writing, software
nms_param=None, # distributed under the License is distributed on an "AS IS" BASIS,
background_label_id=0, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
share_location=True, # See the License for the specific language governing permissions and
keep_top_k=100, # limitations under the License.
confidence_threshold=0.1,
input_shape=None, import paddle
name=None): import paddle.fluid as fluid
if nms_param is None:
nms_param = {"nms_threshold": 0.3, "top_k": 10, "eta": 1.0} def detectionoutput(x0,
mbox_conf_flatten = inputs[1] x1,
mbox_priorbox = inputs[2] x2,
mbox_priorbox_list = fluid.layers.split(mbox_priorbox, 2, dim=1) nms_threshold,
pb = mbox_priorbox_list[0] nms_top_k,
pbv = mbox_priorbox_list[1] keep_top_k,
pb = fluid.layers.reshape(x=pb, shape=[-1, 4]) nms_eta,
pbv = fluid.layers.reshape(x=pbv, shape=[-1, 4]) score_threshold,
mbox_loc = inputs[0] background_label):
mbox_loc = fluid.layers.reshape(x=mbox_loc, shape=[-1, pb.shape[0], 4]) detection_output_layer_attrs = {
mbox_conf_flatten = fluid.layers.reshape( "background_label": background_label,
x=mbox_conf_flatten, shape=[0, pb.shape[0], -1]) "nms_threshold": nms_threshold,
"nms_top_k": nms_top_k,
default = {"nms_threshold": 0.3, "top_k": 10, "eta": 1.0} "keep_top_k": keep_top_k,
fields = ['eta', 'top_k', 'nms_threshold'] "score_threshold": score_threshold,
for f in default.keys(): "nms_eta": nms_eta}
if f not in nms_param: priorbox_list = paddle.split(x2, num_or_sections=2, axis=1)
nms_param[f] = default[f] pb = priorbox_list[0]
out = fluid.layers.detection_output( pbv = priorbox_list[1]
scores=mbox_conf_flatten, pb = paddle.reshape(x=pb, shape=[-1, 4])
loc=mbox_loc, pbv = paddle.reshape(x=pbv, shape=[-1, 4])
pb_dim = fluid.layers.shape(pb)[0]
loc = paddle.reshape(x0, shape=[-1, pb_dim, 4])
conf_flatten = paddle.reshape(x1, shape=[0, pb_dim, -1])
out = fluid.layers.detection_output(loc=loc,
scores=conf_flatten,
prior_box=pb, prior_box=pb,
prior_box_var=pbv, prior_box_var=pbv,
background_label=background_label_id, **detection_output_layer_attrs)
nms_threshold=nms_param["nms_threshold"],
nms_top_k=nms_param["top_k"],
keep_top_k=keep_top_k,
score_threshold=confidence_threshold,
nms_eta=nms_param["eta"])
return out return out
\ No newline at end of file
def detectionoutput_weights(name, data=None):
weights_name = []
return weights_name
register(
kind='DetectionOutput',
shape=detectionoutput_shape,
layer=detectionoutput_layer,
weights=detectionoutput_weights)
from .register import register # Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
from x2paddle.core.util import * #
# Licensed under the Apache License, Version 2.0 (the "License"
# you may not use this file except in compliance with the License.
def normalize_shape(input_shape): # You may obtain a copy of the License at
return input_shape #
# http://www.apache.org/licenses/LICENSE-2.0
#
def normalize_layer(inputs, # Unless required by applicable law or agreed to in writing, software
across_spatial=None, # distributed under the License is distributed on an "AS IS" BASIS,
channel_shared=None, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
input_shape=None, # See the License for the specific language governing permissions and
name=None): # limitations under the License.
assert across_spatial == False, "Only support across_spatial == False for Normalize"
input = inputs[0] import paddle
l2_norm = fluid.layers.l2_normalize(input, axis=1, name=name + '_l2') import paddle.fluid as fluid
scale_param = fluid.layers.create_parameter(
shape=[1] if channel_shared else [1, 1, 1, input_shape[0][1]], def normalize(x, axis, param_name, param_shape, param_dtype):
dtype=input.dtype, l2 = fluid.layers.prior_box(x=x, p=2, axis=1)
attr=fluid.ParamAttr(name=name + '_scale')) param = paddle.static.nn.create_parameter(shape=param_shape,
scale_param = fluid.layers.reshape(x=scale_param, \ dtype=string(param_dtype),
shape=[1] if channel_shared else [input_shape[0][1]]) name=string(param_name))
out = fluid.layers.elementwise_mul( out = paddle.multiply(x=l2, y=param, axis=axis)
x=l2_norm, y=scale_param, axis=-1 if channel_shared else 1)
return out return out
\ No newline at end of file
def normalize_weights(name, data=None):
weights_name = [name + '_scale']
return weights_name
register(
kind='Normalize',
shape=normalize_shape,
layer=normalize_layer,
weights=normalize_weights)
from .register import register
from x2paddle.core.util import *
def permute_shape(input_shape, order=None):
inshape = input_shape[0]
output_shape = []
for ii in order:
assert ii < len(inshape), "invalid order for permute[%s]" % (name)
output_shape.append(inshape[ii])
return [output_shape]
def permute_layer(inputs, order=None, input_shape=None, name=None):
input = inputs[0]
order = list(order)
out = fluid.layers.transpose(input, perm=order, name=name)
return out
def permute_weights(name, data=None):
weights_name = []
return weights_name
register(
kind='Permute',
shape=permute_shape,
layer=permute_layer,
weights=permute_weights)
from .register import register # Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
from x2paddle.core.util import * #
# Licensed under the Apache License, Version 2.0 (the "License"
# you may not use this file except in compliance with the License.
def priorbox_shape(input_shape, max_size=None, aspect_ratio=None): # You may obtain a copy of the License at
fc_shape = input_shape[0] #
N = 1 # http://www.apache.org/licenses/LICENSE-2.0
if not max_size == None: #
N += 1 # Unless required by applicable law or agreed to in writing, software
if not aspect_ratio == None: # distributed under the License is distributed on an "AS IS" BASIS,
N += 2 * len(aspect_ratio) # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
N_bbx = fc_shape[2] * fc_shape[3] * N # See the License for the specific language governing permissions and
output_shape = [1, 2, 4 * N_bbx] # limitations under the License.
return [output_shape]
import paddle
import paddle.fluid as fluid
def priorbox_layer(inputs,
step=0.0, def priorbox(x0,
offset=0.5, x1,
min_size=None, min_sizes,
max_size=[], max_sizes,
aspect_ratio=[1.0], aspect_ratios,
flip=False, variance,
clip=False, flip,
variance=[0.1, 0.1, 0.2, 0.2], clip,
input_shape=None, steps,
name=None): offset,
input = inputs[0] min_max_aspect_ratios_order):
image = inputs[1] priorbox_layer_attrs = {
steps = tuple(step) if type(step) is list or type(step) is tuple else (step, "min_sizes": min_sizes,
step) "max_sizes": max_sizes,
"aspect_ratios": aspect_ratios,
box, variance_ = fluid.layers.prior_box( "variance": variance,
input, "flip": flip,
image, "clip": clip,
min_sizes=min_size, "steps": steps,
max_sizes=max_size, "offset": offset,
aspect_ratios=aspect_ratio, "min_max_aspect_ratios_order": min_max_aspect_ratios_order}
variance=variance, box, var = fluid.layers.prior_box(input=x0,
flip=flip, image=x1,
clip=clip, **priorbox_layer_attrs)
steps=steps, box = paddle.reshape(x=box, shape=[1, 1, -1])
offset=offset, var = paddle.reshape(x=var, shape=[1, 1, -1])
name=name, out = paddle.concat(x=[box, var], axis=1)
min_max_aspect_ratios_order=True)
box = fluid.layers.reshape(box, [1, 1, -1])
variance_ = fluid.layers.reshape(variance_, [1, 1, -1])
out = fluid.layers.concat([box, variance_], axis=1)
return out return out
def priorbox_weights(name, data=None):
weights_name = []
return weights_name
register(
kind='PriorBox',
shape=priorbox_shape,
layer=priorbox_layer,
weights=priorbox_weights)
""" 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)
g_custom_layers[k] = {
'shape': shape,
'layer': layer,
'weights': weights
}
def get_registered_layers():
return g_custom_layers
from .register import register
from x2paddle.core.util import *
def relu6_shape(input_shape):
return input_shape
def relu6_layer(inputs, input_shape=None, name=None):
input = inputs[0]
out = fluid.layers.relu6(x=input)
return out
def relu6_weights(name, data=None):
weights_name = []
return weights_name
register(
kind='ReLU6', shape=relu6_shape, layer=relu6_layer, weights=relu6_weights)
from .register import register # Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
from x2paddle.core.util import * #
# Licensed under the Apache License, Version 2.0 (the "License"
# you may not use this file except in compliance with the License.
def roipooling_shape(input_shape, pooled_w=None, pooled_h=None): # You may obtain a copy of the License at
base_fea_shape = input_shapes[0] #
rois_shape = input_shapes[1] # http://www.apache.org/licenses/LICENSE-2.0
output_shape = base_fea_shape #
output_shape[0] = rois_shape[0] # Unless required by applicable law or agreed to in writing, software
output_shape[2] = pooled_h # distributed under the License is distributed on an "AS IS" BASIS,
output_shape[3] = pooled_w # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
return [output_shape] # See the License for the specific language governing permissions and
# limitations under the License.
def roipooling_layer(inputs, import paddle
pooled_w=None, import paddle.fluid as fluid
pooled_h=None,
spatial_scale=None, def roipooling(x0,
input_shape=None, x1,
name=None): pooled_height,
input = inputs[0] pooled_width,
roi = inputs[1] spatial_scale):
roi = fluid.layers.slice(roi, axes=[1], starts=[1], ends=[5]) roipooling_layer_attrs = {
out = fluid.layers.roi_pool( "pooled_height": pooled_height,
input, "pooled_width": pooled_width,
roi, "spatial_scale": spatial_scale}
pooled_height=pooled_h, slice_x1 = paddle.slice(input=x1, axes=[1],
pooled_width=pooled_w, starts=[1], ends=[5])
spatial_scale=spatial_scale) out = fluid.layers.roi_pool(input=x0,
rois=slice_x1,
**roipooling_layer_attrs)
return out return out
def roipooling_weights(name, data=None):
weights_name = []
return weights_name
register(
kind='ROIPooling',
shape=roipooling_shape,
layer=roipooling_layer,
weights=roipooling_weights)
from .register import register # Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
from x2paddle.core.util import * #
# Licensed under the Apache License, Version 2.0 (the "License"
# you may not use this file except in compliance with the License.
def select_shape(input_shape, axis=None, slice_point=None): # You may obtain a copy of the License at
inshape = input_shape[0] #
slice_point = slice_point # http://www.apache.org/licenses/LICENSE-2.0
start = slice_point[0] #
if len(slice_point) == 2: # Unless required by applicable law or agreed to in writing, software
end = slice_point[1] # 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 paddle
import paddle.fluid as fluid
def select(x,
input_shape,
point,
axis):
start = point[0]
if len(point) == 2:
end = point[1]
else: else:
end = input_shape[axis] end = input_shape[axis]
assert end > start, "invalid slice_point with [start:%d, end:%d]" % (start, out = paddle.slice(x=x,
end) start=start,
output_shape = input_shape end=end,
output_shape[axis] = end - start axes=[axis])
return [output_shape]
def select_layer(inputs,
axis=None,
slice_point=None,
input_shape=None,
name=None):
input = inputs[0]
maxint32 = 2147483647
slice_point = [0] + slice_point
slice_point.append(maxint32)
i = 0
out = []
for i in range(len(slice_point)):
out.append(
fluid.layers.slice(
input,
axes=[axis],
starts=[slice_point[i]],
ends=[slice_point[i + 1]],
name=name + '_' + str(i)))
if i == len(slice_point) - 2:
break
return out return out
\ No newline at end of file
def select_weights(name, data=None):
weights_name = []
return weights_name
register(
kind='Select',
shape=select_shape,
layer=select_layer,
weights=select_weights)
from .register import register
from x2paddle.core.util import *
def shufflechannel_shape(input_shape):
return input_shape
def shufflechannel_layer(inputs, group=None, input_shape=None, name=None):
input = inputs[0]
out = fluid.layers.shuffle_channel(x=input, group=group)
return out
def shufflechannel_weights(name, data=None):
weights_name = []
return weights_name
register(
kind='ShuffleChannel',
shape=shufflechannel_shape,
layer=shufflechannel_layer,
weights=shufflechannel_weights)
# -*- coding: utf-8 -*-
################################################################################
#
# Copyright (c) 2020 Baidu.com, Inc. All Rights Reserved
#
################################################################################
"""
Author: Drift
Email: wutuobang@baidu.com
Date: 2020/04/22 18:45
"""
from .register import register
from x2paddle.core.util import *
def upsample_shape(input_shapes, scale):
"""
:param input_shapes:
:param scale:
:return:
"""
assert len(input_shapes) == 1, "not valid input shape for upsample layer"
assert type(scale) is int
input_shape = input_shapes[0]
new_h = scale * input_shape[2]
new_w = scale * input_shape[3]
output_shape = [input_shape[0], input_shape[1], new_h, new_w]
return [output_shape]
def upsample_layer(inputs, scale, input_shape=None, name=None):
"""
:param inputs:
:param scale:
:param input_shape:
:param name:
:return:
"""
x = inputs[0]
out = fluid.layers.resize_nearest(
x, align_corners=False, scale=scale, name=name)
return out
def upsample_weights(name, data=None):
"""
:param name:
:param data:
:return:
"""
weights_name = []
return weights_name
register(
kind='Upsample',
shape=upsample_shape,
layer=upsample_layer,
weights=upsample_weights)
...@@ -15,88 +15,13 @@ ...@@ -15,88 +15,13 @@
import numbers import numbers
import copy import copy
import numpy as np import numpy as np
from x2paddle.decoder.caffe_decoder import CaffeGraph from x2paddle.decoder.caffe_decoder import CaffeGraph, CaffeGraphNode
from x2paddle.core.op_mapper import OpMapper from x2paddle.core.op_mapper import OpMapper
from x2paddle.core.util import * from x2paddle.core.util import *
from x2paddle.op_mapper.static.caffe2paddle import caffe_shape
from x2paddle.op_mapper.static.caffe2paddle.caffe_custom_layer import *
from x2paddle.core.program import PaddleGraph from x2paddle.core.program import PaddleGraph
class CaffeOpMapper(OpMapper): def _adjust_parameters(node):
directly_map_ops = {
'AbsVal': 'paddle.abs',
'Sigmoid': 'fluid.layers.sigmoid',
'TanH': 'paddle.tanh',
}
def __init__(self, decoder):
super(CaffeOpMapper, self).__init__()
self.graph = decoder.caffe_graph
self.weights = dict()
resolver = decoder.resolver
self.used_custom_layers = {}
self.paddle_graph = PaddleGraph(parent_layer=None, graph_type="static", source_type="caffe")
self.paddle_graph.inputs = self.graph.input_nodes
self.paddle_graph.outputs = self.graph.output_nodes
print("Total nodes: {}".format(len(self.graph.topo_sort)))
for node_name in self.graph.topo_sort:
node = self.graph.get_node(node_name)
if node.layer_type == 'DepthwiseConvolution':
node.layer_type = 'ConvolutionDepthwise'
op = node.layer_type
if hasattr(self, op):
self.set_node_shape(node)
func = getattr(self, op)
func(node)
elif op in custom_layers:
self.set_node_shape(node, is_fluid_op=False)
self.deal_custom_layer(node)
elif op in self.directly_map_ops:
self.set_node_shape(node)
self.directly_map(node)
else:
raise Exception(
"The op {} in model is not supported yet.".format(op))
self.paddle_graph.set_parameters(self.weights)
self.paddle_graph.set_custom(self.used_custom_layers)
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 set_node_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.input_shape = input_shape
func_name = 'shape_' + node.layer_type.lower()
if is_fluid_op:
node.output_shape = getattr(caffe_shape, func_name)(node.layer,
input_shape)
else:
node.output_shape = compute_output_shape(node)
def adjust_parameters(self, node):
data = node.data data = node.data
# When using the protobuf-backend, each parameter initially has four dimensions. # When using the protobuf-backend, each parameter initially has four dimensions.
# In certain cases (like FC layers), we want to eliminate the singleton dimensions. # In certain cases (like FC layers), we want to eliminate the singleton dimensions.
...@@ -132,8 +57,8 @@ class CaffeOpMapper(OpMapper): ...@@ -132,8 +57,8 @@ class CaffeOpMapper(OpMapper):
shape_new = data[idx].shape shape_new = data[idx].shape
return data return data
def get_kernel_parameters(self, kind, params): def _get_kernel_parameters(kind, params):
assert kind in ['Convolution', 'Pooling', 'Deconvolution'] assert kind in ["Convolution", "Pooling", "Deconvolution", "ConvolutionDepthwise"]
[k_h, k_w] = [1, 1] [k_h, k_w] = [1, 1]
if isinstance(params.kernel_size, numbers.Number): if isinstance(params.kernel_size, numbers.Number):
[k_h, k_w] = [params.kernel_size] * 2 [k_h, k_w] = [params.kernel_size] * 2
...@@ -168,7 +93,8 @@ class CaffeOpMapper(OpMapper): ...@@ -168,7 +93,8 @@ class CaffeOpMapper(OpMapper):
dila_h = dila_w = 1 dila_h = dila_w = 1
group = 1 group = 1
c_o = 1 c_o = 1
if kind in ['Convolution', 'Deconvolution']: if kind in ["Convolution", "Deconvolution", "ConvolutionDepthwise"]:
if kind in ["Convolution", "Deconvolution"]:
c_o = params.num_output c_o = params.num_output
dila_len = len(params.dilation) dila_len = len(params.dilation)
if dila_len == 2: if dila_len == 2:
...@@ -187,11 +113,69 @@ class CaffeOpMapper(OpMapper): ...@@ -187,11 +113,69 @@ class CaffeOpMapper(OpMapper):
dilation = [dila_h, dila_w] dilation = [dila_h, dila_w]
return c_o, kernel, stride, pad, dilation, group return c_o, kernel, stride, pad, dilation, group
def get_input_name(self, node):
if hasattr(node, "index"): class CaffeOpMapper(OpMapper):
return "{}_{}".format(node.layer_name, node.index) directly_map_ops = {
'AbsVal': 'paddle.abs',
'Sigmoid': 'paddle.nn.functional.sigmoid',
'TanH': 'paddle.tanh',
}
def __init__(self, decoder):
super(CaffeOpMapper, self).__init__()
self.graph = decoder.caffe_graph
self.params = dict()
resolver = decoder.resolver
self.used_custom_layers = {}
self.paddle_graph = PaddleGraph(parent_layer=None, graph_type="static", source_type="caffe")
self.paddle_graph.inputs = self.graph.input_nodes
self.paddle_graph.outputs = self.graph.output_nodes
print("Total nodes: {}".format(
sum([
isinstance(node, CaffeGraphNode)
for name, node in self.graph.node_map.items()
])))
print("Nodes converting ...")
for node_name in self.graph.topo_sort:
node = self.graph.get_node(node_name)
op = node.layer_type
if hasattr(self, op):
func = getattr(self, op)
func(node)
elif op in self.directly_map_ops:
self.directly_map(node)
print("\nNodes converted.")
self.paddle_graph.set_parameters(self.params)
self.paddle_graph.set_custom(self.used_custom_layers)
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 self.directly_map_ops and \
op not in self.elementwise_ops:
unsupported_ops.add(op)
if len(unsupported_ops) == 0:
return True
else: else:
return node.layer_name if len(unsupported_ops) > 0:
print("\n========= {} OPs are not supported yet ===========".format(
len(unsupported_ops)))
for op in unsupported_ops:
print("========== {} ============".format(op))
return False
def directly_map(self, node):
assert node.layer_type in self.directly_map_ops
op_info = self.directly_map_ops[node.layer_type]
input = self.graph.get_input_node(node, idx=0, copy=True)
self.paddle_graph.add_layer(
kernel=op_info,
inputs={"x": input.name},
outputs=[node.name])
def Input(self, node): def Input(self, node):
shape = list(node.layer.input_param.shape[0].dim)[1:] shape = list(node.layer.input_param.shape[0].dim)[1:]
...@@ -199,97 +183,186 @@ class CaffeOpMapper(OpMapper): ...@@ -199,97 +183,186 @@ class CaffeOpMapper(OpMapper):
layer_attrs = { layer_attrs = {
"dtype": string(dtype), "dtype": string(dtype),
"shape": [-1] + shape, "shape": [-1] + shape,
"name": string(node.layer_name) "name": string(node.name)
} }
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.data", kernel="paddle.static.data",
inputs={}, inputs={},
outputs=[node.layer_name], outputs=[node.name],
**layer_attrs) **layer_attrs)
def Convolution(self, node): def Convolution(self, node):
data = node.data data = node.data
params = node.layer.convolution_param params = node.layer.convolution_param
channel, kernel, stride, pad, dilation, group = self.get_kernel_parameters( channel, kernel, stride, pad, dilation, group = _get_kernel_parameters(
node.layer_type, params) node.layer_type, params)
if data is None: if data is None:
data = [] data = []
print( print(
"The parameter of {} (type is {}) is not set. So we set the parameters as 0" "The parameter of {} (type is {}) is not set. So we set the parameters as 0"
.format(node.layer_name, node.layer_type)) .format(node.name, node.layer_type))
input_c = node.input_shape[0][1] input_c = node.in_shapes[0][1]
output_c = channel output_c = channel
data.append( data.append(
np.zeros([output_c, input_c, kernel[0], kernel[1]]).astype( np.zeros([output_c, input_c, kernel[0], kernel[1]]).astype(
'float32')) 'float32'))
data.append(np.zeros([output_c, ]).astype('float32')) data.append(np.zeros([output_c, ]).astype('float32'))
else: else:
data = self.adjust_parameters(node) data = _adjust_parameters(node)
self.weights[node.layer_name + '_weights'] = data[0] kernel_weight_name = node.name + '_weights'
self.params[kernel_weight_name] = data[0]
self.paddle_graph.add_layer(
kernel="paddle.static.create_parameter",
inputs={},
outputs=[kernel_weight_name],
shape=self.params[kernel_weight_name].shape,
dtype=string(str(self.params[kernel_weight_name].dtype)),
name=string(kernel_weight_name))
if len(data) == 2: if len(data) == 2:
self.weights[node.layer_name + '_bias'] = data[1] kernel_bias_name = node.name + '_bias'
self.params[kernel_bias_name] = data[1]
self.paddle_graph.add_layer(
kernel="paddle.static.create_parameter",
inputs={},
outputs=[kernel_bias_name],
shape=self.params[kernel_bias_name].shape,
dtype=string(str(self.params[kernel_bias_name].dtype)),
name=string(kernel_bias_name))
assert len(node.inputs assert len(node.inputs
) == 1, 'The count of Convolution node\'s input is not 1.' ) == 1, 'The count of Convolution node\'s input is not 1.'
input = self.graph.get_input_node(node, idx=0, copy=True) input = self.graph.get_input_node(node, idx=0, copy=True)
layer_attrs = { layer_inputs = {"x": input.name,
'filter_size': kernel, "weight": kernel_weight_name}
'num_filters': channel, layer_attrs = {'stride': stride,
'stride': stride,
'padding': pad, 'padding': pad,
'dilation': dilation, 'dilation': dilation,
'groups': group, 'groups': group}
'name': string(node.layer_name), if len(data) == 2:
'param_attr': string(node.layer_name + '_weights'), layer_inputs["bias"] = kernel_bias_name
'bias_attr': False else:
if len(data) == 1 else string(node.layer_name + '_bias'), layer_attrs["bias"] = None
}
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.conv2d", kernel="paddle.nn.functional.conv2d",
inputs={"input": self.get_input_name(input)}, inputs=layer_inputs,
outputs=[node.layer_name], outputs=[node.name],
**layer_attrs) **layer_attrs)
def Deconvolution(self, node): def Deconvolution(self, node):
data = node.data data = node.data
params = node.layer.convolution_param params = node.layer.convolution_param
channel, kernel, stride, pad, dilation, group = self.get_kernel_parameters( channel, kernel, stride, pad, dilation, group = _get_kernel_parameters(
node.layer_type, params) node.layer_type, params)
if data is None: if data is None:
data = [] data = []
print( print(
'The parameter of {} (type is {}) is not set. So we set the parameters as 0' 'The parameter of {} (type is {}) is not set. So we set the parameters as 0'
.format(node.layer_name, node.layer_type)) .format(node.name, node.layer_type))
input_c = node.input_shape[0][1] input_c = node.in_shapes[0][1]
output_c = channel output_c = channel
data.append( data.append(
np.zeros([output_c, input_c, kernel[0], kernel[1]]).astype( np.zeros([output_c, input_c, kernel[0], kernel[1]]).astype(
'float32')) 'float32'))
data.append(np.zeros([output_c, ]).astype('float32')) data.append(np.zeros([output_c, ]).astype('float32'))
else: else:
data = self.adjust_parameters(node) data = _adjust_parameters(node)
self.weights[node.layer_name + '_weights'] = data[0] kernel_weight_name = node.name + '_weights'
self.params[kernel_weight_name] = data[0]
self.paddle_graph.add_layer(
kernel="paddle.static.create_parameter",
inputs={},
outputs=[kernel_weight_name],
shape=self.params[kernel_weight_name].shape,
dtype=string(str(self.params[kernel_weight_name].dtype)),
name=string(kernel_weight_name))
if len(data) == 2: if len(data) == 2:
self.weights[node.layer_name + '_bias'] = data[1] kernel_bias_name = node.name + '_bias'
self.params[kernel_bias_name] = data[1]
self.paddle_graph.add_layer(
kernel="paddle.static.create_parameter",
inputs={},
outputs=[kernel_bias_name],
shape=self.params[kernel_bias_name].shape,
dtype=string(str(self.params[kernel_bias_name].dtype)),
name=string(kernel_bias_name))
assert len(node.inputs assert len(node.inputs
) == 1, 'The count of Deconvolution node\'s input is not 1.' ) == 1, 'The count of Deconvolution node\'s input is not 1.'
input = self.graph.get_input_node(node, idx=0, copy=True) input = self.graph.get_input_node(node, idx=0, copy=True)
layer_attrs = { layer_inputs = {"x": input.name,
'output_size': None, "weight": kernel_weight_name}
'filter_size': kernel, layer_attrs = {'stride': stride,
'num_filters': channel,
'stride': stride,
'padding': pad, 'padding': pad,
'dilation': dilation, 'dilation': dilation,
'groups': group, 'groups': group}
'name': string(node.layer_name), if len(data) == 2:
'param_attr': string(node.layer_name + '_weights'), layer_inputs["bias"] = kernel_bias_name
'bias_attr': False else:
if len(data) == 1 else string(node.layer_name + '_bias') layer_attrs["bias"] = None
}
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.conv2d_transpose", kernel="paddle.nn.functional.conv2d_transpose",
inputs={"input": self.get_input_name(input)}, inputs=layer_inputs,
outputs=[node.layer_name], outputs=[node.name],
**layer_attrs)
def DepthwiseConvolution(self, node):
node.layer_type = "ConvolutionDepthwise"
self.ConvolutionDepthwise(node)
def ConvolutionDepthwise(self, node):
data = node.data
params = node.layer.convolution_param
out_channel, kernel, stride, pad, dilation, group = _get_kernel_parameters(
node.layer_type, params)
out_channel = params.num_output if params.num_output is not None else node.in_shapes[0][1]
in_channel = node.in_shapes[0][1]
group = int(in_channel / (in_channel / out_channel)) if in_channel > out_channel else int(in_channel /
(out_channel / in_channel))
if data is None:
data = []
print(
"The parameter of {} (type is {}) is not set. So we set the parameters as 0"
.format(node.layer_name, node.layer_type))
data.append(
np.zeros([out_channel, node.in_shapes[0][1], kernel[0], kernel[1]]).astype(
'float32'))
data.append(np.zeros([out_channel, ]).astype('float32'))
else:
data = _adjust_parameters(node)
kernel_weight_name = node.name + '_weights'
self.params[kernel_weight_name] = data[0]
self.paddle_graph.add_layer(
kernel="paddle.static.create_parameter",
inputs={},
outputs=[kernel_weight_name],
shape=self.params[kernel_weight_name].shape,
dtype=string(str(self.params[kernel_weight_name].dtype)),
name=string(kernel_weight_name))
if len(data) == 2:
kernel_bias_name = node.name + '_bias'
self.params[kernel_bias_name] = data[1]
self.paddle_graph.add_layer(
kernel="paddle.static.create_parameter",
inputs={},
outputs=[kernel_bias_name],
shape=self.params[kernel_bias_name].shape,
dtype=string(str(self.params[kernel_bias_name].dtype)),
name=string(kernel_bias_name))
assert len(node.inputs
) == 1, "The count of Deconvolution node\'s input is not 1."
input = self.graph.get_input_node(node, idx=0, copy=True)
layer_inputs = {"x": input.name,
"weight": kernel_weight_name}
layer_attrs = {'stride': stride,
'padding': pad,
'dilation': dilation,
'groups': group}
if len(data) == 2:
layer_inputs["bias"] = kernel_bias_name
else:
layer_attrs["bias"] = None
self.paddle_graph.add_layer(
kernel="paddle.nn.functional.conv2d",
inputs=layer_inputs,
outputs=[node.name],
**layer_attrs) **layer_attrs)
def Pooling(self, node): def Pooling(self, node):
...@@ -297,30 +370,49 @@ class CaffeOpMapper(OpMapper): ...@@ -297,30 +370,49 @@ class CaffeOpMapper(OpMapper):
ceil_mode = getattr(params, 'ceil_mode', True) ceil_mode = getattr(params, 'ceil_mode', True)
global_pool = getattr(params, 'global_pooling', False) global_pool = getattr(params, 'global_pooling', False)
kernel_default = [1, 1] kernel_default = [1, 1]
channel, kernel, stride, pad, dilation, group = self.get_kernel_parameters( channel, kernel, stride, pad, dilation, group = _get_kernel_parameters(
node.layer_type, params) node.layer_type, params)
if params.pool == 0:
pool_type = 'max'
else:
pool_type = 'avg'
assert len( assert len(
node.inputs) == 1, 'The count of Pooling node\'s input is not 1.' node.inputs) == 1, 'The count of Pooling node\'s input is not 1.'
input = self.graph.get_input_node(node, idx=0, copy=True) input = self.graph.get_input_node(node, idx=0, copy=True)
layer_attrs = { if global_pool:
'pool_size': kernel, if kernel[0] == 0:
'pool_stride': stride, kernel = [1, 1]
'pool_padding': pad, if params.pool == 0:
'ceil_mode': ceil_mode, self.paddle_graph.add_layer(
'pool_type': string(pool_type), "paddle.nn.functional.adaptive_max_pool2d",
'exclusive': False, inputs={"x": input.name},
'global_pooling': global_pool, outputs=layer_outputs,
'name': string(node.layer_name) output_size=kernel)
} else:
self.paddle_graph.add_layer(
"paddle.nn.functional.adaptive_avg_pool2d",
inputs={"x": input.name},
outputs=[node.name],
output_size=kernel)
else:
if params.pool == 0:
self.paddle_graph.add_layer(
kernel="paddle.nn.functional.max_pool2d",
inputs={"x": input.name},
outputs=[node.name],
kernel_size=kernel,
stride=stride,
padding=pad,
ceil_mode=ceil_mode)
else:
# TODO(syf): The op has diff.
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.pool2d", kernel="fluid.layers.pool2d",
inputs={"input": self.get_input_name(input)}, inputs={"input": input.name},
outputs=[node.layer_name], outputs=[node.name],
**layer_attrs) pool_size=kernel,
pool_type=string("avg"),
pool_stride=stride,
pool_padding=pad,
ceil_mode=ceil_mode,
exclusive=False,
global_pooling=False)
def LRN(self, node): def LRN(self, node):
assert len(node.inputs) == 1, 'The count of LRN node\'s input is not 1.' assert len(node.inputs) == 1, 'The count of LRN node\'s input is not 1.'
...@@ -338,12 +430,12 @@ class CaffeOpMapper(OpMapper): ...@@ -338,12 +430,12 @@ class CaffeOpMapper(OpMapper):
'k': params.k, 'k': params.k,
'alpha': alpha, 'alpha': alpha,
'beta': params.beta, 'beta': params.beta,
'name': string(node.layer_name) 'name': string(node.name)
} }
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.lrn", kernel="fluid.layers.lrn",
inputs={"input": self.get_input_name(input)}, inputs={"input": input.name},
outputs=[node.layer_name], outputs=[node.name],
**layer_attrs) **layer_attrs)
def InnerProduct(self, node): def InnerProduct(self, node):
...@@ -353,7 +445,7 @@ class CaffeOpMapper(OpMapper): ...@@ -353,7 +445,7 @@ class CaffeOpMapper(OpMapper):
print( print(
'The parameter of {} (type is {}) is not set. So we set the parameters as 0.' 'The parameter of {} (type is {}) is not set. So we set the parameters as 0.'
.format(node.layer_name, node.layer_type)) .format(node.layer_name, node.layer_type))
input_c = node.input_shape[0][1] input_c = node.in_shapes[0][1]
output_c = params.num_output output_c = params.num_output
data = [] data = []
data.append( data.append(
...@@ -362,7 +454,7 @@ class CaffeOpMapper(OpMapper): ...@@ -362,7 +454,7 @@ class CaffeOpMapper(OpMapper):
data.append( data.append(
np.zeros([output_c]).astype('float32').astype('float32')) np.zeros([output_c]).astype('float32').astype('float32'))
else: else:
data = self.adjust_parameters(node) data = _adjust_parameters(node)
# Reshape the parameters to Paddle's ordering # Reshape the parameters to Paddle's ordering
transpose_order = (1, 0) transpose_order = (1, 0)
w = data[0] w = data[0]
...@@ -372,27 +464,54 @@ class CaffeOpMapper(OpMapper): ...@@ -372,27 +464,54 @@ class CaffeOpMapper(OpMapper):
w = w.transpose(transpose_order) w = w.transpose(transpose_order)
data[0] = w data[0] = w
self.weights[node.layer_name + '_weights'] = data[0] kernel_weight_name = node.name + '_weights'
self.params[kernel_weight_name] = data[0]
self.paddle_graph.add_layer(
kernel="paddle.static.create_parameter",
inputs={},
outputs=[kernel_weight_name],
shape=self.params[kernel_weight_name].shape,
dtype=string(str(self.params[kernel_weight_name].dtype)),
name=string(kernel_weight_name))
if len(data) == 2: if len(data) == 2:
self.weights[node.layer_name + '_bias'] = data[1] kernel_bias_name = node.name + '_bias'
self.params[kernel_bias_name] = data[1]
self.paddle_graph.add_layer(
kernel="paddle.static.create_parameter",
inputs={},
outputs=[kernel_bias_name],
shape=self.params[kernel_bias_name].shape,
dtype=string(str(self.params[kernel_bias_name].dtype)),
name=string(kernel_bias_name))
assert len(node.inputs assert len(node.inputs
) == 1, 'The count of InnerProduct node\'s input is not 1.' ) == 1, 'The count of InnerProduct node\'s input is not 1.'
#params = node.layer.inner_product_param #params = node.layer.inner_product_param
assert params.axis == 1 assert params.axis == 1
assert params.bias_term == True assert params.bias_term == True
input = self.graph.get_input_node(node, idx=0, copy=True) input = self.graph.get_input_node(node, idx=0, copy=True)
layer_attrs = { layer_inputs = {"x": input.name,
'size': params.num_output, "weight": kernel_weight_name}
'name': string(node.layer_name), layer_attrs = dict()
'act': None, if len(data) == 2:
'param_attr': string(node.layer_name + '_weights'), layer_inputs["bias"] = kernel_bias_name
'bias_attr': False else:
if len(data) == 1 else string(node.layer_name + '_bias') layer_attrs["bias"] = None
} if node.in_shapes[0][-1] != data[0].shape[0]:
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.fc", "paddle.reshape",
inputs={"input": self.get_input_name(input)}, inputs={"x": input.name},
outputs=[node.layer_name], outputs=[input.name],
shape=[-1, data[0].shape[0]])
self.paddle_graph.add_layer(
kernel="paddle.nn.functional.linear",
inputs=layer_inputs,
outputs=[node.name],
**layer_attrs)
else:
self.paddle_graph.add_layer(
kernel="paddle.nn.functional.linear",
inputs=layer_inputs,
outputs=[node.name],
**layer_attrs) **layer_attrs)
def Softmax(self, node): def Softmax(self, node):
...@@ -401,19 +520,19 @@ class CaffeOpMapper(OpMapper): ...@@ -401,19 +520,19 @@ class CaffeOpMapper(OpMapper):
input = self.graph.get_input_node(node, idx=0, copy=True) input = self.graph.get_input_node(node, idx=0, copy=True)
params = node.layer.softmax_param params = node.layer.softmax_param
axis = params.axis axis = params.axis
shape = node.input_shape[0] shape = node.in_shapes[0]
dims = len(shape) dims = len(shape)
axis = axis + dims if axis < 0 else axis axis = axis + dims if axis < 0 else axis
layer_attrs = {'axis': axis, 'name': string(node.layer_name + '_softmax')} layer_attrs = {'axis': axis, 'name': string(node.layer_name + '_softmax')}
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="paddle.nn.functional.softmax", kernel="paddle.nn.functional.softmax",
inputs={"x": self.get_input_name(input)}, inputs={"x": input.name},
outputs=[node.layer_name], outputs=[node.layer_name],
**layer_attrs) **layer_attrs)
def Slice(self, node): def Slice(self, node):
assert len( assert len(
node.inputs) == 1, 'The count of Slice node\'s input is not 1.' node.inputs) == 1, "The count of Slice node\'s input is not 1."
input = self.graph.get_input_node(node, idx=0, copy=True) input = self.graph.get_input_node(node, idx=0, copy=True)
top_len = len(node.layer.top) top_len = len(node.layer.top)
params = node.layer.slice_param params = node.layer.slice_param
...@@ -421,20 +540,19 @@ class CaffeOpMapper(OpMapper): ...@@ -421,20 +540,19 @@ class CaffeOpMapper(OpMapper):
slice_dim = params.slice_dim slice_dim = params.slice_dim
if slice_dim != 1 and axis == 1: if slice_dim != 1 and axis == 1:
axis = slice_dim axis = slice_dim
output_shape = node.output_shape output_shape = node.out_shapes
sections_list = list() sections_list = list()
outputs_list = list() outputs_list = list()
for i, s in enumerate(output_shape): for i, s in enumerate(output_shape):
sections_list.append(s[axis]) sections_list.append(s[axis])
outputs_list.append("{}_{}".format(node.layer_name, i)) outputs_list.append("{}_p{}".format(node.layer_name, i))
layer_attrs = { layer_attrs = {
'num_or_sections': sections_list, 'num_or_sections': sections_list,
'dim': axis, 'axis': axis,
'name': string(node.layer_name)
} }
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.split", "paddle.split",
inputs={"input": self.get_input_name(input)}, inputs={"x": input.name},
outputs=outputs_list, outputs=outputs_list,
**layer_attrs) **layer_attrs)
...@@ -445,18 +563,19 @@ class CaffeOpMapper(OpMapper): ...@@ -445,18 +563,19 @@ class CaffeOpMapper(OpMapper):
inputs_list = [] inputs_list = []
for i in range(len(node.inputs)): for i in range(len(node.inputs)):
input = self.graph.get_input_node(node, idx=i, copy=True) input = self.graph.get_input_node(node, idx=i, copy=True)
inputs_list.append(self.get_input_name(input)) inputs_list.append(input.name)
params = node.layer.concat_param params = node.layer.concat_param
axis = params.axis axis = params.axis
layer_attrs = {'axis': axis, 'name': string(node.layer_name)} layer_attrs = {'axis': axis, 'name': string(node.name)}
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="paddle.concat", kernel="paddle.concat",
inputs={"x": inputs_list}, inputs={"x": inputs_list},
outputs=[node.layer_name], outputs=[node.name],
**layer_attrs) **layer_attrs)
def ReLU(self, node): def ReLU(self, node):
""" """
:param node: :param node:
:return: :return:
""" """
...@@ -468,15 +587,15 @@ class CaffeOpMapper(OpMapper): ...@@ -468,15 +587,15 @@ class CaffeOpMapper(OpMapper):
if params.HasField('negative_slope') and params.negative_slope != 0: if params.HasField('negative_slope') and params.negative_slope != 0:
negative_slope = float(params.negative_slope) negative_slope = float(params.negative_slope)
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.leaky_relu", kernel="paddle.nn.functional.leaky_relu",
inputs={"x": self.get_input_name(input)}, inputs={"x": input.name},
outputs=[node.layer_name], outputs=[node.name],
alpha=negative_slope) negative_slope=negative_slope)
else: else:
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.relu", kernel="paddle.nn.functional.relu",
inputs={"x": self.get_input_name(input)}, inputs={"x": input.name},
outputs=[node.layer_name]) outputs=[node.name])
def PReLU(self, node): def PReLU(self, node):
assert len( assert len(
...@@ -484,122 +603,83 @@ class CaffeOpMapper(OpMapper): ...@@ -484,122 +603,83 @@ class CaffeOpMapper(OpMapper):
input = self.graph.get_input_node(node, idx=0, copy=True) input = self.graph.get_input_node(node, idx=0, copy=True)
params = node.layer.prelu_param params = node.layer.prelu_param
mode_bool = params.channel_shared mode_bool = params.channel_shared
output_shape = node.out_shapes[0]
if mode_bool: if mode_bool:
mode = 'all' num_parameters = 1
else: else:
mode = 'channel' num_parameters = output_shape[1]
data = node.data 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( 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) node.name, node.layer_type)
self.weights[node.layer_name + '_weights'] = data[0] kernel_weight_name = node.name + '_weights'
layer_attrs = { self.params[kernel_weight_name] = np.squeeze(data[0])
'mode': string(mode),
'param_attr': string(node.layer_name + '_weights'),
'name': string(node.layer_name)
}
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.prelu", kernel="paddle.static.create_parameter",
inputs={"x": self.get_input_name(input)}, inputs={},
outputs=[node.layer_name], outputs=[kernel_weight_name],
**layer_attrs) shape=[num_parameters],
dtype=string(str(self.params[kernel_weight_name].dtype)),
def Accuracy(self, node): name=string(kernel_weight_name))
assert len(
node.inputs) == 2, 'The count of Accuracy node\'s input is not 2.'
inputs_dict = dict()
for i, shape in enumerate(node.input_shape):
if shape[1] == 1:
input = self.graph.get_input_node(node, idx=i, copy=True)
inputs_dict["label"] = self.get_input_name(input)
else:
input = self.graph.get_input_node(node, idx=i, copy=True)
inputs_dict["input"] = self.get_input_name(input)
params = node.layer.accuracy_param
top_k = params.top_k
axis = params.axis
ignore_label = params.ignore_label
assert axis == 1, 'PaddlePaddle can not support the situation when the axis is not 1.'
assert not ignore_label >= 0, 'PaddlePaddle can not support the situation when the model has ignore label.'
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.accuracy", kernel="paddle.nn.functional.prelu",
inputs=inputs_dict, inputs={"x": input.name,
outputs=[node.layer_name], "weight": kernel_weight_name},
k=top_k) outputs=[node.name])
def Eltwise(self, node): def Eltwise(self, node):
assert len( assert len(
node.inputs) == 2, 'The count of TanH node\'s input is not 2.' node.inputs) == 2, "The count of Eltwise node\'s input is not 2."
params = node.layer.eltwise_param params = node.layer.eltwise_param
mode = params.operation mode = params.operation
inputs = [] inputs = []
input0 = self.graph.get_input_node(node, idx=0, copy=True) input0 = self.graph.get_input_node(node, idx=0, copy=True)
inputs.append(input0)
input1 = self.graph.get_input_node(node, idx=1, copy=True) input1 = self.graph.get_input_node(node, idx=1, copy=True)
inputs.append(input1) input0_name = input0.name
input1_name = input1.name
if mode == 0: if mode == 0:
inputs_dict = {} inputs_dict = {}
inputs_dict['x'] = self.get_input_name(inputs[0]) inputs_dict['x'] = input0_name
inputs_dict['y'] = self.get_input_name(inputs[1]) inputs_dict['y'] = input1_name
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.elementwise_mul", "paddle.multiply",
inputs=inputs_dict, inputs=inputs_dict,
outputs=[node.layer_name]) outputs=[node.name])
elif mode == 1: elif mode == 1:
if hasattr(params, 'coeff') and len(params.coeff) == 2: if hasattr(params, 'coeff') and len(params.coeff) == 2:
coeff = params.coeff coeff = params.coeff
input1_name = self.get_input_name(inputs[0])
layer_attrs = {
'shape': [1],
'value': coeff[0],
'dtype': '{}.dtype'.format(input1_name)
}
self.paddle_graph.add_layer(
kernel="fluid.layers.fill_constant",
inputs={},
outputs=["{}_const1".format(node.layer_name)],
**layer_attrs)
self.paddle_graph.add_layer(
kernel="fluid.layers.elementwise_mul",
inputs={"x": input1_name,
"y": "{}_const1".format(node.layer_name)},
outputs=["{}_mul1".format(node.layer_name)])
input2_name = self.get_input_name(inputs[1])
layer_attrs = {
'shape': [1],
'value': coeff[1],
'dtype': '{}.dtype'.format(input2_name)
}
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.fill_constant", "paddle.scale",
inputs={}, inputs={"x": input0_name},
outputs=["{}_const2".format(node.layer_name)], outputs=[node.name + '_mul0'],
**layer_attrs) scale=coeff[0])
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.elementwise_mul", "paddle.scale",
inputs={"x": input2_name, inputs={"x": input1_name},
"y": "{}_const2".format(node.layer_name)}, outputs=[node.name + '_mul1'],
outputs=["{}_mul2".format(node.layer_name)]) scale=coeff[2])
inputs_dict = {}
inputs_dict['x'] = node.name + '_mul0'
inputs_dict['y'] = node.name + '_mul1'
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.elementwise_add", "paddle.add",
inputs={"x": "{}_mul1".format(node.layer_name), inputs=inputs_dict,
"y": "{}_mul2".format(node.layer_name)}, outputs=[node.name])
outputs=[node.layer_name])
else: else:
inputs_dict = {} inputs_dict = {}
inputs_dict['x'] = self.get_input_name(inputs[0]) inputs_dict['x'] = input0_name
inputs_dict['y'] = self.get_input_name(inputs[1]) inputs_dict['y'] = input1_name
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.elementwise_add", "paddle.add",
inputs=inputs_dict, inputs=inputs_dict,
outputs=[node.layer_name]) outputs=[node.name])
else: else:
inputs_dict = {} inputs_dict = {}
inputs_dict['x'] = self.get_input_name(inputs[0]) inputs_dict['x'] = input0_name
inputs_dict['y'] = self.get_input_name(inputs[1]) inputs_dict['y'] = input1_name
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.elementwise_max", "paddle.max",
inputs=inputs_dict, inputs=inputs_dict,
outputs=[node.layer_name]) outputs=[node.name])
def BatchNorm(self, node): def BatchNorm(self, node):
assert len( assert len(
...@@ -610,11 +690,15 @@ class CaffeOpMapper(OpMapper): ...@@ -610,11 +690,15 @@ class CaffeOpMapper(OpMapper):
eps = params.eps eps = params.eps
else: else:
eps = 1e-5 eps = 1e-5
if hasattr(params, 'moving_average_fraction'):
momentum = params.moving_average_fraction
else:
momentum = 0.9
if node.data is None or len(node.data) != 3: if node.data is None or len(node.data) != 3:
print( print(
'The parameter of {} (type is {}) is not set. So we set the parameters as 0' 'The parameter of {} (type is {}) is not set. So we set the parameters as 0'
.format(node.layer_name, node.layer_type)) .format(node.layer_name, node.layer_type))
input_c = node.input_shape[0][1] input_c = node.in_shapes[0][1]
mean = np.zeros([input_c, ]).astype('float32') mean = np.zeros([input_c, ]).astype('float32')
variance = np.zeros([input_c, ]).astype('float32') variance = np.zeros([input_c, ]).astype('float32')
scale = 0 scale = 0
...@@ -626,235 +710,241 @@ class CaffeOpMapper(OpMapper): ...@@ -626,235 +710,241 @@ class CaffeOpMapper(OpMapper):
scaling_factor = 1.0 / scale if scale != 0 else 0 scaling_factor = 1.0 / scale if scale != 0 else 0
mean *= scaling_factor mean *= scaling_factor
variance *= scaling_factor variance *= scaling_factor
self.weights[node.layer_name + '_mean'] = mean weight_name = node.name + '_weight'
self.weights[node.layer_name + '_variance'] = variance self.paddle_graph.add_layer(
kernel="paddle.ones",
inputs={},
outputs=[weight_name],
shape=mean.shape,
dtype=string("float32"))
bias_name = node.name + '_bias'
self.paddle_graph.add_layer(
kernel="paddle.zeros",
inputs={},
outputs=[bias_name],
shape=mean.shape,
dtype=string("float32"))
mean_name = node.name + '_mean'
self.params[mean_name] = mean
self.paddle_graph.add_layer(
kernel="paddle.static.create_parameter",
inputs={},
outputs=[mean_name],
shape=self.params[mean_name].shape,
dtype=string(str(self.params[mean_name].dtype)),
name=string(mean_name))
variance_name = node.name + '_variance'
self.params[variance_name] = variance
self.paddle_graph.add_layer(
kernel="paddle.static.create_parameter",
inputs={},
outputs=[variance_name],
shape=self.params[variance_name].shape,
dtype=string(str(self.params[variance_name].dtype)),
name=string(variance_name))
layer_attrs = { layer_attrs = {
'is_test': True,
'param_attr': None,
'bias_attr': None,
'moving_mean_name': string(node.layer_name + '_mean'),
'moving_variance_name': string(node.layer_name + '_variance'),
'epsilon': eps, 'epsilon': eps,
'name': string(node.layer_name) 'momentum': momentum
} }
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.batch_norm", kernel="paddle.nn.functional.batch_norm",
inputs={"input": self.get_input_name(input)}, inputs={"x": input.name,
outputs=[node.layer_name], "weight": weight_name,
"bias": bias_name,
"running_mean": mean_name,
"running_var": variance_name,},
outputs=[node.name],
**layer_attrs) **layer_attrs)
def Scale(self, node): def Scale(self, node):
if node.data is None: if node.data is None:
print( print(
'The parameter of {} (type is {}) is not set. So we set the parameters as 0' "The parameter of {} (type is {}) is not set. So we set the parameters as 0"
.format(node.layer_name, node.layer_type)) .format(node.name, node.layer_type))
input_c = node.input_shape[0][1] self.params[node.name + "_cparam1"] = np.zeros([
self.weights[node.layer_name + '_scale'] = np.zeros([ node.in_shapes[0][1],
input_c, ]).astype("float32")
]).astype('float32') self.params[node.name + "_cparam2"] = np.zeros([
self.weights[node.layer_name + '_offset'] = np.zeros([ node.in_shapes[0][1],
input_c, ]).astype("float32")
]).astype('float32')
else: else:
self.weights[node.layer_name + '_scale'] = np.squeeze(node.data[ self.params[node.name + "_cparam1"] = np.squeeze(node.data[
0]).astype('float32') 0]).astype("float32")
self.weights[node.layer_name + '_offset'] = np.squeeze(node.data[ self.params[node.name + "_cparam2"] = np.squeeze(node.data[
1]).astype('float32') 1]).astype("float32")
params = node.layer.scale_param params = node.layer.scale_param
axis = params.axis axis = params.axis
num_axes = params.num_axes
inputs = [] inputs = []
if len(node.inputs) == 2: if len(node.inputs) == 2:
# for two tensor, here resets axis to 1. Maybe there is a bug for unkown case.
axis = 1
bias_shape = node.input_shape[0][axis:axis + num_axes]
input0 = self.graph.get_input_node(node, idx=0, copy=True) input0 = self.graph.get_input_node(node, idx=0, copy=True)
input1 = self.graph.get_input_node(node, idx=1, copy=True) input1 = self.graph.get_input_node(node, idx=1, copy=True)
input0_name = input0.name
input1_name = input1.name
inputs_dict = {} inputs_dict = {}
inputs_dict['x'] = self.get_input_name(input0) inputs_dict['x'] = input0_name
inputs_dict['y'] = self.get_input_name(input1) inputs_dict['y'] = input1_name
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.elementwise_mul", "paddle.multiply",
inputs=inputs_dict, inputs=inputs_dict,
outputs=["{}_mul".format(node.layer_name)], outputs=[node.name + "_mul"],
axis=axis) axis=1)
else: else:
bias_shape = node.input_shape[0][axis:axis + num_axes]
input0 = self.graph.get_input_node(node, idx=0, copy=True)
input0_name = self.get_input_name(input0)
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.ParamAttr", "paddle.static.create_parameter",
inputs={}, inputs={},
outputs=["{}_scale".format(node.layer_name)], outputs=[node.name + "_cparam1"],
name = string("{}_scale".format(node.layer_name))) shape=self.params[node.name + "_cparam1"].shape,
layer_attrs = { dtype=string(str(self.params[node.name + "_cparam1"].dtype)),
'dtype': '{}.dtype'.format(input0_name), name=string(node.name + "_cparam1"))
'shape': bias_shape, input0 = self.graph.get_input_node(node, idx=0, copy=True)
'name': string(node.layer_name + '_cparam1'), input0_name = input0.name
'is_bias': True,
'default_initializer': 'Constant(value=1.0)'
}
self.paddle_graph.add_layer(
kernel="fluid.layers.create_parameter",
inputs={"attr": node.layer_name + '_scale',},
outputs=["{}_cparam1".format(node.layer_name)],
**layer_attrs)
inputs_dict = {} inputs_dict = {}
inputs_dict['x'] = self.get_input_name(input0) inputs_dict['x'] = input0_name
inputs_dict['y'] = "{}_cparam1".format(node.layer_name) inputs_dict['y'] = node.name + "_cparam1"
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.elementwise_mul", "paddle.multiply",
inputs=inputs_dict, inputs=inputs_dict,
outputs=["{}_mul".format(node.layer_name)], outputs=[node.name + "_mul"],
axis=axis) axis=axis)
scale_shape = bias_shape
input0_name = self.get_input_name(input0)
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.ParamAttr", "paddle.static.create_parameter",
inputs={}, inputs={},
outputs=["{}_offset".format(node.layer_name)], outputs=[node.name + "_cparam2"],
name = string("{}_offset".format(node.layer_name))) shape=self.params[node.name + "_cparam2"].shape,
layer_attrs = { dtype=string(str(self.params[node.name + "_cparam2"].dtype)),
'dtype': '{}.dtype'.format(input0_name), name=string(node.name + "_cparam2"))
'shape': scale_shape,
'name': string(node.layer_name + '_cparam2'),
'is_bias': True,
'default_initializer': 'Constant(value=1.0)'
}
self.paddle_graph.add_layer(
kernel="fluid.layers.create_parameter",
inputs={"attr": node.layer_name + '_offset'},
outputs=["{}_cparam2".format(node.layer_name)],
**layer_attrs)
inputs_dict = {} inputs_dict = {}
inputs_dict['x'] = "{}_mul".format(node.layer_name) inputs_dict['x'] = node.name + "_mul"
inputs_dict['y'] = "{}_cparam2".format(node.layer_name) inputs_dict['y'] = node.name + "_cparam2"
output_shape = node.out_shapes[0]
if axis == -1:
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.elementwise_add", "paddle.add",
inputs=inputs_dict, inputs=inputs_dict,
outputs=[node.layer_name], outputs=[node.name])
axis=axis) else:
if axis < 0:
axis = axis + len(output_shape)
param2_shape = self.params[node.name + "_cparam2"].shape
param2_shape_len = len(param2_shape)
diff_len = len(output_shape) - axis - param2_shape_len
new_shape = list(param2_shape) + [1] * diff_len
self.paddle_graph.add_layer(
"paddle.reshape",
inputs={"x": node.name + "_cparam2"},
outputs=[node.name + "_cparam2"],
shape=new_shape)
self.paddle_graph.add_layer(
"paddle.add",
inputs=inputs_dict,
outputs=[node.name])
def Reshape(self, node): def Reshape(self, node):
input = self.graph.get_input_node(node, idx=0, copy=True) input = self.graph.get_input_node(node, idx=0, copy=True)
top_count = len(input.layer.top) output_shape = node.out_shapes[0]
is_inplace = False if top_count == 1 else True
output_shape = node.output_shape[0]
layer_attrs = {
'shape': output_shape,
'inplace': is_inplace,
'act': None,
'name': string(node.layer_name)
}
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.reshape", "paddle.reshape",
inputs={"x": self.get_input_name(input)}, inputs={"x": input.name},
outputs=[node.layer_name], outputs=[node.name],
**layer_attrs) shape=output_shape)
def ArgMax(self, node): def ArgMax(self, node):
assert len(node.inputs) == 1 and len( assert len(node.inputs) == 1 and len(
node.outputs node.outputs
) == 1, 'The count of ArgMax node\'s input and output is not 1.' ) == 1, "The count of ArgMax node\'s input and output is not 1."
input = self.graph.get_input_node(node, idx=0, copy=True) input = self.graph.get_input_node(node, idx=0, copy=True)
input_shape = node.input_shape[0] in_shapes = node.in_shapes[0]
params = node.layer.argmax_param params = node.layer.argmax_param
out_max_val = params.out_max_val if hasattr(params, out_max_val = params.out_max_val if hasattr(params,
out_max_val) else False out_max_val) else False
top_k = params.top_k if hasattr(params, top_k) else 1 top_k = params.top_k if hasattr(params, top_k) else 1
axis = parmas.axis if hasattr(params, axis) else -1 axis = parmas.axis if hasattr(params, axis) else -1
if axis < 0: if axis < 0:
axis += len(input_shape) axis += len(in_shapes)
if out_max_val is True: if out_max_val is True:
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.topk", "paddle.topk",
inputs={"input": self.get_input_name(input)}, inputs={"x": input.name},
outputs=["{}_topk_var".format(node.layer_name), outputs=[node.name + "_topk_var", node.name + "_index_var"],
"{}_index_var".format(node.layer_name)],
k=top_k) k=top_k)
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="paddle.cast", "paddle.cast",
inputs={"x": "{}_topk_var".format(node.layer_name)}, inputs={"x": node.name + "_index_var"},
outputs=["{}_topk_var".format(node.layer_name)], outputs=[node.name + "_index_var"],
dtype="{}_topk_var.dtype".format(node.layer_name)) dtype="{}_topk_var.dtype".format(node.name))
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="paddle.concat", "paddle.concat",
inputs={"x": "[{}_topk_var, {}_index_var]".format(node.layer_name, inputs={"x": [node.name + "_topk_var", node.name + "_index_var"]},
node.layer_name)}, outputs=[node.name],
outputs=[node.layer_name],
axis=axis) axis=axis)
else: else:
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.topk", "paddle.topk",
inputs={"input": self.get_input_name(input)}, inputs={"x": input.name},
outputs=["_", node.layer_name], outputs=["_", node.name],
k=top_k) k=top_k)
def Crop(self, node): def Crop(self, node):
assert len( assert len(
node.inputs) == 2, 'The count of Crop node\'s input is not 2.' node.inputs) == 2, "The count of Crop node\'s input is not 2."
input = self.graph.get_input_node(node, idx=0, copy=True) input = self.graph.get_input_node(node, idx=0, copy=True)
example = self.graph.get_input_node(node, idx=1, copy=True) example = self.graph.get_input_node(node, idx=1, copy=True)
params = node.layer.crop_param params = node.layer.crop_param
axis = params.axis axis = params.axis
input_shape = node.input_shape[0] in_shapes = node.in_shapes[0]
if axis < 0: if axis < 0:
axis += len(input_shape) axis += len(in_shapes)
offset_real = [0] * len(input_shape) offset_real = [0] * len(in_shapes)
if hasattr(params, "offset") and len(params.offset) > 0: if hasattr(params, "offset") and len(params.offset) > 0:
offset = list(params.offset) offset = list(params.offset)
assert (len(input_shape) - axis assert (len(in_shapes) - axis
) == len(offset), "invalid offset[%s] in crop layer" % ( ) == len(offset), "invalid offset[%s] in crop layer" % (
str(offset)) str(offset))
offset_real = [0] * axis + offset offset_real = [0] * axis + offset
layer_attrs = {"offsets": list(offset_real),
"shape": node.input_shape[1]}
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.crop_tensor", "paddle.crop",
inputs={"x": self.get_input_name(input)}, inputs={"x": input.name},
outputs=[node.layer_name], outputs=[node.name],
**layer_attrs) shape=node.in_shapes[1],
offsets=list(offset_real))
def Flatten(self, node): def Flatten(self, node):
assert len( assert len(
node. node.
inputs) == 1, 'The count of DetectionOutput node\'s input is not 1.' inputs) == 1, "The count of DetectionOutput node\'s input is not 1."
input = self.graph.get_input_node(node, idx=0, copy=True) input = self.graph.get_input_node(node, idx=0, copy=True)
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.reshape", "paddle.reshape",
inputs={"x": self.get_input_name(input)}, inputs={"x": input.name},
outputs=[node.layer_name], outputs=[node.name],
shape = node.output_shape[0]) shape=node.out_shapes[0])
def Power(self, node): def Power(self, node):
assert len( assert len(
node.inputs) == 1, 'The count of Permute node\'s input is not 1.' node.inputs) == 1, "The count of Permute node\'s input is not 1."
input = self.graph.get_input_node(node, idx=0, copy=True) input = self.graph.get_input_node(node, idx=0, copy=True)
params = node.layer.power_param params = node.layer.power_param
power = params.power
scale = params.scale
shift = params.shift
layer_attrs = { layer_attrs = {
'scale': scale, 'scale': params.scale,
'bias': shift, 'bias': params.shift,
'bias_after_scale': True, 'bias_after_scale': True
'name': string(node.layer_name + '_scale')
} }
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="paddle.scale", "paddle.scale",
inputs={"x": self.get_input_name(input)}, inputs={"x": input.name},
outputs=[node.layer_name], outputs=[node.name],
**layer_attrs) **layer_attrs)
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="paddle.pow", "paddle.pow",
inputs={"x": node.layer_name}, inputs={"x": node.name},
outputs=[node.layer_name], outputs=[node.name],
factor=power) exponent=params.power)
def Reduction(self, node): def Reduction(self, node):
assert len( assert len(
node.inputs) == 1, 'The count of Reduction node\'s input is not 1.' node.inputs) == 1, "The count of Reduction node\'s input is not 1."
input = self.graph.get_input_node(node, idx=0, copy=True) input = self.graph.get_input_node(node, idx=0, copy=True)
params = node.layer.reduction_param params = node.layer.reduction_param
operation = params.operation operation = params.operation
...@@ -862,86 +952,104 @@ class CaffeOpMapper(OpMapper): ...@@ -862,86 +952,104 @@ class CaffeOpMapper(OpMapper):
coeff = params.coeff coeff = params.coeff
assert operation >= 1 and operation <= 4, "reduction reduction [%s] error" % ( assert operation >= 1 and operation <= 4, "reduction reduction [%s] error" % (
operation) operation)
input_len = len(node.input_shape[0]) input_len = len(node.in_shapes[0])
if axis < 0: if axis < 0:
axis += input_len + 1 axis += input_len + 1
dim = list(range(input_len)) dim = list(range(input_len))
if operation == 1: ## operation = SUM # operation = SUM
if operation == 1:
layer_attrs = { layer_attrs = {
'dim': dim[axis:], "dim": dim[axis:],
'keep_dim': False, "keep_dim": False,
'name': string(node.layer_name)
} }
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.reduce_sum", "paddle.sum",
inputs={"input": self.get_input_name(input)}, inputs={"input": input.name},
outputs=[node.layer_name], outputs=[node.name],
**layer_attrs) **layer_attrs)
elif operation == 2: ## operation = ASUM # operation = ASUM
elif operation == 2:
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="paddle.abs", "paddle.abs",
inputs={"x": self.get_input_name(input)}, inputs={"x": input.name},
outputs=[node.layer_name]) outputs=[node.name])
layer_attrs = { layer_attrs = {
'dim': dim[axis:], "dim": dim[axis:],
'keep_dim': False, "keep_dim": False,
'name': string(node.layer_name)
} }
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.reduce_sum", "paddle.sum",
inputs={"input": node.layer_name}, inputs={"input": node.name},
outputs=[node.layer_name], outputs=[node.name],
**layer_attrs) **layer_attrs)
elif operation == 3: ## operation = SUMSQ # operation = SUMSQ
elif operation == 3:
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="paddle.pow", "paddle.pow",
inputs={"x": self.get_input_name(input)}, inputs={"x": input.name},
outputs=[node.layer_name], outputs=[node.name],
factor=2.0) exponent=2.0)
layer_attrs = { layer_attrs = {
'dim': dim[axis:], "dim": dim[axis:],
'keep_dim': False, "keep_dim": False,
'name': string(node.layer_name)
} }
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.reduce_sum", "paddle.sum",
inputs={"input": node.layer_name}, inputs={"input": node.name},
outputs=[node.layer_name], outputs=[node.name],
**layer_attrs) **layer_attrs)
else: ## operation = MEAN # operation = MEAN
else:
layer_attrs = { layer_attrs = {
'dim': dim[axis:], "dim": dim[axis:],
'keep_dim': False, "keep_dim": False,
'name': string(node.layer_name)
} }
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="fluid.layers.reduce_mean", "paddle.mean",
inputs={"input": node.layer_name}, inputs={"input": input.name},
outputs=[node.layer_name], outputs=[node.name],
**layer_attrs) **layer_attrs)
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel="paddle.scale", "paddle.scale",
inputs={"x": node.layer_name}, inputs={"x": node.name},
outputs=[node.layer_name], outputs=[node.name],
scale=coeff) scale=coeff)
def deal_custom_layer(self, node): def Axpy(self, node):
op = node.layer_type assert len(node.inputs) == 1 and len(
custom_code, func = make_custom_layer(node) node.outputs
params = get_params(node.layer, node.layer_type) ) == 1, "The count of Axpy node\'s input and output is not 1."
arg_names, kwargs = set_args(func, params) input = self.graph.get_input_node(node, idx=0, copy=True)
kwargs['name'] = string(node.layer_name) params = node.layer.axpy_param
kwargs['input_shape'] = node.input_shape input0 = self.graph.get_input_node(node, idx=0, copy=True)
data = node.data input1 = self.graph.get_input_node(node, idx=1, copy=True)
if data is not None: input2 = self.graph.get_input_node(node, idx=2, copy=True)
data = self.adjust_parameters(node) input0_name = input0.name
weights_name = deal_weights(node) input1_name = input1.name
for i in range(len(data)): input2_name = input2.name
self.weights[weights_name[i]] = data[i] inputs_dict = {}
inputs_list = [] inputs_dict['x'] = input1_name
inputs_dict['y'] = input0_name
self.paddle_graph.add_layer(
"paddle.multiply",
inputs=inputs_dict,
outputs=[node.name + "_mul"],
axis=0)
inputs_dict = {}
inputs_dict['x'] = node.name + "_mul"
inputs_dict['y'] = input2_name
self.paddle_graph.add_layer(
"paddle.add",
inputs=inputs_dict,
outputs=[node.name + "_mul"])
def DetectionOutput(self, node):
assert len(
node.inputs) == 3, "The count of DetectionOutput node\'s input is not 3."
inputs_dict = dict()
for i in range(len(node.inputs)): for i in range(len(node.inputs)):
input = self.graph.get_input_node(node, idx=i, copy=True) input = self.graph.get_input_node(node, idx=i, copy=True)
if i == 1 and op == 'DetectionOutput': if i == 1:
input = self.graph.get_input_node(node, idx=i, copy=True) input = self.graph.get_input_node(node, idx=i, copy=True)
while input is not None \ while input is not None \
and input.layer_type != 'Softmax' \ and input.layer_type != 'Softmax' \
...@@ -949,27 +1057,165 @@ class CaffeOpMapper(OpMapper): ...@@ -949,27 +1057,165 @@ class CaffeOpMapper(OpMapper):
input = self.graph.get_input_node(input, idx=0, copy=True) input = self.graph.get_input_node(input, idx=0, copy=True)
assert input is not None, 'This kind of DetectionOutput is not supported!' assert input is not None, 'This kind of DetectionOutput is not supported!'
input = self.graph.get_input_node(input, idx=0, copy=True) input = self.graph.get_input_node(input, idx=0, copy=True)
inputs_list.append(self.get_input_name(input)) inputs_dict["x{}".format(i)] = input.name
kwargs_tmp = copy.deepcopy(kwargs) params = node.layer.detection_output_param
for k, v in kwargs_tmp.items(): nms_param = params.nms_param
if str(type(v)) == "<class 'caffe_pb2.NonMaximumSuppressionParameter'>": nms_param_dict = dict()
kwargs[k] = dict() nms_param_dict["nms_threshold"] = nms_param.nms_threshold
kwargs[k]["nms_threshold"] = v.nms_threshold nms_param_dict["top_k"] = nms_param.top_k
kwargs[k]["top_k"] = v.top_k nms_param_dict["eta"] = nms_param.eta
kwargs[k]["eta"] = v.eta if nms_param is None:
self.paddle_graph.add_layer( nms_param_dict = {"nms_threshold": 0.3, "top_k": 10, "eta": 1.0}
kernel="custom_layer:{}".format(op), default = {"nms_threshold": 0.3, "top_k": 10, "eta": 1.0}
inputs={"inputs": inputs_list}, fields = ["eta", "top_k", "nms_threshold"]
for f in default.keys():
if f not in nms_param_dict:
nms_param_dict[f] = default[f]
layer_attrs = {
"background_label": params.background_label_id,
"nms_threshold": nms_param_dict["nms_threshold"],
"nms_top_k": nms_param_dict["top_k"],
"keep_top_k": params.keep_top_k,
"score_threshold": params.confidence_threshold,
"nms_eta": nms_param_dict["eta"]}
self.paddle_graph.add_layer(
kernel="custom_layer:detectionoutput",
inputs=inputs_dict,
outputs=[node.name],
**layer_attrs)
def Normalize(self, node):
assert len(
node.inputs) == 1, "The count of Normalize node\'s input is not 1."
input = self.graph.get_input_node(node, idx=0, copy=True)
params = node.layer.norm_param
scale_name = node.name + "_scale"
if node.data is None or len(node.data) != 1:
print(
"The parameter of {} (type is {}) is not set. So we set the parameters as 0"
.format(scale_name, node.layer_type))
self.parmas[scale_name] = \
np.zeros([1] if params.channel_shared else [1, 1, 1, node.in_shapes[0][1]]).astype("float32")
else:
self.parmas[scale_name] = _adjust_parameters(node)[0]
layer_attrs = {
"axis": -1 if params.channel_shared else 1,
"param_name": scale_name,
"param_shape": self.parmas[scale_name].shape,
"param_dtype": str(self.parmas[scale_name].dtype)}
self.pd_pdgraph.add_layer(
"custom_layer:normalize",
inputs={"x": input.name},
outputs=[node.name],
**layer_attrs)
def Permute(self, node):
assert len(
node.inputs) == 1, "The count of Permute node\'s input is not 1."
input = self.graph.get_input_node(node, idx=0, copy=True)
params = node.layer.permute_param
order = list(params.order)
self.paddle_graph.add_layer(
"paddle.transpose",
inputs={"x": input.name},
outputs=[node.name],
perm=order)
def PriorBox(self, node):
assert len(
node.inputs) == 2, "The count of PriorBox node\'s input is not 2."
input0 = self.graph.get_input_node(node, idx=0, copy=True)
input1 = self.graph.get_input_node(node, idx=1, copy=True)
inputs_dict = {}
inputs_dict["x0"] = input0.name
inputs_dict["x1"] = input1.name
params = node.layer.prior_box_param
steps = tuple(params.step) if type(params.step) \
is list or type(params.step) is tuple \
else (params.step, params.step)
layer_attrs = {
"min_sizes": params.min_size,
"max_sizes": params.max_size,
"aspect_ratios": params.aspect_ratio,
"variance": params.variance,
"flip": params.flip,
"clip": params.clip,
"steps": steps,
"offset": params.offset,
"min_max_aspect_ratios_order": True}
self.paddle_graph.add_layer(
"custom_layer:priorbox",
inputs=inputs_dict,
outputs=[node.name],
**layer_attrs)
def ReLU6(self, node):
assert len(
node.inputs) == 1, "The count of RelU6 node\'s input is not 1."
input = self.graph.get_input_node(node, idx=0, copy=True)
self.paddle_graph.add_layer(
"paddle.nn.functional.relu6",
inputs={"x": input.name},
outputs=[node.name])
def ROIPooling(self, node):
assert len(
node.inputs) == 2, "The count of ROIPooling node\'s input is not 2."
input0 = self.graph.get_input_node(node, idx=0, copy=True)
input1 = self.graph.get_input_node(node, idx=1, copy=True)
inputs_dict = {}
inputs_dict["x0"] = input0.name
inputs_dict["x1"] = input1.name
params = node.layer.roi_pooling_param
layer_attrs = {
"pooled_height": params.pooled_h,
"pooled_width": params.pooled_w,
"spatial_scale": params.spatial_scale}
self.paddle_graph.add_layer(
"custom_layer:ROIPooling",
inputs=inputs_dict,
outputs=[node.name],
**layer_attrs)
def ShuffleChannel(self, node):
assert len(
node.inputs) == 1, "The count of ShuffleChannel node\'s input is not 1."
input = self.graph.get_input_node(node, idx=0, copy=True)
params = node.layer.shuffle_channel_param
self.paddle_graph.add_layer(
"fluid.layers.shuffle_channel",
inputs={"x": input.name},
outputs=[node.layer_name], outputs=[node.layer_name],
**kwargs) group=params.group)
if op not in self.used_custom_layers:
self.used_custom_layers[op] = custom_code
def directly_map(self, node): def Upsample(self, node):
assert node.layer_type in self.directly_map_ops assert len(
op_info = self.directly_map_ops[node.layer_type] node.inputs) == 1, "The count of Upsample node\'s input is not 1."
input = self.graph.get_input_node(node, idx=0, copy=True) input = self.graph.get_input_node(node, idx=0, copy=True)
params = node.layer.upsample_param
layer_attrs = {
"align_corners": False,
"scale_factor": params.scale,
"mode": "nearest"}
self.paddle_graph.add_layer( self.paddle_graph.add_layer(
kernel=op_info, "paddle.nn.functioanl.interpolate",
inputs={"x": self.get_input_name(input)}, inputs={"input": input.name},
outputs=[node.layer_name]) outputs=[node.layer_name],
\ No newline at end of file **layer_attrs)
def Select(self, node):
assert len(
node.inputs) == 1, "The count of Select node\'s input is not 1."
input = self.graph.get_input_node(node, idx=0, copy=True)
in_shapes = node.in_shapes[0]
params = node.layer.select_param
layer_attrs = {
"in_shapes": in_shapes,
"point": params.slice_point,
"axis": params.axis}
self.paddle_graph.add_layer(
"custom_layer:select",
inputs={"x": input.name},
outputs=[node.name],
**layer_attrs)
# 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 math
import numbers
from functools import reduce
def get_kernel_parameters(params):
[k_h, k_w] = [1, 1]
if isinstance(params.kernel_size, numbers.Number):
[k_h, k_w] = [params.kernel_size] * 2
elif len(params.kernel_size) > 0:
k_h = params.kernel_h if params.kernel_h > 0 else params.kernel_size[0]
k_w = params.kernel_w if params.kernel_w > 0 else params.kernel_size[
len(params.kernel_size) - 1]
elif params.kernel_h > 0 or params.kernel_w > 0:
k_h = params.kernel_h
k_w = params.kernel_w
[s_h, s_w] = [1, 1]
if isinstance(params.stride, numbers.Number):
[s_h, s_w] = [params.stride] * 2
elif len(params.stride) > 0:
s_h = params.stride_h if params.stride_h > 0 else params.stride[0]
s_w = params.stride_w if params.stride_w > 0 else params.stride[len(
params.stride) - 1]
elif params.stride_h > 0 or params.stride_w > 0:
s_h = params.stride_h
s_w = params.stride_w
[p_h, p_w] = [0, 0]
if isinstance(params.pad, numbers.Number):
[p_h, p_w] = [params.pad] * 2
elif len(params.pad) > 0:
p_h = params.pad_h if params.pad_h > 0 else params.pad[0]
p_w = params.pad_w if params.pad_w > 0 else params.pad[len(params.pad) -
1]
elif params.pad_h > 0 or params.pad_w > 0:
p_h = params.pad_h
p_w = params.pad_w
dila_h = dila_w = 1
if hasattr(params, 'dilation'):
dila_len = len(params.dilation)
if dila_len == 2:
dila_h = params.dilation[0]
dila_w = params.dilation[1]
elif dila_len == 1:
dila_h = dila_w = params.dilation[0]
else:
assert dila_len == 0, "invalid length[%s] of dilation in convolution" % (
dila_len)
return dila_h, dila_w, p_h, p_w, k_h, k_w, s_h, s_w
def get_strided_kernel_output_shape(params, input_shape, round_func):
i_h = input_shape[2]
i_w = input_shape[3]
dila_h, dila_w, pad_h, pad_w, kernel_h, kernel_w, stride_h, stride_w = get_kernel_parameters(
params)
o_h = (i_h + 2 * pad_h - (dila_h *
(kernel_h - 1) + 1)) / float(stride_h) + 1
o_w = (i_w + 2 * pad_w - (dila_w *
(kernel_w - 1) + 1)) / float(stride_w) + 1
o_h = int(round_func(o_h))
o_w = int(round_func(o_w))
has_c_o = hasattr(params, 'num_output')
c = params.num_output if has_c_o else input_shape[1]
return [[input_shape[0], c, o_h, o_w]]
def shape_convolution(layer, input_shape):
params = layer.convolution_param
return get_strided_kernel_output_shape(params, input_shape[0], math.floor)
def shape_deconvolution(layer, input_shape):
h_i = input_shape[0][2]
w_i = input_shape[0][3]
params = layer.convolution_param
dila_h, dila_w, pad_h, pad_w, kernel_h, kernel_w, stride_h, stride_w = get_kernel_parameters(
params)
h_o = (h_i - 1) * stride_h - 2 * pad_h + dila_h * (kernel_h - 1) + 1
w_o = (w_i - 1) * stride_w - 2 * pad_w + dila_w * (kernel_w - 1) + 1
has_c_o = hasattr(params, 'num_output')
c = params.num_output if has_c_o else input_shape.channels
return [[input_shape[0][0], c, h_o, w_o]]
def shape_pooling(layer, input_shape):
params = layer.pooling_param
global_pool = getattr(params, 'global_pooling', False)
if global_pool:
return [[input_shape[0][0], input_shape[0][1], 1, 1]]
ceil_mode = getattr(params, 'ceil_mode', True)
if ceil_mode is True:
method = math.ceil
else:
method = math.floor
return get_strided_kernel_output_shape(params, input_shape[0], method)
def shape_innerproduct(layer, input_shape):
params = layer.inner_product_param
return [[input_shape[0][0], params.num_output]]
def shape_lrn(layer, input_shape):
return input_shape
def shape_relu(layer, input_shape):
return input_shape
def shape_softmax(layer, input_shape):
return input_shape
def shape_input(layer, input_shape):
return [list(layer.input_param.shape[0].dim)]
def shape_memorydata(layer, input_shape):
params = layer.memory_data_param
shape = []
shape.append(int(params.batch_size))
shape.append(int(params.channels))
shape.append(int(params.height))
shape.append(int(params.width))
return [shape]
def shape_concat(layer, input_shape):
params = layer.concat_param
axis = params.axis
output_shape = None
for shape in input_shape:
if output_shape is None:
output_shape = []
for i in range(len(shape)):
output_shape.append(shape[i])
else:
output_shape[axis] += shape[axis]
return [output_shape]
def shape_slice(layer, input_shape):
inshape = input_shape[0]
top_len = len(layer.top)
params = layer.slice_param
axis = params.axis
slice_dim = params.slice_dim
if slice_dim != 1 and axis == 1:
axis = slice_dim
points = list(params.slice_point)
count = inshape[axis]
if len(points) == 0:
assert count % top_len == 0, "the parameter of Slice is wrong"
part = count / top_len
t = part
while t < count:
points.append(int(t))
t += part
points = [0] + points + [count]
output_shape = []
for i in range(len(points)):
shape = []
for ii in range(len(inshape)):
shape.append(inshape[ii])
size = points[i + 1] - points[i]
shape[axis] = size
output_shape.append(shape)
if i == len(points) - 2:
break
return output_shape
def shape_prelu(layer, input_shape):
return input_shape
def shape_sigmoid(layer, input_shape):
return input_shape
def shape_absval(layer, input_shape):
return input_shape
def shape_accuracy(layer, input_shape):
return [[1]]
def shape_tanh(layer, input_shape):
return input_shape
def shape_eltwise(layer, input_shape):
return [input_shape[0]]
def shape_batchnorm(layer, input_shape):
return input_shape
def shape_scale(layer, input_shape):
return input_shape
def shape_reshape(layer, input_shape):
def count(num_list):
return reduce(lambda a, b: a * b, num_list)
inshape = input_shape[0]
params = layer.reshape_param
axis = params.axis if hasattr(params, 'axis') else 0
num_axes = params.num_axes if hasattr(params, 'num_axes') else -1
if inshape[0] == -1:
inshape[0] = 1
input_count = count(inshape)
input_num_axes = len(inshape)
input_start_axis = axis
start_axis = input_start_axis if input_start_axis >= 0 \
else input_num_axes + input_start_axis + 1
assert start_axis >= 0, "[Reshape]axis %d out of range" % (input_start_axis)
assert start_axis <= input_num_axes, "[Reshape]axis %d out of range for %d-D input data"\
% (input_start_axis, input_num_axes)
assert num_axes >= -1, "[Reshape]num_axes must be >= 0, or -1 for all"
end_axis = input_num_axes if num_axes == -1 else start_axis + num_axes
assert end_axis <= input_num_axes, "end_axis[%d] = axis[%d] + num_axes[%d] is out of range"\
% (end_axis, start_axis, num_axes)
num_axes_replaced = end_axis - start_axis
num_axes_retained = input_num_axes - num_axes_replaced
num_new_axes = len(list(params.shape.dim))
outshape = []
for i in range(start_axis):
outshape.append(inshape[i])
for i in range(num_new_axes):
outshape.append(params.shape.dim[i])
for i in range(end_axis, input_num_axes):
outshape.append(inshape[i])
assert len(outshape) == num_axes_retained + num_new_axes,\
"[Reshape]invalid dims of output shape[%s]" % (str(outshape))
inferred_axis = -1
copy_axes = []
constant_count = 1
for i in range(num_new_axes):
top_dim = params.shape.dim[i]
if top_dim == 0:
copy_axes.append(i)
copy_axis_index = start_axis + i
outshape[copy_axis_index] = inshape[copy_axis_index]
elif top_dim == -1:
assert inferred_axis == -1, "[Reshape]new shape contains multiple -1 dims"
inferred_axis = i
else:
constant_count *= top_dim
if inferred_axis >= 0:
explicit_count = constant_count
l = inshape[0:start_axis]
if len(l) > 0:
explicit_count *= count(l)
l = inshape[end_axis:]
if len(l) > 0:
explicit_count *= count(l)
for i in range(len(copy_axes)):
explicit_count *= outshape[start_axis + copy_axes[i]]
assert input_count % explicit_count == 0, "[Reshape]botom count[%d] "\
"must be divisible by product of the specified dimensions[%d] "\
% (input_count, explicit_count)
outshape[start_axis + inferred_axis] = int(input_count / explicit_count)
output_count = count(outshape)
assert output_count == input_count, "[Reshape]output count[%d] must match input count[%d]" % (
output_count, input_count)
outshape[0] = -1
return [outshape]
def shape_argmax(layer, input_shape):
inshape = input_shape[0]
params = layer.argmax_param
out_max_val = params.out_max_val if hasattr(params, out_max_val) else False
top_k = params.top_k if hasattr(params, top_k) else 1
axis = parmas.axis if hasattr(params, axis) else -1
if axis < 0:
axis += len(inshape)
assert (axis + 1 == len(inshape)
), 'only can be applied on the last dimension[axis:%d, %s] now,'\
'make sure you have set axis param in xxx.prototxt file' \
% (axis, str(inshape))
outshape = inshape
outshape[-1] = top_k
if out_max_val is True:
outshape[-1] *= 2
return [outshape]
def shape_crop(layer, input_shape):
assert len(input_shape) == 2, "the number of crop's inputs must be 2"
return [input_shape[1]]
def shape_flatten(layer, input_shape):
assert len(input_shape) == 1, "the number of flatten's inputs must be 1"
inshape = input_shape[0]
params = layer.flatten_param
start_axis = params.axis
end_axis = params.end_axis
if start_axis < 0:
start_axis += len(inshape)
if end_axis < 0:
end_axis += len(inshape) + 1
assert start_axis <= end_axis, 'invalid axis[%d] or end_axis[%d] params'\
% (start_axis, end_axis)
output_shape = inshape[0:start_axis]
if len(inshape[start_axis:end_axis]) != 0:
flat_sz = reduce(lambda a, b: a * b, inshape[start_axis:end_axis])
output_shape += [flat_sz]
output_shape += inshape[end_axis:len(inshape)]
output_shape[0] = -1
return [output_shape]
def shape_power(layer, input_shape):
return input_shape
def shape_reduction(layer, input_shape):
params = layer.reduction_param
axis = params.axis
if axis < 0:
axis += len(input_shape[0]) + 1
assert axis <= len(input_shape[0]), 'invalid axis[%d] error' % (axis)
return [input_shape[0:axis]]
...@@ -20,87 +20,126 @@ from x2paddle.core.util import * ...@@ -20,87 +20,126 @@ from x2paddle.core.util import *
class Static_BNScaleFuser(FuseBase): class Static_BNScaleFuser(FuseBase):
def __init__(self): def __init__(self):
super(Static_BNScaleFuser, self).__init__(graph_type="dygraph") super(Static_BNScaleFuser, self).__init__(graph_type="static")
patterns = list()
def build_pattern(self): def build_pattern(self):
""" 描述需要替换的batchnorm2d图结构。 """ 描述需要替换的batchnorm2d图结构。
batchnorm2d层模式python实现代码示例: batchnorm2d层模式python实现代码示例:
conv5_bn = fluid.layers.batch_norm(input=conv5, is_test=True, param_attr=None, bias_attr=None, moving_mean_name='conv5_bn_mean', moving_variance_name='conv5_bn_variance', epsilon=9.999999747378752e-06, name='conv5_bn') 模式一:
conv5_scale_scale = fluid.ParamAttr(name='conv5_scale_scale') conv1_bn = paddle.nn.functional.batch_norm(x=conv1, weight=conv1_bn_weight, bias=conv1_bn_bias, running_mean=conv1_bn_mean, running_var=conv1_bn_variance, epsilon=9.999999747378752e-06, momentum=0.9990000128746033)
conv5_scale_cparam1 = fluid.layers.create_parameter(attr=conv5_scale_scale, dtype=conv5_bn.dtype, shape=[256], name='conv5_scale_cparam1', is_bias=True, default_initializer=Constant(value=1.0)) conv1_scale_cparam1 = paddle.static.create_parameter(shape=(32,), dtype='float32', name='conv1_scale_cparam1')
conv5_scale_mul = fluid.layers.elementwise_mul(x=conv5_bn, y=conv5_scale_cparam1, axis=1) conv1_scale_mul = paddle.multiply(x=conv1_bn, y=conv1_scale_cparam1, axis=1)
conv5_scale_offset = fluid.ParamAttr(name='conv5_scale_offset') conv1_scale_cparam2 = paddle.static.create_parameter(shape=(32,), dtype='float32', name='conv1_scale_cparam2')
conv5_scale_cparam2 = fluid.layers.create_parameter(attr=conv5_scale_offset, dtype=conv5_bn.dtype, shape=[256], name='conv5_scale_cparam2', is_bias=True, default_initializer=Constant(value=1.0)) conv1_scale_cparam2 = paddle.reshape(x=conv1_scale_cparam2, shape=[32, 1, 1])
conv5_scale = fluid.layers.elementwise_add(x=conv5_scale_mul, y=conv5_scale_cparam2, axis=1) conv1_scale = paddle.add(x=conv1_scale_mul, y=conv1_scale_cparam2)
模式二:
conv1_bn = paddle.nn.functional.batch_norm(x=conv1, weight=conv1_bn_weight, bias=conv1_bn_bias, running_mean=conv1_bn_mean, running_var=conv1_bn_variance, epsilon=9.999999747378752e-06, momentum=0.9990000128746033)
conv1_scale_cparam1 = paddle.static.create_parameter(shape=(32,), dtype='float32', name='conv1_scale_cparam1')
conv1_scale_mul = paddle.multiply(x=conv1_bn, y=conv1_scale_cparam1, axis=1)
conv1_scale_cparam2 = paddle.static.create_parameter(shape=(32,), dtype='float32', name='conv1_scale_cparam2')
conv1_scale = paddle.add(x=conv1_scale_mul, y=conv1_scale_cparam2)
""" """
def gen_name(id): def gen_name(id):
return "x" + str(id) return "x" + str(id)
self.pattern.add_layer( pattern = PaddleGraph(graph_type="dygraph")
"fluid.layers.batch_norm", pattern.add_layer(
inputs={"input": "bn-input-0"}, "paddle.nn.functional.batch_norm",
inputs={"input": "bn-input-0",
"weight": "bn-input-1",
"bias": "bn-input-2",
"running_mean": "bn-input-3",
"running_var": "bn-input-4",},
outputs=[gen_name(0)]) outputs=[gen_name(0)])
self.pattern.add_layer( pattern.add_layer(
"fluid.ParamAttr", "paddle.static.create_parameter",
inputs={}, inputs={},
outputs=[gen_name(1)]) outputs=[gen_name(1)])
self.pattern.add_layer(
"fluid.layers.create_parameter",
inputs={"attr": gen_name(1)},
outputs=[gen_name(2)])
inputs_dict = {} inputs_dict = {}
inputs_dict['x'] = gen_name(0) inputs_dict['x'] = gen_name(0)
inputs_dict['y'] = gen_name(2) inputs_dict['y'] = gen_name(1)
self.pattern.add_layer( pattern.add_layer(
"fluid.layers.elementwise_mul", "paddle.multiply",
inputs=inputs_dict, inputs=inputs_dict,
outputs=[gen_name(3)]) outputs=[gen_name(2)])
self.pattern.add_layer( pattern.add_layer(
"fluid.ParamAttr", "paddle.static.create_parameter",
inputs={}, inputs={},
outputs=[gen_name(3)])
pattern.add_layer(
"paddle.reshape",
inputs={"x": gen_name(3)},
outputs=[gen_name(4)]) outputs=[gen_name(4)])
self.pattern.add_layer( inputs_dict = {}
"fluid.layers.create_parameter", inputs_dict['x'] = gen_name(2)
inputs={"attr": gen_name(4)}, inputs_dict['y'] = gen_name(4)
pattern.add_layer(
"paddle.add",
inputs=inputs_dict,
outputs=[gen_name(5)]) outputs=[gen_name(5)])
pattern.build(inputs={"input-0": "bn-input-0",
"input-1": "bn-input-1",
"input-2": "bn-input-2",
"input-3": "bn-input-3",
"input-4": "bn-input-4"})
self.patterns.append(pattern)
pattern = PaddleGraph(graph_type="dygraph")
pattern.add_layer(
"paddle.nn.functional.batch_norm",
inputs={"input": "bn-input-0",
"weight": "bn-input-1",
"bias": "bn-input-2",
"running_mean": "bn-input-3",
"running_var": "bn-input-4",},
outputs=[gen_name(0)])
pattern.add_layer(
"paddle.static.create_parameter",
inputs={},
outputs=[gen_name(1)])
inputs_dict = {} inputs_dict = {}
inputs_dict['x'] = gen_name(3) inputs_dict['x'] = gen_name(0)
inputs_dict['y'] = gen_name(5) inputs_dict['y'] = gen_name(1)
self.pattern.add_layer( pattern.add_layer(
"fluid.layers.elementwise_add", "paddle.multiply",
inputs=inputs_dict, inputs=inputs_dict,
outputs=[gen_name(6)]) outputs=[gen_name(2)])
self.pattern.build(inputs={"input-0": "bn-input-0"}) pattern.add_layer(
"paddle.static.create_parameter",
inputs={},
outputs=[gen_name(3)])
inputs_dict = {}
inputs_dict['x'] = gen_name(2)
inputs_dict['y'] = gen_name(3)
pattern.add_layer(
"paddle.add",
inputs=inputs_dict,
outputs=[gen_name(4)])
pattern.build(inputs={"input-0": "bn-input-0",
"input-1": "bn-input-1",
"input-2": "bn-input-2",
"input-3": "bn-input-3",
"input-4": "bn-input-4"})
self.patterns.append(pattern)
def insert_new_layer(self, graph, parameters, matches): def insert_new_layer(self, graph, parameters, matches):
new_layer = self.gen_new_layer(parameters, matches) new_layer = self.gen_new_layer(parameters, matches)
new_layer_id = list(matches.keys())[0] new_layer_id = list(matches.keys())[-1]
graph.layers[new_layer_id] = new_layer graph.layers[new_layer_id] = new_layer
matches.pop(list(matches.keys())[1])
matches.pop(list(matches.keys())[2])
matches.pop(new_layer_id) matches.pop(new_layer_id)
def gen_new_layer(self, parameters, matches): def gen_new_layer(self, parameters, matches):
layers_id = list(matches.keys()) layers_id = list(matches.keys())
layer = matches[layers_id[0]] bn_layer = matches[layers_id[0]]
layer_inputs = layer.inputs
layer_name = layer.outputs[0]
layer_attrs = layer.attrs
layer_attrs["param_attr"] = string("{}_scale".format(layer_name))
layer_attrs["bias_attr"] = string("{}_offset".format(layer_name))
layer = matches[layers_id[-1]]
layer_outputs = layer.outputs
layer = matches[layers_id[1]] layer = matches[layers_id[1]]
layer_name = layer.outputs[0] bn_layer.inputs["weight"] = layer.outputs[0]
scale_numpy = parameters.pop(layer_name) layer = matches[layers_id[3]]
parameters[layer_attrs["param_attr"][1: -1]] = scale_numpy bn_layer.inputs["bias"] = layer.outputs[0]
layer = matches[layers_id[4]] bn_layer.id = layers_id[-1]
layer_name = layer.outputs[0] layer = matches[layers_id[-1]]
scale_numpy = parameters.pop(layer_name) bn_layer.outputs = layer.outputs
parameters[layer_attrs["bias_attr"][1: -1]] = scale_numpy return bn_layer
new_layer = PaddleLayer( \ No newline at end of file
layers_id[0],
"fluid.layers.batch_norm",
inputs=layer_inputs,
outputs=layer_outputs,
**layer_attrs)
return new_layer
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册