未验证 提交 e020af54 编写于 作者: J Jason 提交者: GitHub

Merge pull request #440 from SunAhong1993/paddle-2.0

modify tf, onnx and caffe
......@@ -141,11 +141,14 @@ def tf2paddle(model_path,
from x2paddle.optimizer.tensorflow.bias import BiasOpt
from x2paddle.optimizer.tensorflow.transpose import TransposeOpt
from x2paddle.optimizer.tensorflow.batch_norm import BatchNormOpt
from x2paddle.optimizer.tensorflow.prelu import PReLUOpt
bias_opt = BiasOpt()
transpose_opt = TransposeOpt()
batch_norm_opt = BatchNormOpt()
prelu_opt = PReLUOpt()
bias_opt.run(mapper.paddle_graph)
batch_norm_opt.run(mapper.paddle_graph)
prelu_opt.run(mapper.paddle_graph)
transpose_opt.run(mapper.paddle_graph)
mapper.paddle_graph.gen_model(save_dir)
......
......@@ -526,7 +526,8 @@ class PaddleGraph(object):
for layer_id, layer in self.layers.items():
if ("paddle.nn" in layer.kernel and "functional" not in layer.kernel
) or layer.kernel == "paddle.to_tensor" or \
layer.kernel.startswith("custom_layer"):
layer.kernel.startswith("custom_layer") or \
layer.kernel.startswith("paddle.fluid.dygraph"):
line = "{}".format(
layer.outputs[0]
) if layer.kernel == "paddle.to_tensor" and not layer.attrs[
......
......@@ -527,20 +527,16 @@ class CaffeOpMapper(OpMapper):
assert len(
node.inputs
) >= 1, "The count of Concat node\'s input is not more than 1."
inputs_dict = dict()
inputs_list = list()
for i in range(len(node.inputs)):
input = self.graph.get_bottom_node(node, idx=i, copy=True)
inputs_dict["input{}".format(i)] = self.get_input_name(input)
inputs_list.append(self.get_input_name(input))
params = node.layer.concat_param
axis = params.axis
layer_attrs = {'axis': axis}
self.paddle_graph.add_layer(
"prim.list",
inputs=inputs_dict,
outputs=[node.layer_name + "_list"])
self.paddle_graph.add_layer(
"paddle.concat",
inputs={"x": node.layer_name + "_list"},
inputs={"x": inputs_list},
outputs=[node.layer_name],
**layer_attrs)
......@@ -578,11 +574,9 @@ class CaffeOpMapper(OpMapper):
mode_bool = params.channel_shared
output_shape = node.output_shape[0]
if mode_bool:
mode = 'all'
channel = None
num_parameters = 1
else:
mode = 'channel'
channel = output_shape[1]
num_parameters = output_shape[1]
data = node.data
self.params[prelu_name + '._weight'] = np.squeeze(data[0])
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(
......@@ -591,8 +585,7 @@ class CaffeOpMapper(OpMapper):
"paddle.nn.PReLU",
inputs={"input": self.get_input_name(input)},
outputs=layer_outputs,
channel=channel,
mode=string(mode))
num_parameters=num_parameters)
def Eltwise(self, node):
assert len(
......@@ -616,15 +609,15 @@ class CaffeOpMapper(OpMapper):
if hasattr(params, 'coeff') and len(params.coeff) == 2:
coeff = params.coeff
self.paddle_graph.add_layer(
"prim.mul",
"paddle.scale",
inputs={"x": input0_name},
outputs=[node.layer_name + '_mul0'],
y=coeff[0])
scale=coeff[0])
self.paddle_graph.add_layer(
"prim.mul",
"paddle.scale",
inputs={"x": input1_name},
outputs=[node.layer_name + '_mul1'],
y=coeff[2])
scale=coeff[2])
inputs_dict = {}
inputs_dict['x'] = node.layer_name + '_mul0'
inputs_dict['y'] = node.layer_name + '_mul1'
......@@ -760,7 +753,7 @@ class CaffeOpMapper(OpMapper):
param2_shape = self.params[node.layer_name + "_cparam2"].shape
param2_shape_len = len(param2_shape)
diff_len = len(output_shape) - axis - param2_shape_len
new_shape = param2_shape + [1] * diff_len
new_shape = list(param2_shape) + [1] * diff_len
self.paddle_graph.add_layer(
"paddle.reshape",
inputs={"x": node.layer_name + "_cparam2"},
......@@ -805,14 +798,9 @@ class CaffeOpMapper(OpMapper):
inputs={"x": node.layer_name + "_index_var"},
outputs=[node.layer_name + "_index_var"],
dtype="{}_topk_var.dtype".format(node.layer_name))
self.paddle_graph.add_layer(
"prim.list",
inputs={"input0": node.layer_name + "_topk_var",
"input1": node.layer_name + "_index_var"},
outputs=[node.layer_name + "_list"])
self.paddle_graph.add_layer(
"paddle.concat",
inputs={"x": node.layer_name + "_list"},
inputs={"x": [node.layer_name + "_topk_var", node.layer_name + "_index_var"]},
outputs=[node.layer_name],
axis=axis)
else:
......
......@@ -1293,25 +1293,23 @@ class OpSet9():
if shape_slope == [1]:
mode = 'all'
elif len(shape_slope) > 2:
mode = 'element'
raise Exception("The 'element' mode is not supported yet!")
if mode == 'channel' and len(shape_slope) == 1:
# paddle params shape need be [1, channel]
slope_data = _const_weight_or_none(val_slope)
slope_data = np.reshape(slope_data, [1] + shape_slope)
self.weights[val_slope.layer_name] = slope_data
num_parameters = val_x.out_shapes[0][1]
else:
num_parameters = 1
layer_attrs = {
"param_attr": string(val_slope.layer_name),
'mode': string(mode),
"channel": val_x.out_shapes[0][1] if mode == "channel" else None,
"input_shape": val_x.out_shapes[0] if mode == "element" else None,
}
self.paddle_graph.add_layer(
"paddle.nn.PReLU",
inputs={"x": self.get_node_name(val_x)},
outputs=layer_outputs,
**layer_attrs)
num_parameters=num_parameters,
weight_attr=string(val_slope.layer_name))
@print_mapping_info
def Squeeze(self, node):
......
......@@ -508,14 +508,6 @@ class TFOpMapper(OpMapper):
param = self.graph.get_node(node.layer.input[1])
input_name = input.name
if input.dtype == 'bool':
cast_name = gen_name('reshape', 'cast')
self.paddle_graph.add_layer(
kernel="paddle.cast",
inputs={"x": input_name},
outputs=[cast_name],
dtype="'int32'")
input_name = cast_name
if param.layer_type == "Const":
shape = param.value.tolist()
......@@ -540,13 +532,6 @@ class TFOpMapper(OpMapper):
outputs=[node.name],
shape=out_shape.tolist())
if input.dtype == 'bool':
self.paddle_graph.add_layer(
kernel="paddle.cast",
inputs={"x": node.name},
outputs=[node.name],
dtype="'bool'")
def Pad(self, node):
input = self.graph.get_node(node.layer.input[0])
paddings = self.graph.get_node(node.layer.input[1])
......@@ -592,14 +577,6 @@ class TFOpMapper(OpMapper):
def Shape(self, node):
input = self.graph.get_node(node.layer.input[0])
input_name = input.name
if input.dtype == 'bool':
cast_name = gen_name('shape', 'cast')
self.paddle_graph.add_layer(
kernel="paddle.cast",
inputs={"x": input.name},
outputs=[cast_name],
dtype=string("int32"))
input_name = cast_name
self.paddle_graph.add_layer(
kernel="paddle.shape",
inputs={"input": input_name},
......@@ -791,26 +768,11 @@ class TFOpMapper(OpMapper):
axis += len(inputs[0].out_shapes[0])
input_names = [i.name for i in inputs]
for i, ipt in enumerate(inputs):
if ipt.dtype == 'bool':
cast_name = gen_name('concat', 'cast')
self.paddle_graph.add_layer(
kernel="paddle.cast",
inputs={"x": ipt.name},
outputs=[cast_name],
dtype="'int32'")
input_names[i] = cast_name
self.paddle_graph.add_layer(
kernel="paddle.concat",
inputs={"x": input_names},
outputs=[node.name],
axis=axis)
if node.dtype == 'bool':
self.paddle_graph.add_layer(
kernel="paddle.cast",
inputs={"x": node.name},
outputs=[node.name],
dtype="'bool'")
def StridedSlice(self, node):
input = self.graph.get_node(node.layer.input[0])
......
......@@ -28,6 +28,8 @@ from .fc_fuser import DygraphFcFuser
from .fc_fuse_pass import DygraphFcFusePass
from .interpolate_bilinear_fuser import DygraphInterpolateBilinearFuser
from .interpolate_bilinear_fuse_pass import DygraphInterpolateBilinearFusePass
from .prelu_fuser import DygraphPReLUFuser
from .prelu_fuse_pass import DygraphPReLUFusePass
from .reshape_fuser import DygraphReshapeFuser
from .reshape_fuse_pass import DygraphReshapeFusePass
from .tf_batchnorm_fuser import DygraphTFBatchNormFuser
......
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from x2paddle.optimizer.pass_ import Pass
from x2paddle.optimizer.fusion.dygraph import DygraphPReLUFuser
from x2paddle.optimizer.pass_manager import pass_register
@pass_register
class DygraphPReLUFusePass(Pass):
name = "dygraph_prelu_fuse_pass"
def __init__(self):
Pass.__init__(self)
def apply(self, graph):
fuser = DygraphPReLUFuser()
fuser.operate(graph, match_kind="edge")
# 用于注册
dygraph_prelu_fuse_pass = DygraphPReLUFusePass()
\ No newline at end of file
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import copy
import numpy as np
from collections import OrderedDict
from x2paddle.optimizer.pattern_matcher import FuseBase
from x2paddle.core.program import PaddleGraph, PaddleLayer
from x2paddle.core.util import *
class DygraphPReLUFuser(FuseBase):
def __init__(self):
self.prelu_index = 0
super(DygraphPReLUFuser, self).__init__(graph_type="dygraph")
def build_pattern(self):
""" 描述需要替换的prelu图结构。
prelu层模式python实现代码示例:
conv2_alphas = self.conv2_alphas
conv2_mul_1_y = paddle.full(dtype='float32', shape=[1], fill_value=0.5)
conv2_Relu = self.relu1(conv2_Conv2D)
conv2_Abs = paddle.abs(x=conv2_Conv2D)
conv2_sub = fluid.layers.elementwise_sub(x=conv2_Conv2D, y=conv2_Abs)
conv2_mul = paddle.multiply(x=conv2_alphas, y=conv2_sub, axis=1)
conv2_mul_1 = paddle.multiply(x=conv2_mul, y=conv2_mul_1_y, axis=1)
conv2_add = paddle.add(x=conv2_Relu, y=conv2_mul_1)
"""
def gen_name(id):
return "x" + str(id)
self.pattern.add_layer(
"self.create_parameter",
inputs={},
outputs=[gen_name(0)])
self.pattern.add_layer(
"paddle.full",
inputs={},
outputs=[gen_name(1)],
shape=[1],
fill_value=0.5)
self.pattern.add_layer(
"paddle.nn.ReLU",
inputs={"x": "prelu-input-0"},
outputs=[gen_name(2)])
self.pattern.add_layer(
"paddle.abs",
inputs={"x": "prelu-input-0"},
outputs=[gen_name(3)])
self.pattern.add_layer(
"fluid.layers.elementwise_sub",
inputs={"x": "prelu-input-0",
"y": gen_name(3)},
outputs=[gen_name(4)])
self.pattern.add_layer(
"paddle.multiply",
inputs={"x": gen_name(0),
"y": gen_name(4)},
outputs=[gen_name(5)])
self.pattern.add_layer(
"paddle.multiply",
inputs={"x": gen_name(5),
"y": gen_name(1)},
outputs=[gen_name(6)])
self.pattern.add_layer(
"paddle.add",
inputs={"x": gen_name(2),
"y": gen_name(6)},
outputs=[gen_name(7)])
self.pattern.build(inputs={"input-0": "prelu-input-0", })
def insert_new_layer(self, graph, parameters, matches):
new_layers, last_layer_id = self.gen_new_layer(matches, parameters, graph)
matches_copy = copy.deepcopy(matches)
for layer_id, layer in matches_copy.items():
for i in range(3):
if layer_id == new_layers[i].id:
matches.pop(new_layers[i].id)
prefix_layers = OrderedDict()
mid_layers = OrderedDict()
suffix_layers = OrderedDict()
is_need_id = False
for layer_id, layer in graph.layers.items():
if is_need_id:
suffix_layers[layer_id] = layer
else:
if layer_id == last_layer_id:
for i in range(3):
mid_layers[new_layers[i].id] = new_layers[i]
is_need_id = True
prefix_layers[layer_id] = layer
prefix_layers.update(mid_layers)
prefix_layers.update(suffix_layers)
graph.layers = prefix_layers
def gen_new_layer(self, matches, parameters, graph):
layer_id_list = list(matches.keys())
layer_id_list.sort(key = int)
for layer_id, layer in matches.items():
if layer.kernel == "paddle.nn.ReLU":
input_name = layer.inputs["x"]
if layer.kernel == "self.create_parameter":
param_name = layer.outputs[0]
if layer.kernel == "paddle.add":
output_name = layer.outputs[0]
transpose0 = PaddleLayer(
id=layer_id_list[-1] + "_1",
kernel="paddle.transpose",
inputs={"x": input_name},
outputs=["{}_transpose_for_prelu".format(input_name)],
perm=[0, 3, 1, 2])
prelu_name = "merge_prelu{}".format(self.prelu_index)
self.prelu_index += 1
param = parameters[param_name]
c = param.shape[0]
prelu = PaddleLayer(id=layer_id_list[-1] + "_2",
kernel="paddle.nn.PReLU",
inputs={"input": "{}_transpose_for_prelu".format(input_name)},
outputs=[prelu_name, "{}_prelu".format(input_name)],
num_parameters=c,
weight_attr=string(param_name))
transpose1 = PaddleLayer(
id=layer_id_list[-1] + "_3",
kernel="paddle.transpose",
inputs={"x": "{}_prelu".format(input_name)},
outputs=[output_name],
perm=[0, 2, 3, 1])
return [transpose0, prelu, transpose1], layer_id_list[-1]
......@@ -41,6 +41,7 @@ class GraphOptimizer(object):
self.passes = [
"dygraph_conv2d_add_fuse_pass",
"dygraph_tf_batchnorm_fuse_pass",
"dygraph_prelu_fuse_pass",
"transpose_eliminate_pass"
]
else:
......
......@@ -20,10 +20,12 @@ class BatchNormOpt:
input_ids0 = graph.edges_in[layer_id]
mul_layer0 = graph.layers[input_ids0[0]]
sub_layer0 = graph.layers[input_ids0[1]]
if mul_layer0.kernel != "fluid.layers.elementwise_mul":
continue
if sub_layer0.kernel != "fluid.layers.elementwise_sub":
continue
axis = mul_layer0.attrs.get('axis', -1)
if axis != -1 and axis != 3:
continue
......@@ -116,7 +118,7 @@ class BatchNormOpt:
other = graph.layers[input_ids6[1]]
if variance.kernel != "fluid.layers.create_parameter":
continue
if other.kernel != "fluid.layers.create_parameter":
if other.kernel != "fluid.layers.fill_constant":
continue
if len(graph.edges_out.get(input_ids6[0], [])) != 1:
continue
......@@ -127,10 +129,6 @@ class BatchNormOpt:
variance_shape = graph.parameters[variance.outputs[0]].shape
if variance_shape != beta_shape:
continue
if other.outputs[0] not in graph.parameters:
continue
if graph.parameters[other.outputs[0]].size != 1:
continue
ids = set([
layer_id, mul_layer0.id, sub_layer0.id, mul_layer1.id, beta.id,
......@@ -163,7 +161,7 @@ class BatchNormOpt:
kernel="fluid.layers.batch_norm",
inputs={"input": "transpose_for_bn"},
outputs=layer.outputs,
epsilon=graph.parameters[other.outputs[0]],
epsilon=other.attrs["value"],
param_attr="'{}'".format(gamma.outputs[0]),
bias_attr="'{}'".format(beta.outputs[0]),
moving_mean_name="'{}'".format(mean.outputs[0]),
......
import copy
import numpy as np
from collections import OrderedDict
from x2paddle.core.program import PaddleLayer
from x2paddle.core.util import *
class PReLUOpt:
def __init__(self):
pass
def run(self, graph):
print("Optimize: PReLUOpt...")
layers = copy.deepcopy(graph.layers)
for layer_id, layer in layers.items():
if layer.kernel != "fluid.layers.elementwise_add":
continue
axis = layer.attrs.get('axis', -1)
if axis != -1 and axis != 3:
continue
input_ids0 = graph.edges_in[layer_id]
relu_layer0 = graph.layers[input_ids0[0]]
mul_layer0 = graph.layers[input_ids0[1]]
if relu_layer0.kernel != "fluid.layers.relu":
continue
if mul_layer0.kernel != "fluid.layers.elementwise_mul":
continue
axis = mul_layer0.attrs.get('axis', -1)
if axis != -1 and axis != 3:
continue
if len(graph.edges_out.get(input_ids0[0], [])) != 1:
continue
if len(graph.edges_out.get(input_ids0[1], [])) != 1:
continue
input_ids1_0 = graph.edges_in[input_ids0[0]]
input_ids1_1 = graph.edges_in[input_ids0[1]]
fill_layer = graph.layers[input_ids1_1[1]]
mul_layer1 = graph.layers[input_ids1_1[0]]
if fill_layer.kernel != "fluid.layers.fill_constant":
continue
if mul_layer1.kernel != "fluid.layers.elementwise_mul":
continue
axis = mul_layer1.attrs.get('axis', -1)
if axis != -1 and axis != 0:
continue
if len(graph.edges_out.get(input_ids1_1[1], [])) != 1:
continue
if len(graph.edges_out.get(input_ids1_0[0], [])) != 3:
continue
input_ids2 = graph.edges_in[input_ids1_1[0]]
alpha = graph.layers[input_ids2[0]]
sub_layer = graph.layers[input_ids2[1]]
if alpha.kernel != "fluid.layers.create_parameter":
continue
if sub_layer.kernel != "fluid.layers.elementwise_sub":
continue
axis = sub_layer.attrs.get('axis', -1)
if axis != -1 and axis != 3:
continue
if len(graph.edges_out.get(input_ids2[0], [])) != 1:
continue
if len(graph.edges_out.get(input_ids2[1], [])) != 1:
continue
if alpha.outputs[0] not in graph.parameters:
continue
input_ids3 = graph.edges_in[input_ids2[1]]
add_layer = graph.layers[input_ids3[0]]
abs_layer = graph.layers[input_ids3[1]]
if abs_layer.kernel != "fluid.layers.abs":
continue
if len(graph.edges_out.get(input_ids3[1], [])) != 1:
continue
ids = set([
layer.id, relu_layer0.id, mul_layer0.id, fill_layer.id, mul_layer1.id, alpha.id,
sub_layer.id, abs_layer.id])
for id in ids:
del graph.layers[id]
if id in graph.edges_in:
del graph.edges_in[id]
if id in graph.edges_out:
del graph.edges_out[id]
copy_layers = copy.deepcopy(graph.layers)
graph.layers = OrderedDict()
for k, v in copy_layers.items():
if k != add_layer.id:
graph.layers[k] = v
continue
graph.layers[k] = v
transpose0 = PaddleLayer(
id='{}_1'.format(k),
kernel="fluid.layers.transpose",
inputs={"x": v.outputs[0]},
outputs=["transpose_for_prelu"],
perm=[0, 3, 1, 2])
prelu = PaddleLayer(
id='{}_2'.format(k),
kernel="fluid.layers.prelu",
inputs={"x": "transpose_for_prelu"},
outputs=layer.outputs,
mode=string("channel"),
param_attr="'{}'".format(alpha.outputs[0]))
transpose1 = PaddleLayer(
id=layer_id,
kernel="fluid.layers.transpose",
inputs={"x": layer.outputs[0]},
outputs=layer.outputs,
perm=[0, 2, 3, 1])
graph.layers[transpose0.id] = transpose0
graph.layers[prelu.id] = prelu
graph.layers[transpose1.id] = transpose1
graph.parameters[alpha.outputs[0]] = np.expand_dims(graph.parameters[alpha.outputs[0]], axis=(0, 2, 3))
graph.build()
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册