diff --git a/x2paddle/convert.py b/x2paddle/convert.py index 62737b5a483e19f0e9c20fe652525cc65038b210..dd0b28c343e198c561468cba4ce5b5a7aa55acc4 100644 --- a/x2paddle/convert.py +++ b/x2paddle/convert.py @@ -218,6 +218,11 @@ def onnx2paddle(model_path, model = ONNXDecoder(model_path) mapper = ONNXOpMapper(model) mapper.paddle_graph.build() + logging.info("Model optimizing ...") + from x2paddle.optimizer.optimizer import GraphOptimizer + graph_opt = GraphOptimizer(source_frame="onnx") + graph_opt.optimize(mapper.paddle_graph) + logging.info("Model optimized.") mapper.paddle_graph.gen_model(save_dir) if convert_to_lite: convert2lite(save_dir, lite_valid_places, lite_model_type) diff --git a/x2paddle/optimizer/fusion/__init__.py b/x2paddle/optimizer/fusion/__init__.py index eef5b169b03911f47a2e4175a309300d8e4f0277..86f78e53470a04327900760fb75b0522f5dfb186 100644 --- a/x2paddle/optimizer/fusion/__init__.py +++ b/x2paddle/optimizer/fusion/__init__.py @@ -38,3 +38,5 @@ from .tf_batchnorm_fuser import TFBatchNormFuser from .tf_batchnorm_fuse_pass import TFBatchNormFusePass from .trace_fc_fuser import TraceFcFuser from .trace_fc_fuse_pass import TraceFcFusePass +from .onnx_layernorm_fuser import LayerNormFuser +from .onnx_layernorm_fuse_pass import LayerNormFusePass diff --git a/x2paddle/optimizer/fusion/onnx_layernorm_fuse_pass.py b/x2paddle/optimizer/fusion/onnx_layernorm_fuse_pass.py new file mode 100644 index 0000000000000000000000000000000000000000..9cf0642b6946f70033740bf27432d625160e527d --- /dev/null +++ b/x2paddle/optimizer/fusion/onnx_layernorm_fuse_pass.py @@ -0,0 +1,33 @@ +# Copyright (c) 2022 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 import LayerNormFuser +from x2paddle.optimizer.pass_manager import pass_register + + +@pass_register +class LayerNormFusePass(Pass): + name = "onnx_layernorm_fuse_pass" + + def __init__(self): + Pass.__init__(self) + + def apply(self, graph): + fuser = LayerNormFuser() + fuser.operate(graph, match_kind="edge") + + +# 用于注册 +onnx_layernorm_fuse_pass = LayerNormFusePass() diff --git a/x2paddle/optimizer/fusion/onnx_layernorm_fuser.py b/x2paddle/optimizer/fusion/onnx_layernorm_fuser.py new file mode 100644 index 0000000000000000000000000000000000000000..d5e47caf2167728a55f31f89f944aa2e0c6c62b7 --- /dev/null +++ b/x2paddle/optimizer/fusion/onnx_layernorm_fuser.py @@ -0,0 +1,154 @@ +# 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 LayerNormFuser(FuseBase): + def __init__(self): + super(LayerNormFuser, self).__init__() + + def build_pattern(self): + """ + code describe: + x2paddle_ln_pre_weight = self.x2paddle_ln_pre_weight + x2paddle_ln_pre_bias = self.x2paddle_ln_pre_bias + x2paddle_166 = paddle.full(dtype='float32', shape=[1], fill_value=2.0) + x2paddle_169 = paddle.full(dtype='float32', shape=[1], fill_value=9.999999747378752e-06) + x2paddle_164 = paddle.mean(x=x2paddle_162, axis=[-1], keepdim=True) + x2paddle_165 = paddle.subtract(x=x2paddle_162, y=x2paddle_164) + x2paddle_167 = paddle.pow(x=x2paddle_165, y=x2paddle_166) + x2paddle_168 = paddle.mean(x=x2paddle_167, axis=[-1], keepdim=True) + x2paddle_170 = paddle.add(x=x2paddle_168, y=x2paddle_169) + x2paddle_171 = paddle.sqrt(x=x2paddle_170) + x2paddle_172 = paddle.divide(x=x2paddle_165, y=x2paddle_171) + x2paddle_173 = paddle.multiply(x=x2paddle_172, y=x2paddle_ln_pre_weight) + x2paddle_174 = paddle.add(x=x2paddle_173, y=x2paddle_ln_pre_bias) + """ + + def gen_name(id): + return "x" + str(id) + + self.pattern.add_layer( + "self.create_parameter", inputs={}, outputs=[gen_name(0)]) + self.pattern.add_layer( + "self.create_parameter", inputs={}, outputs=[gen_name(1)]) + self.pattern.add_layer( + "paddle.full", + inputs={}, + outputs=[gen_name(2)], + shape=[1], + fill_value=0.5) + self.pattern.add_layer( + "paddle.full", + inputs={}, + outputs=[gen_name(3)], + shape=[1], + fill_value=9.999999747378752e-06) + self.pattern.add_layer( + "paddle.mean", + inputs={"x": "layernorm-input-0"}, + outputs=[gen_name(4)], + axis=[-1], + keep_dim=True) + self.pattern.add_layer( + "paddle.subtract", + inputs={"x": "layernorm-input-0", + "y": gen_name(4)}, + outputs=[gen_name(5)]) + self.pattern.add_layer( + "paddle.pow", + inputs={"x": gen_name(5), + "y": gen_name(2)}, + outputs=[gen_name(6)]) + self.pattern.add_layer( + "paddle.mean", + inputs={"x": gen_name(6)}, + outputs=[gen_name(7)], + axis=[-1], + keep_dim=True) + self.pattern.add_layer( + "paddle.add", + inputs={"x": gen_name(7), + "y": gen_name(3)}, + outputs=[gen_name(8)]) + self.pattern.add_layer( + "paddle.sqrt", inputs={"x": gen_name(8)}, outputs=[gen_name(9)]) + self.pattern.add_layer( + "paddle.divide", + inputs={"x": gen_name(5), + "y": gen_name(9)}, + outputs=[gen_name(10)]) + self.pattern.add_layer( + "paddle.multiply", + inputs={"x": gen_name(10), + "y": gen_name(0)}, + outputs=[gen_name(11)]) + self.pattern.add_layer( + "paddle.add", + inputs={"x": gen_name(11), + "y": gen_name(1)}, + outputs=[gen_name(12)]) + self.pattern.build(inputs={"input-0": "layernorm-input-0", }) + + def insert_new_layer(self, graph, parameters, matches): + new_layer, new_layer_id = self.gen_new_layer(parameters, matches) + print("new_layer:", new_layer) + print("=========:", new_layer.outputs[0]) + # new_layer_id = list(matches.keys())[0] + graph.layers[new_layer_id] = new_layer + matches_copy = copy.deepcopy(matches) + for layer_id, layer in matches_copy.items(): + print(layer.kernel) + if layer.kernel in ["self.create_parameter", "paddle.full"]: + matches.pop(layer_id) + matches.pop(new_layer_id) + + def gen_new_layer(self, parameters, matches): + layer_id_list = list(matches.keys()) + layer_id_list.sort(key=int) + layer_inputs = list() + layer_inputs_ids = list() + param_name = list() + for layer_id, layer in matches.items(): + if layer.kernel == "paddle.mean": + layer_inputs.append(layer.inputs) + layer_inputs_ids.append(layer_id) + print("layer_inputs:", layer_inputs) + if layer.kernel == "self.create_parameter": + param_name.append(layer.outputs[0]) + if layer.kernel == "paddle.add": + output_name = layer.outputs[0] + print("output_name:", output_name) + param = parameters[param_name[0]] + print("param.shape:", param.shape) + c = param.shape[0] + weight_param = parameters.pop(param_name[0]) + parameters["{}.weight".format(output_name)] = weight_param + bias_param = parameters.pop(param_name[1]) + parameters["{}.bias".format(output_name)] = bias_param + new_layer = PaddleLayer( + layer_id_list[0], + "paddle.nn.LayerNorm", + inputs=layer_inputs[0], + outputs=[output_name], + normalized_shape=[c]) + # weight_attr=string(param_name[0]), + # bias_attr=string(param_name[1])) + return new_layer, layer_inputs_ids[0] diff --git a/x2paddle/optimizer/optimizer.py b/x2paddle/optimizer/optimizer.py index 0b95b84023ac74c30ad22af7827bed0b9c5168c3..25e496f284008062e42edf8a4079e0ff2a1e0493 100644 --- a/x2paddle/optimizer/optimizer.py +++ b/x2paddle/optimizer/optimizer.py @@ -36,6 +36,8 @@ class GraphOptimizer(object): "conv2d_add_fuse_pass", "tf_batchnorm_fuse_pass", "prelu_fuse_pass", "transpose_eliminate_pass" ] + elif source_frame == "onnx": + self.passes = ["onnx_layernorm_fuse_pass"] else: self.passes = []