diff --git a/x2paddle/convert.py b/x2paddle/convert.py index 857856fcd50de4ed63fdf337e77fafcda55b8f5b..b52aefbb7c16874f5ad968d6670f65e550ecce0e 100644 --- a/x2paddle/convert.py +++ b/x2paddle/convert.py @@ -128,19 +128,25 @@ def tf2paddle(model_path, else: from x2paddle.op_mapper.static.tf2paddle.tf_op_mapper import TFOpMapper - from x2paddle.optimizer.tensorflow.bias import BiasOpt - from x2paddle.optimizer.tensorflow.transpose import TransposeOpt - from x2paddle.optimizer.tensorflow.batch_norm import BatchNormOpt + print("Now translating model from tensorflow to paddle.") model = TFDecoder(model_path, define_input_shape=define_input_shape) mapper = TFOpMapper(model) mapper.paddle_graph.build() - bias_opt = BiasOpt() - transpose_opt = TransposeOpt() - batch_norm_opt = BatchNormOpt() - bias_opt.run(program) - batch_norm_opt.run(program) - transpose_opt.run(program) + if paddle_type == "dygraph": + from x2paddle.optimizer.optimizer import GraphOptimizer + graph_opt = GraphOptimizer(source_frame="tf", paddle_type=paddle_type) + graph_opt.optimize(mapper.paddle_graph) + else: + from x2paddle.optimizer.tensorflow.bias import BiasOpt + from x2paddle.optimizer.tensorflow.transpose import TransposeOpt + from x2paddle.optimizer.tensorflow.batch_norm import BatchNormOpt + bias_opt = BiasOpt() + transpose_opt = TransposeOpt() + batch_norm_opt = BatchNormOpt() + bias_opt.run(program) + batch_norm_opt.run(program) + transpose_opt.run(program) mapper.paddle_graph.gen_model(save_dir) diff --git a/x2paddle/optimizer/__pycache__/__init__.cpython-37.pyc b/x2paddle/optimizer/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ca446d3b764e697952128ef0e6521418ec983c70 Binary files /dev/null and b/x2paddle/optimizer/__pycache__/__init__.cpython-37.pyc differ diff --git a/x2paddle/optimizer/__pycache__/optimizer.cpython-37.pyc b/x2paddle/optimizer/__pycache__/optimizer.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9515ac170885096ddc66e6e0521b95ea0abb8210 Binary files /dev/null and b/x2paddle/optimizer/__pycache__/optimizer.cpython-37.pyc differ diff --git a/x2paddle/optimizer/__pycache__/pass_.cpython-37.pyc b/x2paddle/optimizer/__pycache__/pass_.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..29bad22565afd2c285dcc7d618002cf977857135 Binary files /dev/null and b/x2paddle/optimizer/__pycache__/pass_.cpython-37.pyc differ diff --git a/x2paddle/optimizer/__pycache__/pass_manager.cpython-37.pyc b/x2paddle/optimizer/__pycache__/pass_manager.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d9e3e2a06dd25f50fec45584fed01413415e6943 Binary files /dev/null and b/x2paddle/optimizer/__pycache__/pass_manager.cpython-37.pyc differ diff --git a/x2paddle/optimizer/__pycache__/pattern_matcher.cpython-37.pyc b/x2paddle/optimizer/__pycache__/pattern_matcher.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a8b5c8f598d54b0fbd5edfac0b3cbb5ebd9d3f8d Binary files /dev/null and b/x2paddle/optimizer/__pycache__/pattern_matcher.cpython-37.pyc differ diff --git a/x2paddle/optimizer/elimination/__init__.py b/x2paddle/optimizer/elimination/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/x2paddle/optimizer/elimination/__pycache__/__init__.cpython-37.pyc b/x2paddle/optimizer/elimination/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..61c937cb3a1cddc6660c3465133dbb4d94fbafdc Binary files /dev/null and b/x2paddle/optimizer/elimination/__pycache__/__init__.cpython-37.pyc differ diff --git a/x2paddle/optimizer/elimination/dygraph/__init__.py b/x2paddle/optimizer/elimination/dygraph/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..8c0e3576f3ad115f12bb859bdb1a334f2a201add --- /dev/null +++ b/x2paddle/optimizer/elimination/dygraph/__init__.py @@ -0,0 +1,16 @@ +# 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 .transpose_elimination import Dygraph_TransposeElimination +from .transpose_eliminate_pass import Dygraph_TransposeEliminatePass \ No newline at end of file diff --git a/x2paddle/optimizer/elimination/dygraph/__pycache__/__init__.cpython-37.pyc b/x2paddle/optimizer/elimination/dygraph/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ac8c811c3e2471872225cc3747df7011039de931 Binary files /dev/null and b/x2paddle/optimizer/elimination/dygraph/__pycache__/__init__.cpython-37.pyc differ diff --git a/x2paddle/optimizer/elimination/dygraph/__pycache__/transpose_eliminate_pass.cpython-37.pyc b/x2paddle/optimizer/elimination/dygraph/__pycache__/transpose_eliminate_pass.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6ad4f293a055ef6dfc95e94179415351dc25fa52 Binary files /dev/null and b/x2paddle/optimizer/elimination/dygraph/__pycache__/transpose_eliminate_pass.cpython-37.pyc differ diff --git a/x2paddle/optimizer/elimination/dygraph/__pycache__/transpose_elimination.cpython-37.pyc b/x2paddle/optimizer/elimination/dygraph/__pycache__/transpose_elimination.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0a609613ed0be3f99345c2d383a0b95a4a4e591f Binary files /dev/null and b/x2paddle/optimizer/elimination/dygraph/__pycache__/transpose_elimination.cpython-37.pyc differ diff --git a/x2paddle/optimizer/elimination/dygraph/transpose_eliminate_pass.py b/x2paddle/optimizer/elimination/dygraph/transpose_eliminate_pass.py new file mode 100644 index 0000000000000000000000000000000000000000..c60f0344ae147cae0797ee16cfe004c3758d3ba0 --- /dev/null +++ b/x2paddle/optimizer/elimination/dygraph/transpose_eliminate_pass.py @@ -0,0 +1,33 @@ +# 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.elimination.dygraph import Dygraph_TransposeElimination +from x2paddle.optimizer.pass_manager import pass_register + + +@pass_register +class Dygraph_TransposeEliminatePass(Pass): + name = "transpose_eliminate_pass" + + def __init__(self): + Pass.__init__(self) + + def apply(self, graph): + fuser = Dygraph_TransposeElimination() + fuser.operate(graph) + + +# 用于注册 +transpose_eliminate_pass = Dygraph_TransposeEliminatePass() \ No newline at end of file diff --git a/x2paddle/optimizer/elimination/dygraph/transpose_elimination.py b/x2paddle/optimizer/elimination/dygraph/transpose_elimination.py new file mode 100644 index 0000000000000000000000000000000000000000..8ac5c26b8cd801bc675b5fd167c298ac578039b3 --- /dev/null +++ b/x2paddle/optimizer/elimination/dygraph/transpose_elimination.py @@ -0,0 +1,276 @@ +# 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 x2paddle.optimizer.pattern_matcher import FuseBase +from x2paddle.core.program import PaddleGraph, PaddleLayer +from x2paddle.core.util import * + + +class Dygraph_TransposeElimination(FuseBase): + def __init__(self): + super(Dygraph_TransposeElimination, self).__init__(graph_type="dygraph") + self.direct_layers = [ + 'paddle.nn.ReLU', 'paddle.nn.ReLU6', 'paddle.abs', + 'paddle.nn.Sigmoid', 'paddle.exp', 'paddle.rsqrt', + 'paddle.nn.Swish', 'paddle.nn.Tanh', + 'paddle.nn.Softplus', 'paddle.nn.LeakyReLU', + 'paddle.nn.Softmax', 'paddle.erf', 'paddle.square' + ] + self.elementwise_layers = [ + 'paddle.add', 'fluid.layers.elementwise_sub', + 'paddle.multiply', 'paddle.divide' + ] + # self.reduce_layers = [] + self.reduce_layers = [ + 'paddle.mean', 'paddle.all', + 'paddle.max', 'paddle.any', + 'paddle.sum', 'paddle.prod' + ] + + def get_transpose_num(self, graph): + count = 0 + for layer_id, layer in graph.layers.items(): + if layer.kernel == "paddle.transpose": + count += 1 + return count + + def operate(self, graph): + total_layer_num = len(graph.layers) + scanned_layers = set() + optimized_transpose_layers = list() + optimized_reduce_layers = list() + optimized_concat_layers = list() + optimized_elementwise_layers = list() + + def strip_transpose(_graph): + layers = copy.deepcopy(_graph.layers) + for layer_id, layer in layers.items(): + if layer_id in scanned_layers: + continue + scanned_layers.add(layer_id) + percent = round(len(scanned_layers) / total_layer_num * 100, 2) + print("\rOptimize Transpose Layers...{}%".format( + percent)) + + if layer.kernel != "paddle.transpose": + continue + if layer.attrs["perm"] != [0, 2, 3, 1]: + continue + transpose_layers = list() + propagate_layers = list() + reduce_layers = list() + concat_layers = list() + # 此elementwise_layers专用于存储shape(4) + shape(1)的形式layer + elementwise_layers = list() + can_be_optimized = True + for out in _graph.edges_out.get(layer_id, []): + if _graph.layers[out].kernel == "paddle.transpose": + if _graph.layers[out].attrs["perm"] != [0, 3, 1, 2]: + can_be_optimized = False + break + transpose_layers.append(out) + elif _graph.layers[out].kernel in self.elementwise_layers: + propagate_layers.append(out) + elif _graph.layers[out].kernel in self.direct_layers: + ouput_index = 1 if _graph.layers[out].kernel.startswith("paddle.nn.") else 0 + if _graph.layers[out].outputs[ouput_index] in _graph.outputs: + can_be_optimized = False + break + propagate_layers.append(out) + elif _graph.layers[out].kernel in self.reduce_layers: + if _graph.layers[out].outputs[0] in _graph.outputs: + can_be_optimized = False + break + if not _graph.layers[out].attrs.get('keepdim', False): + can_be_optimized = False + break + propagate_layers.append(out) + reduce_layers.append(out) + elif _graph.layers[out].kernel == "paddle.concat": + if _graph.layers[out].outputs[0] in _graph.outputs: + can_be_optimized = False + break + propagate_layers.append(out) + concat_layers.append(out) + else: + can_be_optimized = False + break + + visited_layers = set() + while len(propagate_layers) > 0 and can_be_optimized: + current_id = propagate_layers.pop(0) + visited_layers.add(current_id) + for out in _graph.edges_out.get(current_id, []): + if _graph.layers[ + out].kernel == "paddle.transpose": + if _graph.layers[out].attrs["perm"] != [0, 3, 1, 2]: + can_be_optimized = False + break + transpose_layers.append(out) + elif _graph.layers[ + out].kernel in self.elementwise_layers: + if _graph.layers[out].outputs[0] in _graph.outputs: + can_be_optimized = False + break + if out not in visited_layers: + propagate_layers.append(out) + elif _graph.layers[out].kernel in self.direct_layers: + ouput_index = 1 if _graph.layers[out].kernel.startswith("paddle.nn.") else 0 + if _graph.layers[out].outputs[ouput_index] in _graph.outputs: + can_be_optimized = False + break + if out not in visited_layers: + propagate_layers.append(out) + elif _graph.layers[out].kernel in self.reduce_layers: + if _graph.layers[out].outputs[0] in _graph.outputs: + can_be_optimized = False + break + if not _graph.layers[out].attrs.get('keepdim', + False): + can_be_optimized = False + break + if out not in visited_layers: + propagate_layers.append(out) + reduce_layers.append(out) + elif _graph.layers[out].kernel == "paddle.concat": + if _graph.layers[out].outputs[0] in _graph.outputs: + can_be_optimized = False + break + if out not in visited_layers: + propagate_layers.append(out) + concat_layers.append(out) + else: + can_be_optimized = False + break + for ipt in _graph.edges_in.get(current_id, []): + if _graph.layers[ + current_id].kernel in self.elementwise_layers: + try: + x_shape = _graph.layers[ + current_id].input_shapes['x'] + y_shape = _graph.layers[ + current_id].input_shapes['y'] + if _graph.layers[ipt].outputs[ + 0] == _graph.layers[current_id].inputs[ + 'x']: + if len(x_shape) <= 1: + elementwise_layers.append(current_id) + continue + elif _graph.layers[ipt].outputs[ + 0] == _graph.layers[current_id].inputs[ + 'y']: + if len(y_shape) <= 1: + elementwise_layers.append(current_id) + continue + else: + raise Exception( + "Unexcepted situation happend while optimizing transpose" + ) + except Exception as e: + can_be_optimized = False + break + if _graph.layers[ + ipt].kernel == "paddle.transpose": + if _graph.layers[ipt].attrs["perm"] != [0, 2, 3, 1]: + can_be_optimized = False + break + if ipt not in visited_layers: + transpose_layers.append(ipt) + elif _graph.layers[ + ipt].kernel in self.elementwise_layers: + if _graph.layers[ipt].outputs[0] in _graph.outputs: + can_be_optimized = False + break + if ipt not in visited_layers: + propagate_layers.append(ipt) + elif _graph.layers[ipt].kernel in self.direct_layers: + ouput_index = 1 if _graph.layers[ipt].kernel.startswith("paddle.nn.") else 0 + if _graph.layers[ipt].outputs[ouput_index] in _graph.outputs: + can_be_optimized = False + break + if ipt not in visited_layers: + propagate_layers.append(ipt) + elif _graph.layers[ipt].kernel in self.reduce_layers: + if _graph.layers[ipt].outputs[0] in _graph.outputs: + can_be_optimized = False + break + if not _graph.layers[ipt].attrs.get('keepdim', + False): + can_be_optimized = False + break + if ipt not in visited_layers: + propagate_layers.append(ipt) + reduce_layers.append(ipt) + elif _graph.layers[ipt].kernel == "paddle.concat": + if _graph.layers[ipt].outputs[0] in _graph.outputs: + can_be_optimized = False + break + if ipt not in visited_layers: + propagate_layers.append(ipt) + concat_layers.append(ipt) + else: + can_be_optimized = False + break + if not can_be_optimized: + break + if not can_be_optimized: + continue + + transpose_layers.append(layer_id) + transpose_layers = list(set(transpose_layers)) + for l in transpose_layers: + if graph.layers[l].outputs[0] in graph.outputs: + can_be_optimized = False + break + if not can_be_optimized: + continue + + for l in transpose_layers: + self.delete_layer_with_associated(_graph, l) + + optimized_transpose_layers.extend(transpose_layers) + optimized_reduce_layers.extend(reduce_layers) + optimized_concat_layers.extend(concat_layers) + optimized_elementwise_layers.extend(elementwise_layers) + return True + return False + + before_transpose_num = self.get_transpose_num(graph) + opt_graph = copy.deepcopy(graph) + total_layer_num = len(opt_graph.layers) + + while strip_transpose(opt_graph): + pass + + for layer_id in list(set(optimized_transpose_layers)): + self.delete_layer_with_associated(graph, layer_id) + for layer_id in list(set(optimized_reduce_layers)): + dim = graph.layers[layer_id].attrs.get('dim', None) + if dim is not None: + for i in range(len(dim)): + dim[i] = [0, 2, 3, 1][dim[i]] + graph.layers[layer_id].attrs['dim'] = dim + for layer_id in list(set(optimized_concat_layers)): + axis = graph.layers[layer_id].attrs.get('axis', 0) + graph.layers[layer_id].attrs['axis'] = [0, 2, 3, 1][axis] + for layer_id in list(set(optimized_elementwise_layers)): + axis = graph.layers[layer_id].attrs.get('axis', -1) + graph.layers[layer_id].attrs['axis'] = [0, 2, 3, 1][axis] + + current_transpose_num = self.get_transpose_num(graph) + print( + "\nTranspose layers optimized, before: transpose_num={}, after: transpose_num={}". + format(before_transpose_num, current_transpose_num)) diff --git a/x2paddle/optimizer/fusion/__pycache__/__init__.cpython-37.pyc b/x2paddle/optimizer/fusion/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..68d33562260803641aea99a589562e288659609a Binary files /dev/null and b/x2paddle/optimizer/fusion/__pycache__/__init__.cpython-37.pyc differ diff --git a/x2paddle/optimizer/fusion/dygraph/__init__.py b/x2paddle/optimizer/fusion/dygraph/__init__.py index 12764492204e7a3ea7d1815384370e1baeeea414..4bbcf483e4a30b73b780da37d852c1579153f6e5 100644 --- a/x2paddle/optimizer/fusion/dygraph/__init__.py +++ b/x2paddle/optimizer/fusion/dygraph/__init__.py @@ -20,6 +20,8 @@ from .bn_scale_fuser import Dygraph_BNScaleFuser from .bn_scale_fuse_pass import Dygraph_BNScaleFusePass from .constant_fuser import Dygraph_ConstantFuser from .constant_fuse_pass import Dygraph_ConstantFusePass +from .conv2d_add_fuser import Dygraph_Conv2D_AddFuser +from .conv2d_add_fuse_pass import Dygraph_Conv2D_AddFusePass from .dropout_fuser import Dygraph_DropoutFuser from .dropout_fuse_pass import Dygraph_DropoutFusePass from .fc_fuser import Dygraph_FcFuser @@ -28,3 +30,5 @@ from .interpolate_bilinear_fuser import Dygraph_InterpolateBilinearFuser from .interpolate_bilinear_fuse_pass import Dygraph_InterpolateBilinearFusePass from .reshape_fuser import Dygraph_ReshapeFuser from .reshape_fuse_pass import Dygraph_ReshapeFusePass +from .tf_batchnorm_fuser import Dygraph_TF_BatchNormFuser +from .tf_batchnorm_fuse_pass import Dygraph_TF_BatchNormFusePass diff --git a/x2paddle/optimizer/fusion/dygraph/__pycache__/__init__.cpython-37.pyc b/x2paddle/optimizer/fusion/dygraph/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4cca494b2fd65d17a698b810a259e38e71577d94 Binary files /dev/null and b/x2paddle/optimizer/fusion/dygraph/__pycache__/__init__.cpython-37.pyc differ diff --git a/x2paddle/optimizer/fusion/dygraph/__pycache__/adaptive_pool2d_fuse_pass.cpython-37.pyc b/x2paddle/optimizer/fusion/dygraph/__pycache__/adaptive_pool2d_fuse_pass.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8b5380ef4f02e956a3af14a24c3780805ea9d3a9 Binary files /dev/null and b/x2paddle/optimizer/fusion/dygraph/__pycache__/adaptive_pool2d_fuse_pass.cpython-37.pyc differ diff --git a/x2paddle/optimizer/fusion/dygraph/__pycache__/adaptive_pool2d_fuser.cpython-37.pyc b/x2paddle/optimizer/fusion/dygraph/__pycache__/adaptive_pool2d_fuser.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2ba78663f8229a5755d98b764a792bba94532455 Binary files /dev/null and b/x2paddle/optimizer/fusion/dygraph/__pycache__/adaptive_pool2d_fuser.cpython-37.pyc differ diff --git a/x2paddle/optimizer/fusion/dygraph/__pycache__/batchnorm2d_fuse_pass.cpython-37.pyc b/x2paddle/optimizer/fusion/dygraph/__pycache__/batchnorm2d_fuse_pass.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a27d176022bea80695ed1c38a970b4fcbf002753 Binary files /dev/null and b/x2paddle/optimizer/fusion/dygraph/__pycache__/batchnorm2d_fuse_pass.cpython-37.pyc differ diff --git a/x2paddle/optimizer/fusion/dygraph/__pycache__/batchnorm2d_fuser.cpython-37.pyc b/x2paddle/optimizer/fusion/dygraph/__pycache__/batchnorm2d_fuser.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..87f85018b34020a79081d658fe1d29dfcf40cb2a Binary files /dev/null and b/x2paddle/optimizer/fusion/dygraph/__pycache__/batchnorm2d_fuser.cpython-37.pyc differ diff --git a/x2paddle/optimizer/fusion/dygraph/__pycache__/bn_scale_fuse_pass.cpython-37.pyc b/x2paddle/optimizer/fusion/dygraph/__pycache__/bn_scale_fuse_pass.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4e23945af42f930c88de2ed7dd5994d09a32397b Binary files /dev/null and b/x2paddle/optimizer/fusion/dygraph/__pycache__/bn_scale_fuse_pass.cpython-37.pyc differ diff --git a/x2paddle/optimizer/fusion/dygraph/__pycache__/bn_scale_fuser.cpython-37.pyc b/x2paddle/optimizer/fusion/dygraph/__pycache__/bn_scale_fuser.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d3e34bc8b2bce3fd8f0efa7325c4d566f782e825 Binary files /dev/null and b/x2paddle/optimizer/fusion/dygraph/__pycache__/bn_scale_fuser.cpython-37.pyc differ diff --git a/x2paddle/optimizer/fusion/dygraph/__pycache__/constant_fuse_pass.cpython-37.pyc b/x2paddle/optimizer/fusion/dygraph/__pycache__/constant_fuse_pass.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8e49bf6f83ede19ba0d38aa6862ff0290ad33f01 Binary files /dev/null and b/x2paddle/optimizer/fusion/dygraph/__pycache__/constant_fuse_pass.cpython-37.pyc differ diff --git a/x2paddle/optimizer/fusion/dygraph/__pycache__/constant_fuser.cpython-37.pyc b/x2paddle/optimizer/fusion/dygraph/__pycache__/constant_fuser.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dc9fce845563df7b10eac9f83303bb93a490de0f Binary files /dev/null and b/x2paddle/optimizer/fusion/dygraph/__pycache__/constant_fuser.cpython-37.pyc differ diff --git a/x2paddle/optimizer/fusion/dygraph/__pycache__/conv2d_add_fuse_pass.cpython-37.pyc b/x2paddle/optimizer/fusion/dygraph/__pycache__/conv2d_add_fuse_pass.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..29cd8df57ad0191b25aa886e6f159994c38a4c12 Binary files /dev/null and b/x2paddle/optimizer/fusion/dygraph/__pycache__/conv2d_add_fuse_pass.cpython-37.pyc differ diff --git a/x2paddle/optimizer/fusion/dygraph/__pycache__/conv2d_add_fuser.cpython-37.pyc b/x2paddle/optimizer/fusion/dygraph/__pycache__/conv2d_add_fuser.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c1542685c5c5cba7f5c6693239852afcb589f363 Binary files /dev/null and b/x2paddle/optimizer/fusion/dygraph/__pycache__/conv2d_add_fuser.cpython-37.pyc differ diff --git a/x2paddle/optimizer/fusion/dygraph/__pycache__/dropout_fuse_pass.cpython-37.pyc b/x2paddle/optimizer/fusion/dygraph/__pycache__/dropout_fuse_pass.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..45423a23839a0cde1d526fb461de3384cb7017e4 Binary files /dev/null and b/x2paddle/optimizer/fusion/dygraph/__pycache__/dropout_fuse_pass.cpython-37.pyc differ diff --git a/x2paddle/optimizer/fusion/dygraph/__pycache__/dropout_fuser.cpython-37.pyc b/x2paddle/optimizer/fusion/dygraph/__pycache__/dropout_fuser.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fffac02b323126cfb0401d7e3b3f4be77cdeaedd Binary files /dev/null and b/x2paddle/optimizer/fusion/dygraph/__pycache__/dropout_fuser.cpython-37.pyc differ diff --git a/x2paddle/optimizer/fusion/dygraph/__pycache__/fc_fuse_pass.cpython-37.pyc b/x2paddle/optimizer/fusion/dygraph/__pycache__/fc_fuse_pass.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f14c8cb37cb0f258c3eabb3efd48e77c27acdb91 Binary files /dev/null and b/x2paddle/optimizer/fusion/dygraph/__pycache__/fc_fuse_pass.cpython-37.pyc differ diff --git a/x2paddle/optimizer/fusion/dygraph/__pycache__/fc_fuser.cpython-37.pyc b/x2paddle/optimizer/fusion/dygraph/__pycache__/fc_fuser.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ca5925bbdce516b907721120f0dbe6ac106e69d5 Binary files /dev/null and b/x2paddle/optimizer/fusion/dygraph/__pycache__/fc_fuser.cpython-37.pyc differ diff --git a/x2paddle/optimizer/fusion/dygraph/__pycache__/interpolate_bilinear_fuse_pass.cpython-37.pyc b/x2paddle/optimizer/fusion/dygraph/__pycache__/interpolate_bilinear_fuse_pass.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..52454c10c9a7f0fd981f315ac11d4e0f98e20166 Binary files /dev/null and b/x2paddle/optimizer/fusion/dygraph/__pycache__/interpolate_bilinear_fuse_pass.cpython-37.pyc differ diff --git a/x2paddle/optimizer/fusion/dygraph/__pycache__/interpolate_bilinear_fuser.cpython-37.pyc b/x2paddle/optimizer/fusion/dygraph/__pycache__/interpolate_bilinear_fuser.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1abdfdb88802ce8c532dddf07b6ee81570e10824 Binary files /dev/null and b/x2paddle/optimizer/fusion/dygraph/__pycache__/interpolate_bilinear_fuser.cpython-37.pyc differ diff --git a/x2paddle/optimizer/fusion/dygraph/__pycache__/reshape_fuse_pass.cpython-37.pyc b/x2paddle/optimizer/fusion/dygraph/__pycache__/reshape_fuse_pass.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f0c278fdf16654ea2467c6aeecd344b6505616e3 Binary files /dev/null and b/x2paddle/optimizer/fusion/dygraph/__pycache__/reshape_fuse_pass.cpython-37.pyc differ diff --git a/x2paddle/optimizer/fusion/dygraph/__pycache__/reshape_fuser.cpython-37.pyc b/x2paddle/optimizer/fusion/dygraph/__pycache__/reshape_fuser.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cf9da6dee6e768ffb47b5d872154cf8d784dfa2e Binary files /dev/null and b/x2paddle/optimizer/fusion/dygraph/__pycache__/reshape_fuser.cpython-37.pyc differ diff --git a/x2paddle/optimizer/fusion/dygraph/__pycache__/tf_batchnorm_fuse_pass.cpython-37.pyc b/x2paddle/optimizer/fusion/dygraph/__pycache__/tf_batchnorm_fuse_pass.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..34b99e01000178accba564a4fae84a7dc0e234e5 Binary files /dev/null and b/x2paddle/optimizer/fusion/dygraph/__pycache__/tf_batchnorm_fuse_pass.cpython-37.pyc differ diff --git a/x2paddle/optimizer/fusion/dygraph/__pycache__/tf_batchnorm_fuser.cpython-37.pyc b/x2paddle/optimizer/fusion/dygraph/__pycache__/tf_batchnorm_fuser.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ddaf25b05aa161d0e39654c0f39b4ad92b0a6dc1 Binary files /dev/null and b/x2paddle/optimizer/fusion/dygraph/__pycache__/tf_batchnorm_fuser.cpython-37.pyc differ diff --git a/x2paddle/optimizer/fusion/dygraph/conv2d_add_fuse_pass.py b/x2paddle/optimizer/fusion/dygraph/conv2d_add_fuse_pass.py new file mode 100644 index 0000000000000000000000000000000000000000..8d796e94f1e328355657301b99def2d6ff603287 --- /dev/null +++ b/x2paddle/optimizer/fusion/dygraph/conv2d_add_fuse_pass.py @@ -0,0 +1,33 @@ +# 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 Dygraph_Conv2D_AddFuser +from x2paddle.optimizer.pass_manager import pass_register + + +@pass_register +class Dygraph_Conv2D_AddFusePass(Pass): + name = "dygraph_conv2d_add_fuse_pass" + + def __init__(self): + Pass.__init__(self) + + def apply(self, graph): + fuser = Dygraph_Conv2D_AddFuser() + fuser.operate(graph, match_kind="edge") + + +# 用于注册 +dygraph_conv2d_add_fuse_pass = Dygraph_Conv2D_AddFusePass() \ No newline at end of file diff --git a/x2paddle/optimizer/fusion/dygraph/conv2d_add_fuser.py b/x2paddle/optimizer/fusion/dygraph/conv2d_add_fuser.py new file mode 100644 index 0000000000000000000000000000000000000000..6d34621d64887f51964f5b18a3b2df115d857e1e --- /dev/null +++ b/x2paddle/optimizer/fusion/dygraph/conv2d_add_fuser.py @@ -0,0 +1,119 @@ +# 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 x2paddle.optimizer.pattern_matcher import FuseBase +from x2paddle.core.program import PaddleGraph, PaddleLayer +from x2paddle.core.util import * + + +class Dygraph_Conv2D_AddFuser(FuseBase): + def __init__(self): + super(Dygraph_Conv2D_AddFuser, self).__init__(graph_type="dygraph") + self.patterns = list() + + def build_pattern(self): + """ 描述需要替换的conv2d+add图结构。 + conv2d+add层模式python实现代码示例: + 模式一: + MobilenetV1_Logits_Conv2d_1c_1x1_biases = self.MobilenetV1_Logits_Conv2d_1c_1x1_biases + conv2d_transpose_14 = paddle.transpose(x=MobilenetV1_Logits_AvgPool_1a_AvgPool, perm=[0, 3, 1, 2]) + MobilenetV1_Logits_Conv2d_1c_1x1_Conv2D = self.conv27(conv2d_transpose_14) + MobilenetV1_Logits_Conv2d_1c_1x1_Conv2D = paddle.transpose(x=MobilenetV1_Logits_Conv2d_1c_1x1_Conv2D, perm=[0, 2, 3, 1]) + MobilenetV1_Logits_Conv2d_1c_1x1_BiasAdd = paddle.add(x=MobilenetV1_Logits_Conv2d_1c_1x1_Conv2D, y=MobilenetV1_Logits_Conv2d_1c_1x1_biases) + 模式二: + MobilenetV1_Logits_Conv2d_1c_1x1_biases = self.MobilenetV1_Logits_Conv2d_1c_1x1_biases + MobilenetV1_Logits_Conv2d_1c_1x1_Conv2D = self.conv27(conv2d_transpose_14) + MobilenetV1_Logits_Conv2d_1c_1x1_BiasAdd = paddle.add(x=MobilenetV1_Logits_Conv2d_1c_1x1_Conv2D, y=MobilenetV1_Logits_Conv2d_1c_1x1_biases) + """ + + def gen_name(id): + return "x" + str(id) + + pattern = PaddleGraph(graph_type="dygraph") + pattern.add_layer( + "self.create_parameter", + inputs={}, + outputs=[gen_name(0)]) + pattern.add_layer( + kernel="paddle.transpose", + inputs={"x": "conv-input-0"}, + outputs=[gen_name(1)], + perm=[0, 3, 1, 2]) + pattern.add_layer( + kernel="paddle.nn.Conv2D", + inputs={"input": gen_name(1)}, + outputs=[gen_name(2)]) + pattern.add_layer( + kernel="paddle.transpose", + inputs={"x": gen_name(2)}, + outputs=[gen_name(2)], + perm=[0, 2, 3, 1]) + pattern.add_layer( + kernel="paddle.add", + inputs={"x": gen_name(2), + "y": gen_name(0)}, + outputs=[gen_name(3)]) + pattern.build(inputs={"input-0": "conv-input-0", }) + self.patterns.append(pattern) + + pattern = PaddleGraph(graph_type="dygraph") + pattern.add_layer( + "self.create_parameter", + inputs={}, + outputs=[gen_name(0)]) + pattern.add_layer( + kernel="paddle.nn.Conv2D", + inputs={"input": "conv-input-0"}, + outputs=[gen_name(1)]) + pattern.add_layer( + kernel="paddle.add", + inputs={"x": gen_name(1), + "y": gen_name(0)}, + outputs=[gen_name(2)]) + pattern.build(inputs={"input-0": "conv-input-0", }) + self.patterns.append(pattern) + + def insert_new_layer(self, graph, parameters, matches): + self.gen_new_layer(matches, graph) + matches_copy = copy.deepcopy(matches) + for layer_id, layer in matches_copy.items(): + if layer.kernel not in ["self.create_parameter", "paddle.add"]: + matches.pop(layer_id) + + def gen_new_layer(self, matches, graph): + is_transpose = False + for layer_id, layer in matches.items(): + if layer.kernel == "self.create_parameter": + bias_name = layer.attrs["attr"] + if layer.kernel == "paddle.transpose": + is_transpose = True + if layer.kernel == "paddle.add": + output_name = layer.outputs[0] + if layer.kernel == "paddle.nn.Conv2D": + conv_id = layer_id + for layer_id, layer in matches.items(): + if layer.kernel == "paddle.nn.functional.conv2d_transpose": + layer.bias = bias_name + if not is_transpose: + layer.outputs[0] = output_name + if layer.kernel == "paddle.nn.Conv2D": + layer.attrs["bias_attr"] = bias_name + if not is_transpose: + layer.outputs[1] = output_name + if layer.kernel == "paddle.transpose": + if conv_id in graph.edges_in[layer_id]: + layer.outputs[0] = output_name + diff --git a/x2paddle/optimizer/fusion/dygraph/tf_batchnorm_fuse_pass.py b/x2paddle/optimizer/fusion/dygraph/tf_batchnorm_fuse_pass.py new file mode 100644 index 0000000000000000000000000000000000000000..52265fb598bab2ed2f15a9ac999e7e2374426349 --- /dev/null +++ b/x2paddle/optimizer/fusion/dygraph/tf_batchnorm_fuse_pass.py @@ -0,0 +1,33 @@ +# 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 Dygraph_TF_BatchNormFuser +from x2paddle.optimizer.pass_manager import pass_register + + +@pass_register +class Dygraph_TF_BatchNormFusePass(Pass): + name = "dygraph_tf_batchnorm_fuse_pass" + + def __init__(self): + Pass.__init__(self) + + def apply(self, graph): + fuser = Dygraph_TF_BatchNormFuser() + fuser.operate(graph, match_kind="edge") + + +# 用于注册 +dygraph_tf_batchnorm_fuse_pass = Dygraph_TF_BatchNormFusePass() \ No newline at end of file diff --git a/x2paddle/optimizer/fusion/dygraph/tf_batchnorm_fuser.py b/x2paddle/optimizer/fusion/dygraph/tf_batchnorm_fuser.py new file mode 100644 index 0000000000000000000000000000000000000000..e7391217c73401bd855ce1f523087f24bfd0253a --- /dev/null +++ b/x2paddle/optimizer/fusion/dygraph/tf_batchnorm_fuser.py @@ -0,0 +1,172 @@ +# 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 Dygraph_TF_BatchNormFuser(FuseBase): + def __init__(self): + self.bn_index = 0 + super(Dygraph_TF_BatchNormFuser, self).__init__(graph_type="dygraph") + + def build_pattern(self): + """ 描述需要替换的batchnorm图结构。 + batchnorm层模式python实现代码示例: + + """ + + 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]) + self.pattern.add_layer( + "paddle.add", + inputs={"x": gen_name(0), "y": gen_name(1)}, + outputs=[gen_name(2)]) + self.pattern.add_layer( + "paddle.rsqrt", + inputs={"x": gen_name(2)}, + outputs=[gen_name(3)]) + self.pattern.add_layer( + "self.create_parameter", + inputs={}, + outputs=[gen_name(4)]) + self.pattern.add_layer( + "paddle.multiply", + inputs={"x": gen_name(3), "y": gen_name(4)}, + outputs=[gen_name(5)]) + self.pattern.add_layer( + "self.create_parameter", + inputs={}, + outputs=[gen_name(6)]) + self.pattern.add_layer( + "paddle.multiply", + inputs={"x": gen_name(6), "y": gen_name(5)}, + outputs=[gen_name(7)]) + self.pattern.add_layer( + "self.create_parameter", + inputs={}, + outputs=[gen_name(8)]) + self.pattern.add_layer( + "fluid.layers.elementwise_sub", + inputs={"x": gen_name(8), "y": gen_name(7)}, + outputs=[gen_name(9)]) + self.pattern.add_layer( + "paddle.multiply", + inputs={"x": "bn-input-0", "y": gen_name(5)}, + outputs=[gen_name(10)]) + self.pattern.add_layer( + "paddle.add", + inputs={"x": gen_name(10), "y": gen_name(9)}, + outputs=[gen_name(11)]) + self.pattern.build(inputs={"input-0": "bn-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.full": + full_layer = layer + out_layer_id = graph.edges_out[layer_id][0] + if matches[out_layer_id].kernel == "paddle.add": + var_layer_id = graph.edges_in[out_layer_id][0] + var_layer = matches[var_layer_id] + if layer.kernel == "paddle.rsqrt": + out_layer_id = graph.edges_out[layer_id][0] + if matches[out_layer_id].kernel == "paddle.multiply": + gamma_layer_id = graph.edges_in[out_layer_id][1] + gamma_layer = matches[gamma_layer_id] + if layer.kernel == "fluid.layers.elementwise_sub": + in_layer_id = graph.edges_in[layer_id][0] + beta_layer = matches[in_layer_id] + in_layer_id = graph.edges_in[layer_id][1] + in_layer_id = graph.edges_in[in_layer_id][0] + mean_layer = matches[in_layer_id] + out_layer_id = graph.edges_out[layer_id][0] + add_layer = matches[out_layer_id] + if layer.kernel == "paddle.multiply": + in_layer_id = graph.edges_in[layer_id][1] + mul_layer = matches[in_layer_id] + if mul_layer.kernel == "paddle.multiply": + in_layer_id = graph.edges_in[layer_id][0] + if in_layer_id not in matches: + input_name = layer.inputs["x"] + transpose0 = PaddleLayer( + id=layer_id_list[-1] + "_1", + kernel="paddle.transpose", + inputs={"x": input_name}, + outputs=["{}_transpose_for_bn".format(input_name)], + perm=[0, 3, 1, 2]) + bn_name = "merge_bn{}".format(self.bn_index) + self.bn_index += 1 + params = parameters[gamma_layer.outputs[0]] + c = params.shape[0] + bn = PaddleLayer( + id=layer_id_list[-1] + "_2", + kernel="paddle.nn.BatchNorm", + inputs={"input": "{}_transpose_for_bn".format(input_name)}, + outputs=[bn_name, "{}_bn".format(input_name)], + num_channels=c, + epsilon=full_layer.attrs["fill_value"], + param_attr=string(gamma_layer.outputs[0]), + bias_attr=string(beta_layer.outputs[0]), + moving_mean_name=string(mean_layer.outputs[0]), + moving_variance_name=string(var_layer.outputs[0]), + is_test=True) + transpose1 = PaddleLayer( + id=layer_id_list[-1] + "_3", + kernel="paddle.transpose", + inputs={"x": "{}_bn".format(input_name)}, + outputs=add_layer.outputs, + perm=[0, 2, 3, 1]) + return [transpose0, bn, transpose1], layer_id_list[-1] + diff --git a/x2paddle/optimizer/fusion/static/__pycache__/__init__.cpython-37.pyc b/x2paddle/optimizer/fusion/static/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bc38809625f72dd47887e9556a56b091d81dc0a0 Binary files /dev/null and b/x2paddle/optimizer/fusion/static/__pycache__/__init__.cpython-37.pyc differ diff --git a/x2paddle/optimizer/fusion/static/__pycache__/bn_scale_fuse_pass.cpython-37.pyc b/x2paddle/optimizer/fusion/static/__pycache__/bn_scale_fuse_pass.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f45c17e9f43a5ff4f02e220d7f19e8d983ca2e6a Binary files /dev/null and b/x2paddle/optimizer/fusion/static/__pycache__/bn_scale_fuse_pass.cpython-37.pyc differ diff --git a/x2paddle/optimizer/fusion/static/__pycache__/bn_scale_fuser.cpython-37.pyc b/x2paddle/optimizer/fusion/static/__pycache__/bn_scale_fuser.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..06a4974a2bac54b6eecbbcc8ebf0ebbc3a8e9d50 Binary files /dev/null and b/x2paddle/optimizer/fusion/static/__pycache__/bn_scale_fuser.cpython-37.pyc differ diff --git a/x2paddle/optimizer/optimizer.py b/x2paddle/optimizer/optimizer.py index 173383a82596916986301cd5de902d95f85b662b..7e014bf0167f1f369d7cffa083a8ef0118361aa8 100644 --- a/x2paddle/optimizer/optimizer.py +++ b/x2paddle/optimizer/optimizer.py @@ -15,6 +15,7 @@ from x2paddle.optimizer.pass_manager import PassManager from x2paddle.optimizer.fusion.dygraph import * from x2paddle.optimizer.fusion.static import * +from x2paddle.optimizer.elimination.dygraph import * class GraphOptimizer(object): def __init__(self, source_frame, paddle_type="dygraph"): @@ -30,6 +31,12 @@ class GraphOptimizer(object): self.passes = ["dygraph_bn_scale_fuse_pass"] else: self.passes = ["static_bn_scale_fuse_pass"] + elif source_frame == "tf": + self.passes = [ + "dygraph_conv2d_add_fuse_pass", + "dygraph_tf_batchnorm_fuse_pass", + "transpose_eliminate_pass" + ] else: # TODO pass @@ -37,11 +44,14 @@ class GraphOptimizer(object): def optimize(self, graph): for pass_name in self.passes: pass_ = PassManager.lookup(pass_name)() - while True: - before_len = len(graph.layers) + if pass_name.endswith("_eliminate_pass"): pass_.apply(graph) - after_len = len(graph.layers) - if before_len == after_len: - break + else: + while True: + before_len = len(graph.layers) + pass_.apply(graph) + after_len = len(graph.layers) + if before_len == after_len: + break print("{} done!".format(pass_name)) return graph diff --git a/x2paddle/optimizer/pattern_matcher.py b/x2paddle/optimizer/pattern_matcher.py index c5b38b0f34242b0d1e462eeb5e9a55210432dc37..cc86025aa2dc4d98101689b975af2a654d8da7e9 100644 --- a/x2paddle/optimizer/pattern_matcher.py +++ b/x2paddle/optimizer/pattern_matcher.py @@ -19,6 +19,7 @@ class PatternMatcher(object): def __init__(self, pattern): self.pattern = pattern # matches的每个match是按照拓扑排序组成layer的dict + self.matches = list() def operate(self, graph, match_kind="topo"): @@ -154,7 +155,7 @@ class PatternMatcher(object): if len(block.layers) > 0: self.detect_patterns_by_topo(layer.blocks[j]) - def detect_patterns_by_edge(self, graph, ignore_list_inputs=True): + def detect_patterns_by_edge(self, graph): """当遇见顺序没有强制规定的pattern时使用该方式 """ @@ -163,8 +164,8 @@ class PatternMatcher(object): pattern_ids = list(pattern_id2layers.keys()) pattern_layer_id = pattern_ids[0] subgraph_id2layers = dict() - graph_layers = dict(list(graph.layers.items())[start_index:]) - layer_id = list(graph_layers.keys())[0] + layer_id = list(graph.layers.keys())[start_index] + graph_layers = graph.layers def update(layer_id, pattern_layer_id): layer = graph_layers[layer_id] @@ -172,14 +173,25 @@ class PatternMatcher(object): if layer.kernel != pattern_layer.kernel: return False subgraph_id2layers[layer_id] = layer - for i, pattern_layer_id_in in enumerate(pattern.edges_in[ - pattern_layer_id]): - if pattern_layer_id_in == -1 or ignore_list_inputs: - continue - layer_id_in = graph.edges_in[layer_id][i] - subgraph_ids = list(subgraph_id2layers.keys()) - if layer_id_in not in subgraph_ids: +# for k, v in subgraph_id2layers.items(): +# print(k) +# print(v.kernel) +# print(v.outputs) +# print("=========") + + if pattern.edges_in.get(pattern_layer_id, 0) != 0: + if len(pattern.edges_in[pattern_layer_id]) != \ + len(graph.edges_in[layer_id]): return False + for i, pattern_layer_id_in in enumerate(pattern.edges_in[ + pattern_layer_id]): + if pattern_layer_id_in == -1: + continue + if pattern_layer_id_in in pattern_ids: + new_layer_id_in = graph.edges_in[layer_id][i] + if new_layer_id_in in subgraph_id2layers: + continue + update(new_layer_id_in, pattern_layer_id_in) if pattern.edges_out.get(pattern_layer_id, 0) != 0: if len(pattern.edges_out[pattern_layer_id]) != \ len(graph.edges_out[layer_id]): @@ -188,17 +200,8 @@ class PatternMatcher(object): pattern_layer_id]): if pattern_layer_id_out in pattern_ids: new_layer_id_out = graph.edges_out[layer_id][i] - for j, new_new_layer_id_in in enumerate( - graph.edges_in[new_layer_id_out]): - if new_new_layer_id_in not in subgraph_id2layers: - if ignore_list_inputs: - continue - new_new_pattern_layer_id_in = pattern.edges_in[ - pattern_layer_id_out][j] - if new_new_pattern_layer_id_in == -1: - continue - update(new_new_layer_id_in, - new_new_pattern_layer_id_in) + if new_layer_id_out in subgraph_id2layers: + continue update(new_layer_id_out, pattern_layer_id_out) while len(subgraph_id2layers) != len(pattern_id2layers): @@ -258,6 +261,7 @@ def get_subgraph(prefix_layer_id, suffix_layer_id, graph): class FuseBase(object): def __init__(self, graph_type): self.pattern = PaddleGraph(graph_type=graph_type) + self.patterns = list() def operate(self, graph, match_kind="topo"): parameters = graph.parameters @@ -267,16 +271,22 @@ class FuseBase(object): first_layer_id = list(match.keys())[0] subgraph = get_subgraph("", first_layer_id, graph) self.insert_new_layer(subgraph, parameters, match) - self.delete_inter_layer(graph) + self.delete_layer(graph) graph.build() def perform_pattern_matcher(self, graph, match_kind="topo"): """ 执行模式匹配,找到匹配的子图。 """ - pattern_matcher = PatternMatcher(self.pattern) - self.matches = pattern_matcher.operate(graph, match_kind) + if len(self.patterns) > 0: + self.matches = list() + for pattern in self.patterns: + pattern_matcher = PatternMatcher(pattern) + self.matches.extend(pattern_matcher.operate(graph, match_kind)) + else: + pattern_matcher = PatternMatcher(self.pattern) + self.matches = pattern_matcher.operate(graph, match_kind) - def delete_inter_layer(self, graph): + def delete_layer(self, graph): """ 删除不需要的中间layer及其对应参数。 """ for match in self.matches: @@ -291,3 +301,52 @@ class FuseBase(object): if layer_id in subgraph.layers: # layer_id可能是属于子图的,此时删除父layer,即删除整个子图 subgraph.layers.pop(layer_id) + + def delete_layer_with_associated(self, graph, layer_id): + """ 删除不需要的中间layer及其相关连接点。 + """ + layer = graph.layers[layer_id] + outputs = graph.edges_out.get(layer_id, []) + inputs = graph.edges_in.get(layer_id, []) + + assert len( + inputs) <= 1, "There should be 0 or 1 input for deleted layer." + + if len(inputs) == 0: + for out in outputs: + while layer_id in graph.edges_in[out]: + index = graph.edges_in[out].index(layer_id) + del graph.edges_in[out][index] + + input_keys = list(graph.layers[out].inputs.keys()) + for k in input_keys: + if graph.layers[out].inputs[k] == layer.outputs[0]: + del graph.layers[out].inputs[k] + + del graph.layers[layer_id] + if layer_id in graph.edges_in: + del graph.edges_in[layer_id] + if layer_id in graph.edges_out: + del graph.edges_out[layer_id] + return + + # 将所有输出layer的输入layer进行替换 + for out in outputs: + for i in range(len(graph.edges_in[out])): + if graph.edges_in[out][i] == layer_id: + graph.edges_in[out][i] = inputs[0] + + # 将输出layer赋给输入layer的输出 + replace_index = graph.edges_out[inputs[0]].index(layer_id) + del graph.edges_out[inputs[0]][replace_index] + for i, out in enumerate(outputs): + graph.edges_out[inputs[0]].insert(replace_index + i, out) + for k, v in graph.layers[out].inputs.items(): + if v == layer.outputs[0]: + graph.layers[out].inputs[k] = list(layer.inputs.values())[0] + + del graph.layers[layer_id] + if layer_id in graph.edges_out: + del graph.edges_out[layer_id] + if layer_id in graph.edges_in: + del graph.edges_in[layer_id] diff --git a/x2paddle/optimizer/tensorflow/__pycache__/__init__.cpython-37.pyc b/x2paddle/optimizer/tensorflow/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c5ed09037dfc2e4c8329e2cd9de5a3577880cac5 Binary files /dev/null and b/x2paddle/optimizer/tensorflow/__pycache__/__init__.cpython-37.pyc differ diff --git a/x2paddle/optimizer/tensorflow/__pycache__/batch_norm.cpython-37.pyc b/x2paddle/optimizer/tensorflow/__pycache__/batch_norm.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b6acff6e41da67ad1e9a9ae862bfe702240f6d34 Binary files /dev/null and b/x2paddle/optimizer/tensorflow/__pycache__/batch_norm.cpython-37.pyc differ diff --git a/x2paddle/optimizer/tensorflow/__pycache__/bias.cpython-37.pyc b/x2paddle/optimizer/tensorflow/__pycache__/bias.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1821cea0d45a50993aaafe17b4b56eda198aa8c5 Binary files /dev/null and b/x2paddle/optimizer/tensorflow/__pycache__/bias.cpython-37.pyc differ diff --git a/x2paddle/optimizer/tensorflow/__pycache__/transpose.cpython-37.pyc b/x2paddle/optimizer/tensorflow/__pycache__/transpose.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..df6fbca9e0c61abcac339fedd760dde34aa84caa Binary files /dev/null and b/x2paddle/optimizer/tensorflow/__pycache__/transpose.cpython-37.pyc differ diff --git a/x2paddle/optimizer/tensorflow/batch_norm.py b/x2paddle/optimizer/tensorflow/batch_norm.py index 3e3d81360598c2b66a00735cd23059998f3bef2d..6b58074ba2db7034c2c1dcc1bf63af84f2483aad 100644 --- a/x2paddle/optimizer/tensorflow/batch_norm.py +++ b/x2paddle/optimizer/tensorflow/batch_norm.py @@ -178,3 +178,4 @@ class BatchNormOpt: graph.layers[bn.id] = bn graph.layers[transpose1.id] = transpose1 graph.build() + print("=============") diff --git a/x2paddle/optimizer/tensorflow/bias.py b/x2paddle/optimizer/tensorflow/bias.py index 593095127b5729f3ef6aae52af41341132b9e73b..f438b33fa9870a79f4e32df2f1ad84abace33212 100644 --- a/x2paddle/optimizer/tensorflow/bias.py +++ b/x2paddle/optimizer/tensorflow/bias.py @@ -6,11 +6,6 @@ class BiasOpt: self.conv_layers = [ 'fluid.layers.conv2d', 'fluid.layers.conv2d_transpose' ] - self.act_layers = [ - 'fluid.layers.relu', 'fluid.layers.relu6', 'fluid.layers.sigmoid', - 'fluid.layers.exp', 'fluid.layers.tanh', 'fluid.layers.softplus', - 'fluid.layers.leaky_relu' - ] def run(self, graph): print("Optimize: BiasOpt...")