diff --git a/README.md b/README.md index 05bd30e0af7cab9b3bedb079c513cc1d506cbcac..d1562e9ef7b6fd62421b4d579e92aa72f263cfe9 100644 --- a/README.md +++ b/README.md @@ -44,24 +44,22 @@ x2paddle --framework=caffe --prototxt=deploy.prototxt --weight=deploy.caffemodel ``` x2paddle --framework=onnx --model=onnx_model.onnx --save_dir=pd_model ``` + ### Paddle2ONNX ``` -# 注意:paddle_infer_model_dir下需包含__model__和__params__两个文件 -x2paddle --framework=paddle2onnx --model=paddle_infer_model_dir --save_dir=onnx_model +Paddle2ONNX功能已迁移至新的github: https://github.com/PaddlePaddle/paddle2onnx, 欢迎大家去新的代码仓库查看详细介绍以及新功能。 ``` ### 参数选项 | 参数 | | |----------|--------------| -|--framework | 源模型类型 (tensorflow、caffe、onnx、paddle2onnx) | +|--framework | 源模型类型 (tensorflow、caffe、onnx) | |--prototxt | 当framework为caffe时,该参数指定caffe模型的proto文件路径 | |--weight | 当framework为caffe时,该参数指定caffe模型的参数文件路径 | |--save_dir | 指定转换后的模型保存目录路径 | |--model | 当framework为tensorflow/onnx时,该参数指定tensorflow的pb模型文件或onnx模型路径 | |--caffe_proto | **[可选]** 由caffe.proto编译成caffe_pb2.py文件的存放路径,当存在自定义Layer时使用,默认为None | -|--without_data_format_optimization | **[可选]** For TensorFlow, 当指定该参数为False时,打开NHWC->NCHW的优化,见[文档Q2](FAQ.md),默认为True| |--define_input_shape | **[可选]** For TensorFlow, 当指定该参数时,强制用户输入每个Placeholder的shape,见[文档Q2](FAQ.md) | |--params_merge | **[可选]** 当指定该参数时,转换完成后,inference_model中的所有模型参数将合并保存为一个文件__params__ | -|--onnx_opset | **[可选]** 当framework为paddle2onnx时,该参数可设置转换为ONNX的OpSet版本,目前支持9、10、11,默认为10 | diff --git a/x2paddle/__init__.py b/x2paddle/__init__.py index 5b80bf179120ff08852f52333a336db9c9afbb77..bd9b93d4054d64bd1c54cb9aabad01fdee806d75 100644 --- a/x2paddle/__init__.py +++ b/x2paddle/__init__.py @@ -1,17 +1,5 @@ -__version__ = "0.8.4" +__version__ = "0.8.8" -from .core.program import PaddleProgram +from .core.program import PaddleGraph -program = PaddleProgram() - -name_counter = dict() - - -def gen_name(op_name, var_name): - name = "{}.{}".format(op_name, var_name) - if name not in name_counter: - name_counter[name] = 0 - else: - name_counter[name] += 1 - name = name + "." + str(name_counter[name]) - return name +program = PaddleGraph() diff --git a/x2paddle/convert.py b/x2paddle/convert.py index c3ba7220ac8d7562705c27951bbff1098f5aee9a..365e1144dc6a049c6c465499e4a868ac73c89cef 100644 --- a/x2paddle/convert.py +++ b/x2paddle/convert.py @@ -75,25 +75,24 @@ def arg_parser(): action="store_true", default=False, help="define input shape for tf model") - parser.add_argument( - "--onnx_opset", - "-oo", - type=int, - default=10, - help="when paddle2onnx set onnx opset version to export") parser.add_argument( "--params_merge", "-pm", action="store_true", default=False, help="define whether merge the params") - + parser.add_argument( + "--input_shapes", + "-is", + action='append', + default=None, + help="define the inputs' shape") return parser def tf2paddle(model_path, save_dir, - without_data_format_optimization, + without_data_format_optimization=False, define_input_shape=False, params_merge=False): # check tensorflow installation and version @@ -112,37 +111,24 @@ def tf2paddle(model_path, "[ERROR] Tensorflow is not installed, use \"pip install tensorflow\"." ) return - + from x2paddle import program from x2paddle.decoder.tf_decoder import TFDecoder from x2paddle.op_mapper.tf_op_mapper import TFOpMapper - from x2paddle.op_mapper.tf_op_mapper_nhwc import TFOpMapperNHWC - from x2paddle.optimizer.tf_optimizer import TFOptimizer + 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) - if not without_data_format_optimization: - mapper = TFOpMapper(model) - optimizer = TFOptimizer(mapper) - # neccesary optimization - optimizer.delete_redundance_code() - # optimizer below is experimental - optimizer.optimize_elementwise_op() - optimizer.merge_activation() - optimizer.merge_bias() - optimizer.optimize_sub_graph() - -# optimizer.merge_batch_norm() -# optimizer.merge_prelu() - else: - mapper = TFOpMapperNHWC(model) - optimizer = TFOptimizer(mapper) - optimizer.delete_redundance_code() - optimizer.strip_graph() - optimizer.merge_activation() - optimizer.merge_bias() - optimizer.make_nchw_input_output() - optimizer.remove_transpose() - mapper.save_inference_model(save_dir, params_merge) + mapper = TFOpMapper(model) + program.build() + bias_opt = BiasOpt() + transpose_opt = TransposeOpt() + batch_norm_opt = BatchNormOpt() + bias_opt.run(program) + batch_norm_opt.run(program) + transpose_opt.run(program) + program.gen_model(save_dir) def caffe2paddle(proto, weight, save_dir, caffe_proto, params_merge=False): @@ -185,6 +171,7 @@ def onnx2paddle(model_path, save_dir, params_merge=False): mapper = ONNXOpMapper(model) print("Model optimizing ...") optimizer = ONNXOptimizer(mapper) + optimizer.delete_redundance_code() print("Model optimized.") print("Paddle model and code generating ...") @@ -192,17 +179,43 @@ def onnx2paddle(model_path, save_dir, params_merge=False): print("Paddle model and code generated.") -def paddle2onnx(model_path, save_dir, opset_version=10): - from x2paddle.decoder.paddle_decoder import PaddleDecoder - from x2paddle.op_mapper.paddle2onnx.paddle_op_mapper import PaddleOpMapper - import paddle.fluid as fluid - model = PaddleDecoder(model_path, '__model__', '__params__') - mapper = PaddleOpMapper() - mapper.convert( - model.program, - save_dir, - scope=fluid.global_scope(), - opset_version=opset_version) +def pytorch2paddle(model_path, save_dir, input_shapes): + # check pytorch installation and version + try: + import torch + version = torch.__version__ + ver_part = version.split('.') + print(ver_part) + if int(ver_part[1]) < 5: + print("[ERROR] pytorch>=1.5.0 is required") + return + except: + print( + "[ERROR] Pytorch is not installed, use \"pip install torch==1.5.0 torchvision\"." + ) + return + print("Now translating model from pytorch to paddle.") + + from x2paddle.decoder.pytorch_decoder import PyTorchDecoder + from x2paddle.op_mapper.pytorch2paddle import pytorch_op_mapper + model = PyTorchDecoder(model_path) + mapper = pytorch_op_mapper.PyTorchOpMapper(model) + mapper.graph.build() + print("Model optimizing ...") + from x2paddle.optimizer.pytorch_optimizer.optimizer import GraphOptimizer + graph_opt = GraphOptimizer() + graph_opt.optimize(mapper.graph) + print("Model optimized.") + if input_shapes is not None: + real_input_shapes = list() + for shape in input_shapes: + sp = shape[1:-1].split(",") + for i, s in enumerate(sp): + sp[i] = int(s) + real_input_shapes.append(sp) + else: + real_input_shapes = None + mapper.graph.gen_model(save_dir, real_input_shapes) def main(): @@ -267,14 +280,13 @@ def main(): if args.params_merge: params_merge = True onnx2paddle(args.model, args.save_dir, params_merge) - + elif args.framework == "paddle2onnx": - assert args.model is not None, "--model should be defined while translating paddle model to onnx" - paddle2onnx(args.model, args.save_dir, opset_version=args.onnx_opset) + print("Paddle to ONNX tool has been migrated to the new github: https://github.com/PaddlePaddle/paddle2onnx") else: raise Exception( - "--framework only support tensorflow/caffe/onnx/paddle2onnx now") + "--framework only support tensorflow/caffe/onnx/ now") if __name__ == "__main__": diff --git a/x2paddle/core/program.py b/x2paddle/core/program.py index 08e4bf8bf2b9b9d318e66e36d673ff582e9c2325..81a541c25c3b1a8964d348ed209faf1f76b74453 100644 --- a/x2paddle/core/program.py +++ b/x2paddle/core/program.py @@ -1,4 +1,5 @@ -# Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved. +# -*- coding:UTF-8 -*- +# 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. @@ -14,62 +15,208 @@ from __future__ import print_function from __future__ import division +import paddle.fluid as fluid +import os.path as osp +import paddle +from paddle.fluid.proto import framework_pb2 +from collections import OrderedDict +import numpy import collections +import sys import os +import six +import pickle class PaddleLayer(object): - def __init__(self, kernel, inputs, outputs, **kwargs): + def __init__(self, id, kernel, inputs, outputs, **kwargs): assert isinstance( inputs, dict), "parameter 'inputs' for PaddleLayer should be type of dict" assert isinstance( outputs, - list), "parameter, 'outputs' for PaddleLayer should be type of list" + list), "parameter 'outputs' for PaddleLayer should be type of list" + for k, v in inputs.items(): + if isinstance(v, list): + for i in v: + assert isinstance( + i, six.string_types + ), "value in inputs should be type of string or list of string" + else: + assert isinstance(v, six.string_types) or isinstance( + v, list + ), "value in inputs should be type of string or list of string" + for v in outputs: + assert isinstance( + v, six. + string_types), "elements in outputs should be type of string" self.kernel = kernel self.inputs = inputs self.outputs = outputs self.attrs = kwargs + self.id = id + self.blocks = list() + + def add_block(self, block): + self.blocks.append(block) -class PaddleProgram(object): - def __init__(self): - self.layers = list() +class PaddleGraph(object): + def __init__(self, parent_layer=None, graph_type="static"): + self.layers = OrderedDict() self.edges_out = dict() self.edges_in = dict() self.inputs = list() self.outputs = list() self.parameters = dict() + self.parent_layer = parent_layer + self.graph_type = graph_type + + def set_name(self, name): + self.name = name + + def set_parameters(self, parameters): + self.parameters = parameters + + def clear(self): + self.layers = OrderedDict() + self.edges_out = dict() + self.edges_in = dict() + self.inputs = list() + self.outputs = list() + self.parameters = dict() + + def clear_edges(self): + self.edges_out = dict() + self.edges_in = dict() def add_layer(self, kernel, inputs, outputs, **kwargs): - layer = PaddleLayer(kernel, inputs, outputs, **kwargs) - self.layers.append(layer) + layer_id = str(len(self.layers)) + if self.parent_layer is not None: + layer_id = "{}.{}.{}".format(self.parent_layer.id, + len(self.parent_layer.blocks), + layer_id) + layer = PaddleLayer(layer_id, kernel, inputs, outputs, **kwargs) + self.layers[layer_id] = layer + return layer_id + + def del_layer(self, layer_id): + layer = self.layers[layer_id] + outputs = self.edges_out.get(layer_id, []) + inputs = self.edges_in.get(layer_id, []) + + assert len( + inputs) <= 1, "There should be 0 or 1 input for deleted layer." - def build(self): - outputs = dict() - for i in range(len(self.layers)): - layer = self.layers[i] + if len(inputs) == 0: + for out in outputs: + while layer_id in self.edges_in[out]: + index = self.edges_in[out].index(layer_id) + del self.edges_in[out][index] + + input_keys = list(self.layers[out].inputs.keys()) + for k in input_keys: + if self.layers[out].inputs[k] == layer.outputs[0]: + del self.layers[out].inputs[k] + + del self.layers[layer_id] + if layer_id in self.edges_in: + del self.edges_in[layer_id] + if layer_id in self.edges_out: + del self.edges_out[layer_id] + return + + # 将所有输出layer的输入layer进行替换 + for out in outputs: + for i in range(len(self.edges_in[out])): + if self.edges_in[out][i] == layer_id: + self.edges_in[out][i] = inputs[0] + + # 将输出layer赋给输入layer的输出 + replace_index = self.edges_out[inputs[0]].index(layer_id) + del self.edges_out[inputs[0]][replace_index] + for i, out in enumerate(outputs): + self.edges_out[inputs[0]].insert(replace_index + i, out) + for k, v in self.layers[out].inputs.items(): + if v == layer.outputs[0]: + self.layers[out].inputs[k] = list(layer.inputs.values())[0] + + del self.layers[layer_id] + if layer_id in self.edges_out: + del self.edges_out[layer_id] + if layer_id in self.edges_in: + del self.edges_in[layer_id] + + def build(self, inputs=None, outputs=None): + self.clear_edges() + outputs_from_nodes = dict() + for layer_id, layer in self.layers.items(): + for input_key, input_var in layer.inputs.items(): + vs = input_var + if not isinstance(vs, list): + vs = [vs] + for v in vs: + assert v in outputs_from_nodes or ( + inputs is not None and v in list(inputs.values()) + ) or ( + outputs is not None and v in outputs + ), "Couldn't find {} in previous layers, the layers should be make by topological sort".format( + v) + if v in outputs_from_nodes: + in_layer_id = outputs_from_nodes[v] + else: + in_layer_id = -1 + if in_layer_id not in self.edges_out: + self.edges_out[in_layer_id] = list() + self.edges_out[in_layer_id].append(layer_id) + + if layer_id not in self.edges_in: + self.edges_in[layer_id] = list() + self.edges_in[layer_id].append(in_layer_id) for output in layer.outputs: - outputs[output] = i + outputs_from_nodes[output] = layer_id - for k, v in layer.inputs.items(): - assert v in outputs, "Couldn't find {} in previous layers, the layers should be make by topological sort".format( - v) - in_layer_index = outputs[v] + # 将block的输出用于父图 + if inputs is not None and outputs is not None and set( + layer.outputs).issubset(outputs): + if layer_id not in self.edges_out: + self.edges_out[layer_id] = list() + self.edges_out[layer_id].append(-1) - if in_layer_index not in self.edges_out: - self.edges_out[in_layer_index] = list() - self.edges_out[in_layer_index].append(i) + # 处理子图 + if len(layer.blocks) > 0: + for block in layer.blocks: + block.build(layer.inputs, layer.outputs) - if i not in self.edges_in: - self.edges_in[i] = list() - self.edges_in[i].append(in_layer_index) + # 删除不必要的节点 + invalid_list = list() + for layer_id, layer in self.layers.items(): + if len(self.layers) > 1: + if self.edges_in.get(layer_id, 0) == 0 and self.edges_out.get( + layer_id, 0) == 0 and layer.kernel != "prim.assert" \ + and layer.kernel != "prim.exception" \ + and layer.kernel != "prim.warnings": + invalid_list.append(layer_id) + for layer_id in invalid_list: + self.layers.pop(layer_id) - def get_layer_outputs(self, i): - return self.edges_out[i] + if self.graph_type == "dygraph": + self.get_dygraph_inputs() + if len(self.outputs) == 0: + self.get_dygraph_outputs() - def get_layer_inputs(self, i): - return self.edges_in[i] + def get_global_layers(self): + # 该全局layers的信息是按照拓扑排序组成的 + def update(layers): + global_layers = dict() + for layer_id, layer in layers.items(): + global_layers[layer_id] = layer + for block in layer.blocks: + block_global_layers = update(block.layers) + global_layers.update(block_global_layers) + return global_layers + + return update(self.layers) def gen_code(self, code_dir): def write_code(f, code_list, indent=0): @@ -80,19 +227,22 @@ class PaddleProgram(object): else: f.write(indent_blank + code_line + '\n') - f = open(os.path.join(code_dir, 'model.py'), 'w') + if not os.path.exists(code_dir): + os.makedirs(code_dir) + f = open(os.path.join(code_dir, 'x2paddle_model.py'), 'w') write_code( f, [ "from paddle.fluid.initializer import Constant", "from paddle.fluid.param_attr import ParamAttr", - "import paddle.fluid as fluid" - "", "def x2paddle_net():" + "import paddle.fluid as fluid", "import math", "", + "def x2paddle_net():" ], indent=0) - - for i, layer in enumerate(self.layers): - if self.edges_in.get(i, 0) == 0 and self.edges_out.get(i, 0) == 0: + for layer_id, layer in self.layers.items(): + edges_in = self.edges_in.get(layer_id, []) + edges_out = self.edges_out.get(layer_id, []) + if len(edges_in) == 0 and len(edges_out) == 0: continue line = "" @@ -106,16 +256,280 @@ class PaddleProgram(object): line += " = {}(".format(layer.kernel) for k, v in layer.inputs.items(): - line += "{}={}, ".format(k, v) + if isinstance(v, list): + line += "{}=[{}], ".format(k, ", ".join(v)) + else: + line += "{}={}, ".format(k, v) for k, v in layer.attrs.items(): line += "{}={}, ".format(k, v) line = line.strip(", ") line += ")" write_code(f, [line], indent=1) + + write_code( + f, [ + "return [{}], [{}]".format(", ".join(self.inputs), + ", ".join(self.outputs)) + ], + indent=1) f.close() - def gen_parameters(self, code_dir): - pass + def gen_model(self, save_dir, input_shapes=None): + if not os.path.exists(save_dir): + os.makedirs(save_dir) + if self.graph_type == "static": + code_dir = os.path.join(save_dir, 'model_with_code') + infer_dir = os.path.join(save_dir, 'inference_model') + self.gen_code(code_dir) + sys.path.append(code_dir) + import x2paddle_model + scope = fluid.Scope() + startup_program = fluid.Program() + main_program = fluid.Program() + with fluid.scope_guard(scope): + with fluid.program_guard(main_program, startup_program): + inputs, outputs = x2paddle_model.x2paddle_net() + exe = fluid.Executor(fluid.CPUPlace()) + exe.run(startup_program) + + param_dir = os.path.join(code_dir, 'weights') + for k, v in self.parameters.items(): + if scope.find_var(k): + self.dump_parameter(k, v, param_dir) + + def if_exist(var): + b = os.path.exists( + os.path.join(os.path.join(param_dir, var.name))) + return b + + fluid.io.load_vars( + exe, param_dir, main_program, predicate=if_exist) + fluid.io.save_inference_model( + dirname=infer_dir, + feeded_var_names=[i.name for i in inputs], + target_vars=outputs, + executor=exe) + else: + self.gen_dygraph_code(save_dir) + self.dump_dygraph_parameter(save_dir) + if input_shapes is not None: + # 如果input_shapes非空,则导出推理模型;其值类似[[None, 3, 224, 224]] + self.dygraph2static(save_dir, input_shapes) + + def dump_parameter(self, param_name, param, save_dir): + if not os.path.exists(save_dir): + os.makedirs(save_dir) + dtype_map = { + "int16": [framework_pb2.VarType.INT16, 'h'], + "int32": [framework_pb2.VarType.INT32, 'i'], + "int64": [framework_pb2.VarType.INT64, 'q'], + "float16": [framework_pb2.VarType.FP16, 'e'], + "float32": [framework_pb2.VarType.FP32, 'f'], + "float64": [framework_pb2.VarType.FP64, 'd'], + "bool": [framework_pb2.VarType.BOOL, None] + } + shape = param.shape + if str(param.dtype) in ['uint8', 'uint_8', 'bool']: + param = param.astype('int64') + if len(shape) == 0: + assert param.size == 1, "Unexpected situation happend!" + shape = [1] + assert str( + param.dtype) in dtype_map, "Unknown dtype {} of params: {}.".format( + str(param.dtype), param_name) + fp = open(os.path.join(save_dir, param_name), 'wb') + numpy.array([0], dtype='int32').tofile(fp) + numpy.array([0], dtype='int64').tofile(fp) + numpy.array([0], dtype='int32').tofile(fp) + tensor_desc = framework_pb2.VarType.TensorDesc() + tensor_desc.data_type = dtype_map[str(param.dtype)][0] + tensor_desc.dims.extend(shape) + desc_size = tensor_desc.ByteSize() + numpy.array([desc_size], dtype='int32').tofile(fp) + fp.write(tensor_desc.SerializeToString()) + param.tofile(fp) + fp.close() + + def get_dygraph_inputs(self): + def update(layers): + for layer_id, layer in layers.items(): + if self.edges_in.get(layer_id, 0) == 0 and self.edges_out.get( + layer_id, 0) == 0: + continue + if layer.kernel == "fluid.dygraph.base.to_variable": + value = layer.attrs["value"] + if not value.startswith("params["): + self.inputs.append(value) + if len(layer.blocks) > 0: + for block in layer.blocks: + block.get_dygraph_inputs() + self.inputs.extend(block.inputs) + + update(self.layers) + self.inputs = list(set(self.inputs)) + if self.inputs is not None: + self.inputs.sort() + + def get_dygraph_outputs(self): + for layer_id, layer in self.layers.items(): + if self.edges_in.get(layer_id, 0) == 0 and self.edges_out.get( + layer_id, 0) == 0: + continue + if self.edges_out.get(layer_id, 0) == 0: + for output_name in layer.outputs: + if not output_name.startswith("x"): + continue + self.outputs.append(output_name) + self.outputs = list(set(self.outputs)) + + def gen_dygraph_code(self, code_dir=None, indent=2): + def gen_codes(code_list, indent=0): + indent_blank = " " * indent + codes = [] + for code_line in code_list: + if code_line.strip() == "": + codes.append('\n') + else: + codes.append(indent_blank + code_line + '\n') + return codes + + def gen_head(): + self.head = gen_codes( + [ + "from paddle.fluid.initializer import Constant", + "from paddle.fluid.param_attr import ParamAttr", + "import paddle", + "import paddle.fluid as fluid", + "", + "class {}(fluid.dygraph.Layer):".format(self.name), + ], + indent=0) + input_data_name = ', '.join(self.inputs) + self.init_func.extend( + gen_codes( + ["def __init__(self, params):"], indent=1)) + self.init_func.extend( + gen_codes( + ["super({}, self).__init__()".format(self.name)], indent=2)) + self.forward_func.extend( + gen_codes( + ["def forward(self, {}):".format(input_data_name)], + indent=1)) + + def write_code(code_dir): + f = open(os.path.join(code_dir, 'x2paddle_code.py'), 'w') + for code_line in self.head: + f.write(code_line) + init_writen_codes = [] + for code_line in self.init_func: + if code_line in init_writen_codes: + continue + f.write(code_line) + init_writen_codes.append(code_line) + f.write("\n") + return_code = "return {}".format(", ".join(self.outputs)) + self.forward_func.extend(gen_codes([return_code], indent=2)) + for code_line in self.forward_func: + f.write(code_line) + f.close() + + self.init_func = [] + self.forward_func = [] + if indent == 2 and code_dir is not None: + gen_head() + + for layer_id, layer in self.layers.items(): + if ("paddle.nn" in layer.kernel and "functional" not in layer.kernel + ) or layer.kernel == "fluid.dygraph.base.to_variable" or \ + "paddle.fluid.dygraph" in layer.kernel: + line = "{}".format( + layer.outputs[0] + ) if layer.kernel == "fluid.dygraph.base.to_variable" and not layer.attrs[ + "value"].startswith("params[") else "self.{}".format( + layer.outputs[0]) + line += " = {}(".format(layer.kernel) + for k, v in layer.attrs.items(): + line += "{}={}, ".format(k, v) + line = line.strip(", ") + line += ")" + + if layer.kernel == "fluid.dygraph.base.to_variable" and not layer.attrs[ + "value"].startswith("params["): + self.forward_func.extend(gen_codes([line], indent=indent)) + continue + else: + self.init_func.extend(gen_codes([line], indent=2)) + + if len(layer.outputs) == 1: + line = layer.outputs[0] + elif len(layer.outputs) == 2: + line = layer.outputs[1] + else: + line = ','.join(layer.outputs[1:]) + if layer.kernel == "fluid.dygraph.base.to_variable" and layer.attrs[ + "value"].startswith("params["): + line += " = self.{}".format(layer.outputs[0]) + else: + line += " = self.{}(".format(layer.outputs[0]) + for k, v in layer.inputs.items(): + line += "{}, ".format(v) + line = line.strip(", ") + line += ")" + self.forward_func.extend(gen_codes([line], indent=indent)) + elif "prim" in layer.kernel: + func_name = layer.kernel.replace(".", "_") + from x2paddle.op_mapper.pytorch2paddle import prim2code + if hasattr(prim2code, func_name): + func = getattr(prim2code, func_name) + func( + layer, + indent=indent, + init_func=self.init_func, + forward_func=self.forward_func) + else: + raise Exception( + "The kind {} in paddle model is not supported yet.". + format(layer.kernel)) + else: + if len(layer.outputs) == 1: + line = layer.outputs[0] + else: + line = ','.join(layer.outputs) + line += " = {}(".format(layer.kernel) + for k, v in layer.inputs.items(): + line += "{}={}, ".format(k, v) + for k, v in layer.attrs.items(): + line += "{}={}, ".format(k, v) + line = line.strip(", ") + line += ")" + self.forward_func.extend(gen_codes([line], indent=indent)) + if indent == 2: + write_code(code_dir) + else: + return self.init_func, self.forward_func + + def dump_dygraph_parameter(self, code_dir): + params_output = open(os.path.join(code_dir, 'model.pdparams'), 'wb') + pickle.dump(self.parameters, params_output) + params_output.close() - def gen_inference_model(self, model_dir): - pass + def dygraph2static(self, save_dir, input_shapes=[]): + from paddle.fluid.dygraph.jit import declarative + sepc_list = list() + for i, name in enumerate(self.inputs): + sepc_list.append( + paddle.static.InputSpec( + shape=input_shapes[i], name=name)) + import sys + path = osp.abspath(save_dir) + sys.path.insert(0, save_dir) + import x2paddle_code + place = fluid.CPUPlace() + with fluid.dygraph.guard(place): + restore, _ = fluid.load_dygraph(osp.join(save_dir, "model")) + model = getattr(x2paddle_code, self.name)(restore) + model.set_dict(restore) + model.eval() + model.forward = declarative(model.forward, sepc_list) + fluid.dygraph.jit.save( + layer=model, model_path=osp.join(save_dir, "inference")) diff --git a/x2paddle/decoder/onnx_decoder.py b/x2paddle/decoder/onnx_decoder.py index 280b5b4f1a27a892e243283c6798164c86d73bb7..0fbcc51034738c0fab1304fe05d51a61c8039eb6 100644 --- a/x2paddle/decoder/onnx_decoder.py +++ b/x2paddle/decoder/onnx_decoder.py @@ -18,7 +18,7 @@ from x2paddle.decoder.onnx_shape_inference import SymbolicShapeInference from onnx.checker import ValidationError from onnx.checker import check_model from onnx.utils import polish_model -from onnx import helper +from onnx import helper, shape_inference from onnx.helper import get_attribute_value, make_attribute from onnx.shape_inference import infer_shapes from onnx.mapping import TENSOR_TYPE_TO_NP_TYPE @@ -141,6 +141,10 @@ class ONNXGraph(Graph): print("shape inferencing ...") self.graph = SymbolicShapeInference.infer_shapes( onnx_model, fixed_input_shape=self.fixed_input_shape) + if self.graph is None: + print('[WARNING] Shape inference by ONNX offical interface.') + onnx_model = shape_inference.infer_shapes(onnx_model) + self.graph = onnx_model.graph print("shape inferenced.") self.build() self.collect_value_infos() @@ -346,8 +350,12 @@ class ONNXGraph(Graph): #if len(value_info['shape']) == 0 or value_info[ # 'dtype'] is None or 0 in value_info['shape']: # #TODO add node shape inference + shape = value_info['shape'] + for idx in range(len(shape)): + if shape[idx] == 0: + shape[idx] = -1 + node.out_shapes.append(shape) node.dtype = value_info['dtype'] - node.out_shapes.append(value_info['shape']) else: node.out_shapes.append([]) diff --git a/x2paddle/decoder/onnx_shape_inference.py b/x2paddle/decoder/onnx_shape_inference.py index ff3fe71c32a6a435f171cc76321ce8acac3c37d3..987fab290848efaafa2dc42e1b389f37ec2b978e 100644 --- a/x2paddle/decoder/onnx_shape_inference.py +++ b/x2paddle/decoder/onnx_shape_inference.py @@ -14,7 +14,6 @@ # Reference Code from https://github.com/microsoft/onnxruntime, Licensed under the MIT License. -# -*- coding: UTF-8 -*- import argparse import numpy as np import onnx @@ -23,7 +22,6 @@ from onnx import helper, numpy_helper, shape_inference import sympy from packaging import version -assert version.parse(onnx.__version__) >= version.parse("1.5.0") def get_attribute(node, attr_name, default_value=None): @@ -45,17 +43,15 @@ def get_shape_from_type_proto(type_proto): def get_shape_from_sympy_shape(sympy_shape): - sympy_shape = [ + return [ None if i is None else (int(i) if is_literal(i) else str(i)) for i in sympy_shape ] - return sympy_shape def is_literal(dim): - return type(dim) in [int, np.int64, np.int32, sympy.Integer] or ( - hasattr(dim, 'is_number') and - dim.is_number) # or (hasattr(dim, 'is_integer') and dim.is_integer) + return type(dim) in [int, np.int64, np.int32, sympy.Integer] or (hasattr( + dim, 'is_number') and dim.is_number) def handle_negative_axis(axis, rank): @@ -119,6 +115,7 @@ class SymbolicShapeInference: 'Div': self._infer_symbolic_compute_ops, 'Expand': self._infer_Expand, 'Equal': self._infer_symbolic_compute_ops, + 'Floor': self._infer_symbolic_compute_ops, 'Gather': self._infer_Gather, 'GatherElements': self._infer_GatherElements, 'GatherND': self._infer_GatherND, @@ -145,13 +142,13 @@ class SymbolicShapeInference: 'Size': self._infer_Size, 'Slice': self._infer_Slice, 'Split': self._infer_Split, + 'SplitToSequence': self._infer_SplitToSequence, 'Squeeze': self._infer_Squeeze, 'Sub': self._infer_symbolic_compute_ops, 'Tile': self._infer_Tile, 'TopK': self._infer_TopK, 'Unsqueeze': self._infer_Unsqueeze, 'Where': self._infer_symbolic_compute_ops, - 'Transpose': self._infer_Transpose, 'ZipMap': self._infer_ZipMap } self.run_ = True @@ -267,8 +264,9 @@ class SymbolicShapeInference: if pending_nodes and self.verbose_ > 0: print('SymbolicShapeInference: orphaned nodes discarded: ') - for n in pending_nodes: - print(n.op_type + ': ' + n.output[0]) + print( + *[n.op_type + ': ' + n.output[0] for n in pending_nodes], + sep='\n') if input_shapes is not None: for input_name, shape in input_shapes.items(): @@ -280,6 +278,7 @@ class SymbolicShapeInference: helper.make_tensor_value_info( value_info.name, value_info.type.tensor_type.elem_type, shape)) + self.initializers_ = dict( [(i.name, i) for i in self.out_mp_.graph.initializer]) self.known_vi_ = dict( @@ -351,21 +350,11 @@ class SymbolicShapeInference: def _get_shape(self, node, idx): name = node.input[idx] - shape = [] if name in self.known_vi_: - shape = get_shape_from_type_proto(self.known_vi_[name].type) - elif name in self.initializers_: - assert name in self.initializers_ - shape = list(self.initializers_[name].dims) - return shape - - def _get_initializer_value(self, node, idx): - name = node.input[idx] - if name in self.initializers_: - value = numpy_helper.to_array(self.initializers_[name]) - return value + return get_shape_from_type_proto(self.known_vi_[name].type) else: - return False + assert name in self.initializers_ + return list(self.initializers_[name].dims) def _get_shape_rank(self, node, idx): return len(self._get_shape(node, idx)) @@ -373,7 +362,7 @@ class SymbolicShapeInference: def _get_sympy_shape(self, node, idx): sympy_shape = [] for d in self._get_shape(node, idx): - if type(d) is str: + if type(d) == str: sympy_shape.append(self.symbolic_dims_[d] if d in self.symbolic_dims_ else sympy.Symbol( d, integer=True)) @@ -416,10 +405,14 @@ class SymbolicShapeInference: # run single node inference with self.known_vi_ shapes # note that inference rely on initializer values is not handled # as we don't copy initializer weights to tmp_graph for inference speed purpose + if node.op_type == 'SplitToSequence': + make_value_info_func = helper.make_sequence_value_info + else: + make_value_info_func = helper.make_tensor_value_info tmp_graph = helper.make_graph( [node], 'tmp', [self.known_vi_[i] for i in node.input if i], [ - helper.make_tensor_value_info(i, onnx.TensorProto.UNDEFINED, - None) for i in node.output + make_value_info_func(i, onnx.TensorProto.UNDEFINED, None) + for i in node.output ]) self.tmp_mp_.graph.CopyFrom(tmp_graph) self.tmp_mp_ = shape_inference.infer_shapes(self.tmp_mp_) @@ -465,6 +458,12 @@ class SymbolicShapeInference: self.verbose_) all_shapes_inferred = False symbolic_shape_inference._preprocess(self.tmp_mp_) + # note that after _preprocess, Constant node will be converted to initializer and should be appended to subgraph.initializer + subgraph.initializer.extend([ + i for i in symbolic_shape_inference.out_mp_.graph.initializer + if i.name not in subgraph_implicit_input and i.name not in + subgraph_inputs + ]) symbolic_shape_inference.suggested_merge_ = self.suggested_merge_.copy() while symbolic_shape_inference.run_: all_shapes_inferred = symbolic_shape_inference._infer_impl( @@ -533,18 +532,13 @@ class SymbolicShapeInference: assert len(node.output) == 1 values = self._get_int_values(node, broadcast=True) if all([v is not None for v in values]): - new_shape = [] is_list = [type(v) == list for v in values] as_list = any(is_list) if as_list: - data = [op_func(vs) for vs in zip(*values)] - self.sympy_data_[node.output[0]] = data - new_shape = np.array(data).shape + self.sympy_data_[node.output[ + 0]] = [op_func(vs) for vs in zip(*values)] else: - data = op_func(values) - self.sympy_data_[node.output[0]] = data - new_shape = np.array(data).shape - vi = self.known_vi_[node.output[0]] + self.sympy_data_[node.output[0]] = op_func(values) def _pass_on_sympy_data(self, node): assert len(node.input) == 1 or node.op_type == 'Reshape' @@ -677,8 +671,8 @@ class SymbolicShapeInference: lhs_reduce_dim = -1 rhs_reduce_dim = -2 new_shape = self._broadcast_shapes( - lhs_shape[:-2], rhs_shape[:-2]) + [lhs_shape[-2] - ] + [rhs_shape[-1]] + lhs_shape[:-2], + rhs_shape[:-2]) + [lhs_shape[-2]] + [rhs_shape[-1]] # merge reduce dim self._check_merged_dims( [lhs_shape[lhs_reduce_dim], rhs_shape[rhs_reduce_dim]], @@ -706,6 +700,7 @@ class SymbolicShapeInference: 'Add': lambda l: l[0] + l[1], 'Div': lambda l: l[0] // l[1], # integer div in sympy 'Equal': lambda l: l[0] == l[1], + 'Floor': lambda l: sympy.floor(l[0]), 'Max': lambda l: l[1] if is_literal(l[0]) and int(l[0]) < -self.int_max_ else (l[0] if is_literal(l[1]) and int(l[1]) < -self.int_max_ else sympy.Max(l[0], l[1])), 'Min': @@ -731,15 +726,6 @@ class SymbolicShapeInference: helper.make_tensor_value_info(node.output[0], output_type, self._get_shape(node, 0))) - def _infer_Transpose(self, node): - input_shape = self._get_shape(node, 0) - perm = get_attribute(node, 'perm') - output_shape = np.array(input_shape)[perm].tolist() - vi = self.known_vi_[node.output[0]] - vi.CopyFrom( - helper.make_tensor_value_info(node.output[0], self.known_vi_[ - node.input[0]].type.tensor_type.elem_type, output_shape)) - def _infer_Compress(self, node): input_shape = self._get_shape(node, 0) # create a new symbolic dimension for Compress output @@ -851,11 +837,11 @@ class SymbolicShapeInference: axis = handle_negative_axis( get_attribute(node, 'axis', 0), len(data_shape)) indices_shape = self._get_shape(node, 1) - new_shape = data_shape[:axis] + indices_shape + data_shape[axis + 1:] vi = self.known_vi_[node.output[0]] vi.CopyFrom( - helper.make_tensor_value_info(node.output[ - 0], vi.type.tensor_type.elem_type, new_shape)) + helper.make_tensor_value_info( + node.output[0], vi.type.tensor_type.elem_type, data_shape[:axis] + + indices_shape + data_shape[axis + 1:])) if node.input[0] in self.sympy_data_: assert 0 == get_attribute(node, 'axis', 0) # only handle 1D sympy compute @@ -863,9 +849,8 @@ class SymbolicShapeInference: data = self.sympy_data_[node.input[0]] if type(data) == list: if type(idx) == np.ndarray and len(idx.shape) == 1: - self.sympy_data_[node.output[0]] = [ - data[int(i)] for i in idx - ] + self.sympy_data_[node.output[ + 0]] = [data[int(i)] for i in idx] else: self.sympy_data_[node.output[0]] = data[int(idx)] else: @@ -896,8 +881,8 @@ class SymbolicShapeInference: def _infer_If(self, node): # special case for constant condition, in case there are mismatching shape from the non-executed branch subgraphs = [ - get_attribute(node, 'then_branch'), - get_attribute(node, 'else_branch') + get_attribute(node, 'then_branch'), get_attribute(node, + 'else_branch') ] cond = self._try_get_value(node, 0) if cond is not None: @@ -976,11 +961,14 @@ class SymbolicShapeInference: 0], vi.type.tensor_type.elem_type, [input_rank, nz_len])) def _infer_OneHot(self, node): - shape = self._get_shape(node, 0) + sympy_shape = self._get_sympy_shape(node, 0) + depth = self._try_get_value(node, 1) axis = get_attribute(node, 'axis', -1) - axis = handle_negative_axis(axis, len(shape) + 1) - new_shape = shape[:axis] + [self._new_symbolic_dim_from_output(node) - ] + shape[axis:] + axis = handle_negative_axis(axis, len(sympy_shape) + 1) + new_shape = get_shape_from_sympy_shape(sympy_shape[:axis] + [ + self._new_symbolic_dim_from_output(node) + if not is_literal(depth) else depth + ] + sympy_shape[axis:]) vi = self.known_vi_[node.output[0]] vi.CopyFrom( helper.make_tensor_value_info(node.output[0], self.known_vi_[ @@ -1125,11 +1113,16 @@ class SymbolicShapeInference: sympy.simplify(sympy.floor(s)) for s in sizes ] self._update_computed_dims(new_sympy_shape) - elif roi is not None and scales is not None: + elif scales is not None: rank = len(scales) - assert len(roi) == 2 * rank - roi_start = list(roi)[:rank] - roi_end = list(roi)[rank:] + if get_attribute(node, 'coordinate_transformation_mode' + ) == 'tf_crop_and_resize': + assert len(roi) == 2 * rank + roi_start = list(roi)[:rank] + roi_end = list(roi)[rank:] + else: + roi_start = [0] * rank + roi_end = [1] * rank scales = list(scales) new_sympy_shape = [ sympy.simplify(sympy.floor(d * (end - start) * scale)) @@ -1265,8 +1258,8 @@ class SymbolicShapeInference: e = new_sympy_shape[i] except Exception: print( - 'Unable to determine if {} <= {}, treat as equal' - .format(e, new_sympy_shape[i])) + 'Unable to determine if {} <= {}, treat as equal'. + format(e, new_sympy_shape[i])) e = new_sympy_shape[i] if is_literal(s) and int(s) < 0: @@ -1290,7 +1283,7 @@ class SymbolicShapeInference: self.sympy_data_[node.output[0]] = self.sympy_data_[node.input[0]][ starts[0]:ends[0]] - def _infer_Split(self, node): + def _infer_Split_Common(self, node, make_value_info_func): input_sympy_shape = self._get_sympy_shape(node, 0) axis = handle_negative_axis( get_attribute(node, 'axis', 0), len(input_sympy_shape)) @@ -1306,14 +1299,20 @@ class SymbolicShapeInference: for i_o in range(len(split)): vi = self.known_vi_[node.output[i_o]] vi.CopyFrom( - helper.make_tensor_value_info( - node.output[i_o], self.known_vi_[node.input[ - 0]].type.tensor_type.elem_type, - get_shape_from_sympy_shape(input_sympy_shape[:axis] + [ - split[i_o] - ] + input_sympy_shape[axis + 1:]))) + make_value_info_func(node.output[i_o], self.known_vi_[ + node.input[0]].type.tensor_type.elem_type, + get_shape_from_sympy_shape( + input_sympy_shape[:axis] + [ + split[i_o] + ] + input_sympy_shape[axis + 1:]))) self.known_vi_[vi.name] = vi + def _infer_Split(self, node): + self._infer_Split_Common(node, helper.make_tensor_value_info) + + def _infer_SplitToSequence(self, node): + self._infer_Split_Common(node, helper.make_sequence_value_info) + def _infer_Squeeze(self, node): self._pass_on_sympy_data(node) @@ -1416,10 +1415,18 @@ class SymbolicShapeInference: self._onnx_infer_single_node(node) if node.op_type in self.dispatcher_: self.dispatcher_[node.op_type](node) + elif node.op_type in ['ConvTranspose']: + # onnx shape inference ops like ConvTranspose may have empty shape for symbolic input + # before adding symbolic compute for them + # mark the output type as UNDEFINED to allow guessing of rank + vi = self.known_vi_[node.output[0]] + if len(vi.type.tensor_type.shape.dim) == 0: + vi.type.tensor_type.elem_type = onnx.TensorProto.UNDEFINED + if self.verbose_ > 2: print(node.op_type + ': ' + node.name) for i, name in enumerate(node.input): - print(' Input {}: {} {}€5€5€5€5€5'.format( + print(' Input {}: {} {}'.format( i, name, 'initializer' if name in self.initializers_ else '')) @@ -1443,6 +1450,7 @@ class SymbolicShapeInference: ] if len(in_dims) > 1: self._check_merged_dims(in_dims, allow_broadcast=True) + for i_o in range(len(node.output)): vi = self.known_vi_[node.output[i_o]] out_type = vi.type @@ -1473,16 +1481,22 @@ class SymbolicShapeInference: if node.op_type in [ 'MatMul', 'MatMulInteger', 'MatMulInteger16' ]: - # only support auto merge for MatMul for dim < rank-2 when rank > 2 - assert len(shapes[0]) > 2 and dim_idx[0] < len( - shapes[0]) - 2 - assert len(shapes[1]) > 2 and dim_idx[1] < len( - shapes[1]) - 2 + if None in out_shape: + idx = out_shape.index(None) + dim_idx = [ + len(s) - len(out_shape) + idx + for s in shapes + ] + # only support auto merge for MatMul for dim < rank-2 when rank > 2 + assert len(shapes[0]) > 2 and dim_idx[ + 0] < len(shapes[0]) - 2 + assert len(shapes[1]) > 2 and dim_idx[ + 1] < len(shapes[1]) - 2 elif node.op_type == 'Expand': # auto merge for cases like Expand([min(batch, 1), min(seq, 512)], [batch, seq]) shapes = [ - self._get_shape(node, 0), - self._get_value(node, 1) + self._get_shape(node, 0), self._get_value(node, + 1) ] else: shapes = [] @@ -1531,9 +1545,9 @@ class SymbolicShapeInference: if self.verbose_ > 0: if is_unknown_op: print( - "Possible unknown op: {} node: {}, guessing {} shape" - .format(node.op_type, node.name, - vi.name)) + "Possible unknown op: {} node: {}, guessing {} shape". + format(node.op_type, node.name, + vi.name)) if self.verbose_ > 2: print(' {}: {} {}'.format( node.output[i_o], @@ -1555,24 +1569,26 @@ class SymbolicShapeInference: if self.auto_merge_ and not out_type_undefined: print('Merging: ' + str(self.suggested_merge_)) return False + self.run_ = False return True def _update_output_from_vi(self): for output in self.out_mp_.graph.output: if output.name in self.known_vi_: - tmp_output = self.known_vi_[output.name] - output.CopyFrom(tmp_output) + output.CopyFrom(self.known_vi_[output.name]) @staticmethod def infer_shapes(in_mp, - int_max=2**31 - 1, fixed_input_shape=None, - auto_merge=True, + int_max=2**31 - 1, + auto_merge=False, guess_output_rank=False, verbose=0): - if get_opset(in_mp) < 7: - print('Only support shape inferencing models of opset 7 and above.') + assert version.parse(onnx.__version__) >= version.parse("1.5.0") + onnx_opset = get_opset(in_mp) + if not onnx_opset or onnx_opset < 7: + print('[WARNING] Symbolic shape inference only support models of onnx opset 7 and above.') return symbolic_shape_inference = SymbolicShapeInference( int_max, auto_merge, guess_output_rank, verbose) @@ -1585,12 +1601,11 @@ class SymbolicShapeInference: in_mp) symbolic_shape_inference._update_output_from_vi() if not all_shapes_inferred: - print('!' * 10) symbolic_shape_inference.out_mp_ = shape_inference.infer_shapes( symbolic_shape_inference.out_mp_) - #onnx.save(symbolic_shape_inference.out_mp_, 'tmp.onnx') + print('[INFO] Complete symbolic shape inference.') except: - print('Stopping at incomplete shape inference') + print('[WARNING] Incomplete symbolic shape inference.') symbolic_shape_inference.out_mp_ = shape_inference.infer_shapes( symbolic_shape_inference.out_mp_) return symbolic_shape_inference.out_mp_.graph diff --git a/x2paddle/decoder/pytorch_decoder.py b/x2paddle/decoder/pytorch_decoder.py new file mode 100644 index 0000000000000000000000000000000000000000..c1a626d58bd352a10f020c95867fffbc1dbf6b47 --- /dev/null +++ b/x2paddle/decoder/pytorch_decoder.py @@ -0,0 +1,34 @@ +# 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 torch + + +class PyTorchDecoder(object): + def __init__(self, script_path): + self.script = torch.jit.load(script_path) + self.graph = self._optimize_graph(self.script.inlined_graph) + + def _optimize_graph(self, graph): + torch._C._jit_pass_constant_propagation(graph) + torch._C._jit_pass_dce(graph) + torch._C._jit_pass_lint(graph) + torch._C._jit_pass_peephole(graph) + torch._C._jit_pass_lint(graph) + torch._C._jit_pass_dce(graph) + torch._C._jit_pass_lint(graph) + torch._C._jit_pass_canonicalize(graph) + torch._C._jit_pass_lint(graph) + torch._C._jit_pass_constant_propagation(graph) + return graph diff --git a/x2paddle/decoder/tf_decoder.py b/x2paddle/decoder/tf_decoder.py index 97714e8be6878c8dd83fb86a639fe5af414fd60e..e55f5c05b4a36d54d26cac3aadc034ec5b347b3b 100644 --- a/x2paddle/decoder/tf_decoder.py +++ b/x2paddle/decoder/tf_decoder.py @@ -60,7 +60,7 @@ class TFGraphNode(GraphNode): @property def dtype(self): - keys = ['dtype', 'Tidx', 'T', 'DstT'] + keys = ['dtype', 'T', 'DstT'] for k in keys: dtype = self.layer.attr[k].type if dtype > 0: @@ -72,6 +72,15 @@ class TFGraphNode(GraphNode): dtype, self.layer.name)) return self.dtype_map[dtype] + def set_dtype(self, dtype): + dtype_idx = 0 + for k, v in self.dtype_map.items(): + if v == dtype: + dtype_idx = k + if dtype_idx == 0: + raise Exception("Cannot set dtype of node to '{}'".format(dtype)) + self.layer.attr['dtype'].type = dtype_idx + @property def raw_dtype(self): keys = ['dtype', 'Tidx', 'T', 'DstT'] @@ -89,6 +98,12 @@ class TFGraphNode(GraphNode): field = getattr(attr, attr.WhichOneof('value')) return tensor_util.MakeNdarray(field) + @property + def name(self): + if hasattr(self, 'index'): + return self.layer_name + "_p{}".format(self.index) + return self.layer_name + def get_attr(self, name): if name not in self.layer.attr: return None diff --git a/x2paddle/op_mapper/caffe_op_mapper.py b/x2paddle/op_mapper/caffe_op_mapper.py index 1ec79dd8ec6a264f8b47daa5e300ac1191c4ce98..4283bfecab13437172be4ec3402c4620642509f7 100644 --- a/x2paddle/op_mapper/caffe_op_mapper.py +++ b/x2paddle/op_mapper/caffe_op_mapper.py @@ -467,7 +467,12 @@ class CaffeOpMapper(OpMapper): data = node.data assert data is not None, 'The parameter of {} (type is {}) is not set. You need to use python package of caffe to set the default value.'.format( node.layer_name, node.layer_type) - self.weights[node.layer_name + '_weights'] = data[0] + import paddle + pd_version = paddle.__version__ + if pd_version.startswith("1.8.4") or pd_version.startswith("1.8.3"): + self.weights[node.layer_name + '_weights'] = data[0].reshape(1, -1) + else: + self.weights[node.layer_name + '_weights'] = data[0] attr = { 'mode': string(mode), 'param_attr': string(node.layer_name + '_weights'), diff --git a/x2paddle/op_mapper/onnx2paddle/opset9/opset.py b/x2paddle/op_mapper/onnx2paddle/opset9/opset.py index ef3c670a114902ed6a1a8930dc44993e3ecefe26..ead2370efef230e8dcccaede2d43b082273dfe32 100644 --- a/x2paddle/op_mapper/onnx2paddle/opset9/opset.py +++ b/x2paddle/op_mapper/onnx2paddle/opset9/opset.py @@ -104,14 +104,6 @@ class OpSet9(): default_op_mapping = { 'Shape': ['shape', ['X'], ['Out']], - 'Clip': [ - 'clip', ['X'], ['Out'], dict(), dict( - min=(np.asarray( - [255, 255, 127, 255], dtype=np.uint8).view(np.float32)[0]), - max=(np.asarray( - [255, 255, 127, 127], dtype=np.uint8).view(np.float32)[0]), - ) - ], 'Erf': ['erf', ['X'], ['Out']], 'Ceil': ['ceil', ['X'], ['Out']], 'ReduceMean': [ @@ -357,6 +349,7 @@ class OpSet9(): 'Warnning: paddle not support op:resize wiht mode: linear, we use bilinear replace linear' ) fluid_op = 'resize_bilinear' + attr['align_corners'] = False node.fluid_code.add_layer( fluid_op, inputs=inputs, output=node, param_attr=attr) @@ -557,8 +550,6 @@ class OpSet9(): def Expand(self, node): val_x = self.graph.get_input_node(node, idx=0, copy=True) val_shape = self.graph.get_input_node(node, idx=1, copy=True) - if len(val_shape.outputs) == 1: - self.omit_nodes.append(val_shape.layer_name) val_x_dtype = val_x.dtype name_ones = node.layer_name + '_ones' attr_ones = { @@ -745,53 +736,59 @@ class OpSet9(): param_attr=None) else: input_inner_indices = node.layer_name + '_input_inner_indices' + shape = val_x.out_shapes[0] + node.fluid_code.add_layer( + 'reshape', + inputs=indices.layer_name, + output=indices.layer_name, + param_attr={'shape': indices.out_shapes[0]}) + + zeros_like_val_x = val_x.layer_name + '_zeros' node.fluid_code.add_layer( - 'scatter_nd', + 'zeros_like', + inputs=val_x, + output=zeros_like_val_x, + param_attr=None) + node.fluid_code.add_layer( + 'scatter_nd_add', inputs={ - 'shape': val_x.out_shapes[0], + 'ref': zeros_like_val_x, 'index': indices, 'updates': updates }, output=input_inner_indices, param_attr=None) - + indices_mask = node.layer_name + '_indices_mask' constant_minus_one = node.layer_name + '_constant_minus_one' + # full_like support create tensor shape like input tensor node.fluid_code.add_layer( - 'fill_constant', - inputs=None, + 'full_like', + inputs=updates, output=constant_minus_one, - param_attr={ - 'shape': updates.out_shapes[0], - 'dtype': string(updates.dtype), - 'value': -1 - }) - - indices_mask = node.layer_name + '_indices_mask' + param_attr={'dtype': string(updates.dtype), + 'fill_value': -1}) node.fluid_code.add_layer( - 'scatter_nd', + 'scatter_nd_add', inputs={ - 'shape': val_x.out_shapes[0], + 'ref': zeros_like_val_x, 'index': indices, 'updates': constant_minus_one }, output=indices_mask, param_attr=None) - - constant_1 = node.layer_name + '_constant_1' + constant_one = node.layer_name + '_constant_1' + # full_like support create tensor shape like input tensor node.fluid_code.add_layer( - 'fill_constant', - inputs=None, - output=constant_1, - param_attr={ - 'shape': val_x.out_shapes[0], - 'dtype': string(val_x.dtype), - 'value': 1 - }) + 'full_like', + inputs=val_x, + output=constant_one, + param_attr={'dtype': string(val_x.dtype), + 'fill_value': 1}) input_out_indices_mask = node.layer_name + '_input_out_indices_mask' node.fluid_code.add_layer( "elementwise_add", inputs={"x": indices_mask, - "y": constant_1}, + "y": constant_one}, output=input_out_indices_mask, param_attr=None) @@ -831,27 +828,35 @@ class OpSet9(): if len(node.inputs) > 1: starts = self.graph.get_input_node(node, idx=1, copy=True) ends = self.graph.get_input_node(node, idx=2, copy=True) + starts_value = _const_weight_or_none(starts) + ends_value = _const_weight_or_none(ends) + if len(node.inputs) > 3: axes = self.graph.get_input_node(node, idx=3, copy=True) axes = _const_weight_or_none(axes, necessary=True) if len(node.inputs) > 4: steps = self.graph.get_input_node(node, idx=4, copy=True) steps = _const_weight_or_none(steps) - if steps is not None: - assert steps == 1, "Only support convert op:Slice, which attribute:steps == 1" attr = { "axes": axes, "starts": starts.layer_name, "ends": ends.layer_name } - starts_value = _const_weight_or_none(starts) - ends_value = _const_weight_or_none(ends) if starts_value is not None and ends_value is not None: self.omit_nodes.append(starts.layer_name) self.omit_nodes.append(ends.layer_name) + starts_value = starts_value.copy() ends_value = ends_value.copy() + #for idx in range(len(ends_value)): + # if ends_value[idx] > 2**31 - 1: + # ends_value[idx] = 2**31 - 1 + #print(val_x.out_shapes) for idx in range(len(ends_value)): - if ends_value[idx] > 2**31 - 1: + if starts_value[idx] >= val_x.out_shapes[0][axes[idx]]: + starts_value[idx] = val_x.out_shapes[0][axes[idx]] - 1 + ends_value[idx] = val_x.out_shapes[0][axes[idx]] + starts_value[idx] = val_x.out_shapes[0][axes[idx]] - 1 + elif ends_value[idx] > 2**31 - 1: ends_value[idx] = 2**31 - 1 attr = { "axes": axes, @@ -869,12 +874,12 @@ class OpSet9(): attr['starts'] = starts_cast if ends.dtype != 'int32': ends_cast = ends.layer_name + '_cast' - node.fluid_code.add_layer( - 'cast', - inputs=ends, - output=ends_cast, - param_attr={'dtype': string('int32')}) - attr['ends'] = ends_cast + node.fluid_code.add_layer( + 'cast', + inputs=ends, + output=ends_cast, + param_attr={'dtype': string('int32')}) + attr['ends'] = ends_cast else: starts = node.get_attr('starts') ends = node.get_attr('ends') @@ -884,8 +889,13 @@ class OpSet9(): ends[idx] = 2**31 - 1 attr = {"axes": axes, "starts": starts, "ends": ends} - node.fluid_code.add_layer( - 'slice', inputs=val_x, output=node, param_attr=attr) + if steps is not None: + attr['strides'] = steps + node.fluid_code.add_layer( + 'strided_slice', inputs=val_x, output=node, param_attr=attr) + else: + node.fluid_code.add_layer( + 'slice', inputs=val_x, output=node, param_attr=attr) @print_mapping_info def ConstantOfShape(self, node): @@ -907,6 +917,38 @@ class OpSet9(): node.fluid_code.add_layer( 'fill_constant', inputs=None, output=node, param_attr=attr) + @print_mapping_info + def Clip(self, node): + val_x = self.graph.get_input_node(node, idx=0, copy=True) + val_y = self.graph.get_node(node.layer.output[0], copy=True) + max_value, min_value = None, None + if len(node.inputs) == 1: + max_value = node.get_attr('max') + min_value = node.get_attr('min') + attr = { + 'max': max_value, + 'min': min_value, + } + node.fluid_code.add_layer( + 'clip', inputs=val_x, output=node, param_attr=attr) + else: + max_ipt = self.graph.get_input_node(node, idx=1, copy=True) + min_ipt = self.graph.get_input_node(node, idx=2, copy=True) + max_value = _const_weight_or_none(max_ipt) + min_value = _const_weight_or_none(min_ipt) + self.omit_nodes.append(max_ipt.layer_name) + self.omit_nodes.append(min_ipt.layer_name) + if max_value.shape == (1, ): + max_value = max_value[0] + if min_value.shape == (1, ): + min_value = min_value[0] + if max_value is not None and min_value is not None: + attr = {'max': max_value, 'min': min_value} + node.fluid_code.add_layer( + 'clip', inputs=val_x, output=node, param_attr=attr) + else: + raise + @print_mapping_info def Split(self, node): val_x = self.graph.get_input_node(node, idx=0, copy=True) @@ -1212,10 +1254,19 @@ class OpSet9(): mode = 'channel' shape_slope = val_slope.out_shapes[0] - if len(shape_slope) == 1: + + if shape_slope == [1]: mode = 'all' elif len(shape_slope) > 2: mode = 'element' + + 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 + + self.omit_nodes.append(val_slope.layer_name) attr = { "param_attr": string(val_slope.layer_name), 'mode': string(mode) diff --git a/x2paddle/op_mapper/paddle2onnx/opset10/opset.py b/x2paddle/op_mapper/paddle2onnx/opset10/opset.py deleted file mode 100644 index f3dfc693049361fe9ba189a954b3b2b2d6adbea4..0000000000000000000000000000000000000000 --- a/x2paddle/op_mapper/paddle2onnx/opset10/opset.py +++ /dev/null @@ -1,49 +0,0 @@ -# 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 sys -import x2paddle -import os -import numpy as np -import paddle.fluid.core as core -import paddle.fluid as fluid -import onnx -from onnx import helper, onnx_pb -from x2paddle.op_mapper.paddle2onnx.opset9.opset import OpSet9 - - -class OpSet10(OpSet9): - def __init__(self): - super(OpSet10, self).__init__() - - def slice(self, op, block): - axes = op.attr('axes') - starts = op.attr('starts') - ends = op.attr('ends') - axes_name = self.get_name(op.type, 'axes') - starts_name = self.get_name(op.type, 'starts') - ends_name = self.get_name(op.type, 'ends') - - axes_node = self.make_constant_node(axes_name, - onnx_pb.TensorProto.INT64, axes) - starts_node = self.make_constant_node(starts_name, - onnx_pb.TensorProto.INT64, starts) - ends_node = self.make_constant_node(ends_name, - onnx_pb.TensorProto.INT64, ends) - node = helper.make_node( - "Slice", - inputs=[op.input('Input')[0], starts_name, ends_name, axes_name], - outputs=op.output('Out'), ) - return [starts_node, ends_node, axes_node, node] diff --git a/x2paddle/op_mapper/paddle2onnx/opset11/__init__.py b/x2paddle/op_mapper/paddle2onnx/opset11/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/x2paddle/op_mapper/paddle2onnx/opset11/opset.py b/x2paddle/op_mapper/paddle2onnx/opset11/opset.py deleted file mode 100644 index dee81ee34be80edba4f6d64981508506414e3b83..0000000000000000000000000000000000000000 --- a/x2paddle/op_mapper/paddle2onnx/opset11/opset.py +++ /dev/null @@ -1,277 +0,0 @@ -# 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 sys -import x2paddle -import os -import numpy as np -import paddle.fluid.core as core -import paddle.fluid as fluid -import onnx -from onnx import helper, onnx_pb -from x2paddle.op_mapper.paddle2onnx.opset10.opset import OpSet10 - - -class OpSet11(OpSet10): - def __init__(self): - super(OpSet11, self).__init__() - - def relu6(self, op, block): - min_name = self.get_name(op.type, 'min') - max_name = self.get_name(op.type, 'max') - min_node = self.make_constant_node(min_name, onnx_pb.TensorProto.FLOAT, - 0) - max_node = self.make_constant_node(max_name, onnx_pb.TensorProto.FLOAT, - op.attr('threshold')) - node = helper.make_node( - 'Clip', - inputs=[op.input('X')[0], min_name, max_name], - outputs=op.output('Out'), ) - return [min_node, max_node, node] - - def pad2d(self, op, block): - x_shape = block.var(op.input('X')[0]).shape - paddings = op.attr('paddings') - onnx_pads = [] - #TODO support pads is Variable - if op.attr('data_format') == 'NCHW': - pads = [ - 0, 0, paddings[0], paddings[2], 0, 0, paddings[1], paddings[3] - ] - else: - pads = [ - 0, paddings[0], paddings[2], 0, 0, paddings[1], paddings[3], 0 - ] - pads_name = self.get_name(op.type, 'pads') - pads_node = self.make_constant_node(pads_name, - onnx_pb.TensorProto.INT64, pads) - constant_value_name = self.get_name(op.type, 'constant_value') - constant_value_node = self.make_constant_node(constant_value_name, - onnx_pb.TensorProto.FLOAT, - op.attr('pad_value')) - node = helper.make_node( - 'Pad', - inputs=op.input('X') + [pads_name, constant_value_name], - outputs=op.output('Out'), - mode=op.attr('mode')) - return [pads_node, constant_value_node, node] - - def clip(self, op, block): - min_name = self.get_name(op.type, 'min') - max_name = self.get_name(op.type, 'max') - min_node = self.make_constant_node(min_name, onnx_pb.TensorProto.FLOAT, - op.attr('min')) - max_node = self.make_constant_node(max_name, onnx_pb.TensorProto.FLOAT, - op.attr('max')) - node = helper.make_node( - 'Clip', - inputs=[op.input('X')[0], min_name, max_name], - outputs=op.output('Out')) - return [min_node, max_node, node] - - def bilinear_interp(self, op, block): - input_names = op.input_names - coordinate_transformation_mode = '' - align_corners = op.attr('align_corners') - align_mode = op.attr('align_mode') - if align_corners: - coordinate_transformation_mode = 'align_corners' - elif align_mode == 1: - coordinate_transformation_mode = 'asymmetric' - else: - coordinate_transformation_mode = 'half_pixel' - - roi_name = self.get_name(op.type, 'roi') - roi_node = self.make_constant_node(roi_name, onnx_pb.TensorProto.FLOAT, - [1, 1, 1, 1, 1, 1, 1, 1]) - if ('OutSize' in input_names and len(op.input('OutSize')) > 0) or ( - 'SizeTensor' in input_names and - len(op.input('SizeTensor')) > 0): - node_list = list() - empty_name = self.get_name(op.type, 'empty') - empty_tensor = helper.make_tensor( - empty_name, - onnx_pb.TensorProto.FLOAT, (0, ), - np.array([]).astype('float32'), - raw=False) - empty_node = helper.make_node( - 'Constant', [], outputs=[empty_name], value=empty_tensor) - shape_name0 = self.get_name(op.type, 'shape') - shape_node0 = helper.make_node( - 'Shape', inputs=op.input('X'), outputs=[shape_name0]) - starts_name = self.get_name(op.type, 'slice.starts') - starts_node = self.make_constant_node( - starts_name, onnx_pb.TensorProto.INT64, [0]) - ends_name = self.get_name(op.type, 'slice.ends') - ends_node = self.make_constant_node(ends_name, - onnx_pb.TensorProto.INT64, [2]) - shape_name1 = self.get_name(op.type, 'shape') - shape_node1 = helper.make_node( - 'Slice', - inputs=[shape_name0, starts_name, ends_name], - outputs=[shape_name1]) - node_list.extend([ - roi_node, empty_node, shape_node0, starts_node, ends_node, - shape_node1 - ]) - if 'OutSize' in input_names and len(op.input('OutSize')) > 0: - cast_shape_name = self.get_name(op.type, "shape.cast") - cast_shape_node = helper.make_node( - 'Cast', - inputs=op.input('OutSize'), - outputs=[cast_shape_name], - to=onnx_pb.TensorProto.INT64) - node_list.append(cast_shape_node) - else: - concat_shape_name = self.get_name(op.type, "shape.concat") - concat_shape_node = helper.make_node( - "Concat", - inputs=op.input('SizeTensor'), - outputs=[concat_shape_name], - axis=0) - cast_shape_name = self.get_name(op.type, "shape.cast") - cast_shape_node = helper.make_node( - 'Cast', - inputs=[concat_shape_name], - outputs=[cast_shape_name], - to=onnx_pb.TensorProto.INT64) - node_list.extend([concat_shape_node, cast_shape_node]) - shape_name3 = self.get_name(op.type, "shape.concat") - shape_node3 = helper.make_node( - 'Concat', - inputs=[shape_name1, cast_shape_name], - outputs=[shape_name3], - axis=0) - result_node = helper.make_node( - 'Resize', - inputs=[op.input('X')[0], roi_name, empty_name, shape_name3], - outputs=op.output('Out'), - mode='linear', - coordinate_transformation_mode=coordinate_transformation_mode) - node_list.extend([shape_node3, result_node]) - return node_list - elif 'Scale' in input_names and len(op.input('Scale')) > 0: - node = helper.make_node( - 'Resize', - inputs=[op.input('X')[0], roi_name, op.input('Scale')[0]], - outputs=op.output('Out'), - mode='linear', - coordinate_transformation_mode=coordinate_transformation_mode) - else: - out_shape = [op.attr('out_h'), op.attr('out_w')] - scale = op.attr('scale') - if out_shape.count(-1) > 0: - scale_name = self.get_name(op.type, 'scale') - scale_node = self.make_constant_node(scale_name, - onnx_pb.TensorProto.FLOAT, - [1, 1, scale, scale]) - node = helper.make_node( - 'Resize', - inputs=[op.input('X')[0], roi_name, scale_name], - outputs=op.output('Out'), - mode='nearest', - coordinate_transformation_mode=coordinate_transformation_mode - ) - return [scale_node, roi_node, node] - else: - raise Exception("Unexpected situation happend") - return [roi_node, node] - - def nearest_interp(self, op, block): - input_names = op.input_names - coordinate_transformation_mode = '' - align_corners = op.attr('align_corners') - if align_corners: - coordinate_transformation_mode = 'align_corners' - else: - coordinate_transformation_mode = 'half_pixel' - roi_name = self.get_name(op.type, 'roi') - roi_node = self.make_constant_node(roi_name, onnx_pb.TensorProto.FLOAT, - [1, 1, 1, 1, 1, 1, 1, 1]) - if 'OutSize' in input_names and len(op.input('OutSize')) > 0: - node = helper.make_node( - 'Resize', - inputs=[op.input('X')[0], roi_name, op.input('OutSize')[0]], - outputs=op.output('Out'), - mode='nearest', - coordinate_transformation_mode=coordinate_transformation_mode) - elif 'Scale' in input_names and len(op.input('Scale')) > 0: - node = helper.make_node( - 'Resize', - inputs=[op.input('X')[0], roi_name, op.input('Scale')[0]], - outputs=op.output('Out'), - mode='nearest', - coordinate_transformation_mode=coordinate_transformation_mode) - else: - out_shape = [op.attr('out_h'), op.attr('out_w')] - scale = op.attr('scale') - if out_shape.count(-1) > 0: - scale_name = self.get_name(op.type, 'scale') - scale_node = self.make_constant_node(scale_name, - onnx_pb.TensorProto.FLOAT, - [1, 1, scale, scale]) - node = helper.make_node( - 'Resize', - inputs=[op.input('X')[0], roi_name, scale_name], - outputs=op.output('Out'), - mode='nearest', - coordinate_transformation_mode=coordinate_transformation_mode - ) - return [scale_node, roi_node, node] - else: - raise Exception("Unexpected situation happend") - return [roi_node, node] - - def hard_swish(self, op, block): - min_name = self.get_name(op.type, 'min') - max_name = self.get_name(op.type, 'max') - scale_name = self.get_name(op.type, 'scale') - offset_name = self.get_name(op.type, 'offset') - min_node = self.make_constant_node(min_name, onnx_pb.TensorProto.FLOAT, - 0) - max_node = self.make_constant_node(max_name, onnx_pb.TensorProto.FLOAT, - op.attr('threshold')) - scale_node = self.make_constant_node(scale_name, - onnx_pb.TensorProto.FLOAT, - op.attr('scale')) - offset_node = self.make_constant_node(offset_name, - onnx_pb.TensorProto.FLOAT, - op.attr('offset')) - - name0 = self.get_name(op.type, 'add') - node0 = helper.make_node( - 'Add', inputs=[op.input('X')[0], offset_name], outputs=[name0]) - name1 = self.get_name(op.type, 'relu') - node1 = helper.make_node( - 'Clip', - inputs=[name0, min_name, max_name], - outputs=[name1], ) - name2 = self.get_name(op.type, 'mul') - node2 = helper.make_node( - 'Mul', inputs=[op.input('X')[0], name1], outputs=[name2]) - node3 = helper.make_node( - 'Div', inputs=[name2, scale_name], outputs=op.output('Out')) - return [ - min_node, max_node, scale_node, offset_node, node0, node1, node2, - node3 - ] - - def yolo_box(self, op, block): - from .paddle_custom_layer.yolo_box import yolo_box - return yolo_box(op, block) - - def multiclass_nms(self, op, block): - from .paddle_custom_layer.multiclass_nms import multiclass_nms - return multiclass_nms(op, block) diff --git a/x2paddle/op_mapper/paddle2onnx/opset11/paddle_custom_layer/__init__.py b/x2paddle/op_mapper/paddle2onnx/opset11/paddle_custom_layer/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/x2paddle/op_mapper/paddle2onnx/opset11/paddle_custom_layer/multiclass_nms.py b/x2paddle/op_mapper/paddle2onnx/opset11/paddle_custom_layer/multiclass_nms.py deleted file mode 100644 index f953ad99d38958f1f8e6fc9927086401a4f28014..0000000000000000000000000000000000000000 --- a/x2paddle/op_mapper/paddle2onnx/opset11/paddle_custom_layer/multiclass_nms.py +++ /dev/null @@ -1,442 +0,0 @@ -# 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 sys -import os -import numpy as np -import paddle.fluid.core as core -import paddle.fluid as fluid -import onnx -import logging -from onnx import helper, onnx_pb - - -def multiclass_nms(op, block): - """ - Convert the paddle multiclass_nms to onnx op. - This op is get the select boxes from origin boxes. - """ - inputs = dict() - outputs = dict() - attrs = dict() - for name in op.input_names: - inputs[name] = op.input(name) - for name in op.output_names: - outputs[name] = op.output(name) - for name in op.attr_names: - attrs[name] = op.attr(name) - - result_name = outputs['Out'][0] - background = attrs['background_label'] - normalized = attrs['normalized'] - if normalized == False: - logging.warn( - "The parameter normalized of multiclass_nms OP of Paddle is False, which has diff with ONNX." \ - " Please set normalized=True in multiclass_nms of Paddle, see doc Q4 in https://github.com/PaddlePaddle/X2Paddle/blob/develop/FAQ.md") - - #convert the paddle attribute to onnx tensor - name_score_threshold = [outputs['Out'][0] + "@score_threshold"] - name_iou_threshold = [outputs['Out'][0] + "@iou_threshold"] - name_keep_top_k = [outputs['Out'][0] + '@keep_top_k'] - name_keep_top_k_2D = [outputs['Out'][0] + '@keep_top_k_1D'] - - node_score_threshold = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_score_threshold, - value=onnx.helper.make_tensor( - name=name_score_threshold[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=(), - vals=[float(attrs['score_threshold'])])) - - node_iou_threshold = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_iou_threshold, - value=onnx.helper.make_tensor( - name=name_iou_threshold[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=(), - vals=[float(attrs['nms_threshold'])])) - - boxes_num = block.var(outputs['Out'][0]).shape[0] - top_k_value = np.int64(boxes_num if attrs['keep_top_k'] == -1 else attrs['keep_top_k']) - node_keep_top_k = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_keep_top_k, - value=onnx.helper.make_tensor( - name=name_keep_top_k[0] + "@const", - data_type=onnx.TensorProto.INT64, - dims=(), - vals=[top_k_value])) - - node_keep_top_k_2D = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_keep_top_k_2D, - value=onnx.helper.make_tensor( - name=name_keep_top_k_2D[0] + "@const", - data_type=onnx.TensorProto.INT64, - dims=[1, 1], - vals=[top_k_value])) - - # the paddle data format is x1,y1,x2,y2 - kwargs = {'center_point_box': 0} - - name_select_nms = [outputs['Out'][0] + "@select_index"] - node_select_nms= onnx.helper.make_node( - 'NonMaxSuppression', - inputs=inputs['BBoxes'] + inputs['Scores'] + name_keep_top_k +\ - name_iou_threshold + name_score_threshold, - outputs=name_select_nms) - # step 1 nodes select the nms class - node_list = [ - node_score_threshold, node_iou_threshold, node_keep_top_k, - node_keep_top_k_2D, node_select_nms - ] - - # create some const value to use - name_const_value = [result_name+"@const_0", - result_name+"@const_1",\ - result_name+"@const_2",\ - result_name+"@const_-1"] - value_const_value = [0, 1, 2, -1] - for name, value in zip(name_const_value, value_const_value): - node = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=[name], - value=onnx.helper.make_tensor( - name=name + "@const", - data_type=onnx.TensorProto.INT64, - dims=[1], - vals=[value])) - node_list.append(node) - - # In this code block, we will deocde the raw score data, reshape N * C * M to 1 * N*C*M - # and the same time, decode the select indices to 1 * D, gather the select_indices - outputs_gather_1 = [result_name + "@gather_1"] - node_gather_1 = onnx.helper.make_node( - 'Gather', - inputs=name_select_nms + [result_name + "@const_1"], - outputs=outputs_gather_1, - axis=1) - node_list.append(node_gather_1) - - outputs_squeeze_gather_1 = [result_name + "@sequeeze_gather_1"] - node_squeeze_gather_1 = onnx.helper.make_node( - 'Squeeze', - inputs=outputs_gather_1, - outputs=outputs_squeeze_gather_1, - axes=[1]) - node_list.append(node_squeeze_gather_1) - - outputs_gather_2 = [result_name + "@gather_2"] - node_gather_2 = onnx.helper.make_node( - 'Gather', - inputs=name_select_nms + [result_name + "@const_2"], - outputs=outputs_gather_2, - axis=1) - node_list.append(node_gather_2) - - #slice the class is not 0 - if background == 0: - outputs_nonzero = [result_name + "@nonzero"] - node_nonzero = onnx.helper.make_node( - 'NonZero', inputs=outputs_squeeze_gather_1, outputs=outputs_nonzero) - node_list.append(node_nonzero) - else: - name_thresh = [result_name + "@thresh"] - node_thresh = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_thresh, - value=onnx.helper.make_tensor( - name=name_thresh[0] + "@const", - data_type=onnx.TensorProto.INT32, - dims=[1], - vals=[-1])) - node_list.append(node_thresh) - - outputs_cast = [result_name + "@cast"] - node_cast = onnx.helper.make_node( - 'Cast', inputs=outputs_squeeze_gather_1, outputs=outputs_cast, to=6) - node_list.append(node_cast) - - outputs_greater = [result_name + "@greater"] - node_greater = onnx.helper.make_node( - 'Greater', - inputs=outputs_cast + name_thresh, - outputs=outputs_greater) - node_list.append(node_greater) - - outputs_nonzero = [result_name + "@nonzero"] - node_nonzero = onnx.helper.make_node( - 'NonZero', inputs=outputs_greater, outputs=outputs_nonzero) - node_list.append(node_nonzero) - - outputs_gather_1_nonzero = [result_name + "@gather_1_nonzero"] - node_gather_1_nonzero = onnx.helper.make_node( - 'Gather', - inputs=outputs_gather_1 + outputs_nonzero, - outputs=outputs_gather_1_nonzero, - axis=0) - node_list.append(node_gather_1_nonzero) - - outputs_gather_2_nonzero = [result_name + "@gather_2_nonzero"] - node_gather_2_nonzero = onnx.helper.make_node( - 'Gather', - inputs=outputs_gather_2 + outputs_nonzero, - outputs=outputs_gather_2_nonzero, - axis=0) - node_list.append(node_gather_2_nonzero) - - # reshape scores N * C * M to (N*C*M) * 1 - outputs_reshape_scores_rank1 = [result_name + "@reshape_scores_rank1"] - node_reshape_scores_rank1 = onnx.helper.make_node( - "Reshape", - inputs=inputs['Scores'] + [result_name + "@const_-1"], - outputs=outputs_reshape_scores_rank1) - node_list.append(node_reshape_scores_rank1) - - # get the shape of scores - outputs_shape_scores = [result_name + "@shape_scores"] - node_shape_scores = onnx.helper.make_node( - 'Shape', inputs=inputs['Scores'], outputs=outputs_shape_scores) - node_list.append(node_shape_scores) - - # gather the index: 2 shape of scores - outputs_gather_scores_dim1 = [result_name + "@gather_scores_dim1"] - node_gather_scores_dim1 = onnx.helper.make_node( - 'Gather', - inputs=outputs_shape_scores + [result_name + "@const_2"], - outputs=outputs_gather_scores_dim1, - axis=0) - node_list.append(node_gather_scores_dim1) - - # mul class * M - outputs_mul_classnum_boxnum = [result_name + "@mul_classnum_boxnum"] - node_mul_classnum_boxnum = onnx.helper.make_node( - 'Mul', - inputs=outputs_gather_1_nonzero + outputs_gather_scores_dim1, - outputs=outputs_mul_classnum_boxnum) - node_list.append(node_mul_classnum_boxnum) - - # add class * M * index - outputs_add_class_M_index = [result_name + "@add_class_M_index"] - node_add_class_M_index = onnx.helper.make_node( - 'Add', - inputs=outputs_mul_classnum_boxnum + outputs_gather_2_nonzero, - outputs=outputs_add_class_M_index) - node_list.append(node_add_class_M_index) - - # Squeeze the indices to 1 dim - outputs_squeeze_select_index = [result_name + "@squeeze_select_index"] - node_squeeze_select_index = onnx.helper.make_node( - 'Squeeze', - inputs=outputs_add_class_M_index, - outputs=outputs_squeeze_select_index, - axes=[0, 2]) - node_list.append(node_squeeze_select_index) - - # gather the data from flatten scores - outputs_gather_select_scores = [result_name + "@gather_select_scores"] - node_gather_select_scores = onnx.helper.make_node('Gather', - inputs=outputs_reshape_scores_rank1 + \ - outputs_squeeze_select_index, - outputs=outputs_gather_select_scores, - axis=0) - node_list.append(node_gather_select_scores) - - # get nums to input TopK - outputs_shape_select_num = [result_name + "@shape_select_num"] - node_shape_select_num = onnx.helper.make_node( - 'Shape', - inputs=outputs_gather_select_scores, - outputs=outputs_shape_select_num) - node_list.append(node_shape_select_num) - - outputs_gather_select_num = [result_name + "@gather_select_num"] - node_gather_select_num = onnx.helper.make_node( - 'Gather', - inputs=outputs_shape_select_num + [result_name + "@const_0"], - outputs=outputs_gather_select_num, - axis=0) - node_list.append(node_gather_select_num) - - outputs_unsqueeze_select_num = [result_name + "@unsqueeze_select_num"] - node_unsqueeze_select_num = onnx.helper.make_node( - 'Unsqueeze', - inputs=outputs_gather_select_num, - outputs=outputs_unsqueeze_select_num, - axes=[0]) - node_list.append(node_unsqueeze_select_num) - - outputs_concat_topK_select_num = [result_name + "@conat_topK_select_num"] - node_conat_topK_select_num = onnx.helper.make_node( - 'Concat', - inputs=outputs_unsqueeze_select_num + name_keep_top_k_2D, - outputs=outputs_concat_topK_select_num, - axis=0) - node_list.append(node_conat_topK_select_num) - - outputs_cast_concat_topK_select_num = [ - result_name + "@concat_topK_select_num" - ] - node_outputs_cast_concat_topK_select_num = onnx.helper.make_node( - 'Cast', - inputs=outputs_concat_topK_select_num, - outputs=outputs_cast_concat_topK_select_num, - to=6) - node_list.append(node_outputs_cast_concat_topK_select_num) - # get min(topK, num_select) - outputs_compare_topk_num_select = [result_name + "@compare_topk_num_select"] - node_compare_topk_num_select = onnx.helper.make_node( - 'ReduceMin', - inputs=outputs_cast_concat_topK_select_num, - outputs=outputs_compare_topk_num_select, - keepdims=0) - node_list.append(node_compare_topk_num_select) - - # unsqueeze the indices to 1D tensor - outputs_unsqueeze_topk_select_indices = [ - result_name + "@unsqueeze_topk_select_indices" - ] - node_unsqueeze_topk_select_indices = onnx.helper.make_node( - 'Unsqueeze', - inputs=outputs_compare_topk_num_select, - outputs=outputs_unsqueeze_topk_select_indices, - axes=[0]) - node_list.append(node_unsqueeze_topk_select_indices) - - # cast the indices to INT64 - outputs_cast_topk_indices = [result_name + "@cast_topk_indices"] - node_cast_topk_indices = onnx.helper.make_node( - 'Cast', - inputs=outputs_unsqueeze_topk_select_indices, - outputs=outputs_cast_topk_indices, - to=7) - node_list.append(node_cast_topk_indices) - - # select topk scores indices - outputs_topk_select_topk_indices = [result_name + "@topk_select_topk_values",\ - result_name + "@topk_select_topk_indices"] - node_topk_select_topk_indices = onnx.helper.make_node( - 'TopK', - inputs=outputs_gather_select_scores + outputs_cast_topk_indices, - outputs=outputs_topk_select_topk_indices) - node_list.append(node_topk_select_topk_indices) - - # gather topk label, scores, boxes - outputs_gather_topk_scores = [result_name + "@gather_topk_scores"] - node_gather_topk_scores = onnx.helper.make_node( - 'Gather', - inputs=outputs_gather_select_scores + - [outputs_topk_select_topk_indices[1]], - outputs=outputs_gather_topk_scores, - axis=0) - node_list.append(node_gather_topk_scores) - - outputs_gather_topk_class = [result_name + "@gather_topk_class"] - node_gather_topk_class = onnx.helper.make_node( - 'Gather', - inputs=outputs_gather_1_nonzero + - [outputs_topk_select_topk_indices[1]], - outputs=outputs_gather_topk_class, - axis=1) - node_list.append(node_gather_topk_class) - - # gather the boxes need to gather the boxes id, then get boxes - outputs_gather_topk_boxes_id = [result_name + "@gather_topk_boxes_id"] - node_gather_topk_boxes_id = onnx.helper.make_node( - 'Gather', - inputs=outputs_gather_2_nonzero + - [outputs_topk_select_topk_indices[1]], - outputs=outputs_gather_topk_boxes_id, - axis=1) - node_list.append(node_gather_topk_boxes_id) - - # squeeze the gather_topk_boxes_id to 1 dim - outputs_squeeze_topk_boxes_id = [result_name + "@squeeze_topk_boxes_id"] - node_squeeze_topk_boxes_id = onnx.helper.make_node( - 'Squeeze', - inputs=outputs_gather_topk_boxes_id, - outputs=outputs_squeeze_topk_boxes_id, - axes=[0, 2]) - node_list.append(node_squeeze_topk_boxes_id) - - outputs_gather_select_boxes = [result_name + "@gather_select_boxes"] - node_gather_select_boxes = onnx.helper.make_node( - 'Gather', - inputs=inputs['BBoxes'] + outputs_squeeze_topk_boxes_id, - outputs=outputs_gather_select_boxes, - axis=1) - node_list.append(node_gather_select_boxes) - - # concat the final result - # before concat need to cast the class to float - outputs_cast_topk_class = [result_name + "@cast_topk_class"] - node_cast_topk_class = onnx.helper.make_node( - 'Cast', - inputs=outputs_gather_topk_class, - outputs=outputs_cast_topk_class, - to=1) - node_list.append(node_cast_topk_class) - - outputs_unsqueeze_topk_scores = [result_name + "@unsqueeze_topk_scores"] - node_unsqueeze_topk_scores = onnx.helper.make_node( - 'Unsqueeze', - inputs=outputs_gather_topk_scores, - outputs=outputs_unsqueeze_topk_scores, - axes=[0, 2]) - node_list.append(node_unsqueeze_topk_scores) - - inputs_concat_final_results = outputs_cast_topk_class + outputs_unsqueeze_topk_scores +\ - outputs_gather_select_boxes - outputs_sort_by_socre_results = [result_name + "@concat_topk_scores"] - node_sort_by_socre_results = onnx.helper.make_node( - 'Concat', - inputs=inputs_concat_final_results, - outputs=outputs_sort_by_socre_results, - axis=2) - node_list.append(node_sort_by_socre_results) - - # select topk classes indices - outputs_squeeze_cast_topk_class = [result_name + "@squeeze_cast_topk_class"] - node_squeeze_cast_topk_class = onnx.helper.make_node( - 'Squeeze', - inputs=outputs_cast_topk_class, - outputs=outputs_squeeze_cast_topk_class, - axes=[0, 2]) - node_list.append(node_squeeze_cast_topk_class) - outputs_topk_select_classes_indices = [result_name + "@topk_select_topk_classes_scores",\ - result_name + "@topk_select_topk_classes_indices"] - node_topk_select_topk_indices = onnx.helper.make_node( - 'TopK', - inputs=outputs_squeeze_cast_topk_class + outputs_cast_topk_indices, - outputs=outputs_topk_select_classes_indices, - largest=0) - node_list.append(node_topk_select_topk_indices) - outputs_concat_final_results = outputs['Out'] - node_concat_final_results = onnx.helper.make_node( - 'Gather', - inputs=outputs_sort_by_socre_results + - [outputs_topk_select_classes_indices[1]], - outputs=outputs_concat_final_results, - axis=1) - node_list.append(node_concat_final_results) - return node_list diff --git a/x2paddle/op_mapper/paddle2onnx/opset11/paddle_custom_layer/yolo_box.py b/x2paddle/op_mapper/paddle2onnx/opset11/paddle_custom_layer/yolo_box.py deleted file mode 100644 index 919022167b235899422e9bb8079e03ada683a8c5..0000000000000000000000000000000000000000 --- a/x2paddle/op_mapper/paddle2onnx/opset11/paddle_custom_layer/yolo_box.py +++ /dev/null @@ -1,844 +0,0 @@ -# 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 onnx -import numpy as np -from onnx import onnx_pb, helper -from x2paddle.op_mapper.paddle2onnx.opset9.paddle_custom_layer.yolo_box import is_static_shape -from x2paddle.op_mapper.paddle2onnx.opset9.paddle_custom_layer.yolo_box import get_old_name -from x2paddle.op_mapper.paddle2onnx.opset9.paddle_custom_layer.yolo_box import MAX_FLOAT32 - - -def yolo_box(op, block): - inputs = dict() - outputs = dict() - attrs = dict() - for name in op.input_names: - inputs[name] = op.input(name) - for name in op.output_names: - outputs[name] = op.output(name) - for name in op.attr_names: - attrs[name] = op.attr(name) - model_name = outputs['Boxes'][0] - input_shape = block.vars[get_old_name(inputs['X'][0])].shape - is_static_shape(input_shape) - image_size = inputs['ImgSize'] - input_height = input_shape[2] - input_width = input_shape[3] - - class_num = attrs['class_num'] - anchors = attrs['anchors'] - num_anchors = int(len(anchors)) // 2 - downsample_ratio = attrs['downsample_ratio'] - input_size = input_height * downsample_ratio - conf_thresh = attrs['conf_thresh'] - conf_thresh_mat = np.ones([num_anchors * input_height * - input_width]) * conf_thresh - - node_list = [] - im_outputs = [] - - x_shape = [1, num_anchors, 5 + class_num, input_height, input_width] - name_x_shape = [model_name + "@x_shape"] - node_x_shape = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_x_shape, - value=onnx.helper.make_tensor( - name=name_x_shape[0] + "@const", - data_type=onnx.TensorProto.INT64, - dims=[5], - vals=x_shape)) - node_list.append(node_x_shape) - - outputs_x_reshape = [model_name + "@reshape"] - node_x_reshape = onnx.helper.make_node( - 'Reshape', inputs=inputs['X'] + name_x_shape, outputs=outputs_x_reshape) - node_list.append(node_x_reshape) - - outputs_x_transpose = [model_name + "@x_transpose"] - node_x_transpose = onnx.helper.make_node( - 'Transpose', - inputs=outputs_x_reshape, - outputs=outputs_x_transpose, - perm=[0, 1, 3, 4, 2]) - node_list.append(node_x_transpose) - - range_x = [] - range_y = [] - for i in range(0, input_width): - range_x.append(i) - for j in range(0, input_height): - range_y.append(j) - - name_range_x = [model_name + "@range_x"] - node_range_x = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_range_x, - value=onnx.helper.make_tensor( - name=name_range_x[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=[input_width], - vals=range_x)) - node_list.append(node_range_x) - - name_range_y = [model_name + "@range_y"] - node_range_y = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_range_y, - value=onnx.helper.make_tensor( - name=name_range_y[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=[input_height], - vals=range_y)) - node_list.append(node_range_y) - - range_x_new_shape = [1, input_width] - range_y_new_shape = [input_height, 1] - - name_range_x_new_shape = [model_name + "@range_x_new_shape"] - node_range_x_new_shape = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_range_x_new_shape, - value=onnx.helper.make_tensor( - name=name_range_x_new_shape[0] + "@const", - data_type=onnx.TensorProto.INT64, - dims=[len(range_x_new_shape)], - vals=range_x_new_shape)) - node_list.append(node_range_x_new_shape) - - name_range_y_new_shape = [model_name + "@range_y_new_shape"] - node_range_y_new_shape = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_range_y_new_shape, - value=onnx.helper.make_tensor( - name=name_range_y_new_shape[0] + "@const", - data_type=onnx.TensorProto.INT64, - dims=[len(range_y_new_shape)], - vals=range_y_new_shape)) - node_list.append(node_range_y_new_shape) - - outputs_range_x_reshape = [model_name + "@range_x_reshape"] - node_range_x_reshape = onnx.helper.make_node( - 'Reshape', - inputs=name_range_x + name_range_x_new_shape, - outputs=outputs_range_x_reshape) - node_list.append(node_range_x_reshape) - - outputs_range_y_reshape = [model_name + "@range_y_reshape"] - node_range_y_reshape = onnx.helper.make_node( - 'Reshape', - inputs=name_range_y + name_range_y_new_shape, - outputs=outputs_range_y_reshape) - node_list.append(node_range_y_reshape) - - outputs_grid_x = [model_name + "@grid_x"] - node_grid_x = onnx.helper.make_node( - "Tile", - inputs=outputs_range_x_reshape + name_range_y_new_shape, - outputs=outputs_grid_x) - node_list.append(node_grid_x) - - outputs_grid_y = [model_name + "@grid_y"] - node_grid_y = onnx.helper.make_node( - "Tile", - inputs=outputs_range_y_reshape + name_range_x_new_shape, - outputs=outputs_grid_y) - node_list.append(node_grid_y) - - outputs_box_x = [model_name + "@box_x"] - outputs_box_y = [model_name + "@box_y"] - outputs_box_w = [model_name + "@box_w"] - outputs_box_h = [model_name + "@box_h"] - outputs_conf = [model_name + "@conf"] - outputs_prob = [model_name + "@prob"] - - node_split_input = onnx.helper.make_node( - "Split", - inputs=outputs_x_transpose, - outputs=outputs_box_x + outputs_box_y + outputs_box_w\ - + outputs_box_h + outputs_conf + outputs_prob, - axis=-1, - split=[1, 1, 1, 1, 1, class_num]) - node_list.append(node_split_input) - - outputs_box_x_sigmoid = [model_name + "@box_x_sigmoid"] - outputs_box_y_sigmoid = [model_name + "@box_y_sigmoid"] - - node_box_x_sigmoid = onnx.helper.make_node( - "Sigmoid", inputs=outputs_box_x, outputs=outputs_box_x_sigmoid) - node_list.append(node_box_x_sigmoid) - - node_box_y_sigmoid = onnx.helper.make_node( - "Sigmoid", inputs=outputs_box_y, outputs=outputs_box_y_sigmoid) - node_list.append(node_box_y_sigmoid) - - outputs_box_x_squeeze = [model_name + "@box_x_squeeze"] - outputs_box_y_squeeze = [model_name + "@box_y_squeeze"] - - node_box_x_squeeze = onnx.helper.make_node( - 'Squeeze', - inputs=outputs_box_x_sigmoid, - outputs=outputs_box_x_squeeze, - axes=[4]) - node_list.append(node_box_x_squeeze) - - node_box_y_squeeze = onnx.helper.make_node( - 'Squeeze', - inputs=outputs_box_y_sigmoid, - outputs=outputs_box_y_squeeze, - axes=[4]) - node_list.append(node_box_y_squeeze) - - outputs_box_x_add_grid = [model_name + "@box_x_add_grid"] - outputs_box_y_add_grid = [model_name + "@box_y_add_grid"] - - node_box_x_add_grid = onnx.helper.make_node( - "Add", - inputs=outputs_grid_x + outputs_box_x_squeeze, - outputs=outputs_box_x_add_grid) - node_list.append(node_box_x_add_grid) - - node_box_y_add_grid = onnx.helper.make_node( - "Add", - inputs=outputs_grid_y + outputs_box_y_squeeze, - outputs=outputs_box_y_add_grid) - node_list.append(node_box_y_add_grid) - - name_input_h = [model_name + "@input_h"] - name_input_w = [model_name + "@input_w"] - - node_input_h = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_input_h, - value=onnx.helper.make_tensor( - name=name_input_w[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=(), - vals=[input_height])) - node_list.append(node_input_h) - - node_input_w = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_input_w, - value=onnx.helper.make_tensor( - name=name_input_w[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=(), - vals=[input_width])) - node_list.append(node_input_w) - - outputs_box_x_encode = [model_name + "@box_x_encode"] - outputs_box_y_encode = [model_name + "@box_y_encode"] - - node_box_x_encode = onnx.helper.make_node( - 'Div', - inputs=outputs_box_x_add_grid + name_input_w, - outputs=outputs_box_x_encode) - node_list.append(node_box_x_encode) - - node_box_y_encode = onnx.helper.make_node( - 'Div', - inputs=outputs_box_y_add_grid + name_input_h, - outputs=outputs_box_y_encode) - node_list.append(node_box_y_encode) - - name_anchor_tensor = [model_name + "@anchor_tensor"] - node_anchor_tensor = onnx.helper.make_node( - "Constant", - inputs=[], - outputs=name_anchor_tensor, - value=onnx.helper.make_tensor( - name=name_anchor_tensor[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=[len(anchors)], - vals=anchors)) - node_list.append(node_anchor_tensor) - - anchor_shape = [int(num_anchors), 2] - name_anchor_shape = [model_name + "@anchor_shape"] - node_anchor_shape = onnx.helper.make_node( - "Constant", - inputs=[], - outputs=name_anchor_shape, - value=onnx.helper.make_tensor( - name=name_anchor_shape[0] + "@const", - data_type=onnx.TensorProto.INT64, - dims=[2], - vals=anchor_shape)) - node_list.append(node_anchor_shape) - - outputs_anchor_tensor_reshape = [model_name + "@anchor_tensor_reshape"] - node_anchor_tensor_reshape = onnx.helper.make_node( - "Reshape", - inputs=name_anchor_tensor + name_anchor_shape, - outputs=outputs_anchor_tensor_reshape) - node_list.append(node_anchor_tensor_reshape) - - name_input_size = [model_name + "@input_size"] - node_input_size = onnx.helper.make_node( - "Constant", - inputs=[], - outputs=name_input_size, - value=onnx.helper.make_tensor( - name=name_input_size[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=(), - vals=[input_size])) - node_list.append(node_input_size) - - outputs_anchors_div_input_size = [model_name + "@anchors_div_input_size"] - node_anchors_div_input_size = onnx.helper.make_node( - "Div", - inputs=outputs_anchor_tensor_reshape + name_input_size, - outputs=outputs_anchors_div_input_size) - node_list.append(node_anchors_div_input_size) - - outputs_anchor_w = [model_name + "@anchor_w"] - outputs_anchor_h = [model_name + "@anchor_h"] - - node_anchor_split = onnx.helper.make_node( - 'Split', - inputs=outputs_anchors_div_input_size, - outputs=outputs_anchor_w + outputs_anchor_h, - axis=1, - split=[1, 1]) - node_list.append(node_anchor_split) - - new_anchor_shape = [1, int(num_anchors), 1, 1] - name_new_anchor_shape = [model_name + "@new_anchor_shape"] - node_new_anchor_shape = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_new_anchor_shape, - value=onnx.helper.make_tensor( - name=name_new_anchor_shape[0] + "@const", - data_type=onnx.TensorProto.INT64, - dims=[len(new_anchor_shape)], - vals=new_anchor_shape)) - node_list.append(node_new_anchor_shape) - - outputs_anchor_w_reshape = [model_name + "@anchor_w_reshape"] - outputs_anchor_h_reshape = [model_name + "@anchor_h_reshape"] - - node_anchor_w_reshape = onnx.helper.make_node( - 'Reshape', - inputs=outputs_anchor_w + name_new_anchor_shape, - outputs=outputs_anchor_w_reshape) - node_list.append(node_anchor_w_reshape) - - node_anchor_h_reshape = onnx.helper.make_node( - 'Reshape', - inputs=outputs_anchor_h + name_new_anchor_shape, - outputs=outputs_anchor_h_reshape) - node_list.append(node_anchor_h_reshape) - - outputs_box_w_squeeze = [model_name + "@box_w_squeeze"] - node_box_w_squeeze = onnx.helper.make_node( - 'Squeeze', - inputs=outputs_box_w, - outputs=outputs_box_w_squeeze, - axes=[4]) - node_list.append(node_box_w_squeeze) - - outputs_box_h_squeeze = [model_name + "@box_h_squeeze"] - node_box_h_squeeze = onnx.helper.make_node( - 'Squeeze', - inputs=outputs_box_h, - outputs=outputs_box_h_squeeze, - axes=[4]) - node_list.append(node_box_h_squeeze) - - outputs_box_w_exp = [model_name + "@box_w_exp"] - node_box_w_exp = onnx.helper.make_node( - "Exp", inputs=outputs_box_w_squeeze, outputs=outputs_box_w_exp) - node_list.append(node_box_w_exp) - - outputs_box_h_exp = [model_name + "@box_h_exp"] - node_box_h_exp = onnx.helper.make_node( - "Exp", inputs=outputs_box_h_squeeze, outputs=outputs_box_h_exp) - node_list.append(node_box_h_exp) - - outputs_box_w_encode = [model_name + "box_w_encode"] - outputs_box_h_encode = [model_name + "box_h_encode"] - - node_box_w_encode = onnx.helper.make_node( - 'Mul', - inputs=outputs_box_w_exp + outputs_anchor_w_reshape, - outputs=outputs_box_w_encode) - node_list.append(node_box_w_encode) - - node_box_h_encode = onnx.helper.make_node( - 'Mul', - inputs=outputs_box_h_exp + outputs_anchor_h_reshape, - outputs=outputs_box_h_encode) - node_list.append(node_box_h_encode) - - outputs_conf_sigmoid = [model_name + "@conf_sigmoid"] - node_conf_sigmoid = onnx.helper.make_node( - 'Sigmoid', inputs=outputs_conf, outputs=outputs_conf_sigmoid) - node_list.append(node_conf_sigmoid) - - name_conf_thresh = [model_name + "@conf_thresh"] - node_conf_thresh = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_conf_thresh, - value=onnx.helper.make_tensor( - name=name_conf_thresh[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=[num_anchors * input_height * input_width], - vals=conf_thresh_mat)) - node_list.append(node_conf_thresh) - - conf_shape = [1, int(num_anchors), input_height, input_width, 1] - name_conf_shape = [model_name + "@conf_shape"] - node_conf_shape = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_conf_shape, - value=onnx.helper.make_tensor( - name=name_conf_shape[0] + "@const", - data_type=onnx.TensorProto.INT64, - dims=[len(conf_shape)], - vals=conf_shape)) - node_list.append(node_conf_shape) - - outputs_conf_thresh_reshape = [model_name + "@conf_thresh_reshape"] - node_conf_thresh_reshape = onnx.helper.make_node( - 'Reshape', - inputs=name_conf_thresh + name_conf_shape, - outputs=outputs_conf_thresh_reshape) - node_list.append(node_conf_thresh_reshape) - - outputs_conf_sub = [model_name + "@conf_sub"] - node_conf_sub = onnx.helper.make_node( - 'Sub', - inputs=outputs_conf_sigmoid + outputs_conf_thresh_reshape, - outputs=outputs_conf_sub) - node_list.append(node_conf_sub) - - outputs_conf_clip = [model_name + "@conf_clip"] - node_conf_clip = onnx.helper.make_node( - 'Clip', inputs=outputs_conf_sub, outputs=outputs_conf_clip) - node_list.append(node_conf_clip) - - zeros = [0] - name_zeros = [model_name + "@zeros"] - node_zeros = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_zeros, - value=onnx.helper.make_tensor( - name=name_zeros[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=(), - vals=zeros)) - node_list.append(node_zeros) - - outputs_conf_clip_bool = [model_name + "@conf_clip_bool"] - node_conf_clip_bool = onnx.helper.make_node( - 'Greater', - inputs=outputs_conf_clip + name_zeros, - outputs=outputs_conf_clip_bool) - node_list.append(node_conf_clip_bool) - - outputs_conf_clip_cast = [model_name + "@conf_clip_cast"] - node_conf_clip_cast = onnx.helper.make_node( - 'Cast', - inputs=outputs_conf_clip_bool, - outputs=outputs_conf_clip_cast, - to=1) - node_list.append(node_conf_clip_cast) - - outputs_conf_set_zero = [model_name + "@conf_set_zero"] - node_conf_set_zero = onnx.helper.make_node( - 'Mul', - inputs=outputs_conf_sigmoid + outputs_conf_clip_cast, - outputs=outputs_conf_set_zero) - node_list.append(node_conf_set_zero) - - outputs_prob_sigmoid = [model_name + "@prob_sigmoid"] - node_prob_sigmoid = onnx.helper.make_node( - 'Sigmoid', inputs=outputs_prob, outputs=outputs_prob_sigmoid) - node_list.append(node_prob_sigmoid) - - new_shape = [1, int(num_anchors), input_height, input_width, 1] - name_new_shape = [model_name + "@new_shape"] - node_new_shape = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_new_shape, - value=onnx.helper.make_tensor( - name=name_new_shape[0] + "@const", - data_type=onnx.TensorProto.INT64, - dims=[len(new_shape)], - vals=new_shape)) - node_list.append(node_new_shape) - - outputs_conf_new_shape = [model_name + "@_conf_new_shape"] - node_conf_new_shape = onnx.helper.make_node( - 'Reshape', - inputs=outputs_conf_set_zero + name_new_shape, - outputs=outputs_conf_new_shape) - node_list.append(node_conf_new_shape) - - outputs_score = [model_name + "@score"] - node_score = onnx.helper.make_node( - 'Mul', - inputs=outputs_prob_sigmoid + outputs_conf_new_shape, - outputs=outputs_score) - node_list.append(node_score) - - outputs_conf_bool = [model_name + "@conf_bool"] - node_conf_bool = onnx.helper.make_node( - 'Greater', - inputs=outputs_conf_new_shape + name_zeros, - outputs=outputs_conf_bool) - node_list.append(node_conf_bool) - - outputs_box_x_new_shape = [model_name + "@box_x_new_shape"] - node_box_x_new_shape = onnx.helper.make_node( - 'Reshape', - inputs=outputs_box_x_encode + name_new_shape, - outputs=outputs_box_x_new_shape) - node_list.append(node_box_x_new_shape) - - outputs_box_y_new_shape = [model_name + "@box_y_new_shape"] - node_box_y_new_shape = onnx.helper.make_node( - 'Reshape', - inputs=outputs_box_y_encode + name_new_shape, - outputs=outputs_box_y_new_shape) - node_list.append(node_box_y_new_shape) - - outputs_box_w_new_shape = [model_name + "@box_w_new_shape"] - node_box_w_new_shape = onnx.helper.make_node( - 'Reshape', - inputs=outputs_box_w_encode + name_new_shape, - outputs=outputs_box_w_new_shape) - node_list.append(node_box_w_new_shape) - - outputs_box_h_new_shape = [model_name + "@box_h_new_shape"] - node_box_h_new_shape = onnx.helper.make_node( - 'Reshape', - inputs=outputs_box_h_encode + name_new_shape, - outputs=outputs_box_h_new_shape) - node_list.append(node_box_h_new_shape) - - outputs_pred_box = [model_name + "@pred_box"] - node_pred_box = onnx.helper.make_node( - 'Concat', - inputs=outputs_box_x_new_shape + outputs_box_y_new_shape + \ - outputs_box_w_new_shape + outputs_box_h_new_shape, - outputs=outputs_pred_box, - axis=4) - node_list.append(node_pred_box) - - outputs_conf_cast = [model_name + "conf_cast"] - node_conf_cast = onnx.helper.make_node( - 'Cast', inputs=outputs_conf_bool, outputs=outputs_conf_cast, to=1) - node_list.append(node_conf_cast) - - outputs_pred_box_mul_conf = [model_name + "@pred_box_mul_conf"] - node_pred_box_mul_conf = onnx.helper.make_node( - 'Mul', - inputs=outputs_pred_box + outputs_conf_cast, - outputs=outputs_pred_box_mul_conf) - node_list.append(node_pred_box_mul_conf) - - box_shape = [1, int(num_anchors) * input_height * input_width, 4] - name_box_shape = [model_name + "@box_shape"] - node_box_shape = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_box_shape, - value=onnx.helper.make_tensor( - name=name_box_shape[0] + "@const", - data_type=onnx.TensorProto.INT64, - dims=[len(box_shape)], - vals=box_shape)) - node_list.append(node_box_shape) - - outputs_pred_box_new_shape = [model_name + "@pred_box_new_shape"] - node_pred_box_new_shape = onnx.helper.make_node( - 'Reshape', - inputs=outputs_pred_box_mul_conf + name_box_shape, - outputs=outputs_pred_box_new_shape) - node_list.append(node_pred_box_new_shape) - - outputs_pred_box_x = [model_name + "@_pred_box_x"] - outputs_pred_box_y = [model_name + "@_pred_box_y"] - outputs_pred_box_w = [model_name + "@_pred_box_w"] - outputs_pred_box_h = [model_name + "@_pred_box_h"] - - node_pred_box_split = onnx.helper.make_node( - 'Split', - inputs=outputs_pred_box_new_shape, - outputs=outputs_pred_box_x + outputs_pred_box_y + outputs_pred_box_w + - outputs_pred_box_h, - axis=2) - node_list.append(node_pred_box_split) - - name_number_two = [model_name + "@number_two"] - node_number_two = onnx.helper.make_node( - "Constant", - inputs=[], - outputs=name_number_two, - value=onnx.helper.make_tensor( - name=name_number_two[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=(), - vals=[2])) - node_list.append(node_number_two) - - outputs_half_w = [model_name + "@half_w"] - node_half_w = onnx.helper.make_node( - "Div", - inputs=outputs_pred_box_w + name_number_two, - outputs=outputs_half_w) - node_list.append(node_half_w) - - outputs_half_h = [model_name + "@half_h"] - node_half_h = onnx.helper.make_node( - "Div", - inputs=outputs_pred_box_h + name_number_two, - outputs=outputs_half_h) - node_list.append(node_half_h) - - outputs_pred_box_x1 = [model_name + "@pred_box_x1"] - node_pred_box_x1 = onnx.helper.make_node( - 'Sub', - inputs=outputs_pred_box_x + outputs_half_w, - outputs=outputs_pred_box_x1) - node_list.append(node_pred_box_x1) - - outputs_pred_box_y1 = [model_name + "@pred_box_y1"] - node_pred_box_y1 = onnx.helper.make_node( - 'Sub', - inputs=outputs_pred_box_y + outputs_half_h, - outputs=outputs_pred_box_y1) - node_list.append(node_pred_box_y1) - - outputs_pred_box_x2 = [model_name + "@pred_box_x2"] - node_pred_box_x2 = onnx.helper.make_node( - 'Add', - inputs=outputs_pred_box_x + outputs_half_w, - outputs=outputs_pred_box_x2) - node_list.append(node_pred_box_x2) - - outputs_pred_box_y2 = [model_name + "@pred_box_y2"] - node_pred_box_y2 = onnx.helper.make_node( - 'Add', - inputs=outputs_pred_box_y + outputs_half_h, - outputs=outputs_pred_box_y2) - node_list.append(node_pred_box_y2) - - outputs_sqeeze_image_size = [model_name + "@sqeeze_image_size"] - node_sqeeze_image_size = onnx.helper.make_node( - "Squeeze", - axes=[0], - inputs=image_size, - outputs=outputs_sqeeze_image_size) - node_list.append(node_sqeeze_image_size) - - output_img_height = [model_name + "@img_height"] - output_img_width = [model_name + "@img_width"] - node_image_size_split = onnx.helper.make_node( - "Split", - inputs=outputs_sqeeze_image_size, - outputs=output_img_height + output_img_width, - axis=-1, - split=[1, 1]) - node_list.append(node_image_size_split) - - output_img_width_cast = [model_name + "@img_width_cast"] - node_img_width_cast = onnx.helper.make_node( - 'Cast', inputs=output_img_width, outputs=output_img_width_cast, to=1) - node_list.append(node_img_width_cast) - - output_img_height_cast = [model_name + "@img_height_cast"] - node_img_height_cast = onnx.helper.make_node( - 'Cast', inputs=output_img_height, outputs=output_img_height_cast, to=1) - node_list.append(node_img_height_cast) - - outputs_pred_box_x1_decode = [model_name + "@pred_box_x1_decode"] - outputs_pred_box_y1_decode = [model_name + "@pred_box_y1_decode"] - outputs_pred_box_x2_decode = [model_name + "@pred_box_x2_decode"] - outputs_pred_box_y2_decode = [model_name + "@pred_box_y2_decode"] - - node_pred_box_x1_decode = onnx.helper.make_node( - 'Mul', - inputs=outputs_pred_box_x1 + output_img_width_cast, - outputs=outputs_pred_box_x1_decode) - node_list.append(node_pred_box_x1_decode) - - node_pred_box_y1_decode = onnx.helper.make_node( - 'Mul', - inputs=outputs_pred_box_y1 + output_img_height_cast, - outputs=outputs_pred_box_y1_decode) - node_list.append(node_pred_box_y1_decode) - - node_pred_box_x2_decode = onnx.helper.make_node( - 'Mul', - inputs=outputs_pred_box_x2 + output_img_width_cast, - outputs=outputs_pred_box_x2_decode) - node_list.append(node_pred_box_x2_decode) - - node_pred_box_y2_decode = onnx.helper.make_node( - 'Mul', - inputs=outputs_pred_box_y2 + output_img_height_cast, - outputs=outputs_pred_box_y2_decode) - node_list.append(node_pred_box_y2_decode) - - name_number_one = [model_name + "@one"] - node_number_one = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_number_one, - value=onnx.helper.make_tensor( - name=name_number_one[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=(), - vals=[1])) - node_list.append(node_number_one) - - output_new_img_height = [model_name + "@new_img_height"] - node_new_img_height = onnx.helper.make_node( - 'Sub', - inputs=output_img_height_cast + name_number_one, - outputs=output_new_img_height) - node_list.append(node_new_img_height) - - output_new_img_width = [model_name + "@new_img_width"] - node_new_img_width = onnx.helper.make_node( - 'Sub', - inputs=output_img_width_cast + name_number_one, - outputs=output_new_img_width) - node_list.append(node_new_img_width) - - outputs_pred_box_x2_sub_w = [model_name + "@pred_box_x2_sub_w"] - node_pred_box_x2_sub_w = onnx.helper.make_node( - 'Sub', - inputs=outputs_pred_box_x2_decode + output_new_img_width, - outputs=outputs_pred_box_x2_sub_w) - node_list.append(node_pred_box_x2_sub_w) - - outputs_pred_box_y2_sub_h = [model_name + "@pred_box_y2_sub_h"] - node_pred_box_y2_sub_h = onnx.helper.make_node( - 'Sub', - inputs=outputs_pred_box_y2_decode + output_new_img_height, - outputs=outputs_pred_box_y2_sub_h) - node_list.append(node_pred_box_y2_sub_h) - - outputs_pred_box_x1_clip = [model_name + "@pred_box_x1_clip"] - outputs_pred_box_y1_clip = [model_name + "@pred_box_y1_clip"] - outputs_pred_box_x2_clip = [model_name + "@pred_box_x2_clip"] - outputs_pred_box_y2_clip = [model_name + "@pred_box_y2_clip"] - - min_const_name = model_name + "@pred_box_min_const" - max_const_name = model_name + "@pred_box_max_const" - - min_const = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=[min_const_name], - value=onnx.helper.make_tensor( - name=min_const_name, - data_type=onnx.TensorProto.FLOAT, - dims=(), - vals=[0.0])) - node_list.append(min_const) - - max_const = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=[max_const_name], - value=onnx.helper.make_tensor( - name=max_const_name, - data_type=onnx.TensorProto.FLOAT, - dims=(), - vals=[MAX_FLOAT32])) - node_list.append(max_const) - - node_pred_box_x1_clip = onnx.helper.make_node( - 'Clip', - inputs=outputs_pred_box_x1_decode + [min_const_name, max_const_name], - outputs=outputs_pred_box_x1_clip) - node_list.append(node_pred_box_x1_clip) - - node_pred_box_y1_clip = onnx.helper.make_node( - 'Clip', - inputs=outputs_pred_box_y1_decode + [min_const_name, max_const_name], - outputs=outputs_pred_box_y1_clip) - node_list.append(node_pred_box_y1_clip) - - node_pred_box_x2_clip = onnx.helper.make_node( - 'Clip', - inputs=outputs_pred_box_x2_sub_w + [min_const_name, max_const_name], - outputs=outputs_pred_box_x2_clip) - node_list.append(node_pred_box_x2_clip) - - node_pred_box_y2_clip = onnx.helper.make_node( - 'Clip', - inputs=outputs_pred_box_y2_sub_h + [min_const_name, max_const_name], - outputs=outputs_pred_box_y2_clip) - node_list.append(node_pred_box_y2_clip) - - outputs_pred_box_x2_res = [model_name + "@box_x2_res"] - node_pred_box_x2_res = onnx.helper.make_node( - 'Sub', - inputs=outputs_pred_box_x2_decode + outputs_pred_box_x2_clip, - outputs=outputs_pred_box_x2_res) - node_list.append(node_pred_box_x2_res) - - outputs_pred_box_y2_res = [model_name + "@box_y2_res"] - node_pred_box_y2_res = onnx.helper.make_node( - 'Sub', - inputs=outputs_pred_box_y2_decode + outputs_pred_box_y2_clip, - outputs=outputs_pred_box_y2_res) - node_list.append(node_pred_box_y2_res) - - node_pred_box_result = onnx.helper.make_node( - 'Concat', - inputs=outputs_pred_box_x1_clip + outputs_pred_box_y1_clip + - outputs_pred_box_x2_res + outputs_pred_box_y2_res, - outputs=outputs['Boxes'], - axis=-1) - node_list.append(node_pred_box_result) - - score_shape = [1, input_height * input_width * int(num_anchors), class_num] - name_score_shape = [model_name + "@score_shape"] - node_score_shape = onnx.helper.make_node( - "Constant", - inputs=[], - outputs=name_score_shape, - value=onnx.helper.make_tensor( - name=name_score_shape[0] + "@const", - data_type=onnx.TensorProto.INT64, - dims=[len(score_shape)], - vals=score_shape)) - node_list.append(node_score_shape) - - node_score_new_shape = onnx.helper.make_node( - 'Reshape', - inputs=outputs_score + name_score_shape, - outputs=outputs['Scores']) - node_list.append(node_score_new_shape) - return node_list diff --git a/x2paddle/op_mapper/paddle2onnx/opset9/__init__.py b/x2paddle/op_mapper/paddle2onnx/opset9/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/x2paddle/op_mapper/paddle2onnx/opset9/opset.py b/x2paddle/op_mapper/paddle2onnx/opset9/opset.py deleted file mode 100644 index 0cec86f336db2ce8a5f0098ba6b3081ef499f5ad..0000000000000000000000000000000000000000 --- a/x2paddle/op_mapper/paddle2onnx/opset9/opset.py +++ /dev/null @@ -1,962 +0,0 @@ -# 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 sys -import x2paddle -import os -import numpy as np -import paddle.fluid.core as core -import paddle.fluid as fluid -import onnx -from onnx import helper, onnx_pb - - -class OpSet9(object): - def __init__(self): - self.paddle_onnx_dtype_map = { - core.VarDesc.VarType.FP32: onnx_pb.TensorProto.FLOAT, - core.VarDesc.VarType.FP64: onnx_pb.TensorProto.DOUBLE, - core.VarDesc.VarType.INT32: onnx_pb.TensorProto.INT32, - core.VarDesc.VarType.INT16: onnx_pb.TensorProto.INT16, - core.VarDesc.VarType.INT16: onnx_pb.TensorProto.UINT16, - core.VarDesc.VarType.INT64: onnx_pb.TensorProto.INT64, - core.VarDesc.VarType.BOOL: onnx_pb.TensorProto.BOOL - } - self.name_counter = dict() - - def get_name(self, op_name, var_name): - name = 'p2o.{}.{}'.format(op_name, var_name) - if name not in self.name_counter: - self.name_counter[name] = 0 - else: - self.name_counter[name] += 1 - return name + '.{}'.format(self.name_counter[name]) - - def make_constant_node(self, name, dtype, value=None): - if isinstance(value, list): - dims = (len(value), ) - elif value is None: - dims = () - value = [] - else: - dims = () - value = [value] - tensor = helper.make_tensor( - name=name, data_type=dtype, dims=dims, vals=value) - node = helper.make_node( - 'Constant', inputs=[], outputs=[name], value=tensor) - return node - - def convert_weights(self, program, scope=None): - var_names = program.global_block().vars - nodes = list() - for name in var_names: - var = program.global_block().var(name) - if name.endswith('feed') or name.endswith('fetch'): - continue - if not var.persistable: - continue - weight = np.array(scope.find_var(name).get_tensor()) - tensor = helper.make_tensor( - name=name, - dims=var.shape, - data_type=self.paddle_onnx_dtype_map[var.dtype], - vals=weight.flatten().tolist()) - node = helper.make_node( - 'Constant', inputs=[], outputs=[name], value=tensor) - nodes.append(node) - return nodes - - def conv2d(self, op, block): - kernel_shape = block.var(op.input('Filter')[0]).shape - node = helper.make_node( - 'Conv', - inputs=op.input('Input') + op.input('Filter'), - outputs=op.output('Output'), - dilations=op.attr('dilations'), - kernel_shape=kernel_shape[-2:], - strides=op.attr('strides'), - group=op.attr('groups'), - pads=op.attr('paddings') + op.attr('paddings')) - return node - - def conv2d_transpose(self, op, block): - kernel_shape = block.var(op.input('Filter')[0]).shape - node = helper.make_node( - 'ConvTranspose', - inputs=op.input('Input') + op.input('Filter'), - outputs=op.output('Output'), - dilations=op.attr('dilations'), - kernel_shape=kernel_shape[-2:], - strides=op.attr('strides'), - group=1, - pads=op.attr('paddings') + op.attr('paddings')) - return node - - def relu(self, op, block): - node = helper.make_node( - 'Relu', inputs=op.input('X'), outputs=op.output('Out')) - return node - - def tanh(self, op, block): - node = helper.make_node( - 'Tanh', inputs=op.input('X'), outputs=op.output('Out')) - return node - - def log(self, op, block): - node = helper.make_node( - 'Log', inputs=op.input('X'), outputs=op.output('Out')) - return node - - def sigmoid(self, op, block): - node = helper.make_node( - 'Sigmoid', inputs=op.input('X'), outputs=op.output('Out')) - return node - - def clip(self, op, block): - min_value = op.attr('min') - max_value = op.attr('max') - node = helper.make_node( - 'Clip', - inputs=[op.input('X')[0]], - outputs=op.output('Out'), - max=max_value, - min=min_value) - return node - - def exp(self, op, block): - node = helper.make_node( - 'Exp', inputs=op.input('X'), outputs=op.output('Out')) - return node - - def abs(self, op, block): - node = helper.make_node( - 'Abs', inputs=op.input('X'), outputs=op.output('Out')) - return node - - def leaky_relu(self, op, block): - node = helper.make_node( - 'LeakyRelu', - inputs=op.input('X'), - outputs=op.output('Out'), - alpha=op.attr('alpha')) - return node - - def elementwise_add(self, op, block): - axis = op.attr('axis') - x_shape = block.var(op.input('X')[0]).shape - y_shape = block.var(op.input('Y')[0]).shape - if len(y_shape) == 1 and axis == 1: - shape_name = self.get_name(op.type, 'shape') - shape_value = [1] * len(x_shape) - shape_value[axis] = y_shape[0] - shape_node = self.make_constant_node( - shape_name, onnx_pb.TensorProto.INT64, shape_value) - temp_value = self.get_name(op.type, 'temp') - y_node = helper.make_node( - 'Reshape', - inputs=[op.input('Y')[0], shape_name], - outputs=[temp_value]) - node = helper.make_node( - 'Add', - inputs=[op.input('X')[0], temp_value], - outputs=op.output('Out')) - return [shape_node, y_node, node] - elif axis == -1 or axis == (len(x_shape) - 1 - ) or len(x_shape) == len(y_shape): - node = helper.make_node( - 'Add', - inputs=[op.input('X')[0], op.input('Y')[0]], - outputs=op.output('Out')) - return node - else: - raise Exception("Unexpected situation happend in elementwise_add") - - def elementwise_sub(self, op, block): - axis = op.attr('axis') - x_shape = block.var(op.input('X')[0]).shape - y_shape = block.var(op.input('Y')[0]).shape - if len(y_shape) == 1 and axis == 1: - shape_name = self.get_name(op.type, 'shape') - shape_value = [1] * len(x_shape) - shape_value[axis] = y_shape[0] - shape_node = self.make_constant_node( - shape_name, onnx_pb.TensorProto.INT64, shape_value) - temp_value = self.get_name(op.type, 'temp') - y_node = helper.make_node( - 'Reshape', - inputs=[op.input('Y')[0], shape_name], - outputs=[temp_value]) - node = helper.make_node( - 'Sub', - inputs=[op.input('X')[0], temp_value], - outputs=op.output('Out')) - return [shape_node, y_node, node] - elif axis == -1 or axis == (len(x_shape) - 1 - ) or len(x_shape) == len(y_shape): - node = helper.make_node( - 'Sub', - inputs=[op.input('X')[0], op.input('Y')[0]], - outputs=op.output('Out')) - return node - else: - raise Exception("Unexpected situation happend in elementwise_sub") - - def pool2d(self, op, block): - pool_type = { - 'max': ('MaxPool', 'GlobalMaxPool'), - 'avg': ('AveragePool', 'GlobalAveragePool') - } - if op.attr('global_pooling'): - node = helper.make_node( - pool_type[op.attr('pooling_type')][1], - inputs=op.input('X'), - outputs=op.output('Out'), ) - elif op.attr('adaptive'): - raise Excpetion("ONNX cannot support adaptive pool") - else: - input_shape = block.var(op.input('X')[0]).shape - k_size = op.attr('ksize') - paddings = op.attr('paddings') - if input_shape[2] > 0 and input_shape[2] + paddings[0] < k_size[0]: - k_size[0] = input_shape[2] + paddings[0] - if input_shape[3] > 0 and input_shape[3] + paddings[1] < k_size[1]: - k_size[1] = input_shape[3] + paddings[1] - node = helper.make_node( - pool_type[op.attr('pooling_type')][0], - inputs=op.input('X'), - outputs=op.output('Out'), - kernel_shape=k_size, - strides=op.attr('strides'), - pads=op.attr('paddings') + op.attr('paddings')) - return node - - def pad2d(self, op, block): - x_shape = block.var(op.input('X')[0]).shape - paddings = op.attr('paddings') - onnx_pads = [] - if op.attr('data_format') == 'NCHW': - pads = [ - 0, 0, paddings[0], paddings[2], 0, 0, paddings[1], paddings[3] - ] - else: - pads = [ - 0, paddings[0], paddings[2], 0, 0, paddings[1], paddings[3], 0 - ] - #TODO support pads is Variable - node = helper.make_node( - 'Pad', - inputs=op.input('X'), - outputs=op.output('Out'), - mode=op.attr('mode'), - value=op.attr('pad_value'), - pads=pads) - return node - - def softmax(self, op, block): - axis = op.attr('axis') - shape = block.var(op.output('Out')[0]).shape - if axis < 0: - axis += len(shape) - if axis == len(shape) - 1: - node = helper.make_node( - 'Softmax', - inputs=op.input('X'), - outputs=op.output('Out'), - axis=op.attr('axis')) - return node - else: - perm = [i for i in range(len(shape))] - perm[-1] = axis - perm[axis] = len(shape) - 1 - transpose_name0 = self.get_name(op.type, 'transpose') - transpose_node0 = helper.make_node( - 'Transpose', - inputs=op.input('X'), - outputs=[transpose_name0], - perm=perm) - softmax_name = self.get_name(op.type, 'softmax') - softmax_node = helper.make_node( - 'Softmax', - inputs=[transpose_name0], - outputs=[softmax_name], - axis=-1) - transpose_name1 = self.get_name(op.type, 'transpose') - transpose_node1 = helper.make_node( - 'Transpose', - inputs=[softmax_name], - outputs=op.output('Out'), - perm=perm) - return [transpose_node0, softmax_node, transpose_node1] - - def scale(self, op, block): - scale = op.attr('scale') - bias = op.attr('bias') - if math.fabs(scale - 1.0) < 1e-06 and math.fabs(bias - 0.0) < 1e-06: - node = helper.make_node( - 'Identity', inputs=op.input('X'), outputs=op.output('Out')) - return node - else: - scale_name = self.get_name(op.type, 'scale') - bias_name = self.get_name(op.type, 'bias') - scale_node = self.make_constant_node( - scale_name, onnx_pb.TensorProto.FLOAT, scale) - bias_node = self.make_constant_node(bias_name, - onnx_pb.TensorProto.FLOAT, bias) - temp_tensor_name = self.get_name(op.type, 'temporary') - if op.attr('bias_after_scale'): - node1 = helper.make_node( - 'Mul', - inputs=[scale_name, op.input('X')[0]], - outputs=[temp_tensor_name]) - node2 = helper.make_node( - 'Add', - inputs=[bias_name, temp_tensor_name], - outputs=op.output('Out')) - else: - node1 = helper.make_node( - 'Add', - inputs=[bias_name, op.input('X')[0]], - outputs=temp_tensor_name) - node2 = helper.make_node( - 'Mul', - inputs=[scale_name, temp_tensor_name], - outputs=[op.output('Out')]) - return [scale_node, bias_node, node1, node2] - - def mul(self, op, block): - x_shape = block.var(op.input('X')[0]).shape - y_shape = block.var(op.input('Y')[0]).shape - out_shape = list(block.var(op.output('Out')[0]).shape) - x_num_col_dims = op.attr('x_num_col_dims') - y_num_col_dims = op.attr('y_num_col_dims') - flatten_x_name = 'flatten_{}'.format(op.input('X')[0]) - flatten_y_name = 'flatten_{}'.format(op.input('Y')[0]) - shape_name = 'temp_shape_{}'.format(op.output('Out')[0]) - temp_out_name = 'temp_{}'.format(op.output('Out')[0]) - flatten_x = helper.make_node( - 'Flatten', - inputs=op.input('X'), - outputs=[flatten_x_name], - axis=x_num_col_dims) - flatten_y = helper.make_node( - 'Flatten', - inputs=op.input('Y'), - outputs=[flatten_y_name], - axis=y_num_col_dims) - shape_node = self.make_constant_node( - shape_name, onnx_pb.TensorProto.INT64, out_shape) - node = helper.make_node( - 'MatMul', - inputs=[flatten_x_name, flatten_y_name], - outputs=[temp_out_name]) - reshape_out = helper.make_node( - 'Reshape', - inputs=[temp_out_name, shape_name], - outputs=op.output('Out')) - return [flatten_x, flatten_y, shape_node, node, reshape_out] - - def batch_norm(self, op, block): - kwargs = { - 'epsilon': op.attr('epsilon'), - 'momentum': op.attr('momentum') - } - inputs = op.input('X') + op.input('Scale') + op.input( - 'Bias') + op.input('Mean') + op.input('Variance') - node = helper.make_node( - 'BatchNormalization', - inputs=inputs, - outputs=op.output('Y'), - **kwargs) - return node - - def instance_norm(self, op, block): - kwargs = {'epsilon': op.attr('epsilon'), } - inputs = op.input('X') + op.input('Scale') + op.input('Bias') - node = helper.make_node( - 'InstanceNormalization', - inputs=inputs, - outputs=op.output('Y'), - **kwargs) - return node - - def concat(self, op, block): - node = helper.make_node( - 'Concat', - inputs=op.input('X'), - outputs=op.output('Out'), - axis=op.attr('axis')) - return node - - def sum(self, op, block): - node = helper.make_node( - 'Sum', inputs=op.input('X'), outputs=op.output('Out')) - return node - - def floor(self, op, block): - node = helper.make_node( - 'Floor', inputs=op.input('X'), outputs=op.output('Out')) - return node - - def uniform_random_batch_size_like(self, op, block): - node = helper.make_node( - 'RandomUniformLike', - inputs=op.input('Input'), - outputs=op.output('Out'), - high=op.attr('max'), - dtype=self.paddle_onnx_dtype_map[op.attr('dtype')], - low=op.attr('min'), - seed=float(op.attr('seed')), ) - return node - - def depthwise_conv2d(self, op, block): - return self.conv2d(op, block) - - def relu6(self, op, block): - threshold = op.attr('threshold') - node = helper.make_node( - 'Clip', - inputs=[op.input('X')[0]], - outputs=op.output('Out'), - max=threshold, - min=0.0) - return [node] - - def shape(self, op, block): - node = helper.make_node( - 'Shape', inputs=op.input('Input'), outputs=op.output('Out')) - return node - - def split(self, op, block): - sections = op.attr('sections') - if len(sections) > 0: - node = helper.make_node( - 'Split', - inputs=op.input('X'), - outputs=op.output('Out'), - axis=op.attr('axis'), - split=sections) - else: - node = helper.make_node( - 'Split', - inputs=op.input('X'), - outputs=op.output('Out'), - axis=op.attr('axis')) - return node - - def slice(self, op, block): - axes = op.attr('axes') - starts = op.attr('starts') - ends = op.attr('ends') - node = helper.make_node( - "Slice", - inputs=[op.input('Input')[0]], - outputs=op.output('Out'), - axes=axes, - starts=starts, - ends=ends) - return [node] - - def fill_constant(self, op, block): - value = op.attr('value') - dtype = op.attr('dtype') - shape = op.attr('shape') - value = np.ones(shape) * value - if dtype == 2: - value = value.astype('int32') - node = helper.make_node( - 'Constant', - inputs=[], - outputs=op.output('Out'), - value=helper.make_tensor( - name=op.output('Out')[0], - data_type=self.paddle_onnx_dtype_map[dtype], - dims=shape, - vals=value.tolist())) - return node - - def transpose2(self, op, block): - node = helper.make_node( - 'Transpose', - inputs=op.input('X'), - outputs=op.output('Out'), - perm=op.attr('axis')) - return node - - def flatten2(self, op, block): - node = helper.make_node( - 'Flatten', - inputs=op.input('X'), - outputs=op.output('Out'), - axis=op.attr('axis')) - return node - - def reshape2(self, op, block): - input_names = op.input_names - if len(op.input('ShapeTensor')) > 1: - cast_shape_nodes = list() - cast_shape_names = list() - for i in range(len(op.input('ShapeTensor'))): - dim = op.input('ShapeTensor')[i] - temp_name = self.get_name(op.type, 'shape.cast') - node = helper.make_node( - 'Cast', - inputs=[dim], - outputs=[temp_name], - to=onnx_pb.TensorProto.INT64) - cast_shape_nodes.append(node) - cast_shape_names.append(temp_name) - - temp_name = self.get_name(op.type, 'shape.concat') - shape_node = helper.make_node( - 'Concat', inputs=cast_shape_names, outputs=[temp_name], axis=-1) - node = helper.make_node( - 'Reshape', - inputs=[op.input('X')[0], temp_name], - outputs=op.output('Out')) - return cast_shape_nodes + [shape_node, node] - elif len(op.input('ShapeTensor')) == 1: - temp_name = self.get_name(op.type, 'shape.cast') - cast_shape_node = helper.make_node( - 'Cast', - inputs=op.input('ShapeTensor'), - outputs=[temp_name], - to=onnx_pb.TensorProto.INT64) - node = helper.make_node( - 'Reshape', - inputs=[op.input('X')[0], temp_name], - outputs=op.output('Out')) - return [cast_shape_node, node] - elif op.attr('shape') is not None and len(op.attr('shape')) > 0: - shape_name = self.get_name(op.type, 'shape') - shape_node = self.make_constant_node(shape_name, - onnx_pb.TensorProto.INT64, - op.attr('shape')) - reshape_node = helper.make_node( - 'Reshape', - inputs=[op.input('X')[0], shape_name], - outputs=op.output('Out')) - return [shape_node, reshape_node] - - def dropout(self, op, block): - dropout_mode = op.attr('dropout_implementation') - dropout_prob = op.attr('dropout_prob') - if dropout_mode == 'upscale_in_train': - node = helper.make_node( - 'Identity', inputs=op.input('X'), outputs=op.output('Out')) - return node - elif dropout_mode == 'downgrade_in_infer': - scale_name = self.get_name(op.type, 'scale') - scale_node = self.make_constant_node( - scale_name, onnx_pb.TensorProto.FLOAT, 1 - dropout_prob) - node = helper.make_node( - "Mul", - inputs=[op.input('X')[0], scale_name], - outputs=op.output('Out')) - return [scale_node, node] - else: - raise Exception("Unexpected situation happend") - - def reduce_mean(self, op, block): - node = helper.make_node( - 'ReduceMean', - inputs=op.input('X'), - outputs=op.output('Out'), - axes=op.attr('dim'), - keepdims=op.attr('keep_dim')) - return node - - def bilinear_interp(self, op, block): - input_names = op.input_names - input_shape = block.vars[op.input('X')[0]].shape - if op.attr('align_corners') or op.attr('align_mode') == 0: - raise Exception( - "Resize in onnx(opset<=10) only support coordinate_transformation_mode: 'asymmetric', Try converting with --onnx_opset 11" - ) - if ('OutSize' in input_names and len(op.input('OutSize')) > 0) or ( - 'SizeTensor' in input_names and - len(op.input('SizeTensor')) > 0): - node_list = list() - shape_name0 = self.get_name(op.type, 'shape') - shape_node0 = helper.make_node( - 'Shape', inputs=op.input('X'), outputs=[shape_name0]) - starts_name = self.get_name(op.type, 'slice.starts') - starts_node = self.make_constant_node( - starts_name, onnx_pb.TensorProto.INT64, [0]) - ends_name = self.get_name(op.type, 'slice.ends') - ends_node = self.make_constant_node(ends_name, - onnx_pb.TensorProto.INT64, [2]) - shape_name1 = self.get_name(op.type, 'shape') - shape_node1 = helper.make_node( - 'Slice', - inputs=[shape_name0, starts_name, ends_name], - outputs=[shape_name1]) - node_list.extend([shape_node0, starts_node, ends_node, shape_node1]) - if 'OutSize' in input_names and len(op.input('OutSize')) > 0: - cast_shape_name = self.get_name(op.type, "shape.cast") - cast_shape_node = helper.make_node( - 'Cast', - inputs=op.input('OutSize'), - outputs=[cast_shape_name], - to=onnx_pb.TensorProto.INT64) - node_list.append(cast_shape_node) - else: - concat_shape_name = self.get_name( - op.type, op.output('Out')[0] + "shape.concat") - concat_shape_node = helper.make_node( - "Concat", - inputs=op.input('SizeTensor'), - outputs=[concat_shape_name], - axis=0) - cast_shape_name = self.get_name(op.type, "shape.cast") - cast_shape_node = helper.make_node( - 'Cast', - inputs=[concat_shape_name], - outputs=[cast_shape_name], - to=onnx_pb.TensorProto.INT64) - node_list.extend([concat_shape_node, cast_shape_node]) - shape_name2 = self.get_name(op.type, "shape.concat") - shape_node2 = helper.make_node( - 'Concat', - inputs=[shape_name1, cast_shape_name], - outputs=[shape_name2], - axis=0) - node_list.append(shape_node2) - cast_shape_name2 = self.get_name(op.type, "shape.cast") - cast_shape_node2 = helper.make_node( - 'Cast', - inputs=[shape_name2], - outputs=[cast_shape_name2], - to=onnx_pb.TensorProto.FLOAT) - node_list.append(cast_shape_node2) - cast_shape_name0 = self.get_name(op.type, "shape.cast") - cast_shape_node0 = helper.make_node( - 'Cast', - inputs=[shape_name0], - outputs=[cast_shape_name0], - to=onnx_pb.TensorProto.FLOAT) - node_list.append(cast_shape_node0) - outputs_h_w_scales = op.output('Out')[0] + "@out_hw_scales" - node_h_w_scales = helper.make_node( - 'Div', - inputs=[cast_shape_name2, cast_shape_name0], - outputs=[outputs_h_w_scales]) - node_list.append(node_h_w_scales) - result_node = helper.make_node( - 'Resize', - inputs=[op.input('X')[0], outputs_h_w_scales], - outputs=op.output('Out'), - mode='linear') - node_list.extend([result_node]) - return node_list - elif 'Scale' in input_names and len(op.input('Scale')) > 0: - node = helper.make_node( - 'Resize', - inputs=[op.input('X')[0], op.input('Scale')[0]], - outputs=op.output('Out'), - mode='linear') - else: - out_shape = [op.attr('out_h'), op.attr('out_w')] - scale = op.attr('scale') - if out_shape.count(-1) > 0: - scale_name = self.get_name(op.type, 'scale') - scale_node = self.make_constant_node(scale_name, - onnx_pb.TensorProto.FLOAT, - [1, 1, scale, scale]) - node = helper.make_node( - 'Resize', - inputs=[op.input('X')[0], scale_name], - outputs=op.output('Out'), - mode='linear') - return [scale_node, node] - else: - raise Exception("Unexpected situation happend") - return node - - def nearest_interp(self, op, block): - input_names = op.input_names - if op.attr('align_corners'): - raise Exception( - "Resize in onnx(opset<=10) only support coordinate_transformation_mode: 'asymmetric', Try converting with --onnx_opset 11" - ) - if 'OutSize' in input_names and len(op.input('OutSize')) > 0: - node_list = list() - shape_name0 = self.get_name(op.type, 'shape') - shape_node0 = helper.make_node( - 'Shape', inputs=op.input('X'), outputs=[shape_name0]) - starts_name = self.get_name(op.type, 'slice.starts') - starts_node = self.make_constant_node( - starts_name, onnx_pb.TensorProto.INT64, [0]) - ends_name = self.get_name(op.type, 'slice.ends') - ends_node = self.make_constant_node(ends_name, - onnx_pb.TensorProto.INT64, [2]) - shape_name1 = self.get_name(op.type, 'shape') - shape_node1 = helper.make_node( - 'Slice', - inputs=[shape_name0, starts_name, ends_name], - outputs=[shape_name1]) - node_list.extend([shape_node0, starts_node, ends_node, shape_node1]) - if 'OutSize' in input_names and len(op.input('OutSize')) > 0: - cast_shape_name = self.get_name(op.type, "shape.cast") - cast_shape_node = helper.make_node( - 'Cast', - inputs=op.input('OutSize'), - outputs=[cast_shape_name], - to=onnx_pb.TensorProto.INT64) - node_list.append(cast_shape_node) - else: - concat_shape_name = self.get_name( - op.type, op.output('Out')[0] + "shape.concat") - concat_shape_node = helper.make_node( - "Concat", - inputs=op.input('SizeTensor'), - outputs=[concat_shape_name], - axis=0) - cast_shape_name = self.get_name(op.type, "shape.cast") - cast_shape_node = helper.make_node( - 'Cast', - inputs=[concat_shape_name], - outputs=[cast_shape_name], - to=onnx_pb.TensorProto.INT64) - node_list.extend([concat_shape_node, cast_shape_node]) - shape_name2 = self.get_name(op.type, "shape.concat") - shape_node2 = helper.make_node( - 'Concat', - inputs=[shape_name1, cast_shape_name], - outputs=[shape_name2], - axis=0) - node_list.append(shape_node2) - cast_shape_name2 = self.get_name(op.type, "shape.cast") - cast_shape_node2 = helper.make_node( - 'Cast', - inputs=[shape_name2], - outputs=[cast_shape_name2], - to=onnx_pb.TensorProto.FLOAT) - node_list.append(cast_shape_node2) - cast_shape_name0 = self.get_name(op.type, "shape.cast") - cast_shape_node0 = helper.make_node( - 'Cast', - inputs=[shape_name0], - outputs=[cast_shape_name0], - to=onnx_pb.TensorProto.FLOAT) - node_list.append(cast_shape_node0) - outputs_h_w_scales = op.output('Out')[0] + "@out_hw_scales" - node_h_w_scales = helper.make_node( - 'Div', - inputs=[cast_shape_name2, cast_shape_name0], - outputs=[outputs_h_w_scales]) - node_list.append(node_h_w_scales) - result_node = helper.make_node( - 'Resize', - inputs=[op.input('X')[0], outputs_h_w_scales], - outputs=op.output('Out'), - mode='linear') - node_list.extend([result_node]) - return node_list - elif 'Scale' in input_names and len(op.input('Scale')) > 0: - node = helper.make_node( - 'Resize', - inputs=[op.input('X')[0], op.input('Scale')[0]], - outputs=op.output('Out'), - mode='nearest') - else: - out_shape = [op.attr('out_h'), op.attr('out_w')] - scale = op.attr('scale') - if out_shape.count(-1) > 0: - scale_name = self.get_name(op.type, 'scale') - scale_node = self.make_constant_node(scale_name, - onnx_pb.TensorProto.FLOAT, - [1, 1, scale, scale]) - node = helper.make_node( - 'Resize', - inputs=[op.input('X')[0], scale_name], - outputs=op.output('Out'), - mode='nearest') - return [scale_node, node] - else: - raise Exception("Unexpected situation happend") - return node - - def hard_sigmoid(self, op, block): - slope = op.attr('slope') - offset = op.attr('offset') - node = helper.make_node( - 'HardSigmoid', - inputs=op.input('X'), - outputs=op.output('Out'), - alpha=slope, - beta=offset) - return node - - def swish(self, op, block): - beta = op.attr('beta') - beta_name = self.get_name(op.type, 'beta') - beta_node = onnx.helper.make_node( - 'Constant', - name=beta_name, - inputs=[], - outputs=[beta_name], - value=onnx.helper.make_tensor( - name=beta_name, - data_type=onnx.TensorProto.FLOAT, - dims=(), - vals=[beta])) - - beta_x_name = self.get_name(op.type, 'beta_x') - beta_x_node = onnx.helper.make_node( - 'Mul', - name=beta_x_name, - inputs=[op.input('X')[0], beta_name], - outputs=[beta_x_name]) - sigmoid_name = self.get_name(op.type, 'sigmoid') - sigmoid_node = onnx.helper.make_node( - 'Sigmoid', - name=sigmoid_name, - inputs=[beta_x_name], - outputs=[sigmoid_name]) - swish_node = onnx.helper.make_node( - 'Mul', - inputs=[op.input('X')[0], sigmoid_name], - outputs=op.output('Out')) - return [beta_node, beta_x_node, sigmoid_node, swish_node] - - def hard_swish(self, op, block): - scale_name = self.get_name(op.type, 'scale') - offset_name = self.get_name(op.type, 'offset') - scale_node = self.make_constant_node(scale_name, - onnx_pb.TensorProto.FLOAT, - op.attr('scale')) - offset_node = self.make_constant_node(offset_name, - onnx_pb.TensorProto.FLOAT, - op.attr('offset')) - - name0 = self.get_name(op.type, 'add') - node0 = helper.make_node( - 'Add', inputs=[op.input('X')[0], offset_name], outputs=[name0]) - name1 = self.get_name(op.type, 'relu') - min_value = 0.0 - max_value = op.attr('threshold') - node1 = helper.make_node( - 'Clip', - inputs=[name0], - outputs=[name1], - max=max_value, - min=min_value) - name2 = self.get_name(op.type, 'mul') - node2 = helper.make_node( - 'Mul', inputs=[op.input('X')[0], name1], outputs=[name2]) - node3 = helper.make_node( - 'Div', inputs=[name2, scale_name], outputs=op.output('Out')) - return [scale_node, offset_node, node0, node1, node2, node3] - - def elementwise_mul(self, op, block): - axis = op.attr('axis') - x_shape = block.var(op.input('X')[0]).shape - y_shape = block.var(op.input('Y')[0]).shape - if len(y_shape) == 1 and axis == 1: - shape_name = self.get_name(op.type, 'shape') - shape_value = [1] * len(x_shape) - shape_value[axis] = y_shape[0] - shape_node = self.make_constant_node( - shape_name, onnx_pb.TensorProto.INT64, shape_value) - temp_value = self.get_name(op.type, 'temp') - y_node = helper.make_node( - 'Reshape', - inputs=[op.input('Y')[0], shape_name], - outputs=[temp_value]) - node = helper.make_node( - 'Mul', - inputs=[op.input('X')[0], temp_value], - outputs=op.output('Out')) - return [shape_node, y_node, node] - elif axis == -1 or axis == (len(x_shape) - 1 - ) or len(x_shape) == len(y_shape): - node = helper.make_node( - 'Mul', - inputs=[op.input('X')[0], op.input('Y')[0]], - outputs=op.output('Out')) - return node - else: - raise Exception("Unexpected situation happend in elementwise_mul") - return node - - def feed(self, op, block): - name = op.output('Out')[0] - var = block.var(name) - tensor_info = helper.make_tensor_value_info( - name=name, - shape=var.shape, - elem_type=self.paddle_onnx_dtype_map[var.dtype]) - return tensor_info - - def fetch(self, op, block): - name = op.input('X')[0] - var = block.var(name) - tensor_info = helper.make_tensor_value_info( - name=name, - shape=var.shape, - elem_type=self.paddle_onnx_dtype_map[var.dtype]) - return tensor_info - - def unsqueeze2(self, op, block): - node = helper.make_node( - 'Unsqueeze', - inputs=op.input('X'), - outputs=op.output('Out'), - axes=op.attr('axes')) - return node - - def cast(self, op, block): - node = helper.make_node( - 'Cast', - inputs=op.input('X'), - outputs=op.output('Out'), - to=self.paddle_onnx_dtype_map[op.attr('out_dtype')]) - return node - - def arg_max(self, op, block): - node = helper.make_node( - 'ArgMax', - inputs=op.input('X'), - outputs=op.output('Out'), - axis=op.attr('axis'), - keepdims=0) - return node - - def reciprocal(self, op, block): - inputs = op.input(op.input_names[0]) - outputs = op.output(op.output_names[0]) - node = helper.make_node('Reciprocal', inputs=inputs, outputs=outputs) - return node - - def im2sequence(self, op, block): - from .paddle_custom_layer.im2sequence import im2sequence - return im2sequence(op, block) - - def yolo_box(self, op, block): - from .paddle_custom_layer.yolo_box import yolo_box - return yolo_box(op, block) - - def multiclass_nms(self, op, block): - from .paddle_custom_layer.multiclass_nms import multiclass_nms - return multiclass_nms(op, block) - - def box_coder(self, op, block): - from .paddle_custom_layer.box_coder import box_coder - return box_coder(op, block) - - def prior_box(self, op, block): - from .paddle_custom_layer.prior_box import prior_box - return prior_box(op, block) diff --git a/x2paddle/op_mapper/paddle2onnx/opset9/paddle_custom_layer/__init__.py b/x2paddle/op_mapper/paddle2onnx/opset9/paddle_custom_layer/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/x2paddle/op_mapper/paddle2onnx/opset9/paddle_custom_layer/box_coder.py b/x2paddle/op_mapper/paddle2onnx/opset9/paddle_custom_layer/box_coder.py deleted file mode 100644 index 00111fee526b53a735da60da19495231e808f852..0000000000000000000000000000000000000000 --- a/x2paddle/op_mapper/paddle2onnx/opset9/paddle_custom_layer/box_coder.py +++ /dev/null @@ -1,401 +0,0 @@ -# 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 sys -import math -import onnx -import warnings -import numpy as np -from functools import partial -from onnx import TensorProto -from onnx.helper import make_node, make_tensor -from onnx import onnx_pb -from paddle.fluid.executor import _fetch_var as fetch_var -from onnx import helper -import paddle.fluid as fluid -import paddle.fluid.core as core - - -def box_coder(op, block): - """ - In this function, we will use the decode the prior box to target box, - we just use the decode mode to transform this op. - """ - node_list = [] - input_names = op.input_names - - prior_var = block.var(op.input('PriorBox')[0]) - t_size = block.var(op.input('TargetBox')[0]).shape - p_size = prior_var.shape - - # get the outout_name - result_name = op.output('OutputBox')[0] - # n is size of batch, m is boxes num of targe_boxes - n = t_size[0] - m = t_size[0] - - axis = int(op.attr('axis')) - - #norm - norm = bool(op.attr('box_normalized')) - - name_slice_x1 = op.output('OutputBox')[0] + "@x1" - name_slice_y1 = op.output('OutputBox')[0] + "@y1" - name_slice_x2 = op.output('OutputBox')[0] + "@x2" - name_slice_y2 = op.output('OutputBox')[0] + "@y2" - - #make onnx tensor to save the intermeidate reslut - name_slice_indices = [[op.output('OutputBox')[0] + "@slice_" + str(i)] - for i in range(1, 3)] - node_slice_indices = [None for i in range(1, 3)] - - # create the range(0, 4) const data to slice - for i in range(1, 3): - node = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_slice_indices[i - 1], - value=onnx.helper.make_tensor( - name=name_slice_indices[i - 1][0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=(), - vals=[i])) - node_list.append(node) - # make node split data - name_box_split = [ - name_slice_x1, name_slice_y1, name_slice_x2, name_slice_y2 - ] - split_shape = list(p_size) - split_shape[-1] = 1 - - node_split_prior_node = onnx.helper.make_node( - 'Split', inputs=op.input('PriorBox'), outputs=name_box_split, axis=1) - node_list.append(node_split_prior_node) - - # make node get centor node for decode - final_outputs_vars = [] - if not norm: - name_centor_w_tmp = [op.output('OutputBox')[0] + "@centor_w_tmp"] - name_centor_h_tmp = [op.output('OutputBox')[0] + "@centor_h_tmp"] - node_centor_w_tmp = None - node_centor_h_tmp = None - name_centor_tmp_list = [name_centor_w_tmp, name_centor_h_tmp] - node_centor_tmp_list = [node_centor_w_tmp, node_centor_h_tmp] - - count = 2 - for (name, node) in zip(name_centor_tmp_list, node_centor_tmp_list): - node = onnx.helper.make_node('Add', - inputs=[op.output('OutputBox')[0] + "@slice_" + str(1)]\ - + [name_box_split[count]], - outputs=name) - node_list.append(node) - count = count + 1 - if not norm: - inputs_sub = [[name_centor_w_tmp[0], name_box_split[0]], - [name_centor_h_tmp[0], name_box_split[1]]] - else: - inputs_sub = [[name_box_split[2], name_box_split[0]], - [name_box_split[3], name_box_split[1]]] - outputs_sub = [result_name + "@pb_w", result_name + "@pb_h"] - for i in range(0, 2): - node = onnx.helper.make_node( - 'Sub', inputs=inputs_sub[i], outputs=[outputs_sub[i]]) - node_list.append(node) - # according to prior_box height and weight to get centor x, y - name_half_value = [result_name + "@half_value"] - node_half_value = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_half_value, - value=onnx.helper.make_tensor( - name=name_slice_indices[i][0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=(), - vals=[0.5])) - node_list.append(node_half_value) - outputs_half_wh = [[result_name + "@pb_w_half"], - [result_name + "@pb_h_half"]] - inputs_half_wh = [[result_name + "@pb_w", name_half_value[0]], - [result_name + "@pb_h", name_half_value[0]]] - - for i in range(0, 2): - node = onnx.helper.make_node( - 'Mul', inputs=inputs_half_wh[i], outputs=outputs_half_wh[i]) - node_list.append(node) - - inputs_centor_xy = [[outputs_half_wh[0][0], name_slice_x1], - [outputs_half_wh[1][0], name_slice_y1]] - - outputs_centor_xy = [[result_name + "@pb_x"], [result_name + "@pb_y"]] - - # final calc the centor x ,y - for i in range(0, 2): - node = onnx.helper.make_node( - 'Add', inputs=inputs_centor_xy[i], outputs=outputs_centor_xy[i]) - node_list.append(node) - # reshape the data - shape = (1, split_shape[0]) if axis == 0 else (split_shape[0], 1) - - # need to reshape the data - inputs_transpose_pb = [ - [result_name + "@pb_w"], - [result_name + "@pb_h"], - [result_name + "@pb_x"], - [result_name + "@pb_y"], - ] - outputs_transpose_pb = [ - [result_name + "@pb_w_transpose"], - [result_name + "@pb_h_transpose"], - [result_name + "@pb_x_transpose"], - [result_name + "@pb_y_transpose"], - ] - if axis == 0: - name_reshape_pb = [result_name + "@pb_transpose"] - # reshape the data - for i in range(0, 4): - node = onnx.helper.make_node( - 'Transpose', - inputs=inputs_transpose_pb[i], - outputs=outputs_transpose_pb[i]) - node_list.append(node) - # decoder the box according to the target_box and variacne - name_variance_raw = [result_name + "@variance_raw"] - name_variance_unsqueeze = [result_name + "@variance_unsqueeze"] - shape = [] - # make node to extend the data - var_split_axis = 0 - var_split_inputs_name = [] - if 'PriorBoxVar' in input_names and len(op.input('PriorBoxVar')) > 0: - if axis == 1: - raise Exception( - "The op box_coder has variable do not support aixs broadcast") - prior_variance_var = block.var(op.input('PriorBoxVar')[0]) - axes = [] - var_split_inputs_name = [result_name + "@variance_split"] - node = onnx.helper.make_node( - 'Transpose', - inputs=op.input('PriorBoxVar'), - outputs=var_split_inputs_name) - node_list.append(node) - var_split_axis = 0 - else: - variances = [1.0, 1.0, 1.0, 1.0] - if 'variance' in op.attr and len(op.attr('variance')) > 0: - variances = [float(var) for var in op.attr('variance')] - node_variance_create = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_variance_raw, - value=onnx.helper.make_tensor( - name=name_variance_raw[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=[len(variances)], - vals=variances)) - node_list.append(node_variance_create) - var_split_axis = 0 - var_split_inputs_name = name_variance_raw - - # decode the result - outputs_split_variance = [ - result_name + "@variance_split" + str(i) for i in range(0, 4) - ] - outputs_split_targebox = [ - result_name + "@targebox_split" + str(i) for i in range(0, 4) - ] - node_split_var = onnx.helper.make_node( - 'Split', - inputs=var_split_inputs_name, - outputs=outputs_split_variance, - axis=var_split_axis) - node_split_target = onnx.helper.make_node( - 'Split', - inputs=op.input('TargetBox'), - outputs=outputs_split_targebox, - axis=2) - node_list.extend([node_split_var, node_split_target]) - - outputs_squeeze_targebox = [ - result_name + "@targebox_squeeze" + str(i) for i in range(0, 4) - ] - for (input_name, output_name) in zip(outputs_split_targebox, - outputs_squeeze_targebox): - node = onnx.helper.make_node( - 'Squeeze', inputs=[input_name], outputs=[output_name], axes=[2]) - node_list.append(node) - - output_shape_step1 = list(t_size)[:-1] - - inputs_tb_step1 = [ - [outputs_squeeze_targebox[0], outputs_split_variance[0]], - [outputs_squeeze_targebox[1], outputs_split_variance[1]], - [outputs_squeeze_targebox[2], outputs_split_variance[2]], - [outputs_squeeze_targebox[3], outputs_split_variance[3]] - ] - outputs_tb_step1 = [[result_name + "@decode_x_step1"], - [result_name + "@decode_y_step1"], - [result_name + "@decode_w_step1"], - [result_name + "@decode_h_step1"]] - - for input_step1, output_step_1 in zip(inputs_tb_step1, outputs_tb_step1): - node = onnx.helper.make_node( - 'Mul', inputs=input_step1, outputs=output_step_1) - node_list.append(node) - if axis == 0: - inputs_tbxy_step2 = [ - [outputs_tb_step1[0][0], outputs_transpose_pb[0][0]], - [outputs_tb_step1[1][0], outputs_transpose_pb[1][0]] - ] - else: - inputs_tbxy_step2 = [ - [outputs_tb_step1[0][0], inputs_transpose_pb[0][0]], - [outputs_tb_step1[1][0], inputs_transpose_pb[1][0]] - ] - - outputs_tbxy_step2 = [[result_name + "@decode_x_step2"], - [result_name + "@decode_y_step2"]] - - for input_step2, output_step_2 in zip(inputs_tbxy_step2, - outputs_tbxy_step2): - node = onnx.helper.make_node( - 'Mul', inputs=input_step2, outputs=output_step_2) - node_list.append(node) - if axis == 0: - inputs_tbxy_step3 = [ - [outputs_tbxy_step2[0][0], outputs_transpose_pb[2][0]], - [outputs_tbxy_step2[1][0], outputs_transpose_pb[3][0]] - ] - else: - inputs_tbxy_step3 = [ - [outputs_tbxy_step2[0][0], inputs_transpose_pb[2][0]], - [outputs_tbxy_step2[1][0], inputs_transpose_pb[3][0]] - ] - - outputs_tbxy_step3 = [[result_name + "@decode_x_step3"], - [result_name + "@decode_y_step3"]] - - for input_step3, output_step_3 in zip(inputs_tbxy_step3, - outputs_tbxy_step3): - node = onnx.helper.make_node( - 'Add', inputs=input_step3, outputs=output_step_3) - node_list.append(node) - - # deal with width & height - inputs_tbwh_step2 = [outputs_tb_step1[2], outputs_tb_step1[3]] - outputs_tbwh_step2 = [[result_name + "@decode_w_step2"], - [result_name + "@decode_h_step2"]] - - for input_name, output_name in zip(inputs_tbwh_step2, outputs_tbwh_step2): - node = onnx.helper.make_node( - 'Exp', inputs=input_name, outputs=output_name) - node_list.append(node) - - if axis == 0: - inputs_tbwh_step3 = [ - [outputs_tbwh_step2[0][0], outputs_transpose_pb[0][0]], - [outputs_tbwh_step2[1][0], outputs_transpose_pb[1][0]] - ] - else: - inputs_tbwh_step3 = [ - [outputs_tbwh_step2[0][0], inputs_transpose_pb[0][0]], - [outputs_tbwh_step2[1][0], inputs_transpose_pb[1][0]] - ] - - outputs_tbwh_step3 = [[result_name + "@decode_w_step3"], - [result_name + "@decode_h_step3"]] - - for input_name, output_name in zip(inputs_tbwh_step3, outputs_tbwh_step3): - node = onnx.helper.make_node( - 'Mul', inputs=input_name, outputs=output_name) - node_list.append(node) - - # final step to calc the result, and concat the result to output - # return the output box, [(x1, y1), (x2, y2)] - - inputs_half_tbwh_step4 = [ - [outputs_tbwh_step3[0][0], result_name + "@slice_2"], - [outputs_tbwh_step3[1][0], result_name + "@slice_2"] - ] - - outputs_half_tbwh_step4 = [[result_name + "@decode_half_w_step4"], - [result_name + "@decode_half_h_step4"]] - for inputs_name, outputs_name in zip(inputs_half_tbwh_step4, - outputs_half_tbwh_step4): - node = onnx.helper.make_node( - 'Div', inputs=inputs_name, outputs=outputs_name) - node_list.append(node) - inputs_output_point1 = [ - [outputs_tbxy_step3[0][0], outputs_half_tbwh_step4[0][0]], - [outputs_tbxy_step3[1][0], outputs_half_tbwh_step4[1][0]] - ] - - outputs_output_point1 = [[result_name + "@ouput_x1"], - [result_name + "@output_y1"]] - for input_name, output_name in zip(inputs_output_point1, - outputs_output_point1): - node = onnx.helper.make_node( - 'Sub', inputs=input_name, outputs=output_name) - node_list.append(node) - - inputs_output_point2 = [ - [outputs_tbxy_step3[0][0], outputs_half_tbwh_step4[0][0]], - [outputs_tbxy_step3[1][0], outputs_half_tbwh_step4[1][0]] - ] - - outputs_output_point2 = [[result_name + "@ouput_x2"], - [result_name + "@output_y2"]] - - for input_name, output_name in zip(inputs_output_point2, - outputs_output_point2): - node = onnx.helper.make_node( - 'Add', inputs=input_name, outputs=output_name) - node_list.append(node) - if not norm: - inputs_unnorm_point2 = [ - [outputs_output_point2[0][0], result_name + "@slice_1"], - [outputs_output_point2[1][0], result_name + "@slice_1"] - ] - outputs_unnorm_point2 = [[result_name + "@ouput_unnorm_x2"], - [result_name + "@ouput_unnorm_y2"]] - - for input_name, output_name in zip(inputs_unnorm_point2, - outputs_unnorm_point2): - node = onnx.helper.make_node( - 'Sub', inputs=input_name, outputs=output_name) - node_list.append(node) - outputs_output_point2 = outputs_unnorm_point2 - - outputs_output_point1.extend(outputs_output_point2) - ouputs_points_unsqueeze = [[result_name + "@points_unsqueeze_x1"], - [result_name + "points_unsqueeze_y1"], - [result_name + "points_unsqueeze_x2"], - [result_name + "points_unsqueeze_y2"]] - - for input_name, output_name in zip(outputs_output_point1, - ouputs_points_unsqueeze): - node = onnx.helper.make_node( - 'Unsqueeze', - inputs=input_name, - outputs=output_name, - axes=[len(output_shape_step1)]) - node_list.append(node) - outputs_points_unsqueeze_list = [ - output[0] for output in ouputs_points_unsqueeze - ] - node_point_final = onnx.helper.make_node( - 'Concat', - inputs=outputs_points_unsqueeze_list, - outputs=op.output('OutputBox'), - axis=len(output_shape_step1)) - node_list.append(node_point_final) - return node_list diff --git a/x2paddle/op_mapper/paddle2onnx/opset9/paddle_custom_layer/im2sequence.py b/x2paddle/op_mapper/paddle2onnx/opset9/paddle_custom_layer/im2sequence.py deleted file mode 100644 index ab5a90d3b2a64f5c61fad957c0f0c4e1835bb165..0000000000000000000000000000000000000000 --- a/x2paddle/op_mapper/paddle2onnx/opset9/paddle_custom_layer/im2sequence.py +++ /dev/null @@ -1,94 +0,0 @@ -# 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 onnx -import numpy as np -from onnx import onnx_pb, helper - -im2seq_counter = 0 - - -def im2sequence(op, block): - global im2sequence_counter - n, c, h, w = block.var(op.input('X')[0]).shape - assert h > 0 and w > 0, "Only supported fixed input shape for im2sequence operator." - stride_h, stride_w = op.attr('strides') - paddings = op.attr('paddings') - assert op.attr( - 'out_stride' - ) != 1, "Only out_stride==1 is supported for im2sequence operator." - h = h + paddings[0] + paddings[1] - w = w + paddings[1] + paddings[2] - kernel_h, kernel_w = op.attr('kernels') - out_h = 1 + (h - kernel_h + stride_h - 1) // stride_h - out_w = 1 + (w - kernel_w + stride_w - 1) // stride_w - h_steps = list() - for i in range(out_h): - h_steps.append([i * stride_h, i * stride_h + kernel_h]) - w_steps = list() - for i in range(out_w): - w_steps.append([i * stride_w, i * stride_w + kernel_w]) - - nodes = list() - slice_blocks = list() - for i in range(out_h): - for j in range(out_w): - starts_name = "im2sequence.starts.{}.{}.{}".format(im2seq_counter, - i, j) - starts_tensor = helper.make_tensor( - name=starts_name, - data_type=onnx_pb.TensorProto.INT64, - dims=[4], - vals=[0, 0, h_steps[i][0], w_steps[j][0]]) - ends_name = "im2sequence.ends.{}.{}.{}".format(im2seq_counter, i, j) - ends_tensor = helper.make_tensor( - name=ends_name, - data_type=onnx_pb.TensorProto.INT64, - dims=[4], - vals=[999999, 999999, h_steps[i][1], w_steps[j][1]]) - starts_node = helper.make_node( - 'Constant', - inputs=[], - outputs=[starts_name], - value=starts_tensor) - ends_node = helper.make_node( - 'Constant', inputs=[], outputs=[ends_name], value=ends_tensor) - nodes.extend([starts_node, ends_node]) - - slice_block_name = "im2sequence.slice.{}.{}.{}".format( - im2seq_counter, i, j) - slice_block_node = helper.make_node( - 'Slice', - inputs=[op.input('X')[0], starts_name, ends_name], - outputs=[slice_block_name]) - flatten_block_name = "im2sequence.flatten.{}.{}.{}".format( - im2seq_counter, i, j) - flatten_block_node = helper.make_node( - "Flatten", - inputs=[slice_block_name], - outputs=[flatten_block_name], - axis=0) - nodes.extend([slice_block_node, flatten_block_node]) - slice_blocks.append(flatten_block_name) - concat_block_name = "im2sequence.concat_block.{}".format(im2seq_counter) - # concat_block_node = helper.make_node("Concat", inputs=slice_blocks, outputs=[concat_block_name], axis=0) - concat_block_node = helper.make_node( - "Concat", inputs=slice_blocks, outputs=op.output('Out'), axis=0) - nodes.append(concat_block_node) - print("\n\n==========Importance Notice===========") - print( - "Since im2sequence operator is used in your paddlepaddle model, the translated onnx model only support input data with batch_size=1." - ) - print("======================================\n") - return nodes diff --git a/x2paddle/op_mapper/paddle2onnx/opset9/paddle_custom_layer/multiclass_nms.py b/x2paddle/op_mapper/paddle2onnx/opset9/paddle_custom_layer/multiclass_nms.py deleted file mode 100644 index 6d8172fc63c7441ff96b49da44ea700d5700289e..0000000000000000000000000000000000000000 --- a/x2paddle/op_mapper/paddle2onnx/opset9/paddle_custom_layer/multiclass_nms.py +++ /dev/null @@ -1,449 +0,0 @@ -# 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 sys -import os -import numpy as np -import paddle.fluid.core as core -import paddle.fluid as fluid -import onnx -import logging -from onnx import helper, onnx_pb - - -def multiclass_nms(op, block): - """ - Convert the paddle multiclass_nms to onnx op. - This op is get the select boxes from origin boxes. - """ - inputs = dict() - outputs = dict() - attrs = dict() - for name in op.input_names: - inputs[name] = op.input(name) - for name in op.output_names: - outputs[name] = op.output(name) - for name in op.attr_names: - attrs[name] = op.attr(name) - - result_name = outputs['Out'][0] - background = attrs['background_label'] - normalized = attrs['normalized'] - if normalized == False: - logging.warn( - "The parameter normalized of multiclass_nms OP of Paddle is False, which has diff with ONNX." \ - " Please set normalized=True in multiclass_nms of Paddle, see doc Q4 in https://github.com/PaddlePaddle/X2Paddle/blob/develop/FAQ.md") - - #convert the paddle attribute to onnx tensor - name_score_threshold = [outputs['Out'][0] + "@score_threshold"] - name_iou_threshold = [outputs['Out'][0] + "@iou_threshold"] - name_keep_top_k = [outputs['Out'][0] + '@keep_top_k'] - name_keep_top_k_2D = [outputs['Out'][0] + '@keep_top_k_1D'] - - node_score_threshold = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_score_threshold, - value=onnx.helper.make_tensor( - name=name_score_threshold[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=(), - vals=[float(attrs['score_threshold'])])) - - node_iou_threshold = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_iou_threshold, - value=onnx.helper.make_tensor( - name=name_iou_threshold[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=(), - vals=[float(attrs['nms_threshold'])])) - - boxes_num = block.var(outputs['Out'][0]).shape[0] - top_k_value = np.int64(boxes_num if attrs['keep_top_k'] == -1 else attrs['keep_top_k']) - node_keep_top_k = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_keep_top_k, - value=onnx.helper.make_tensor( - name=name_keep_top_k[0] + "@const", - data_type=onnx.TensorProto.INT64, - dims=(), - vals=[top_k_value])) - - node_keep_top_k_2D = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_keep_top_k_2D, - value=onnx.helper.make_tensor( - name=name_keep_top_k_2D[0] + "@const", - data_type=onnx.TensorProto.INT64, - dims=[1, 1], - vals=[top_k_value])) - - # the paddle data format is x1,y1,x2,y2 - kwargs = {'center_point_box': 0} - - name_select_nms = [outputs['Out'][0] + "@select_index"] - node_select_nms= onnx.helper.make_node( - 'NonMaxSuppression', - inputs=inputs['BBoxes'] + inputs['Scores'] + name_keep_top_k +\ - name_iou_threshold + name_score_threshold, - outputs=name_select_nms) - # step 1 nodes select the nms class - node_list = [ - node_score_threshold, node_iou_threshold, node_keep_top_k, - node_keep_top_k_2D, node_select_nms - ] - - # create some const value to use - name_const_value = [result_name+"@const_0", - result_name+"@const_1",\ - result_name+"@const_2",\ - result_name+"@const_-1"] - value_const_value = [0, 1, 2, -1] - for name, value in zip(name_const_value, value_const_value): - node = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=[name], - value=onnx.helper.make_tensor( - name=name + "@const", - data_type=onnx.TensorProto.INT64, - dims=[1], - vals=[value])) - node_list.append(node) - - # In this code block, we will deocde the raw score data, reshape N * C * M to 1 * N*C*M - # and the same time, decode the select indices to 1 * D, gather the select_indices - outputs_gather_1 = [result_name + "@gather_1"] - node_gather_1 = onnx.helper.make_node( - 'Gather', - inputs=name_select_nms + [result_name + "@const_1"], - outputs=outputs_gather_1, - axis=1) - node_list.append(node_gather_1) - - outputs_squeeze_gather_1 = [result_name + "@sequeeze_gather_1"] - node_squeeze_gather_1 = onnx.helper.make_node( - 'Squeeze', - inputs=outputs_gather_1, - outputs=outputs_squeeze_gather_1, - axes=[1]) - node_list.append(node_squeeze_gather_1) - - outputs_gather_2 = [result_name + "@gather_2"] - node_gather_2 = onnx.helper.make_node( - 'Gather', - inputs=name_select_nms + [result_name + "@const_2"], - outputs=outputs_gather_2, - axis=1) - node_list.append(node_gather_2) - - #slice the class is not 0 - if background == 0: - outputs_nonzero = [result_name + "@nonzero"] - node_nonzero = onnx.helper.make_node( - 'NonZero', inputs=outputs_squeeze_gather_1, outputs=outputs_nonzero) - node_list.append(node_nonzero) - else: - name_thresh = [result_name + "@thresh"] - node_thresh = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_thresh, - value=onnx.helper.make_tensor( - name=name_thresh[0] + "@const", - data_type=onnx.TensorProto.INT32, - dims=[1], - vals=[-1])) - node_list.append(node_thresh) - - outputs_cast = [result_name + "@cast"] - node_cast = onnx.helper.make_node( - 'Cast', inputs=outputs_squeeze_gather_1, outputs=outputs_cast, to=6) - node_list.append(node_cast) - - outputs_greater = [result_name + "@greater"] - node_greater = onnx.helper.make_node( - 'Greater', - inputs=outputs_cast + name_thresh, - outputs=outputs_greater) - node_list.append(node_greater) - - outputs_nonzero = [result_name + "@nonzero"] - node_nonzero = onnx.helper.make_node( - 'NonZero', inputs=outputs_greater, outputs=outputs_nonzero) - node_list.append(node_nonzero) - - outputs_gather_1_nonzero = [result_name + "@gather_1_nonzero"] - node_gather_1_nonzero = onnx.helper.make_node( - 'Gather', - inputs=outputs_gather_1 + outputs_nonzero, - outputs=outputs_gather_1_nonzero, - axis=0) - node_list.append(node_gather_1_nonzero) - - outputs_gather_2_nonzero = [result_name + "@gather_2_nonzero"] - node_gather_2_nonzero = onnx.helper.make_node( - 'Gather', - inputs=outputs_gather_2 + outputs_nonzero, - outputs=outputs_gather_2_nonzero, - axis=0) - node_list.append(node_gather_2_nonzero) - - # reshape scores N * C * M to (N*C*M) * 1 - outputs_reshape_scores_rank1 = [result_name + "@reshape_scores_rank1"] - node_reshape_scores_rank1 = onnx.helper.make_node( - "Reshape", - inputs=inputs['Scores'] + [result_name + "@const_-1"], - outputs=outputs_reshape_scores_rank1) - node_list.append(node_reshape_scores_rank1) - - # get the shape of scores - outputs_shape_scores = [result_name + "@shape_scores"] - node_shape_scores = onnx.helper.make_node( - 'Shape', inputs=inputs['Scores'], outputs=outputs_shape_scores) - node_list.append(node_shape_scores) - - # gather the index: 2 shape of scores - outputs_gather_scores_dim1 = [result_name + "@gather_scores_dim1"] - node_gather_scores_dim1 = onnx.helper.make_node( - 'Gather', - inputs=outputs_shape_scores + [result_name + "@const_2"], - outputs=outputs_gather_scores_dim1, - axis=0) - node_list.append(node_gather_scores_dim1) - - # mul class * M - outputs_mul_classnum_boxnum = [result_name + "@mul_classnum_boxnum"] - node_mul_classnum_boxnum = onnx.helper.make_node( - 'Mul', - inputs=outputs_gather_1_nonzero + outputs_gather_scores_dim1, - outputs=outputs_mul_classnum_boxnum) - node_list.append(node_mul_classnum_boxnum) - - # add class * M * index - outputs_add_class_M_index = [result_name + "@add_class_M_index"] - node_add_class_M_index = onnx.helper.make_node( - 'Add', - inputs=outputs_mul_classnum_boxnum + outputs_gather_2_nonzero, - outputs=outputs_add_class_M_index) - node_list.append(node_add_class_M_index) - - # Squeeze the indices to 1 dim - outputs_squeeze_select_index = [result_name + "@squeeze_select_index"] - node_squeeze_select_index = onnx.helper.make_node( - 'Squeeze', - inputs=outputs_add_class_M_index, - outputs=outputs_squeeze_select_index, - axes=[0, 2]) - node_list.append(node_squeeze_select_index) - - # gather the data from flatten scores - outputs_gather_select_scores = [result_name + "@gather_select_scores"] - node_gather_select_scores = onnx.helper.make_node('Gather', - inputs=outputs_reshape_scores_rank1 + \ - outputs_squeeze_select_index, - outputs=outputs_gather_select_scores, - axis=0) - node_list.append(node_gather_select_scores) - - # get nums to input TopK - outputs_shape_select_num = [result_name + "@shape_select_num"] - node_shape_select_num = onnx.helper.make_node( - 'Shape', - inputs=outputs_gather_select_scores, - outputs=outputs_shape_select_num) - node_list.append(node_shape_select_num) - - outputs_gather_select_num = [result_name + "@gather_select_num"] - node_gather_select_num = onnx.helper.make_node( - 'Gather', - inputs=outputs_shape_select_num + [result_name + "@const_0"], - outputs=outputs_gather_select_num, - axis=0) - node_list.append(node_gather_select_num) - - outputs_unsqueeze_select_num = [result_name + "@unsqueeze_select_num"] - node_unsqueeze_select_num = onnx.helper.make_node( - 'Unsqueeze', - inputs=outputs_gather_select_num, - outputs=outputs_unsqueeze_select_num, - axes=[0]) - node_list.append(node_unsqueeze_select_num) - - outputs_concat_topK_select_num = [result_name + "@conat_topK_select_num"] - node_conat_topK_select_num = onnx.helper.make_node( - 'Concat', - inputs=outputs_unsqueeze_select_num + name_keep_top_k_2D, - outputs=outputs_concat_topK_select_num, - axis=0) - node_list.append(node_conat_topK_select_num) - - outputs_cast_concat_topK_select_num = [ - result_name + "@concat_topK_select_num" - ] - node_outputs_cast_concat_topK_select_num = onnx.helper.make_node( - 'Cast', - inputs=outputs_concat_topK_select_num, - outputs=outputs_cast_concat_topK_select_num, - to=6) - node_list.append(node_outputs_cast_concat_topK_select_num) - # get min(topK, num_select) - outputs_compare_topk_num_select = [result_name + "@compare_topk_num_select"] - node_compare_topk_num_select = onnx.helper.make_node( - 'ReduceMin', - inputs=outputs_cast_concat_topK_select_num, - outputs=outputs_compare_topk_num_select, - keepdims=0) - node_list.append(node_compare_topk_num_select) - - # unsqueeze the indices to 1D tensor - outputs_unsqueeze_topk_select_indices = [ - result_name + "@unsqueeze_topk_select_indices" - ] - node_unsqueeze_topk_select_indices = onnx.helper.make_node( - 'Unsqueeze', - inputs=outputs_compare_topk_num_select, - outputs=outputs_unsqueeze_topk_select_indices, - axes=[0]) - node_list.append(node_unsqueeze_topk_select_indices) - - # cast the indices to INT64 - outputs_cast_topk_indices = [result_name + "@cast_topk_indices"] - node_cast_topk_indices = onnx.helper.make_node( - 'Cast', - inputs=outputs_unsqueeze_topk_select_indices, - outputs=outputs_cast_topk_indices, - to=7) - node_list.append(node_cast_topk_indices) - - # select topk scores indices - outputs_topk_select_topk_indices = [result_name + "@topk_select_topk_values",\ - result_name + "@topk_select_topk_indices"] - node_topk_select_topk_indices = onnx.helper.make_node( - 'TopK', - inputs=outputs_gather_select_scores + outputs_cast_topk_indices, - outputs=outputs_topk_select_topk_indices) - node_list.append(node_topk_select_topk_indices) - - # gather topk label, scores, boxes - outputs_gather_topk_scores = [result_name + "@gather_topk_scores"] - node_gather_topk_scores = onnx.helper.make_node( - 'Gather', - inputs=outputs_gather_select_scores + - [outputs_topk_select_topk_indices[1]], - outputs=outputs_gather_topk_scores, - axis=0) - node_list.append(node_gather_topk_scores) - - outputs_gather_topk_class = [result_name + "@gather_topk_class"] - node_gather_topk_class = onnx.helper.make_node( - 'Gather', - inputs=outputs_gather_1_nonzero + - [outputs_topk_select_topk_indices[1]], - outputs=outputs_gather_topk_class, - axis=1) - node_list.append(node_gather_topk_class) - - # gather the boxes need to gather the boxes id, then get boxes - outputs_gather_topk_boxes_id = [result_name + "@gather_topk_boxes_id"] - node_gather_topk_boxes_id = onnx.helper.make_node( - 'Gather', - inputs=outputs_gather_2_nonzero + - [outputs_topk_select_topk_indices[1]], - outputs=outputs_gather_topk_boxes_id, - axis=1) - node_list.append(node_gather_topk_boxes_id) - - # squeeze the gather_topk_boxes_id to 1 dim - outputs_squeeze_topk_boxes_id = [result_name + "@squeeze_topk_boxes_id"] - node_squeeze_topk_boxes_id = onnx.helper.make_node( - 'Squeeze', - inputs=outputs_gather_topk_boxes_id, - outputs=outputs_squeeze_topk_boxes_id, - axes=[0, 2]) - node_list.append(node_squeeze_topk_boxes_id) - - outputs_gather_select_boxes = [result_name + "@gather_select_boxes"] - node_gather_select_boxes = onnx.helper.make_node( - 'Gather', - inputs=inputs['BBoxes'] + outputs_squeeze_topk_boxes_id, - outputs=outputs_gather_select_boxes, - axis=1) - node_list.append(node_gather_select_boxes) - - # concat the final result - # before concat need to cast the class to float - outputs_cast_topk_class = [result_name + "@cast_topk_class"] - node_cast_topk_class = onnx.helper.make_node( - 'Cast', - inputs=outputs_gather_topk_class, - outputs=outputs_cast_topk_class, - to=1) - node_list.append(node_cast_topk_class) - - outputs_unsqueeze_topk_scores = [result_name + "@unsqueeze_topk_scores"] - node_unsqueeze_topk_scores = onnx.helper.make_node( - 'Unsqueeze', - inputs=outputs_gather_topk_scores, - outputs=outputs_unsqueeze_topk_scores, - axes=[0, 2]) - node_list.append(node_unsqueeze_topk_scores) - - inputs_concat_final_results = outputs_cast_topk_class + outputs_unsqueeze_topk_scores +\ - outputs_gather_select_boxes - outputs_sort_by_socre_results = [result_name + "@concat_topk_scores"] - node_sort_by_socre_results = onnx.helper.make_node( - 'Concat', - inputs=inputs_concat_final_results, - outputs=outputs_sort_by_socre_results, - axis=2) - node_list.append(node_sort_by_socre_results) - - # select topk classes indices - outputs_squeeze_cast_topk_class = [result_name + "@squeeze_cast_topk_class"] - node_squeeze_cast_topk_class = onnx.helper.make_node( - 'Squeeze', - inputs=outputs_cast_topk_class, - outputs=outputs_squeeze_cast_topk_class, - axes=[0, 2]) - node_list.append(node_squeeze_cast_topk_class) - outputs_neg_squeeze_cast_topk_class = [ - result_name + "@neg_squeeze_cast_topk_class" - ] - node_neg_squeeze_cast_topk_class = onnx.helper.make_node( - 'Neg', - inputs=outputs_squeeze_cast_topk_class, - outputs=outputs_neg_squeeze_cast_topk_class) - node_list.append(node_neg_squeeze_cast_topk_class) - outputs_topk_select_classes_indices = [result_name + "@topk_select_topk_classes_scores",\ - result_name + "@topk_select_topk_classes_indices"] - node_topk_select_topk_indices = onnx.helper.make_node( - 'TopK', - inputs=outputs_neg_squeeze_cast_topk_class + outputs_cast_topk_indices, - outputs=outputs_topk_select_classes_indices) - node_list.append(node_topk_select_topk_indices) - outputs_concat_final_results = outputs['Out'] - node_concat_final_results = onnx.helper.make_node( - 'Gather', - inputs=outputs_sort_by_socre_results + - [outputs_topk_select_classes_indices[1]], - outputs=outputs_concat_final_results, - axis=1) - node_list.append(node_concat_final_results) - return node_list diff --git a/x2paddle/op_mapper/paddle2onnx/opset9/paddle_custom_layer/prior_box.py b/x2paddle/op_mapper/paddle2onnx/opset9/paddle_custom_layer/prior_box.py deleted file mode 100644 index 71f6f3f60b6ce82a9cad809aeccef40e08209baf..0000000000000000000000000000000000000000 --- a/x2paddle/op_mapper/paddle2onnx/opset9/paddle_custom_layer/prior_box.py +++ /dev/null @@ -1,174 +0,0 @@ -# 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 sys -import math -import onnx -import warnings -import numpy as np -from functools import partial -from onnx import TensorProto -from onnx.helper import make_node, make_tensor -from onnx import onnx_pb -from paddle.fluid.executor import _fetch_var as fetch_var -from onnx import helper -import paddle.fluid as fluid -import paddle.fluid.core as core - - -def ExpandAspectRations(input_aspect_ratior, flip): - expsilon = 1e-6 - output_ratios = [1.0] - for input_ratio in input_aspect_ratior: - already_exis = False - for output_ratio in output_ratios: - if abs(input_ratio - output_ratio) < expsilon: - already_exis = True - break - if already_exis == False: - output_ratios.append(input_ratio) - if flip: - output_ratios.append(1.0 / input_ratio) - return output_ratios - - -def prior_box(op, block): - """ - In this function, use the attribute to get the prior box, because we do not use - the image data and feature map, wo could the python code to create the varaible, - and to create the onnx tensor as output. - """ - flip = bool(op.attr('flip')) - clip = bool(op.attr('clip')) - min_max_aspect_ratios_order = bool(op.attr('min_max_aspect_ratios_order')) - min_sizes = [float(size) for size in op.attr('min_sizes')] - max_sizes = [float(size) for size in op.attr('max_sizes')] - if isinstance(op.attr('aspect_ratios'), list): - aspect_ratios = [float(ratio) for ratio in op.attr('aspect_ratios')] - else: - aspect_ratios = [float(op.attr('aspect_ratios'))] - variances = [float(var) for var in op.attr('variances')] - # set min_max_aspect_ratios_order = false - output_ratios = ExpandAspectRations(aspect_ratios, flip) - - step_w = float(op.attr('step_w')) - step_h = float(op.attr('step_h')) - offset = float(op.attr('offset')) - - input_shape = block.var(op.input('Input')[0]).shape - image_shape = block.var(op.input('Image')[0]).shape - - img_width = image_shape[3] - img_height = image_shape[2] - feature_width = input_shape[3] - feature_height = input_shape[2] - - step_width = 1.0 - step_height = 1.0 - - if step_w == 0.0 or step_h == 0.0: - step_w = float(img_width / feature_width) - step_h = float(img_height / feature_height) - - num_priors = len(output_ratios) * len(min_sizes) - if len(max_sizes) > 0: - num_priors += len(max_sizes) - out_dim = (feature_height, feature_width, num_priors, 4) - out_boxes = np.zeros(out_dim).astype('float32') - out_var = np.zeros(out_dim).astype('float32') - - idx = 0 - for h in range(feature_height): - for w in range(feature_width): - c_x = (w + offset) * step_w - c_y = (h + offset) * step_h - idx = 0 - for s in range(len(min_sizes)): - min_size = min_sizes[s] - if not min_max_aspect_ratios_order: - # rest of priors - for r in range(len(output_ratios)): - ar = output_ratios[r] - c_w = min_size * math.sqrt(ar) / 2 - c_h = (min_size / math.sqrt(ar)) / 2 - out_boxes[h, w, idx, :] = [ - (c_x - c_w) / img_width, (c_y - c_h) / img_height, - (c_x + c_w) / img_width, (c_y + c_h) / img_height - ] - idx += 1 - - if len(max_sizes) > 0: - max_size = max_sizes[s] - # second prior: aspect_ratio = 1, - c_w = c_h = math.sqrt(min_size * max_size) / 2 - out_boxes[h, w, idx, :] = [ - (c_x - c_w) / img_width, (c_y - c_h) / img_height, - (c_x + c_w) / img_width, (c_y + c_h) / img_height - ] - idx += 1 - else: - c_w = c_h = min_size / 2. - out_boxes[h, w, idx, :] = [ - (c_x - c_w) / img_width, (c_y - c_h) / img_height, - (c_x + c_w) / img_width, (c_y + c_h) / img_height - ] - idx += 1 - if len(max_sizes) > 0: - max_size = max_sizes[s] - # second prior: aspect_ratio = 1, - c_w = c_h = math.sqrt(min_size * max_size) / 2 - out_boxes[h, w, idx, :] = [ - (c_x - c_w) / img_width, (c_y - c_h) / img_height, - (c_x + c_w) / img_width, (c_y + c_h) / img_height - ] - idx += 1 - - # rest of priors - for r in range(len(output_ratios)): - ar = output_ratios[r] - if abs(ar - 1.) < 1e-6: - continue - c_w = min_size * math.sqrt(ar) / 2 - c_h = (min_size / math.sqrt(ar)) / 2 - out_boxes[h, w, idx, :] = [ - (c_x - c_w) / img_width, (c_y - c_h) / img_height, - (c_x + c_w) / img_width, (c_y + c_h) / img_height - ] - idx += 1 - - if clip: - out_boxes = np.clip(out_boxes, 0.0, 1.0) - # set the variance. - out_var = np.tile(variances, (feature_height, feature_width, num_priors, 1)) - - #make node that - node_boxes = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=op.output('Boxes'), - value=onnx.helper.make_tensor( - name=op.output('Boxes')[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=out_boxes.shape, - vals=out_boxes.flatten())) - node_vars = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=op.output('Variances'), - value=onnx.helper.make_tensor( - name=op.output('Variances')[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=out_var.shape, - vals=out_var.flatten())) - return [node_boxes, node_vars] diff --git a/x2paddle/op_mapper/paddle2onnx/opset9/paddle_custom_layer/yolo_box.py b/x2paddle/op_mapper/paddle2onnx/opset9/paddle_custom_layer/yolo_box.py deleted file mode 100644 index bee7d8c6ccf7d5aa7e42a2939891dd48f1908ace..0000000000000000000000000000000000000000 --- a/x2paddle/op_mapper/paddle2onnx/opset9/paddle_custom_layer/yolo_box.py +++ /dev/null @@ -1,847 +0,0 @@ -# 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 onnx -import numpy as np -from onnx import onnx_pb, helper - -MAX_FLOAT32 = np.asarray( - [255, 255, 127, 127], dtype=np.uint8).view(np.float32)[0] - - -def get_old_name(arg, name_prefix=''): - prefix_index = arg.find(name_prefix) - - if prefix_index != -1: - last_prefix = arg[len(name_prefix):] - else: - last_prefix = arg - idx = last_prefix.find('@') - if idx != -1: - last_prefix = last_prefix[:idx] - return name_prefix + last_prefix - - -def is_static_shape(shape): - if len(shape) > 1 and shape.count(-1) > 1: - raise Exception( - "Converting this model to ONNX need with static input shape, please fix input shape of this model, see doc Q5 in https://github.com/PaddlePaddle/X2Paddle/blob/develop/FAQ.md." - ) - - -def yolo_box(op, block): - inputs = dict() - outputs = dict() - attrs = dict() - for name in op.input_names: - inputs[name] = op.input(name) - for name in op.output_names: - outputs[name] = op.output(name) - for name in op.attr_names: - attrs[name] = op.attr(name) - model_name = outputs['Boxes'][0] - input_shape = block.vars[get_old_name(inputs['X'][0])].shape - is_static_shape(input_shape) - image_size = inputs['ImgSize'] - input_height = input_shape[2] - input_width = input_shape[3] - - class_num = attrs['class_num'] - anchors = attrs['anchors'] - num_anchors = int(len(anchors)) // 2 - downsample_ratio = attrs['downsample_ratio'] - input_size = input_height * downsample_ratio - conf_thresh = attrs['conf_thresh'] - conf_thresh_mat = np.ones([num_anchors * input_height * - input_width]) * conf_thresh - - node_list = [] - im_outputs = [] - - x_shape = [1, num_anchors, 5 + class_num, input_height, input_width] - name_x_shape = [model_name + "@x_shape"] - node_x_shape = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_x_shape, - value=onnx.helper.make_tensor( - name=name_x_shape[0] + "@const", - data_type=onnx.TensorProto.INT64, - dims=[5], - vals=x_shape)) - node_list.append(node_x_shape) - - outputs_x_reshape = [model_name + "@reshape"] - node_x_reshape = onnx.helper.make_node( - 'Reshape', inputs=inputs['X'] + name_x_shape, outputs=outputs_x_reshape) - node_list.append(node_x_reshape) - - outputs_x_transpose = [model_name + "@x_transpose"] - node_x_transpose = onnx.helper.make_node( - 'Transpose', - inputs=outputs_x_reshape, - outputs=outputs_x_transpose, - perm=[0, 1, 3, 4, 2]) - node_list.append(node_x_transpose) - - range_x = [] - range_y = [] - for i in range(0, input_width): - range_x.append(i) - for j in range(0, input_height): - range_y.append(j) - - name_range_x = [model_name + "@range_x"] - node_range_x = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_range_x, - value=onnx.helper.make_tensor( - name=name_range_x[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=[input_width], - vals=range_x)) - node_list.append(node_range_x) - - name_range_y = [model_name + "@range_y"] - node_range_y = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_range_y, - value=onnx.helper.make_tensor( - name=name_range_y[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=[input_height], - vals=range_y)) - node_list.append(node_range_y) - - range_x_new_shape = [1, input_width] - range_y_new_shape = [input_height, 1] - - name_range_x_new_shape = [model_name + "@range_x_new_shape"] - node_range_x_new_shape = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_range_x_new_shape, - value=onnx.helper.make_tensor( - name=name_range_x_new_shape[0] + "@const", - data_type=onnx.TensorProto.INT64, - dims=[len(range_x_new_shape)], - vals=range_x_new_shape)) - node_list.append(node_range_x_new_shape) - - name_range_y_new_shape = [model_name + "@range_y_new_shape"] - node_range_y_new_shape = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_range_y_new_shape, - value=onnx.helper.make_tensor( - name=name_range_y_new_shape[0] + "@const", - data_type=onnx.TensorProto.INT64, - dims=[len(range_y_new_shape)], - vals=range_y_new_shape)) - node_list.append(node_range_y_new_shape) - - outputs_range_x_reshape = [model_name + "@range_x_reshape"] - node_range_x_reshape = onnx.helper.make_node( - 'Reshape', - inputs=name_range_x + name_range_x_new_shape, - outputs=outputs_range_x_reshape) - node_list.append(node_range_x_reshape) - - outputs_range_y_reshape = [model_name + "@range_y_reshape"] - node_range_y_reshape = onnx.helper.make_node( - 'Reshape', - inputs=name_range_y + name_range_y_new_shape, - outputs=outputs_range_y_reshape) - node_list.append(node_range_y_reshape) - - outputs_grid_x = [model_name + "@grid_x"] - node_grid_x = onnx.helper.make_node( - "Tile", - inputs=outputs_range_x_reshape + name_range_y_new_shape, - outputs=outputs_grid_x) - node_list.append(node_grid_x) - - outputs_grid_y = [model_name + "@grid_y"] - node_grid_y = onnx.helper.make_node( - "Tile", - inputs=outputs_range_y_reshape + name_range_x_new_shape, - outputs=outputs_grid_y) - node_list.append(node_grid_y) - - outputs_box_x = [model_name + "@box_x"] - outputs_box_y = [model_name + "@box_y"] - outputs_box_w = [model_name + "@box_w"] - outputs_box_h = [model_name + "@box_h"] - outputs_conf = [model_name + "@conf"] - outputs_prob = [model_name + "@prob"] - - node_split_input = onnx.helper.make_node( - "Split", - inputs=outputs_x_transpose, - outputs=outputs_box_x + outputs_box_y + outputs_box_w\ - + outputs_box_h + outputs_conf + outputs_prob, - axis=-1, - split=[1, 1, 1, 1, 1, class_num]) - node_list.append(node_split_input) - - outputs_box_x_sigmoid = [model_name + "@box_x_sigmoid"] - outputs_box_y_sigmoid = [model_name + "@box_y_sigmoid"] - - node_box_x_sigmoid = onnx.helper.make_node( - "Sigmoid", inputs=outputs_box_x, outputs=outputs_box_x_sigmoid) - node_list.append(node_box_x_sigmoid) - - node_box_y_sigmoid = onnx.helper.make_node( - "Sigmoid", inputs=outputs_box_y, outputs=outputs_box_y_sigmoid) - node_list.append(node_box_y_sigmoid) - - outputs_box_x_squeeze = [model_name + "@box_x_squeeze"] - outputs_box_y_squeeze = [model_name + "@box_y_squeeze"] - - node_box_x_squeeze = onnx.helper.make_node( - 'Squeeze', - inputs=outputs_box_x_sigmoid, - outputs=outputs_box_x_squeeze, - axes=[4]) - node_list.append(node_box_x_squeeze) - - node_box_y_squeeze = onnx.helper.make_node( - 'Squeeze', - inputs=outputs_box_y_sigmoid, - outputs=outputs_box_y_squeeze, - axes=[4]) - node_list.append(node_box_y_squeeze) - - outputs_box_x_add_grid = [model_name + "@box_x_add_grid"] - outputs_box_y_add_grid = [model_name + "@box_y_add_grid"] - - node_box_x_add_grid = onnx.helper.make_node( - "Add", - inputs=outputs_grid_x + outputs_box_x_squeeze, - outputs=outputs_box_x_add_grid) - node_list.append(node_box_x_add_grid) - - node_box_y_add_grid = onnx.helper.make_node( - "Add", - inputs=outputs_grid_y + outputs_box_y_squeeze, - outputs=outputs_box_y_add_grid) - node_list.append(node_box_y_add_grid) - - name_input_h = [model_name + "@input_h"] - name_input_w = [model_name + "@input_w"] - - node_input_h = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_input_h, - value=onnx.helper.make_tensor( - name=name_input_w[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=(), - vals=[input_height])) - node_list.append(node_input_h) - - node_input_w = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_input_w, - value=onnx.helper.make_tensor( - name=name_input_w[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=(), - vals=[input_width])) - node_list.append(node_input_w) - - outputs_box_x_encode = [model_name + "@box_x_encode"] - outputs_box_y_encode = [model_name + "@box_y_encode"] - - node_box_x_encode = onnx.helper.make_node( - 'Div', - inputs=outputs_box_x_add_grid + name_input_w, - outputs=outputs_box_x_encode) - node_list.append(node_box_x_encode) - - node_box_y_encode = onnx.helper.make_node( - 'Div', - inputs=outputs_box_y_add_grid + name_input_h, - outputs=outputs_box_y_encode) - node_list.append(node_box_y_encode) - - name_anchor_tensor = [model_name + "@anchor_tensor"] - node_anchor_tensor = onnx.helper.make_node( - "Constant", - inputs=[], - outputs=name_anchor_tensor, - value=onnx.helper.make_tensor( - name=name_anchor_tensor[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=[len(anchors)], - vals=anchors)) - node_list.append(node_anchor_tensor) - - anchor_shape = [int(num_anchors), 2] - name_anchor_shape = [model_name + "@anchor_shape"] - node_anchor_shape = onnx.helper.make_node( - "Constant", - inputs=[], - outputs=name_anchor_shape, - value=onnx.helper.make_tensor( - name=name_anchor_shape[0] + "@const", - data_type=onnx.TensorProto.INT64, - dims=[2], - vals=anchor_shape)) - node_list.append(node_anchor_shape) - - outputs_anchor_tensor_reshape = [model_name + "@anchor_tensor_reshape"] - node_anchor_tensor_reshape = onnx.helper.make_node( - "Reshape", - inputs=name_anchor_tensor + name_anchor_shape, - outputs=outputs_anchor_tensor_reshape) - node_list.append(node_anchor_tensor_reshape) - - name_input_size = [model_name + "@input_size"] - node_input_size = onnx.helper.make_node( - "Constant", - inputs=[], - outputs=name_input_size, - value=onnx.helper.make_tensor( - name=name_input_size[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=(), - vals=[input_size])) - node_list.append(node_input_size) - - outputs_anchors_div_input_size = [model_name + "@anchors_div_input_size"] - node_anchors_div_input_size = onnx.helper.make_node( - "Div", - inputs=outputs_anchor_tensor_reshape + name_input_size, - outputs=outputs_anchors_div_input_size) - node_list.append(node_anchors_div_input_size) - - outputs_anchor_w = [model_name + "@anchor_w"] - outputs_anchor_h = [model_name + "@anchor_h"] - - node_anchor_split = onnx.helper.make_node( - 'Split', - inputs=outputs_anchors_div_input_size, - outputs=outputs_anchor_w + outputs_anchor_h, - axis=1, - split=[1, 1]) - node_list.append(node_anchor_split) - - new_anchor_shape = [1, int(num_anchors), 1, 1] - name_new_anchor_shape = [model_name + "@new_anchor_shape"] - node_new_anchor_shape = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_new_anchor_shape, - value=onnx.helper.make_tensor( - name=name_new_anchor_shape[0] + "@const", - data_type=onnx.TensorProto.INT64, - dims=[len(new_anchor_shape)], - vals=new_anchor_shape)) - node_list.append(node_new_anchor_shape) - - outputs_anchor_w_reshape = [model_name + "@anchor_w_reshape"] - outputs_anchor_h_reshape = [model_name + "@anchor_h_reshape"] - - node_anchor_w_reshape = onnx.helper.make_node( - 'Reshape', - inputs=outputs_anchor_w + name_new_anchor_shape, - outputs=outputs_anchor_w_reshape) - node_list.append(node_anchor_w_reshape) - - node_anchor_h_reshape = onnx.helper.make_node( - 'Reshape', - inputs=outputs_anchor_h + name_new_anchor_shape, - outputs=outputs_anchor_h_reshape) - node_list.append(node_anchor_h_reshape) - - outputs_box_w_squeeze = [model_name + "@box_w_squeeze"] - node_box_w_squeeze = onnx.helper.make_node( - 'Squeeze', - inputs=outputs_box_w, - outputs=outputs_box_w_squeeze, - axes=[4]) - node_list.append(node_box_w_squeeze) - - outputs_box_h_squeeze = [model_name + "@box_h_squeeze"] - node_box_h_squeeze = onnx.helper.make_node( - 'Squeeze', - inputs=outputs_box_h, - outputs=outputs_box_h_squeeze, - axes=[4]) - node_list.append(node_box_h_squeeze) - - outputs_box_w_exp = [model_name + "@box_w_exp"] - node_box_w_exp = onnx.helper.make_node( - "Exp", inputs=outputs_box_w_squeeze, outputs=outputs_box_w_exp) - node_list.append(node_box_w_exp) - - outputs_box_h_exp = [model_name + "@box_h_exp"] - node_box_h_exp = onnx.helper.make_node( - "Exp", inputs=outputs_box_h_squeeze, outputs=outputs_box_h_exp) - node_list.append(node_box_h_exp) - - outputs_box_w_encode = [model_name + "box_w_encode"] - outputs_box_h_encode = [model_name + "box_h_encode"] - - node_box_w_encode = onnx.helper.make_node( - 'Mul', - inputs=outputs_box_w_exp + outputs_anchor_w_reshape, - outputs=outputs_box_w_encode) - node_list.append(node_box_w_encode) - - node_box_h_encode = onnx.helper.make_node( - 'Mul', - inputs=outputs_box_h_exp + outputs_anchor_h_reshape, - outputs=outputs_box_h_encode) - node_list.append(node_box_h_encode) - - outputs_conf_sigmoid = [model_name + "@conf_sigmoid"] - node_conf_sigmoid = onnx.helper.make_node( - 'Sigmoid', inputs=outputs_conf, outputs=outputs_conf_sigmoid) - node_list.append(node_conf_sigmoid) - - name_conf_thresh = [model_name + "@conf_thresh"] - node_conf_thresh = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_conf_thresh, - value=onnx.helper.make_tensor( - name=name_conf_thresh[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=[num_anchors * input_height * input_width], - vals=conf_thresh_mat)) - node_list.append(node_conf_thresh) - - conf_shape = [1, int(num_anchors), input_height, input_width, 1] - name_conf_shape = [model_name + "@conf_shape"] - node_conf_shape = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_conf_shape, - value=onnx.helper.make_tensor( - name=name_conf_shape[0] + "@const", - data_type=onnx.TensorProto.INT64, - dims=[len(conf_shape)], - vals=conf_shape)) - node_list.append(node_conf_shape) - - outputs_conf_thresh_reshape = [model_name + "@conf_thresh_reshape"] - node_conf_thresh_reshape = onnx.helper.make_node( - 'Reshape', - inputs=name_conf_thresh + name_conf_shape, - outputs=outputs_conf_thresh_reshape) - node_list.append(node_conf_thresh_reshape) - - outputs_conf_sub = [model_name + "@conf_sub"] - node_conf_sub = onnx.helper.make_node( - 'Sub', - inputs=outputs_conf_sigmoid + outputs_conf_thresh_reshape, - outputs=outputs_conf_sub) - node_list.append(node_conf_sub) - - outputs_conf_clip = [model_name + "@conf_clip"] - node_conf_clip = onnx.helper.make_node( - 'Clip', inputs=outputs_conf_sub, outputs=outputs_conf_clip) - node_list.append(node_conf_clip) - - zeros = [0] - name_zeros = [model_name + "@zeros"] - node_zeros = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_zeros, - value=onnx.helper.make_tensor( - name=name_zeros[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=(), - vals=zeros)) - node_list.append(node_zeros) - - outputs_conf_clip_bool = [model_name + "@conf_clip_bool"] - node_conf_clip_bool = onnx.helper.make_node( - 'Greater', - inputs=outputs_conf_clip + name_zeros, - outputs=outputs_conf_clip_bool) - node_list.append(node_conf_clip_bool) - - outputs_conf_clip_cast = [model_name + "@conf_clip_cast"] - node_conf_clip_cast = onnx.helper.make_node( - 'Cast', - inputs=outputs_conf_clip_bool, - outputs=outputs_conf_clip_cast, - to=1) - node_list.append(node_conf_clip_cast) - - outputs_conf_set_zero = [model_name + "@conf_set_zero"] - node_conf_set_zero = onnx.helper.make_node( - 'Mul', - inputs=outputs_conf_sigmoid + outputs_conf_clip_cast, - outputs=outputs_conf_set_zero) - node_list.append(node_conf_set_zero) - - outputs_prob_sigmoid = [model_name + "@prob_sigmoid"] - node_prob_sigmoid = onnx.helper.make_node( - 'Sigmoid', inputs=outputs_prob, outputs=outputs_prob_sigmoid) - node_list.append(node_prob_sigmoid) - - new_shape = [1, int(num_anchors), input_height, input_width, 1] - name_new_shape = [model_name + "@new_shape"] - node_new_shape = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_new_shape, - value=onnx.helper.make_tensor( - name=name_new_shape[0] + "@const", - data_type=onnx.TensorProto.INT64, - dims=[len(new_shape)], - vals=new_shape)) - node_list.append(node_new_shape) - - outputs_conf_new_shape = [model_name + "@_conf_new_shape"] - node_conf_new_shape = onnx.helper.make_node( - 'Reshape', - inputs=outputs_conf_set_zero + name_new_shape, - outputs=outputs_conf_new_shape) - node_list.append(node_conf_new_shape) - - outputs_score = [model_name + "@score"] - node_score = onnx.helper.make_node( - 'Mul', - inputs=outputs_prob_sigmoid + outputs_conf_new_shape, - outputs=outputs_score) - node_list.append(node_score) - - outputs_conf_bool = [model_name + "@conf_bool"] - node_conf_bool = onnx.helper.make_node( - 'Greater', - inputs=outputs_conf_new_shape + name_zeros, - outputs=outputs_conf_bool) - node_list.append(node_conf_bool) - - outputs_box_x_new_shape = [model_name + "@box_x_new_shape"] - node_box_x_new_shape = onnx.helper.make_node( - 'Reshape', - inputs=outputs_box_x_encode + name_new_shape, - outputs=outputs_box_x_new_shape) - node_list.append(node_box_x_new_shape) - - outputs_box_y_new_shape = [model_name + "@box_y_new_shape"] - node_box_y_new_shape = onnx.helper.make_node( - 'Reshape', - inputs=outputs_box_y_encode + name_new_shape, - outputs=outputs_box_y_new_shape) - node_list.append(node_box_y_new_shape) - - outputs_box_w_new_shape = [model_name + "@box_w_new_shape"] - node_box_w_new_shape = onnx.helper.make_node( - 'Reshape', - inputs=outputs_box_w_encode + name_new_shape, - outputs=outputs_box_w_new_shape) - node_list.append(node_box_w_new_shape) - - outputs_box_h_new_shape = [model_name + "@box_h_new_shape"] - node_box_h_new_shape = onnx.helper.make_node( - 'Reshape', - inputs=outputs_box_h_encode + name_new_shape, - outputs=outputs_box_h_new_shape) - node_list.append(node_box_h_new_shape) - - outputs_pred_box = [model_name + "@pred_box"] - node_pred_box = onnx.helper.make_node( - 'Concat', - inputs=outputs_box_x_new_shape + outputs_box_y_new_shape + \ - outputs_box_w_new_shape + outputs_box_h_new_shape, - outputs=outputs_pred_box, - axis=4) - node_list.append(node_pred_box) - - outputs_conf_cast = [model_name + "conf_cast"] - node_conf_cast = onnx.helper.make_node( - 'Cast', inputs=outputs_conf_bool, outputs=outputs_conf_cast, to=1) - node_list.append(node_conf_cast) - - outputs_pred_box_mul_conf = [model_name + "@pred_box_mul_conf"] - node_pred_box_mul_conf = onnx.helper.make_node( - 'Mul', - inputs=outputs_pred_box + outputs_conf_cast, - outputs=outputs_pred_box_mul_conf) - node_list.append(node_pred_box_mul_conf) - - box_shape = [1, int(num_anchors) * input_height * input_width, 4] - name_box_shape = [model_name + "@box_shape"] - node_box_shape = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_box_shape, - value=onnx.helper.make_tensor( - name=name_box_shape[0] + "@const", - data_type=onnx.TensorProto.INT64, - dims=[len(box_shape)], - vals=box_shape)) - node_list.append(node_box_shape) - - outputs_pred_box_new_shape = [model_name + "@pred_box_new_shape"] - node_pred_box_new_shape = onnx.helper.make_node( - 'Reshape', - inputs=outputs_pred_box_mul_conf + name_box_shape, - outputs=outputs_pred_box_new_shape) - node_list.append(node_pred_box_new_shape) - - outputs_pred_box_x = [model_name + "@_pred_box_x"] - outputs_pred_box_y = [model_name + "@_pred_box_y"] - outputs_pred_box_w = [model_name + "@_pred_box_w"] - outputs_pred_box_h = [model_name + "@_pred_box_h"] - - node_pred_box_split = onnx.helper.make_node( - 'Split', - inputs=outputs_pred_box_new_shape, - outputs=outputs_pred_box_x + outputs_pred_box_y + outputs_pred_box_w + - outputs_pred_box_h, - axis=2) - node_list.append(node_pred_box_split) - - name_number_two = [model_name + "@number_two"] - node_number_two = onnx.helper.make_node( - "Constant", - inputs=[], - outputs=name_number_two, - value=onnx.helper.make_tensor( - name=name_number_two[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=(), - vals=[2])) - node_list.append(node_number_two) - - outputs_half_w = [model_name + "@half_w"] - node_half_w = onnx.helper.make_node( - "Div", - inputs=outputs_pred_box_w + name_number_two, - outputs=outputs_half_w) - node_list.append(node_half_w) - - outputs_half_h = [model_name + "@half_h"] - node_half_h = onnx.helper.make_node( - "Div", - inputs=outputs_pred_box_h + name_number_two, - outputs=outputs_half_h) - node_list.append(node_half_h) - - outputs_pred_box_x1 = [model_name + "@pred_box_x1"] - node_pred_box_x1 = onnx.helper.make_node( - 'Sub', - inputs=outputs_pred_box_x + outputs_half_w, - outputs=outputs_pred_box_x1) - node_list.append(node_pred_box_x1) - - outputs_pred_box_y1 = [model_name + "@pred_box_y1"] - node_pred_box_y1 = onnx.helper.make_node( - 'Sub', - inputs=outputs_pred_box_y + outputs_half_h, - outputs=outputs_pred_box_y1) - node_list.append(node_pred_box_y1) - - outputs_pred_box_x2 = [model_name + "@pred_box_x2"] - node_pred_box_x2 = onnx.helper.make_node( - 'Add', - inputs=outputs_pred_box_x + outputs_half_w, - outputs=outputs_pred_box_x2) - node_list.append(node_pred_box_x2) - - outputs_pred_box_y2 = [model_name + "@pred_box_y2"] - node_pred_box_y2 = onnx.helper.make_node( - 'Add', - inputs=outputs_pred_box_y + outputs_half_h, - outputs=outputs_pred_box_y2) - node_list.append(node_pred_box_y2) - - outputs_sqeeze_image_size = [model_name + "@sqeeze_image_size"] - node_sqeeze_image_size = onnx.helper.make_node( - "Squeeze", - axes=[0], - inputs=image_size, - outputs=outputs_sqeeze_image_size) - node_list.append(node_sqeeze_image_size) - - output_img_height = [model_name + "@img_height"] - output_img_width = [model_name + "@img_width"] - node_image_size_split = onnx.helper.make_node( - "Split", - inputs=outputs_sqeeze_image_size, - outputs=output_img_height + output_img_width, - axis=-1, - split=[1, 1]) - node_list.append(node_image_size_split) - - output_img_width_cast = [model_name + "@img_width_cast"] - node_img_width_cast = onnx.helper.make_node( - 'Cast', inputs=output_img_width, outputs=output_img_width_cast, to=1) - node_list.append(node_img_width_cast) - - output_img_height_cast = [model_name + "@img_height_cast"] - node_img_height_cast = onnx.helper.make_node( - 'Cast', inputs=output_img_height, outputs=output_img_height_cast, to=1) - node_list.append(node_img_height_cast) - - outputs_pred_box_x1_decode = [model_name + "@pred_box_x1_decode"] - outputs_pred_box_y1_decode = [model_name + "@pred_box_y1_decode"] - outputs_pred_box_x2_decode = [model_name + "@pred_box_x2_decode"] - outputs_pred_box_y2_decode = [model_name + "@pred_box_y2_decode"] - - node_pred_box_x1_decode = onnx.helper.make_node( - 'Mul', - inputs=outputs_pred_box_x1 + output_img_width_cast, - outputs=outputs_pred_box_x1_decode) - node_list.append(node_pred_box_x1_decode) - - node_pred_box_y1_decode = onnx.helper.make_node( - 'Mul', - inputs=outputs_pred_box_y1 + output_img_height_cast, - outputs=outputs_pred_box_y1_decode) - node_list.append(node_pred_box_y1_decode) - - node_pred_box_x2_decode = onnx.helper.make_node( - 'Mul', - inputs=outputs_pred_box_x2 + output_img_width_cast, - outputs=outputs_pred_box_x2_decode) - node_list.append(node_pred_box_x2_decode) - - node_pred_box_y2_decode = onnx.helper.make_node( - 'Mul', - inputs=outputs_pred_box_y2 + output_img_height_cast, - outputs=outputs_pred_box_y2_decode) - node_list.append(node_pred_box_y2_decode) - - name_number_one = [model_name + "@one"] - node_number_one = onnx.helper.make_node( - 'Constant', - inputs=[], - outputs=name_number_one, - value=onnx.helper.make_tensor( - name=name_number_one[0] + "@const", - data_type=onnx.TensorProto.FLOAT, - dims=(), - vals=[1])) - node_list.append(node_number_one) - - output_new_img_height = [model_name + "@new_img_height"] - node_new_img_height = onnx.helper.make_node( - 'Sub', - inputs=output_img_height_cast + name_number_one, - outputs=output_new_img_height) - node_list.append(node_new_img_height) - - output_new_img_width = [model_name + "@new_img_width"] - node_new_img_width = onnx.helper.make_node( - 'Sub', - inputs=output_img_width_cast + name_number_one, - outputs=output_new_img_width) - node_list.append(node_new_img_width) - - outputs_pred_box_x2_sub_w = [model_name + "@pred_box_x2_sub_w"] - node_pred_box_x2_sub_w = onnx.helper.make_node( - 'Sub', - inputs=outputs_pred_box_x2_decode + output_new_img_width, - outputs=outputs_pred_box_x2_sub_w) - node_list.append(node_pred_box_x2_sub_w) - - outputs_pred_box_y2_sub_h = [model_name + "@pred_box_y2_sub_h"] - node_pred_box_y2_sub_h = onnx.helper.make_node( - 'Sub', - inputs=outputs_pred_box_y2_decode + output_new_img_height, - outputs=outputs_pred_box_y2_sub_h) - node_list.append(node_pred_box_y2_sub_h) - - outputs_pred_box_x1_clip = [model_name + "@pred_box_x1_clip"] - outputs_pred_box_y1_clip = [model_name + "@pred_box_y1_clip"] - outputs_pred_box_x2_clip = [model_name + "@pred_box_x2_clip"] - outputs_pred_box_y2_clip = [model_name + "@pred_box_y2_clip"] - - node_pred_box_x1_clip = onnx.helper.make_node( - 'Clip', - inputs=outputs_pred_box_x1_decode, - outputs=outputs_pred_box_x1_clip, - min=0.0, - max=float(MAX_FLOAT32)) - node_list.append(node_pred_box_x1_clip) - - node_pred_box_y1_clip = onnx.helper.make_node( - 'Clip', - inputs=outputs_pred_box_y1_decode, - outputs=outputs_pred_box_y1_clip, - min=0.0, - max=float(MAX_FLOAT32)) - node_list.append(node_pred_box_y1_clip) - - node_pred_box_x2_clip = onnx.helper.make_node( - 'Clip', - inputs=outputs_pred_box_x2_sub_w, - outputs=outputs_pred_box_x2_clip, - min=0.0, - max=float(MAX_FLOAT32)) - node_list.append(node_pred_box_x2_clip) - - node_pred_box_y2_clip = onnx.helper.make_node( - 'Clip', - inputs=outputs_pred_box_y2_sub_h, - outputs=outputs_pred_box_y2_clip, - min=0.0, - max=float(MAX_FLOAT32)) - node_list.append(node_pred_box_y2_clip) - - outputs_pred_box_x2_res = [model_name + "@box_x2_res"] - node_pred_box_x2_res = onnx.helper.make_node( - 'Sub', - inputs=outputs_pred_box_x2_decode + outputs_pred_box_x2_clip, - outputs=outputs_pred_box_x2_res) - node_list.append(node_pred_box_x2_res) - - outputs_pred_box_y2_res = [model_name + "@box_y2_res"] - node_pred_box_y2_res = onnx.helper.make_node( - 'Sub', - inputs=outputs_pred_box_y2_decode + outputs_pred_box_y2_clip, - outputs=outputs_pred_box_y2_res) - node_list.append(node_pred_box_y2_res) - - node_pred_box_result = onnx.helper.make_node( - 'Concat', - inputs=outputs_pred_box_x1_clip + outputs_pred_box_y1_clip + - outputs_pred_box_x2_res + outputs_pred_box_y2_res, - outputs=outputs['Boxes'], - axis=-1) - node_list.append(node_pred_box_result) - - score_shape = [1, input_height * input_width * int(num_anchors), class_num] - name_score_shape = [model_name + "@score_shape"] - node_score_shape = onnx.helper.make_node( - "Constant", - inputs=[], - outputs=name_score_shape, - value=onnx.helper.make_tensor( - name=name_score_shape[0] + "@const", - data_type=onnx.TensorProto.INT64, - dims=[len(score_shape)], - vals=score_shape)) - node_list.append(node_score_shape) - - node_score_new_shape = onnx.helper.make_node( - 'Reshape', - inputs=outputs_score + name_score_shape, - outputs=outputs['Scores']) - node_list.append(node_score_new_shape) - return node_list diff --git a/x2paddle/op_mapper/paddle2onnx/paddle_op_mapper.py b/x2paddle/op_mapper/paddle2onnx/paddle_op_mapper.py deleted file mode 100644 index f167dfdd73b05aae2036c2ab4001c7c6a838d267..0000000000000000000000000000000000000000 --- a/x2paddle/op_mapper/paddle2onnx/paddle_op_mapper.py +++ /dev/null @@ -1,108 +0,0 @@ -# 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 sys -import x2paddle -import os -import numpy as np -import paddle.fluid.core as core -import paddle.fluid as fluid -import onnx -from onnx import helper, onnx_pb -from x2paddle.op_mapper.paddle2onnx.opset9.opset import OpSet9 -from x2paddle.op_mapper.paddle2onnx.opset10.opset import OpSet10 -from x2paddle.op_mapper.paddle2onnx.opset11.opset import OpSet11 - - -class PaddleOpMapper(object): - def __init__(self): - self.support_opsets = [9, 10, 11] - self.default_opset = 10 - self.name_counter = dict() - self.op_set = None - - def convert(self, program, save_dir, scope=None, opset_version=10): - self.op_set = self.create_opset(opset_version) - weight_nodes = self.op_set.convert_weights(program, scope=scope) - op_nodes = list() - input_nodes = list() - output_nodes = list() - unsupported_ops = set() - - print("Translating PaddlePaddle to ONNX...\n") - for block in program.blocks: - for i, op in enumerate(block.ops): - sys.stdout.write("\rTotal:{}, Current:{} : {} ".format( - len(block.ops), i + 1, op.type)) - sys.stdout.flush() - if not hasattr(self.op_set, op.type): - unsupported_ops.add(op.type) - continue - if len(unsupported_ops) > 0: - continue - node = getattr(self.op_set, op.type)(op, block) - if op.type == 'feed': - print(node.name) - input_nodes.append(node) - elif op.type == 'fetch': - output_nodes.append(node) - else: - if isinstance(node, list): - op_nodes = op_nodes + node - else: - op_nodes.append(node) - - if len(unsupported_ops) > 0: - print("\nThere's {} ops are not supported yet".format( - len(unsupported_ops))) - for op in unsupported_ops: - print("=========== {} ===========".format(op)) - return - - graph = helper.make_graph( - nodes=weight_nodes + op_nodes, - name='onnx_model_from_paddle', - initializer=[], - inputs=input_nodes, - outputs=output_nodes) - opset_imports = [helper.make_opsetid("", opset_version)] - model = helper.make_model( - graph, producer_name='X2Paddle', opset_imports=opset_imports) - onnx.checker.check_model(model) - - if not os.path.isdir(save_dir): - os.makedirs(save_dir) - with open(os.path.join(save_dir, 'x2paddle_model.onnx'), 'wb') as f: - f.write(model.SerializeToString()) - print("\nTranslated model saved in {}".format( - os.path.join(save_dir, 'x2paddle_model.onnx'))) - - def create_opset(self, opset_version=10): - run_opset = self.default_opset - opset = '' - if opset_version in self.support_opsets: - run_opset = opset_version - else: - for support_opset_version in self.support_opsets: - if support_opset_version < opset_version: - run_opset = support_opset_version - else: - break - print( - 'Now, onnx2paddle support convert onnx model opset_verison {},' - 'opset_verison of your onnx model is {}, automatically treated as op_set: {}.' - .format(self.support_opsets, opset_version, run_opset)) - opset = 'OpSet' + str(run_opset) - return eval(opset)() diff --git a/x2paddle/op_mapper/paddle2onnx/__init__.py b/x2paddle/op_mapper/pytorch2paddle/__init__.py similarity index 100% rename from x2paddle/op_mapper/paddle2onnx/__init__.py rename to x2paddle/op_mapper/pytorch2paddle/__init__.py diff --git a/x2paddle/op_mapper/pytorch2paddle/aten.py b/x2paddle/op_mapper/pytorch2paddle/aten.py new file mode 100644 index 0000000000000000000000000000000000000000..b5f25ad65a17a7f80f0f95d43912e888408b2a06 --- /dev/null +++ b/x2paddle/op_mapper/pytorch2paddle/aten.py @@ -0,0 +1,4154 @@ +# 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.core.util import * +from x2paddle.core.program import PaddleGraph + +dtype_dict = { + 0: string("uint8"), + 1: string("int8"), + 2: string("int16"), + 3: string("int32"), + 4: string("int64"), + 5: string("float16"), + 6: string("float32"), + 7: string("float64"), + 11: string("bool") +} + + +def aten_abs(mapper, graph, node): + """ 构造获取绝对值的PaddleLayer。 + + TorchScript示例: + %n0.3 : Tensor = aten::abs(%n.3) + 参数含义: + %n0.3 (Tensor): 绝对值后的Tensor。 + %n.3 (Tensor): 绝对值前的Tensor。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%n.3 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "paddle.fluid.layers.abs", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_adaptive_avg_pool2d(mapper, graph, node): + """ 构造average adaptive pool2d的PaddleLayer。 + + TorchScript示例: + %x.5 : Tensor = aten::adaptive_avg_pool2d(%x.3, %_output_size.1) + 参数含义: + %x.5 (Tensor): 池化后结果Tensor。 + %x.3 (Tensor): 输入Tensor。 + %_output_size.1 (list): 自适应池化后的Tensor的宽、高大小。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%x.3 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%_output_size.1 + if inputs_name[1] in mapper.attrs: + layer_attrs["pool_size"] = mapper.attrs[inputs_name[1]] + else: + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + layer_inputs["pool_size"] = inputs_name[1] + current_inputs.append(inputs_name[1]) + layer_attrs["pool_type"] = string("avg") + + graph.add_layer( + "fluid.layers.adaptive_pool2d", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_addmm(mapper, graph, node): + """ 构造addmm的PaddleLayer,该节点实现out = alpha ∗ x ∗ y + beta ∗ input。 + + TorchScript示例: + %ret.2 : Tensor = aten::addmm(%150, %input.3, %156, %151, %152) + 参数含义: + %ret.2 (Tensor): addmm结果Tensor。 + %150 (Tensor): 输入Tensor input。 + %input.3 (Tensor): 输入Tensor x。 + %156 (Tensor): 输入Tensor y。 + %151 (int/float): 输入alpha。 + %152 (int/float): 输入beta。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%150 + mapper._check_input( + graph, inputs_node[0], inputs_name[0], current_outputs, add_dim=True) + layer_inputs["input"] = inputs_name[0] + # 处理输入1,即%input.3 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + layer_inputs["x"] = inputs_name[1] + # 处理输入2,即%156 + mapper._check_input(graph, inputs_node[2], inputs_name[2], current_outputs) + layer_inputs["y"] = inputs_name[2] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + # 处理输入3,即%152 + if inputs_name[3] in mapper.attrs: + layer_attrs["beta"] = mapper.attrs[inputs_name[3]] + else: + mapper._check_input(graph, inputs_node[3], inputs_name[3], + current_outputs) + layer_inputs["beta"] = inputs_name[3] + current_inputs.append(inputs_name[3]) + # 处理输入4,即%151 + if inputs_name[4] in mapper.attrs: + layer_attrs["alpha"] = mapper.attrs[inputs_name[4]] + else: + mapper._check_input(graph, inputs_node[4], inputs_name[4], + current_outputs) + layer_inputs["alpha"] = inputs_name[4] + current_inputs.append(inputs_name[4]) + + graph.add_layer( + "paddle.addmm", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_add(mapper, graph, node): + """ 构造数值相加的PaddleLayer,该节点实现out = x + y。 + + TorchScript示例: + %296 : int = aten::add(%i.12, %288) + 参数含义: + %296 (-): 相加结果。 + %i.12 (-): 输入数值 x。 + %288 (-): 输入数值 y。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%i.12 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 处理输入1,即%288 + mapper._check_input( + graph, inputs_node[1], inputs_name[1], current_outputs, add_dim=True) + layer_inputs["y"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.add", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_add_(mapper, graph, node): + """ 构造数值相加的PaddleLayer,该节点实现out = x + alpha * y。 + + TorchScript示例: + %137 : Tensor = aten::add(%136, %130, %130) + 参数含义: + %output.5 (Tensor): add结果Tensor。 + %output.2 (Tensor): 输入Tensor x。 + %150 (Tensor): 输入Tensor y。 + %151 (int/float): 输入alpha。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%output.2 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 处理输入1,即%150 + mapper._check_input( + graph, inputs_node[1], inputs_name[1], current_outputs, add_dim=True) + layer_inputs["y"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + # 处理输入2,即%151 + if inputs_name[2] in mapper.attrs: + layer_attrs["alpha"] = mapper.attrs[inputs_name[2]] + else: + mapper._check_input(graph, inputs_node[2], inputs_name[2], + current_outputs) + layer_inputs["alpha"] = inputs_name[2] + current_inputs.append(inputs_name[2]) + + graph.add_layer( + "prim.add_", inputs=layer_inputs, outputs=layer_outputs, **layer_attrs) + return current_inputs, current_outputs + + +def aten___and__(mapper, graph, node): + """ 构造与计算的PaddleLayer。 + + TorchScript示例: + %361 : bool = aten::__and__(%360, %358) + 参数含义: + %361 (bool): 输出,与计算结果。 + %360 (-): 输入 x。 + %358 (-): 输入 y。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%i.12 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 处理输入1,即%288 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + layer_inputs["y"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.and", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_append(mapper, graph, node): + """ 构造对list进行append的PaddleLayer。 + + TorchScript示例: + %90 : int[] = aten::append(%_output_size.1, %v.1) + 参数含义: + %90 (list): 输出,append后的list。 + %_output_size.1 (list): 需要进行append的list。 + %v.1 (-): append的元素。 + """ + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + layer_outputs = [inputs_name[0]] + # 获取当前节点输出的list + current_outputs = [inputs_name[0]] + # 处理输入0,即_output_size.1 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["list"] = inputs_name[0] + # 处理输入1,即v.1 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + layer_inputs["element"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.append", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_arange(mapper, graph, node): + """ 构造以步长均匀分隔给定数值区间的PaddleLayer。 + + TorchScript示例: + 有三种情况,分别处理。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + current_inputs = [] + if len(inputs_name) == 5: + # %position_ids.1 : Tensor = aten::arange(%52, %43, %45, %42, %46) + # 输入的后三者分别代表layout、device、是否使用梯度 + # 处理输入0,即%52,代表end + if inputs_name[0] in mapper.attrs: + layer_attrs["end"] = mapper.attrs[inputs_name[0]] + else: + mapper._check_input(graph, inputs_node[0], inputs_name[0], + current_outputs) + layer_inputs["end"] = inputs_name[0] + current_inputs.append(inputs_name[0]) + # 处理输入1,即%43,代表dtype + if mapper.attrs[inputs_name[1]] is None: + layer_attrs["dtype"] = None + else: + layer_attrs["dtype"] = dtype_dict[mapper.attrs[inputs_name[1]]] + elif len(inputs_name) == 6: + # %position_ids.1 : Tensor = aten::arange(%51, %52, %43, %45, %42, %46) + # 输入的后三者分别代表layout、device、是否使用梯度 + # 处理输入0,即%51,代表start + if inputs_name[0] in mapper.attrs: + layer_attrs["start"] = mapper.attrs[inputs_name[0]] + else: + mapper._check_input(graph, inputs_node[0], inputs_name[0], + current_outputs) + layer_inputs["start"] = inputs_name[0] + current_inputs.append(inputs_name[0]) + # 处理输入1,即%52,代表end + if inputs_name[1] in mapper.attrs: + layer_attrs["end"] = mapper.attrs[inputs_name[1]] + else: + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + layer_inputs["end"] = inputs_name[1] + current_inputs.append(inputs_name[1]) + # 处理输入2,即%43,代表dtype + if mapper.attrs[inputs_name[2]] is None: + layer_attrs["dtype"] = None + else: + layer_attrs["dtype"] = dtype_dict[mapper.attrs[inputs_name[2]]] + elif len(inputs_name) == 7: + # %position_ids.1 : Tensor = aten::arange(%51, %52, %53, %43, %45, %42, %46) + # 输入的后三者分别代表layout、device、是否使用梯度 + # 处理输入0,即%51,代表start + if inputs_name[0] in mapper.attrs: + layer_attrs["start"] = mapper.attrs[inputs_name[0]] + else: + mapper._check_input(graph, inputs_node[0], inputs_name[0], + current_outputs) + layer_inputs["start"] = inputs_name[0] + current_inputs.append(inputs_name[0]) + # 处理输入1,即%52,代表end + if inputs_name[1] in mapper.attrs: + layer_attrs["end"] = mapper.attrs[inputs_name[1]] + else: + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + layer_inputs["end"] = inputs_name[1] + current_inputs.append(inputs_name[1]) + # 处理输入2,即%53,代表step + if inputs_name[2] in mapper.attrs: + layer_attrs["step"] = mapper.attrs[inputs_name[2]] + else: + mapper._check_input(graph, inputs_node[2], inputs_name[2], + current_outputs) + layer_inputs["step"] = inputs_name[2] + current_inputs.append(inputs_name[2]) + # 处理输入3,即%43,代表dtype + if mapper.attrs[inputs_name[3]] is None: + layer_attrs["dtype"] = None + else: + layer_attrs["dtype"] = dtype_dict[mapper.attrs[inputs_name[3]]] + else: + raise Exception("Unknown aten::arange signature taking " + str( + len(inputs_name)) + " arguments.") + + graph.add_layer( + "paddle.arange", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_avg_pool2d(mapper, graph, node): + """ 构造最大池化的PaddleLayer。 + + TorchScript示例: + %branch_pool.2 : Tensor = aten::avg_pool2d(%x.43, %538, %539, %540, %273, %272, %271) + 参数含义: + %branch_pool.2 (Tensor): 输出,池化后的结果。 + %x.43 (Tensor): 需要池化的Tensor。 + %538 (list): 池化kernel的大小。 + %539 (list): 步长大小。 + %540 (list): 填充大小。 + %273 (bool): 是否用ceil函数计算输出高度和宽度。 + %272 (bool): 是否在平均池化模式不忽略填充值,False为忽略。 + %271 (int): 如果指定,它将用作除数,否则将使用池化区域的大小。 + """ + if "pool" in mapper.dygraph_name_id: + mapper.dygraph_name_id["pool"] += 1 + else: + mapper.dygraph_name_id["pool"] = 0 + pool_name = "pool" + str(mapper.dygraph_name_id["pool"]) + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [pool_name, output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%x.34 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%538 + layer_attrs["pool_size"] = mapper.attrs[inputs_name[1]] + # 处理输入2,即%539 + layer_attrs["pool_stride"] = mapper.attrs[inputs_name[2]] + # 处理输入3,即%540 + layer_attrs["pool_padding"] = mapper.attrs[inputs_name[3]] + # 处理输入4,即%273 + layer_attrs["ceil_mode"] = mapper.attrs[inputs_name[4]] + # 处理输入5,即%272 + layer_attrs["exclusive"] = not mapper.attrs[inputs_name[5]] + # 处理输入6,即%271 + graph.add_layer( + "prim.assert", + inputs={}, + outputs=[inputs_name[6] + "_assert"], + type="eq", + key=mapper.attrs[inputs_name[6]], + value=None) + layer_attrs["pool_type"] = string("avg") + + graph.add_layer( + "paddle.nn.Pool2D", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_batch_norm(mapper, graph, node): + """ 构造BatchNorm的PaddleLayer。 + + TorchScript示例: + %input.81 : Tensor = aten::batch_norm(%input.80, %778, %779, %776, %777, %780, + %exponential_average_factor.23, %766, %781) + 参数含义: + %input.81 (Tensor): 输出,批处理后的结果。 + %input.80 (Tensor): 需要进行批处理的特征层。 + %778 (Tensor): weights。 + %779 (Tensor): bias。 + %776 (Tensor): 全局均值。 + %777 (Tensor): 全局方差。 + %780 (bool): 是否训练。 + %exponential_average_factor.23 (float): 用于计算均值和方差的比例。 + %766 (float): 为了数值稳定加在分母上的值。 + %781 (bool): 是否启用cudnn。 + """ + if "batchnorm" in mapper.dygraph_name_id: + mapper.dygraph_name_id["batchnorm"] += 1 + else: + mapper.dygraph_name_id["batchnorm"] = 0 + batchnorm_name = "batchnorm" + str(mapper.dygraph_name_id["batchnorm"]) + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [batchnorm_name, output_name] + layer_inputs = {} + layer_attrs = {} + layer_attrs["is_test"] = True + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%input.80 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入、输出的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%778 + weights = mapper.pytorch_params[inputs_name[1]] + mapper.paddle_params[batchnorm_name + ".weight"] = weights + layer_attrs['num_channels'] = weights.shape[0] + # 处理输入2,即%779 + if inputs_name[2] in mapper.pytorch_params: + bias = mapper.pytorch_params[inputs_name[2]] + if bias is not None: + mapper.paddle_params[batchnorm_name + ".bias"] = bias + else: + mapper.paddle_params[batchnorm_name + ".bias"] = False + # 处理输入3,即%776 + mean = mapper.pytorch_params[inputs_name[3]] + mapper.paddle_params[batchnorm_name + "._mean"] = mean + # 处理输入4,即%777 + var = mapper.pytorch_params[inputs_name[4]] + mapper.paddle_params[batchnorm_name + "._variance"] = var + # 处理输入6,即%exponential_average_factor.23 + layer_attrs["momentum"] = mapper.attrs[inputs_name[6]] + # 处理输入7,即%766 + layer_attrs["epsilon"] = mapper.attrs[inputs_name[7]] + + graph.add_layer( + "paddle.nn.BatchNorm", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_cat(mapper, graph, node): + """ 构造连接Tensor的PaddleLayer。 + + TorchScript示例: + %x.222 : Tensor = aten::cat(%32, %7) + 参数含义: + %x.222 (Tensor): 输出,连接后的结果。 + %i.12 (list): 需要连接的Tensor组成的list。 + %7 (int): 连接的轴。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%13 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%12 + if inputs_name[1] in mapper.attrs: + layer_attrs["axis"] = mapper.attrs[inputs_name[1]] + else: + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + layer_inputs["axis"] = inputs_name[1] + current_inputs.append(inputs_name[1]) + graph.add_layer( + "fluid.layers.concat", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_chunk(mapper, graph, node): + """构造分割Tensor的PaddleLayer。 + + TorchScript示例: + %724 : Tensor[] = aten::chunk(%input.170, %720, %719) + 参数含义: + %724 (Tensor): 输出,分割后的结果。 + %input.170 (Tensor): 需要进行分割的Tensor。 + %720 (int): 分割的块数。 + %719 (int): 分割的维度。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%input.170 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%720 + if inputs_name[1] in mapper.attrs: + layer_attrs["num_or_sections"] = mapper.attrs[inputs_name[1]] + else: + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + layer_inputs["num_or_sections"] = inputs_name[1] + current_inputs.append(inputs_name[1]) + # 处理输入2,即%719 + if inputs_name[2] in mapper.attrs: + layer_attrs["dim"] = mapper.attrs[inputs_name[2]] + else: + mapper._check_input(graph, inputs_node[2], inputs_name[2], + current_outputs) + layer_inputs["dim"] = inputs_name[2] + current_inputs.append(inputs_name[2]) + graph.add_layer( + "fluid.layers.split", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten___contains__(mapper, graph, node): + """ 构造in的PaddleLayer。 + + TorchScript示例: + %51 : bool = aten::__contains__(%50, %name.1) + 参数含义: + %51 (bool): 输出,第一个元素是否包含第二个元素。 + %50 (-): 需对比的输入1。 + %name.1 (-): 需对比的输入2。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%50 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 处理输入1,即%name.1 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + layer_inputs["element"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.contain", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_constant_pad_nd(mapper, graph, node): + """ 构造填充固定值的PaddleLayer。 + + TorchScript示例: + %58 : Tensor = aten::constant_pad_nd(%input1.24, %4876, %42) + 参数含义: + %58 (Tensor): 输出,填充后的Tensor。 + %input1.24 (Tensor): 需要填充的Tensor。 + %4876 (list): 填充大小。 + %42 (-): 填充值。 + """ + if "constant_pad" in mapper.dygraph_name_id: + mapper.dygraph_name_id["constant_pad"] += 1 + else: + mapper.dygraph_name_id["constant_pad"] = 0 + constant_pad_name = "constant_pad" + str(mapper.dygraph_name_id[ + "constant_pad"]) + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [constant_pad_name, output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%input1.24 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%4876 + layer_attrs["padding"] = mapper.attrs[inputs_name[1]] + # 处理输入2,即%42 + layer_attrs["value"] = mapper.attrs[inputs_name[2]] + + graph.add_layer( + "fluid.layers.shape", + inputs={"input": inputs_name[0]}, + outputs=[inputs_name[0] + "_shape"]) + graph.add_layer( + "prim.len", + inputs={"input": inputs_name[0] + "_shape"}, + outputs=[inputs_name[0] + "_len"]) + + def add_pad_layers(kernel, dim): + graph.add_layer( + "prim.ne", + inputs={"x": inputs_name[0] + "_len"}, + outputs=[inputs_name[0] + "_cond"], + y=dim) + graph.add_layer( + "prim.if", {'input': inputs_name[0] + "_cond"}, + outputs=[inputs_name[0] + "_if", output_name]) + if_layer = graph.layers[list(graph.layers.keys())[-1]] + block = PaddleGraph(if_layer, graph_type="dygraph") + block.add_layer( + "prim.sub", + inputs={"y": inputs_name[0] + "_len"}, + outputs=[inputs_name[0] + "_len0"], + x=dim) + block.add_layer( + "prim.len2list", + inputs={"len": inputs_name[0] + "_len0"}, + outputs=[inputs_name[0] + "_list"]) + block.add_layer( + "paddle.tensor.unsqueeze", + inputs={"x": inputs_name[0], + "axis": inputs_name[0] + "_list"}, + outputs=[inputs_name[0] + "_var"]) + block.add_layer( + kernel, + inputs={"input": inputs_name[0] + "_var"}, + outputs=layer_outputs, + **layer_attrs) + block.add_layer( + "paddle.tensor.squeeze", + inputs={"x": output_name, + "axis": inputs_name[0] + "_list"}, + outputs=[output_name]) + if_layer.add_block(block) + block = PaddleGraph(if_layer, graph_type="dygraph") + layer_inputs["input"] = inputs_name[0] + block.add_layer( + kernel, inputs=layer_inputs, outputs=layer_outputs, **layer_attrs) + if_layer.add_block(block) + if_layer.inputs["input-0"] = inputs_name[0] + if_layer.inputs["input-1"] = inputs_name[0] + "_len" + + if len(layer_attrs["padding"]) == 2: + add_pad_layers("paddle.nn.ConstantPad1d", 3) + elif len(layer_attrs["padding"]) == 4: + add_pad_layers("paddle.nn.ConstantPad2d", 4) + elif len(layer_attrs["padding"]) == 6: + add_pad_layers("paddle.nn.ConstantPad3d", 5) + else: + raise Exception("The lenght of padding list must be 2, 4 or 6!") + return current_inputs, current_outputs + + +def aten_contiguous(mapper, graph, node): + """ 构造在内存中连续存储的PaddleLayer。 + + TorchScript示例: + %x.7 : Tensor = aten::contiguous(%4058, %4046) + 参数含义: + %x.7 (Tensor): 输出,在内存中连续存储的Tensor。 + %4058 (Tensor): 原始Tensor。 + %4046 (int): 存储的形式。 + + 【注意】Paddle中无此用法,所以此处翻译成赋值。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%4058 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.equal", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_conv2d(mapper, graph, node): + """ 构造conv2d的PaddleLayer。 + + TorchScript示例: + %input.10 : Tensor = aten::conv2d(%input.8, %25, %27, %28, %29, %30, %26) + 参数含义: + %input.10 (Tensor): 输出,卷积后的结果。 + %input.8 (Tensor): 需要进行卷积的特征层。 + %25 (Tensor): weights。 + %27 (Tensor): bias。 + %28 (int): 步长大小。 + %29 (int): 填充大小。 + %30 (int): 膨胀系数大小。 + %26 (int): 卷积的组数。 + """ + if "conv" in mapper.dygraph_name_id: + mapper.dygraph_name_id["conv"] += 1 + else: + mapper.dygraph_name_id["conv"] = 0 + conv2d_name = "conv" + str(mapper.dygraph_name_id["conv"]) + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [conv2d_name, output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%input.8 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%25 + weights = mapper.pytorch_params[inputs_name[1]] + mapper.paddle_params[conv2d_name + ".weight"] = weights + layer_attrs["out_channels"] = weights.shape[0] + layer_attrs["kernel_size"] = weights.shape[2:] + # 处理输入2,即%27 + if inputs_name[2] in mapper.pytorch_params: + bias = mapper.pytorch_params[inputs_name[2]] + if bias is not None: + mapper.paddle_params[conv2d_name + ".bias"] = bias + else: + layer_attrs["bias_attr"] = False + else: + layer_attrs["bias_attr"] = False + # 处理输入3,即%28 + layer_attrs["stride"] = mapper.attrs[inputs_name[3]] + # 处理输入4,即%29 + layer_attrs["padding"] = mapper.attrs[inputs_name[4]] + # 处理输入5,即%30 + layer_attrs["dilation"] = mapper.attrs[inputs_name[5]] + # 处理输入6,即%26 + layer_attrs["groups"] = mapper.attrs[inputs_name[6]] + layer_attrs['in_channels'] = weights.shape[1] * mapper.attrs[inputs_name[6]] + + graph.add_layer( + "paddle.nn.Conv2d", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten__convolution(mapper, graph, node): + """ 构造conv2d的PaddleLayer。 + + TorchScript示例: + %input.10 : Tensor = aten::_convolution(%input.8, %25, %27, %28, %29, %30, %26) + 参数含义: + %input.10 (Tensor): 输出,卷积后的结果。 + %input.8 (Tensor): 需要进行卷积的特征层。 + %25 (Tensor): weights。 + %27 (Tensor): bias。 + %28 (int): 步长大小。 + %29 (int): 填充大小。 + %30 (int): 膨胀系数大小。 + %26 (int): 卷积的组数。 + """ + if "conv" in mapper.dygraph_name_id: + mapper.dygraph_name_id["conv"] += 1 + else: + mapper.dygraph_name_id["conv"] = 0 + conv2d_name = "conv" + str(mapper.dygraph_name_id["conv"]) + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [conv2d_name, output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%input.8 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%25 + weights = mapper.pytorch_params[inputs_name[1]] + mapper.paddle_params[conv2d_name + ".weight"] = weights + layer_attrs["num_filters"] = weights.shape[0] + layer_attrs["filter_size"] = weights.shape[2:] + # 处理输入2,即%27 + if inputs_name[2] in mapper.pytorch_params: + bias = mapper.pytorch_params[inputs_name[2]] + if bias is not None: + mapper.paddle_params[conv2d_name + ".bias"] = bias + else: + layer_attrs["bias_attr"] = False + else: + layer_attrs["bias_attr"] = False + # 处理输入3,即%28 + layer_attrs["stride"] = mapper.attrs[inputs_name[3]] + # 处理输入4,即%29 + layer_attrs["padding"] = mapper.attrs[inputs_name[4]] + # 处理输入5,即%30 + layer_attrs["dilation"] = mapper.attrs[inputs_name[5]] + # 处理输入6,即%26 + layer_attrs["groups"] = mapper.attrs[inputs_name[6]] + layer_attrs['num_channels'] = weights.shape[1] * mapper.attrs[inputs_name[ + 6]] + + graph.add_layer( + "paddle.nn.Conv2D", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_cos(mapper, graph, node): + """ 构造数学计算cos的PaddleLayer。 + + TorchScript示例: + %94 : Tensor = aten::cos(%sinusoid_inp.1) + 参数含义: + %94 (Tensor): 输出,cos之后的结果。 + %sinusoid_inp.1 (Tensor): 需要进行shape的Tensor。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%sinusoid_inp.1 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入、输出的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("paddle.cos", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_cumsum(mapper, graph, node): + """ 构造与前一个元素累加的PaddleLayer。 + + TorchScript示例: + %56 : Tensor = aten::cumsum(%mask.1, %46, %48) + 参数含义: + %56 (Tensor): 输出,累加后的结果。 + %mask.1 (Tensor): 输入,需要累加的Tensor。 + %46 (int): 累加的维度。 + %48 (int/None): Tensor的类型。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%mask.1 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入、输出的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%46 + if inputs_name[1] in mapper.attrs: + layer_attrs["axis"] = mapper.attrs[inputs_name[1]] + else: + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + layer_inputs["axis"] = inputs_name[1] + current_inputs.append(inputs_name[1]) + # 处理输入1,即%48,代表dtype + if mapper.attrs[inputs_name[2]] is None: + layer_attrs["dtype"] = None + else: + layer_attrs["dtype"] = dtype_dict[mapper.attrs[inputs_name[2]]] + + graph.add_layer( + "paddle.cumsum", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_detach(mapper, graph, node): + """ 构造返回一个新的Tensor,从当前计算图中分离下来的,但是仍指向原变量的存放位置的PaddleLayer。 + + TorchScript示例: + %107 : Tensor = aten::detach(%new_mem.1) + 参数含义: + %107 (Tensor): 输出,得到的Scalar。 + %new_mem.1 (Tensor): 输入。 + + 【注意】由于Paddle无此操作,所以此处制转换为赋值。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%end.1 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + graph.add_layer("prim.equal", inputs=layer_inputs, outputs=layer_outputs) + + return current_inputs, current_outputs + + +def aten_dict(mapper, graph, node): + """ 构造初始化dict的PaddleLayer。 + + TorchScript示例: + %features.1 : Dict(str, Tensor) = aten::dict() + 参数含义: + %features.1: 输出,初始化的dict。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + current_inputs = {} + # 获取当前节点输出的list + current_outputs = [output_name] + + graph.add_layer("prim.dict", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_dim(mapper, graph, node): + """ 构造获取维度的PaddleLayer。 + + TorchScript示例: + %106 : int = aten::dim(%101) + 参数含义: + %106 (int): 输出,Tensor的维度。 + %101 (Tensor): 输入的Tensor。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%input.8 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "fluid.layers.shape", inputs=layer_inputs, outputs=layer_outputs) + graph.add_layer( + "prim.len", inputs={"input": output_name}, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_div_(mapper, graph, node): + """ 构造除法的PaddleLayer。 + + TorchScript示例: + %bx_bw0.3 : Tensor = aten::div_(%bx_bw.3, %2678) + 参数含义: + %bx_bw0.3 (-): 除后的结果。 + %bx_bw.3 (-): 被除数。 + %2678 (int): 除数。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%124 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 处理输入1,即%123 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + layer_inputs["y"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.div", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_div(mapper, graph, node): + """ 构造除法的PaddleLayer。 + + TorchScript示例: + %bx_bw0.3 : Tensor = aten::div_(%bx_bw.3, %2678) + 参数含义: + %bx_bw0.3 (-): 除后的结果。 + %bx_bw.3 (-): 被除数。 + %2678 (int): 除数。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%124 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 处理输入1,即%123 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + layer_inputs["y"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.div", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_dropout(mapper, graph, node): + """ 构造Dropout的PaddleLayer。 + + TorchScript示例: + %119 : Tensor = aten::dropout(%result.3, %117, %118) + 参数含义: + %119 (Tensor): Dropout后的Tensor。 + %result.3 (Tensor): 输入Tensor。 + %118 (bool): 是否是训练阶段。 + """ + if "dropout" in mapper.dygraph_name_id: + mapper.dygraph_name_id["dropout"] += 1 + else: + mapper.dygraph_name_id["dropout"] = 0 + dropout_name = "dropout" + str(mapper.dygraph_name_id["dropout"]) + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [dropout_name, output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%119 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入、输出的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "paddle.nn.Dropout", inputs=layer_inputs, outputs=layer_outputs, p=0.0) + return current_inputs, current_outputs + + +def aten_dropout_(mapper, graph, node): + """ 构造Dropout的PaddleLayer。 + + TorchScript示例: + %119 : Tensor = aten::dropout_(%result.3, %117, %118) + 参数含义: + %119 (Tensor): Dropout后的Tensor。 + %result.3 (Tensor): 输入Tensor。 + %118 (bool): 是否是训练阶段。 + """ + if "dropout" in mapper.dygraph_name_id: + mapper.dygraph_name_id["dropout"] += 1 + else: + mapper.dygraph_name_id["dropout"] = 0 + dropout_name = "dropout" + str(mapper.dygraph_name_id["dropout"]) + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [dropout_name, output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%119 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入、输出的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "paddle.nn.Dropout", inputs=layer_inputs, outputs=layer_outputs, p=0.0) + return current_inputs, current_outputs + + +def aten_embedding(mapper, graph, node): + """ 构造embedding的PaddleLayer。 + + TorchScript示例: + %inputs_embeds.1 : Tensor = aten::embedding(%57, %input_ids.1, %45, %46, %46) + 参数含义: + %inputs_embeds.1 (Tensor): 输出,embedding后的结果。 + %57 (Tensor): weights。 + %input_ids.1 (Tensor): 需要进行embedding的特征层。 + %45 (int): padding_idx。 + %46 (bool): scale_grad_by_freq。 + %46 (bool): sparse。 + """ + if "embedding" in mapper.dygraph_name_id: + mapper.dygraph_name_id["embedding"] += 1 + else: + mapper.dygraph_name_id["embedding"] = 0 + embedding_name = "embedding" + str(mapper.dygraph_name_id["embedding"]) + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [embedding_name, output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%57 + weights = mapper.pytorch_params[inputs_name[0]] + mapper.paddle_params[embedding_name + ".weight"] = weights + # layer_attrs["num_embeddings"] = weights.shape[0] + # layer_attrs["embedding_dim"] = weights.shape[1] + layer_attrs["size"] = weights.shape + # 处理输入1,即%input_ids.1 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + layer_inputs["input"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + # 处理输入2,即%45 + if mapper.attrs[inputs_name[2]] == -1: + layer_attrs["padding_idx"] = None + else: + layer_attrs["padding_idx"] = mapper.attrs[inputs_name[2]] + # 处理输入4,即%46 + # layer_attrs["sparse"] = mapper.attrs[inputs_name[4]] + layer_attrs["is_sparse"] = mapper.attrs[inputs_name[4]] + + graph.add_layer( + "paddle.fluid.dygraph.Embedding", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_eq(mapper, graph, node): + """ 构造判断数值是否相等的PaddleLayer。 + + TorchScript示例: + %125 : bool = aten::eq(%124, %123) + 参数含义: + %125 (bool): 对比后结果。 + %124 (-): 需对比的输入1。 + %123 (-): 需对比的输入2。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%124 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + x_value = list(node.inputs())[0] + x_type = x_value.type() + # 处理输入1,即%123 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + layer_inputs["y"] = inputs_name[1] + y_value = list(node.inputs())[1] + y_type = y_value.type() + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + graph.add_layer("prim.eq", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_exp(mapper, graph, node): + """ 构造以自然数e为底指数运算的PaddleLayer。 + + TorchScript示例: + %55 : Tensor = aten::tanh(%54) + 参数含义: + %55 (Tensor): 输出,运算后的结果。 + %54 (Tensor): 需要指数运算的Tensor。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%result.5 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入、输出的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "fluid.layers.exp", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_expand(mapper, graph, node): + """ 构造对某维度进行广播的PaddleLayer。 + + TorchScript示例: + %1889 : Tensor = aten::expand(%1875, %1888, %1567) + 参数含义: + %1889 (Tensor): 广播后的结果。 + %1875 (Tensor): 需要广播的Tensor。 + %1888 (int): 广播的维度。 + %1567 (bool): 未使用。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%1875 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 处理输入1,即%1888 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + + graph.add_layer( + "prim.type", + inputs={"input": inputs_name[0]}, + outputs=[inputs_name[0] + "_type"]) + graph.add_layer( + "prim.str", + inputs={"input": inputs_name[0] + "_type"}, + outputs=[inputs_name[0] + "_type"]) + graph.add_layer( + "prim.eq", + inputs={"x": inputs_name[0] + "_type"}, + outputs=[inputs_name[0] + "_cond"], + y=string("VarType.BOOL")) + graph.add_layer( + "prim.if", {'input': inputs_name[0] + "_cond"}, + outputs=[inputs_name[0] + "_if1", inputs_name[1] + "_var"]) + if_layer = graph.layers[list(graph.layers.keys())[-1]] + block = PaddleGraph(if_layer, graph_type="dygraph") + block.add_layer( + "fluid.layers.cast", + inputs={"x": inputs_name[0]}, + outputs=[inputs_name[0]], + dtype=string("int64")) + block.add_layer( + "fluid.layers.create_global_var", + inputs={"shape": inputs_name[1]}, + outputs=[inputs_name[1] + "_var"], + value=1.0, + dtype=string("int64"), + persistable=True) + if_layer.add_block(block) + block = PaddleGraph(if_layer, graph_type="dygraph") + block.add_layer( + "prim.type", + inputs={"input": inputs_name[0]}, + outputs=[inputs_name[0] + "_type"]) + block.add_layer( + "fluid.layers.create_global_var", + inputs={"shape": inputs_name[1]}, + outputs=[inputs_name[1] + "_var"], + value=1.0, + dtype=inputs_name[0] + "_type", + persistable=True) + if_layer.add_block(block) + if_layer.inputs["input-0"] = inputs_name[0] + if_layer.inputs["input-1"] = inputs_name[1] + + layer_inputs["target_tensor"] = inputs_name[1] + "_var" + current_outputs.append(inputs_name[1] + "_var") + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + current_inputs.append(inputs_name[1]) + + graph.add_layer( + "fluid.layers.expand_as", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_expand_as(mapper, graph, node): + """ 构造广播的PaddleLayer。 + + TorchScript示例: + %1889 : Tensor = aten::expand_as(%1875, %1888) + 参数含义: + %1889 (Tensor): 广播后的结果。 + %1875 (Tensor): 需要广播的Tensor。 + %1888 (Tensor): 广播的示例。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%1875 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 处理输入1,即%1888 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + layer_inputs["target_tensor"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "prim.type", + inputs={"input": inputs_name[0]}, + outputs=[inputs_name[0] + "_type"]) + graph.add_layer( + "prim.str", + inputs={"input": inputs_name[0] + "_type"}, + outputs=[inputs_name[0] + "_type"]) + graph.add_layer( + "prim.eq", + inputs={"x": inputs_name[0] + "_type"}, + outputs=[inputs_name[0] + "_cond"], + y=string("VarType.BOOL")) + graph.add_layer( + "prim.if", {'input': inputs_name[0] + "_cond"}, + outputs=[inputs_name[0] + "_if1"]) + if_layer = graph.layers[list(graph.layers.keys())[-1]] + block = PaddleGraph(if_layer, graph_type="dygraph") + block.add_layer( + "prim.type", + inputs={"input": inputs_name[1]}, + outputs=[inputs_name[1] + "_type"]) + block.add_layer( + "fluid.layers.cast", + inputs={"x": inputs_name[0]}, + outputs=[inputs_name[0]], + dtype=inputs_name[1] + "_type") + if_layer.add_block(block) + block = PaddleGraph(if_layer, graph_type="dygraph") + if_layer.add_block(block) + if_layer.inputs["input-0"] = inputs_name[0] + if_layer.inputs["input-1"] = inputs_name[1] + graph.add_layer( + "fluid.layers.expand_as", inputs=layer_inputs, outputs=layer_outputs) + graph.add_layer( + "prim.if", {'input': inputs_name[0] + "_cond"}, + outputs=[inputs_name[0] + "_if2"]) + if_layer = graph.layers[list(graph.layers.keys())[-1]] + block = PaddleGraph(if_layer, graph_type="dygraph") + block.add_layer( + "fluid.layers.cast", + inputs={"x": layer_outputs[0]}, + outputs=layer_outputs, + dtype=string("bool")) + if_layer.add_block(block) + block = PaddleGraph(if_layer, graph_type="dygraph") + if_layer.add_block(block) + if_layer.inputs["input-0"] = layer_outputs[0] + return current_inputs, current_outputs + + +def aten_eye(mapper, graph, node): + """ 构造批次二维矩阵的PaddleLayer。 + + TorchScript示例: + %68 : Tensor = aten::eye(%49, %_50, %_51, %15, %9, %67, %7) + 参数含义: + %68 (Tensor): 输出,构造的矩阵。 + %49 (int): 行数。 + %_50 (int): 列数,非必须。 + %_51 (Tensor): 非必须。 + %9 (int): layout。 + %67 (str): 设备。 + %7 (bool): 是否计算梯度。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%49 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["num_rows"] = inputs_name[0] + if len(inputs_name) > 5: + # 处理输入1,即%_50 + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + layer_inputs["num_columns"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + # 处理倒数第4个输入,即%15 + layer_attrs["dtype"] = dtype_dict[mapper.attrs[inputs_name[-4]]] + + graph.add_layer( + "fluid.layers.eye", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_flatten(mapper, graph, node): + """ 构造flatten的PaddleLayer。 + + TorchScript示例: + %x.8 : Tensor = aten::flatten(%x, %4, %2) + 参数含义: + %x.8 (Tensor): flatten后结果。 + %x (Tensor): 输入Tensor。 + %4 (int): flatten的开始维度。 + %2 (int): flatten的结束维度。 + + 注意:目前flatten只支持第一维的flatten + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入1,即%4 + graph.add_layer( + "prim.assert", + inputs={}, + outputs=[inputs_name[1] + "_assert"], + type='eq', + key=mapper.attrs[inputs_name[1]], + value=1) + # 处理输入2,即%2 + graph.add_layer( + "prim.assert", + inputs={}, + outputs=[inputs_name[2] + "_assert"], + type='eq', + key=mapper.attrs[inputs_name[2]], + value=-1) + # 处理输入0,即%x + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "fluid.layers.flatten", + inputs=layer_inputs, + outputs=layer_outputs, + axis=1) + return current_inputs, current_outputs + + +def aten_Float(mapper, graph, node): + """ 构造取浮点型的PaddleLayer。 + + TorchScript示例: + %3992 : float = aten::Float(%3991) + 参数含义: + %3992 (int): 向上取整后的整数。 + %3991 (float): 需要取整的浮点数。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%3991 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.float", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_floor(mapper, graph, node): + """ 构造向上取整的PaddleLayer。 + + TorchScript示例: + %3978 : int = aten::floor(%scale.18) + 参数含义: + %3978 (int): 向上取整后的整数。 + %scale.18 (float): 需要取整的浮点数。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%scale.18 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.floor", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_floordiv(mapper, graph, node): + """ 构造向上取整除法的PaddleLayer。 + + TorchScript示例: + %channels_per_group.2 : int = aten::floordiv(%num_channels.2, %3690) + 参数含义: + %channels_per_group.2 (-): 除后的结果。 + %num_channels.2 (-): 被除数。 + %2 (int): 除数。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%124 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 处理输入1,即%123 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + layer_inputs["y"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.floordiv", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_floor_divide(mapper, graph, node): + """ 构造向上取整除法的PaddleLayer。 + + TorchScript示例: + %channels_per_group.2 : int = aten::floor_divide(%num_channels.2, %3690) + 参数含义: + %channels_per_group.2 (-): 除后的结果。 + %num_channels.2 (-): 被除数。 + %2 (int): 除数。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%124 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 处理输入1,即%123 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + layer_inputs["y"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.floordiv", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_full_like(mapper, graph, node): + """ 构造创建一个与输入具有相同的形状并且数据类型固定的Tensor的PaddleLayer。 + + TorchScript示例: + %159 : Tensor = aten::full_like(%val_if_large.3, %51, %50, %62, %53, %65, %66) + 参数含义: + %159 (Tensor): 输出,全为固定值的Tensor。 + %val_if_large.3 (Tensor): 类似形状的Tensor。 + %51 (int/float/bool): 填充值。 + %50 (int): dtype。 + %62 (int): layout。 + %53 (int): device。 + %65 (bool): 是否计算梯度。 + %66 (int): 内存形式。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%val_if_large.3 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%51 + if inputs_name[1] in mapper.attrs: + layer_attrs["fill_value"] = mapper.attrs[inputs_name[1]] + else: + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + layer_inputs["fill_value"] = inputs_name[1] + current_inputs.append(inputs_name[1]) + # 处理输入2,即%50,代表dtype + layer_attrs["dtype"] = dtype_dict[mapper.attrs[inputs_name[2]]] + + graph.add_layer( + "paddle.full_like", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_gelu(mapper, graph, node): + """ 构造GeLU激活的PaddleLayer。 + + TorchScript示例: + %result.3 : Tensor = aten::gelu(%input.5) + 参数含义: + %result.3 (Tensor): 输出,GELU后的结果。 + %result.5 (Tensor): 需要GELU的Tensor。 + + 注意: inplace这个参数在paddle中未实现 + """ + if "gelu" in mapper.dygraph_name_id: + mapper.dygraph_name_id["gelu"] += 1 + else: + mapper.dygraph_name_id["gelu"] = 0 + gelu_name = "gelu" + str(mapper.dygraph_name_id["gelu"]) + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [gelu_name, output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%result.5 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "paddle.nn.GELU", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten___getitem__(mapper, graph, node): + """ 构造获取list中元素的PaddleLayer。 + + TorchScript示例: + %v.1 : int = aten::__getitem__(%72, %88) + 参数含义: + %v.1 (-): 输出,list中的元素。 + %72 (list): 需要获取元素的list。 + %88 (int): 索引。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%72 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["list"] = inputs_name[0] + # 处理输入1,即%88 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + layer_inputs["index"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.getitem", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_gt(mapper, graph, node): + """ 构造对比大小的PaddleLayer。 + + TorchScript示例: + %83 : bool = aten::gt(%82, %78) + 参数含义: + %83 (bool): 输出,第一个元素是否大于第二个元素。 + %82 (-): 需对比的输入1。 + %78 (-): 需对比的输入2。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%82 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 处理输入1,即%78 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + layer_inputs["y"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.gt", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_hardtanh_(mapper, graph, node): + """ 构造hardtanh激活的PaddleLayer。 + + TorchScript示例: + %result.9 : Tensor = aten::hardtanh_(%input.20, %67, %66) + 参数含义: + %result.9 (Tensor): 输出,hardtanh激活后的Tensor。 + %input.20 (Tensor): 需要hardtanh激活的Tensor。 + %67 (float): hardtanh激活的最小阈值。 + %66 (float): hardtanh激活的最大阈值。 + """ + if "tanh" in mapper.dygraph_name_id: + mapper.dygraph_name_id["tanh"] += 1 + else: + mapper.dygraph_name_id["tanh"] = 0 + tanh_name = "tanh" + str(mapper.dygraph_name_id["tanh"]) + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [tanh_name, output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%input.20 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%67 + layer_attrs["min"] = mapper.attrs[inputs_name[1]] + # 处理输入2,即%66 + layer_attrs["max"] = mapper.attrs[inputs_name[2]] + + graph.add_layer( + 'paddle.nn.Hardtanh', + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_index_select(mapper, graph, node): + """ 构造对dict加入元素的PaddleLayer。 + + TorchScript示例: + %bd.3 : Tensor = aten::index_select(%x2.3, %320, %371) + 参数含义: + %bd.3 (Tensor): 输出,选择后的Tensor。 + %x2.3 (Tensor): 需要选择的Tensor。 + %320 (int): 维度。 + %371 (Tensor): 选择的索引。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%x2.3 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 处理输入1,即%320 + if inputs_name[1] in mapper.attrs: + layer_attrs["axis"] = mapper.attrs[inputs_name[1]] + else: + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + layer_inputs["axis"] = inputs_name[1] + current_inputs.append(inputs_name[1]) + # 处理输入2,即%371 + mapper._check_input(graph, inputs_node[2], inputs_name[2], current_outputs) + layer_inputs["index"] = inputs_name[2] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "prim.index_select", + inputs=layer_inputs, + outputs=current_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_Int(mapper, graph, node): + """ 构造强转为int的PaddleLayer。 + + TorchScript示例: + %1739 : int = aten::Int(%1738) + 参数含义: + %1739 (int): 输出,int型数据。 + %1738 (-): 需要强转的数据。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%1738 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.int", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten___is__(mapper, graph, node): + """ 构造is not的PaddleLayer。 + + TorchScript示例: + %3949 : bool = aten::__isnot__(%size.122, %3931) + 参数含义: + %3949 (bool): 输出,第一个元素是否不是第二个元素。 + %size.122 (-): 需对比的输入1。 + %3931 (-): 需对比的输入2。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%size.122 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 处理输入1,即%3931 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + layer_inputs["y"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.is", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten___isnot__(mapper, graph, node): + """ 构造is not的PaddleLayer。 + + TorchScript示例: + %3949 : bool = aten::__isnot__(%size.122, %3931) + 参数含义: + %3949 (bool): 输出,第一个元素是否不是第二个元素。 + %size.122 (-): 需对比的输入1。 + %3931 (-): 需对比的输入2。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%size.122 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 处理输入1,即%3931 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + layer_inputs["y"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.isnot", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_layer_norm(mapper, graph, node): + """ 构造层归一化的PaddleLayer。 + + TorchScript示例: + %input0.4 : Tensor = aten::layer_norm(%input.6, %1181, %174, %173, %70, %71) + 参数含义: + %input0.4 (Tensor): 输出,层归一化后的结果。 + %input.6 (Tensor): 需要进行层归一化的特征层。 + %1181 (list/int/tuple): 需规范化的shape。 + %174 (Tensor): weights。 + %173 (Tensor): bias。 + %70 (float): 指明在计算过程中是否添加较小的值到方差中以防止除零。 + %71 (bool): 是否启用cudnn。 + """ + if "layernorm" in mapper.dygraph_name_id: + mapper.dygraph_name_id["layernorm"] += 1 + else: + mapper.dygraph_name_id["layernorm"] = 0 + layernorm_name = "layernorm" + str(mapper.dygraph_name_id["layernorm"]) + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [layernorm_name, output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%input.6 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入、输出的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%1181 + layer_attrs["normalized_shape"] = mapper.attrs[inputs_name[1]] + # 处理输入2,即%174 + weights = mapper.pytorch_params[inputs_name[2]] + mapper.paddle_params[layernorm_name + ".weight"] = weights + # 处理输入3,即%173 + if inputs_name[3] in mapper.pytorch_params: + bias = mapper.pytorch_params[inputs_name[3]] + if bias is not None: + mapper.paddle_params[layernorm_name + ".bias"] = bias + else: + mapper.paddle_params[layernorm_name + ".bias"] = False + # 处理输入4,即%70 + layer_attrs["epsilon"] = mapper.attrs[inputs_name[4]] + + graph.add_layer( + "paddle.nn.LayerNorm", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_le(mapper, graph, node): + """ 构造对比大小的PaddleLayer。 + + TorchScript示例: + %80 : bool = aten::le(%78, %79) + 参数含义: + %80 (bool): 输出,第一个元素是否小于等于第二个元素。 + %78 (-): 需对比的输入1。 + %79 (-): 需对比的输入2。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%78 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 处理输入1,即%79 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + layer_inputs["y"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.le", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_leaky_relu_(mapper, graph, node): + """ 构造leaky relu激活的PaddleLayer。 + + TorchScript示例: + %input.117 : Tensor = aten::leaky_relu_(%input.114, %1570) + 参数含义: + %input.117 (Tensor): 输出,leaky relu后的结果。 + %input.114 (Tensor): 需要leaky relu的Tensor。 + %1570 (float): 输入中的元素小于0时的斜率。 + """ + if "leaky_relu" in mapper.dygraph_name_id: + mapper.dygraph_name_id["leaky_relu"] += 1 + else: + mapper.dygraph_name_id["leaky_relu"] = 0 + leaky_relu_name = "leaky_relu" + str(mapper.dygraph_name_id["leaky_relu"]) + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [leaky_relu_name, output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%result.5 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入、输出的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%1570 + layer_attrs["negative_slope"] = mapper.attrs[inputs_name[1]] + + graph.add_layer( + "paddle.nn.LeakyReLU", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_len(mapper, graph, node): + """ 构造获取list长度的PaddleLayer。 + + TorchScript示例: + %85 : int = aten::len(%83) + 参数含义: + %85 (int): 输出,list的长度。 + %72 (list): 需要获取长度的list。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%72 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.len", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_log(mapper, graph, node): + """ 构构造log的PaddleLayer。 + + TorchScript示例: + %787 : Tensor = aten::log(%786) + 参数含义: + %787 (Tensor): 输出,取log的Tensor。 + %786 (Tensor): 需要获取log的Tensor。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%786 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "fluid.layers.log", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_lt(mapper, graph, node): + """ 构造对比大小的PaddleLayer。 + + TorchScript示例: + %80 : bool = aten::lt(%78, %79) + 参数含义: + %80 (bool): 输出,第一个元素是否小于第二个元素。 + %78 (-): 需对比的输入1。 + %79 (-): 需对比的输入2。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%78 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 处理输入1,即%79 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + layer_inputs["y"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.lt", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_masked_fill_(mapper, graph, node): + """ 构造填充mask的PaddleLayer。 + + TorchScript示例: + %input.4 : Tensor = aten::masked_fill_(%scores.2, %mask.2, %46) + 参数含义: + %input.4 (Tensor): 输出,填充后的结果。 + %scores.2 (Tensor): 需要填充的Tensor。 + %mask.2 (Tensor): bool型的Tensor,哪些位置需要填充。 + %46 (-): 填充的值。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输入的list + current_inputs = [] + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%input.4 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + current_inputs.append(inputs_name[0]) + graph.add_layer( + "prim.type", + inputs={"input": inputs_name[0]}, + outputs=[inputs_name[0] + "_type"]) + # 处理输入1,即%scores.2 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + current_inputs.append(inputs_name[1]) + graph.add_layer( + "paddle.logical_not", + inputs={"x": inputs_name[1]}, + outputs=[inputs_name[1] + "_not"]) + graph.add_layer( + "fluid.layers.cast", + inputs={"x": inputs_name[1]}, + outputs=[inputs_name[1] + "_mask"], + dtype=inputs_name[0] + "_type") + graph.add_layer( + "fluid.layers.cast", + inputs={"x": inputs_name[1] + "_not"}, + outputs=[inputs_name[1] + "_not_mask"], + dtype=inputs_name[0] + "_type") + graph.add_layer( + "paddle.multiply", + inputs={"x": inputs_name[0], + "y": inputs_name[1] + "_not_mask"}, + outputs=[inputs_name[0] + "_not_mask"]) + # 处理输入2,即%46 + mapper._check_input(graph, inputs_node[2], inputs_name[2], current_outputs) + graph.add_layer( + "prim.eq", + inputs={"x": inputs_name[2]}, + outputs=[inputs_name[2] + "_cond1"], + y="-float('inf')") + graph.add_layer( + "prim.eq", + inputs={"x": inputs_name[2]}, + outputs=[inputs_name[2] + "_cond2"], + y="float('inf')") + graph.add_layer( + "prim.or", + inputs={ + "x": inputs_name[2] + "_cond1", + "y": inputs_name[2] + "_cond2" + }, + outputs=[inputs_name[2] + "_cond"]) + graph.add_layer( + "prim.if", {'input': inputs_name[2] + "_cond"}, + outputs=[inputs_name[2] + "_if"]) + if_layer = graph.layers[list(graph.layers.keys())[-1]] + block = PaddleGraph(if_layer, graph_type="dygraph") + block.add_layer( + "prim.equal", + inputs={"input": inputs_name[1] + "_mask"}, + outputs=[inputs_name[2] + "_1"]) + if_layer.add_block(block) + block = PaddleGraph(if_layer, graph_type="dygraph") + block.add_layer( + "prim.mul", + inputs={"x": inputs_name[1] + "_mask", + "y": inputs_name[2]}, + outputs=[inputs_name[2] + "_1"]) + if_layer.add_block(block) + if_layer.inputs["input-0"] = inputs_name[1] + "_mask" + if_layer.inputs["input-1"] = inputs_name[2] + if_layer.outputs.append(inputs_name[2] + "_1") + graph.add_layer( + "fluid.layers.elementwise_add", + inputs={"x": inputs_name[2] + "_1", + "y": inputs_name[0] + "_not_mask"}, + outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_masked_fill(mapper, graph, node): + """ 构造填充mask的PaddleLayer。 + + TorchScript示例: + %input.4 : Tensor = aten::masked_fill(%scores.2, %mask.2, %46) + 参数含义: + %input.4 (Tensor): 输出,填充后的结果。 + %scores.2 (Tensor): 需要填充的Tensor。 + %mask.2 (Tensor): bool型的Tensor,哪些位置需要填充。 + %46 (-): 填充的值。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输入的list + current_inputs = [] + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%input.4 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + current_inputs.append(inputs_name[0]) + graph.add_layer( + "prim.type", + inputs={"input": inputs_name[0]}, + outputs=[inputs_name[0] + "_type"]) + # 处理输入1,即%scores.2 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + current_inputs.append(inputs_name[1]) + graph.add_layer( + "paddle.logical_not", + inputs={"x": inputs_name[1]}, + outputs=[inputs_name[1] + "_not"]) + graph.add_layer( + "fluid.layers.cast", + inputs={"x": inputs_name[1]}, + outputs=[inputs_name[1] + "_mask"], + dtype=inputs_name[0] + "_type") + graph.add_layer( + "fluid.layers.cast", + inputs={"x": inputs_name[1] + "_not"}, + outputs=[inputs_name[1] + "_not_mask"], + dtype=inputs_name[0] + "_type") + graph.add_layer( + "paddle.multiply", + inputs={"x": inputs_name[0], + "y": inputs_name[1] + "_not_mask"}, + outputs=[inputs_name[0] + "_not_mask"]) + # 处理输入2,即%46 + mapper._check_input(graph, inputs_node[2], inputs_name[2], current_outputs) + graph.add_layer( + "prim.eq", + inputs={"x": inputs_name[2]}, + outputs=[inputs_name[2] + "_cond1"], + y="-float('inf')") + graph.add_layer( + "prim.eq", + inputs={"x": inputs_name[2]}, + outputs=[inputs_name[2] + "_cond2"], + y="float('inf')") + graph.add_layer( + "prim.or", + inputs={ + "x": inputs_name[2] + "_cond1", + "y": inputs_name[2] + "_cond2" + }, + outputs=[inputs_name[2] + "_cond"]) + graph.add_layer( + "prim.if", {'input': inputs_name[2] + "_cond"}, + outputs=[inputs_name[2] + "_if"]) + if_layer = graph.layers[list(graph.layers.keys())[-1]] + block = PaddleGraph(if_layer, graph_type="dygraph") + block.add_layer( + "prim.equal", + inputs={"input": inputs_name[1] + "_mask"}, + outputs=[inputs_name[2] + "_1"]) + if_layer.add_block(block) + block = PaddleGraph(if_layer, graph_type="dygraph") + block.add_layer( + "prim.mul", + inputs={"x": inputs_name[1] + "_mask", + "y": inputs_name[2]}, + outputs=[inputs_name[2] + "_1"]) + if_layer.add_block(block) + if_layer.inputs["input-0"] = inputs_name[1] + "_mask" + if_layer.inputs["input-1"] = inputs_name[2] + if_layer.outputs.append(inputs_name[2] + "_1") + graph.add_layer( + "fluid.layers.elementwise_add", + inputs={"x": inputs_name[2] + "_1", + "y": inputs_name[0] + "_not_mask"}, + outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_max(mapper, graph, node): + """ 构造获取最大值的PaddleLayer。 + + TorchScript示例: + %val_if_large0.3 : Tensor = aten::max(%val_if_large.3, %159) + 参数含义: + %val_if_large0.3 (Tensor): 输出,对比后的结果。 + %val_if_large.3 (Tensor): 输入,需要对比的Tensor1。 + %159 (Tensor): 输入,需要对比的Tensor2。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + input_type = list(node.inputs())[1].type() + if str(input_type) == "Tensor": + # 处理输入0,即%val_if_large.3 + mapper._check_input(graph, inputs_node[0], inputs_name[0], + current_outputs) + layer_inputs["x"] = inputs_name[0] + # 处理输入1,即%159 + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + layer_inputs["y"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + graph.add_layer( + "paddle.maximum", inputs=layer_inputs, outputs=layer_outputs) + else: + pass + return current_inputs, current_outputs + + +def aten_max_pool2d(mapper, graph, node): + """ 构造最大池化的PaddleLayer。 + + TorchScript示例: + %input.8 : Tensor = aten::max_pool2d(%result.11, %20, %23, %21, %22, %19) + 参数含义: + %input.8 (Tensor): 输出,池化后的结果。 + %result.11 (Tensor): 需要池化的Tensor。 + %20 (list): 池化kernel的大小。 + %23 (list): 步长大小。 + %21 (list): 填充大小。 + %22 (list): 膨胀系数大小。 + %19 (bool): 是否用ceil函数计算输出高度和宽度。 + """ + if "pool" in mapper.dygraph_name_id: + mapper.dygraph_name_id["pool"] += 1 + else: + mapper.dygraph_name_id["pool"] = 0 + pool_name = "pool" + str(mapper.dygraph_name_id["pool"]) + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [pool_name, output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%result.11 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%20 + layer_attrs["pool_size"] = mapper.attrs[inputs_name[1]] + # 处理输入2,即%23 + layer_attrs["pool_stride"] = mapper.attrs[inputs_name[2]] + # 处理输入3,即%21 + layer_attrs["pool_padding"] = mapper.attrs[inputs_name[3]] + # 处理输入4,即%22 + graph.add_layer( + "prim.assert", + inputs={}, + outputs=[inputs_name[4] + "_assert"], + type="eq", + key=mapper.attrs[inputs_name[4]], + value=[1, [1, 1]]) + # 处理输入5,即%19 + layer_attrs["ceil_mode"] = mapper.attrs[inputs_name[5]] + layer_attrs["pool_type"] = string("max") + + graph.add_layer( + "paddle.nn.Pool2D", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_matmul(mapper, graph, node): + """ 构造矩阵相乘的PaddleLayer。 + + TorchScript示例: + %output.2 : Tensor = aten::matmul(%101, %111) + 参数含义: + %output.2 (Tensor): 输出,相乘后的结果。 + %101 (Tensor): 矩阵1。 + %102 (Tensor): 矩阵2。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%101 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 处理输入1,即%102 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + layer_inputs["y"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("paddle.matmul", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_min(mapper, graph, node): + """ 构造获取最小值的PaddleLayer。 + + TorchScript示例: + %val_if_large0.3 : Tensor = aten::min(%val_if_large.3, %159) + 参数含义: + %val_if_large0.3 (Tensor): 输出,对比后的结果。 + %val_if_large.3 (Tensor): 输入,需要对比的Tensor1。 + %159 (Tensor): 输入,需要对比的Tensor2。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + input_type = list(node.inputs())[1].type() + if str(input_type) == "Tensor": + # 处理输入0,即%val_if_large.3 + mapper._check_input(graph, inputs_node[0], inputs_name[0], + current_outputs) + layer_inputs["x"] = inputs_name[0] + # 处理输入1,即%159 + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + layer_inputs["y"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + graph.add_layer( + "paddle.minimum", inputs=layer_inputs, outputs=layer_outputs) + else: + pass + return current_inputs, current_outputs + + +def aten_mean(mapper, graph, node): + """ 构造求均值的PaddleLayer。 + + TorchScript示例: + %x.28 : Tensor = aten::mean(%result.1, %4967, %3, %2) + 参数含义: + %x.28 (Tensor): 输出,求均值后的结果。 + %result.1 (Tensor): 输入,需要求均值的Tensor。 + %4967 (int/list): 求平均值运算的维度。 + %3 (bool): 是否在输出Tensor中保留减小的维度。 + %2 (Tensor): 结果Tensor。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%result.1 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%4967 + if inputs_name[1] in mapper.attrs: + layer_attrs["dim"] = mapper.attrs[inputs_name[1]] + else: + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + layer_inputs["dim"] = inputs_name[1] + current_inputs.append(inputs_name[1]) + # 处理输入2,即%3 + if inputs_name[1] in mapper.attrs: + layer_attrs["keep_dim"] = mapper.attrs[inputs_name[2]] + else: + mapper._check_input(graph, inputs_node[2], inputs_name[2], + current_outputs) + layer_inputs["keep_dim"] = inputs_name[2] + current_inputs.append(inputs_name[2]) + + graph.add_layer( + "fluid.layers.reduce_mean", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_mul(mapper, graph, node): + """ 构造数值相乘的PaddleLayer。 + + TorchScript示例: + %size_prods.39 : int = aten::mul(%size_prods.38, %114) + 参数含义: + %size_prods.39 (Tensor): 输出,相乘后的结果。 + %size_prods.38 (-): 数值1。 + %114 (-): 数值2。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%size_prods.38 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 处理输入1,即%114 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + layer_inputs["y"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + current_outputs = layer_outputs + + graph.add_layer("prim.mul", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_mul_(mapper, graph, node): + """ 构造数值相乘的PaddleLayer。 + + TorchScript示例: + %size_prods.39 : int = aten::mul_(%size_prods.38, %114) + 参数含义: + %size_prods.39 (Tensor): 输出,相乘后的结果。 + %size_prods.38 (-): 数值1。 + %114 (-): 数值2。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%size_prods.38 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 处理输入1,即%114 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + layer_inputs["y"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + current_outputs = layer_outputs + + graph.add_layer("prim.mul", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_ne(mapper, graph, node): + """ 构造判断数值是否不相等的PaddleLayer。 + + TorchScript示例: + %134 : bool = aten::ne(%133, %132) + 参数含义: + %134 (bool): 对比后结果。 + %133 (-): 需对比的输入1。 + %132 (-): 需对比的输入2。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%124 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 处理输入1,即%123 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + layer_inputs["y"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.ne", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_neg(mapper, graph, node): + """ 构造对数值取负的PaddleLayer。 + + TorchScript示例: + %909 : int = aten::neg(%908) + 参数含义: + %909 (int): 取负后结果。 + %908 (int): 需取负的输入。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%124 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.neg", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten___not__(mapper, graph, node): + """ 构造对bool型取负的PaddleLayer。 + + TorchScript示例: + %4498 : bool = aten::__not__(%aux_defined.2) + 参数含义: + %4498 (bool): 取负后结果。 + %aux_defined.2 (bool): 需取负的输入。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%124 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.not", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_ones(mapper, graph, node): + """ 构造创建固定形状、数据类型且值全为0的Tensor的PaddleLayer。 + + TorchScript示例: + %input.49 : Tensor = aten::ones(%23, %8, %6, %24, %5) + 参数含义: + %input.49 (Tensor): 输出,全0的Tensor。 + %23 (list): 形状。 + %8 (int): 类型dtype。 + %6 (int): layout。 + %4995 (Device): 设备。 + %4995 (bool): 是否计算梯度。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + current_inputs = [] + # 处理输入0,即%23,代表end + if inputs_name[0] in mapper.attrs: + layer_attrs["shape"] = mapper.attrs[inputs_name[0]] + else: + mapper._check_input(graph, inputs_node[0], inputs_name[0], + current_outputs) + layer_inputs["shape"] = inputs_name[0] + current_inputs.append(inputs_name[0]) + # 处理输入1,即%8,代表dtype + layer_attrs["dtype"] = dtype_dict[mapper.attrs[inputs_name[1]]] + + graph.add_layer( + "paddle.ones", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_permute(mapper, graph, node): + """ 构造对bool型取负的PaddleLayer。 + + TorchScript示例: + %2385 : Tensor = aten::permute(%cls_confs0.2, %2384) + 参数含义: + %2385 (Tensor): 重排后的结果。 + %cls_confs0.2 (Tensor): 需要重排的Tensor。 + %2348 (list): 依照此参数进行重排。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%cls_confs0.2 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%2348 + if inputs_name[1] in mapper.attrs: + layer_attrs["perm"] = mapper.attrs[inputs_name[1]] + else: + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + layer_inputs["perm"] = inputs_name[1] + current_inputs.append(inputs_name[1]) + + graph.add_layer( + "fluid.layers.transpose", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_pow(mapper, graph, node): + """ 构造指数激活的PaddleLayer。 + + TorchScript示例: + %x.6 : Tensor = aten::pow(%4700, %4703) + 参数含义: + %x.6 (Tensor): 输出,指数激活后的Tensor。 + %4700 (Tensor): 需要指数激活的Tensor。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%4700 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入、输出的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%4703 + if inputs_name[1] in mapper.attrs: + layer_attrs["factor"] = mapper.attrs[inputs_name[1]] + else: + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + layer_inputs["factor"] = inputs_name[1] + current_inputs.append(inputs_name[1]) + + graph.add_layer( + "fluid.layers.pow", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_relu(mapper, graph, node): + """ 构造ReLU激活的PaddleLayer。 + + TorchScript示例: + %result.3 : Tensor = aten::relu(%input.5) + 参数含义: + %result.3 (Tensor): 输出,ReLU后的结果。 + %result.5 (Tensor): 需要ReLU的Tensor。 + + 注意: inplace这个参数在paddle中未实现 + """ + if "relu" in mapper.dygraph_name_id: + mapper.dygraph_name_id["relu"] += 1 + else: + mapper.dygraph_name_id["relu"] = 0 + relu_name = "relu" + str(mapper.dygraph_name_id["relu"]) + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [relu_name, output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%result.5 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "paddle.nn.ReLU", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_relu_(mapper, graph, node): + """ 构造ReLU激活的PaddleLayer。 + + TorchScript示例: + %result.3 : Tensor = aten::relu_(%input.5) + 参数含义: + %result.3 (Tensor): 输出,ReLU后的结果。 + %result.5 (Tensor): 需要ReLU的Tensor。 + + 注意: inplace这个参数在paddle中未实现 + """ + if "relu" in mapper.dygraph_name_id: + mapper.dygraph_name_id["relu"] += 1 + else: + mapper.dygraph_name_id["relu"] = 0 + relu_name = "relu" + str(mapper.dygraph_name_id["relu"]) + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [relu_name, output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%result.5 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "paddle.nn.ReLU", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_relu6(mapper, graph, node): + """ 构造ReLU6激活的PaddleLayer。 + + TorchScript示例: + %result.3 : Tensor = aten::relu6(%input.5) + 参数含义: + %result.3 (Tensor): 输出,ReLU6后的结果。 + %result.5 (Tensor): 需要ReLU6的Tensor。 + + 注意: inplace这个参数在paddle中未实现 + """ + if "relu6" in mapper.dygraph_name_id: + mapper.dygraph_name_id["relu6"] += 1 + else: + mapper.dygraph_name_id["relu6"] = 0 + relu6_name = "relu6" + str(mapper.dygraph_name_id["relu6"]) + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [relu6_name, output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%result.5 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "paddle.nn.ReLU6", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_repeat(mapper, graph, node): + """ 构造根据参数对输入各维度进行复制的PaddleLayer。 + + TorchScript示例: + 701 : Tensor = aten::repeat(%699, %700) + 参数含义: + %701 (Tensor): 输出,复制后的Tensor。 + %699 (Tensor): 需要复制的Tensor。 + %700 (list): 指定每个维度复制的次数。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%699 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入、输出的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%700 + if inputs_name[1] in mapper.attrs: + layer_attrs["repeat_times"] = mapper.attrs[inputs_name[1]] + else: + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + layer_inputs["repeat_times"] = inputs_name[1] + current_inputs.append(inputs_name[1]) + + graph.add_layer( + "paddle.tile", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_reshape(mapper, graph, node): + """ 构造调整大小的PaddleLayer。 + + TorchScript示例: + %x.6 : Tensor = aten::reshape(%4700, %4703) + 参数含义: + %x.6 (Tensor): 输出,reshape后的Tensor。 + %4700 (Tensor): 需要reshape的Tensor。 + %4703 (list): 形状大小组成的list。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%4700 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入、输出的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%4703 + if inputs_name[1] in mapper.attrs: + layer_attrs["shape"] = mapper.attrs[inputs_name[1]] + else: + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + layer_inputs["shape"] = inputs_name[1] + current_inputs.append(inputs_name[1]) + + graph.add_layer( + "prim.type", + inputs={"input": inputs_name[0]}, + outputs=[inputs_name[0] + "_type"]) + graph.add_layer( + "prim.str", + inputs={"input": inputs_name[0] + "_type"}, + outputs=[inputs_name[0] + "_type"]) + graph.add_layer( + "prim.eq", + inputs={"x": inputs_name[0] + "_type"}, + outputs=[inputs_name[0] + "_cond"], + y=string("VarType.BOOL")) + graph.add_layer( + "prim.if", {'input': inputs_name[0] + "_cond"}, + outputs=[inputs_name[0] + "_if1"]) + if_layer = graph.layers[list(graph.layers.keys())[-1]] + block = PaddleGraph(if_layer, graph_type="dygraph") + block.add_layer( + "fluid.layers.cast", + inputs={"x": inputs_name[0]}, + outputs=[inputs_name[0]], + dtype=string("int32")) + if_layer.add_block(block) + block = PaddleGraph(if_layer, graph_type="dygraph") + if_layer.add_block(block) + if_layer.inputs["input-0"] = inputs_name[0] + graph.add_layer( + "fluid.layers.reshape", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + graph.add_layer( + "prim.if", {'input': inputs_name[0] + "_cond"}, + outputs=[inputs_name[0] + "_if2"]) + if_layer = graph.layers[list(graph.layers.keys())[-1]] + block = PaddleGraph(if_layer, graph_type="dygraph") + block.add_layer( + "fluid.layers.cast", + inputs={"x": layer_outputs[0]}, + outputs=layer_outputs, + dtype=string("bool")) + if_layer.add_block(block) + block = PaddleGraph(if_layer, graph_type="dygraph") + if_layer.add_block(block) + if_layer.inputs["input-0"] = layer_outputs[0] + return current_inputs, current_outputs + + +def aten_rsub(mapper, graph, node): + """ 构造数值相减的PaddleLayer,计算公式为:out = y - alpha * x。 + + TorchScript示例: + %31 : Tensor = aten::rsub(%30, %13, %7) + 参数含义: + %31 (Tensor): 相减结果。 + %30 (Tensor): 输入Tensor x。 + %13 (int/float): 输入数值 y。 + %7 (int/float): alpha。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%30 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 处理输入1,即%13 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + layer_inputs["y"] = inputs_name[1] + # 处理输入2,即%7 + mapper._check_input(graph, inputs_node[2], inputs_name[2], current_outputs) + layer_inputs["alpha"] = inputs_name[2] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.rsub", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_ScalarImplicit(mapper, graph, node): + """ 构造获取scalar的PaddleLayer。 + + TorchScript示例: + %89 : Scalar = aten::ScalarImplicit(%end.1) + 参数含义: + %89 (Scalar): 输出,得到的Scalar。 + %end.1 (-): 组要转换的数据。 + + 【注意】由于Paddle无Scalar,所以最后转换为Tensor。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%end.1 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + input_type = list(node.inputs())[0].type() + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + if str(input_type) == "Tensor": + graph.add_layer( + "prim.equal", inputs=layer_inputs, outputs=layer_outputs) + else: + raise Exception( + "The input type {} of aten::ScalarImplicit is not implemented yet!" + ).format(input_type) + return current_inputs, current_outputs + + +def aten_select(mapper, graph, node): + """ 构造选取特定维度Variable的PaddleLayer。 + + TorchScript示例: + %19 : Tensor = aten::select(%18, %8, %7) + 参数含义: + %19 (Tensor): 输出,选取的Tensor。 + %18 (Tensor): 需要选取的Tensor。 + %8 (int): select的维度。 + %7 (int): select的第n个向量。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%18 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 处理输入1,即%8 + layer_attrs["dim"] = mapper.attrs[inputs_name[1]] + # 处理输入2,即%75 + mapper._check_input(graph, inputs_node[2], inputs_name[2], current_outputs) + layer_inputs["index"] = inputs_name[2] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "prim.select", + inputs=layer_inputs, + outputs=current_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten__set_item(mapper, graph, node): + """ 构造对dict加入元素的PaddleLayer。 + + TorchScript示例: + = aten::_set_item(%features.1, %out_name.1, %x.3) + 参数含义: + %features.1 (list): dict。 + %out_name.1 (-): dict的key。 + %x.3 (-): dict的value。 + """ + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [] + # 处理输入0,即%features.1 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["dict"] = inputs_name[0] + # 处理输入1,即%out_name.1 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + layer_inputs["key"] = inputs_name[1] + # 处理输入2,即%x.3 + mapper._check_input(graph, inputs_node[2], inputs_name[2], current_outputs) + layer_inputs["value"] = inputs_name[2] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.set_item", inputs=layer_inputs, outputs=[]) + return current_inputs, current_outputs + + +def aten_sigmoid(mapper, graph, node): + """ 构造sigmoid激活的PaddleLayer。 + + TorchScript示例: + %55 : Tensor = aten::sigmoid(%54) + 参数含义: + %55 (Tensor): 输出,sigmoid后的结果。 + %54 (Tensor): 需要tanh的Tensor。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%54 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入、输出的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "fluid.layers.sigmoid", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_sin(mapper, graph, node): + """ 构造数学计算sin的PaddleLayer。 + + TorchScript示例: + %94 : Tensor = aten::sin(%sinusoid_inp.1) + 参数含义: + %94 (Tensor): 输出,sin之后的结果。 + %sinusoid_inp.1 (Tensor): 需要进行shape的Tensor。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%sinusoid_inp.1 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入、输出的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("paddle.sin", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_size(mapper, graph, node): + """ 构造获取shape的PaddleLayer。 + + TorchScript示例: + %73 : int[] = aten::size(%x.12, %10) + 参数含义: + %73 (list): 输出,shape的list。 + %x.12 (Tensor): 需要获取shape的Tensor。 + %10 (int): 非必须,代表维度。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%x.12 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + if len(inputs_name) > 1: + # 处理输入1,即%12 + if inputs_name[1] in mapper.attrs: + layer_attrs["dim"] = mapper.attrs[inputs_name[1]] + else: + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + layer_inputs["dim"] = inputs_name[1] + current_inputs.append(inputs_name[1]) + graph.add_layer( + "prim.shape_dim", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + graph.add_layer( + "fluid.layers.shape", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_slice(mapper, graph, node): + """ 构造切分list或Variable的PaddleLayer。 + + TorchScript示例: + %83 : int[] = aten::slice(%73, %_81, %82, %75, %77) + 参数含义: + %83 (list/Tensor): 输出,切分后的list。 + %73 (list/Tensor): 需要切分的list。 + %_81 (int): 切分的维度,不一定存在。 + %82 (int): 切分的开始索引。 + %75 (int): 切分的结束索引。 + %77 (int): 切分的步长。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + if len(inputs_name) == 5: + # 处理输入0,即%73 + mapper._check_input(graph, inputs_node[0], inputs_name[0], + current_outputs) + layer_inputs["input"] = inputs_name[0] + + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%_81 + if inputs_name[1] in mapper.attrs: + graph.add_layer( + "prim.list", + inputs={}, + outputs=[inputs_name[1] + "_list"], + input0=mapper.attrs[inputs_name[1]]) + else: + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + graph.add_layer( + "prim.list", + inputs={"input0": inputs_name[1]}, + outputs=[inputs_name[1] + "_list"]) + current_inputs.append(inputs_name[1]) + layer_inputs["axes"] = inputs_name[1] + "_list" + current_inputs.append(inputs_name[1] + "_list") + current_outputs.append(inputs_name[1] + "_list") + # 处理输入2,即%82 + if inputs_name[2] in mapper.attrs: + graph.add_layer( + "prim.list", + inputs={}, + outputs=[inputs_name[2] + "_list"], + input0=mapper.attrs[inputs_name[2]]) + else: + mapper._check_input(graph, inputs_node[2], inputs_name[2], + current_outputs) + graph.add_layer( + "prim.list", + inputs={"input0": inputs_name[2]}, + outputs=[inputs_name[2] + "_list"]) + current_inputs.append(inputs_name[2]) + layer_inputs["starts"] = inputs_name[2] + "_list" + current_inputs.append(inputs_name[2] + "_list") + current_outputs.append(inputs_name[2] + "_list") + # 处理输入3,即%85 + if inputs_name[3] in mapper.attrs: + graph.add_layer( + "prim.list", + inputs={}, + outputs=[inputs_name[3] + "_list"], + input0=mapper.attrs[inputs_name[3]]) + else: + mapper._check_input(graph, inputs_node[3], inputs_name[3], + current_outputs) + graph.add_layer( + "prim.list", + inputs={"input0": inputs_name[3]}, + outputs=[inputs_name[3] + "_list"]) + current_inputs.append(inputs_name[3]) + layer_inputs["ends"] = inputs_name[3] + "_list" + current_inputs.append(inputs_name[3] + "_list") + current_outputs.append(inputs_name[3] + "_list") + # 处理输入4,即%77 + if inputs_name[4] in mapper.attrs: + graph.add_layer( + "prim.list", + inputs={}, + outputs=[inputs_name[4] + "_list"], + input0=mapper.attrs[inputs_name[4]]) + else: + mapper._check_input(graph, inputs_node[4], inputs_name[4], + current_outputs) + graph.add_layer( + "prim.list", + inputs={"input0": inputs_name[4]}, + outputs=[inputs_name[4] + "_list"]) + current_inputs.append(inputs_name[4]) + layer_inputs["strides"] = inputs_name[4] + "_list" + current_inputs.append(inputs_name[4] + "_list") + current_outputs.append(inputs_name[4] + "_list") + + graph.add_layer( + "fluid.layers.strided_slice", + inputs=layer_inputs, + outputs=layer_outputs) + else: + # 处理输入0,即%73 + mapper._check_input(graph, inputs_node[0], inputs_name[0], + current_outputs) + layer_inputs["input"] = inputs_name[0] + # 处理输入1,即%82 + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + layer_inputs["start"] = inputs_name[1] + # 处理输入2,即%75 + mapper._check_input(graph, inputs_node[2], inputs_name[2], + current_outputs) + layer_inputs["end"] = inputs_name[2] + # 处理输入3,即%77 + mapper._check_input(graph, inputs_node[3], inputs_name[3], + current_outputs) + layer_inputs["step"] = inputs_name[3] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "prim.slice", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_softmax(mapper, graph, node): + """ 构造softmax激活的PaddleLayer。 + + TorchScript示例: + %input2.1 : Tensor = aten::softmax(%input.5, %80, %72) + 参数含义: + %input2.1 (Tensor): 激活后结果。 + %input.5 (Tensor): 需要激活的Tensor。 + %80 (int): 指定对输入Tensor进行运算的轴。 + %72 (str): 类型,默认为None。 + """ + if "softmax" in mapper.dygraph_name_id: + mapper.dygraph_name_id["softmax"] += 1 + else: + mapper.dygraph_name_id["softmax"] = 0 + softmax_name = "softmax" + str(mapper.dygraph_name_id["softmax"]) + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [softmax_name, output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%x.31 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + layer_attrs["axis"] = mapper.attrs[inputs_name[1]] + + graph.add_layer( + "paddle.nn.Softmax", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_softplus(mapper, graph, node): + """ 构造softplus激活的PaddleLayer。 + + TorchScript示例: + %54 : Tensor = aten::softplus(%x.31, %30, %29) + 参数含义: + %54 (Tensor): 激活后结果。 + %x.31 (Tensor): 需要激活的Tensor。 + %30 (int): beta。 + %29 (int): 阈值。 + """ + if "softplus" in mapper.dygraph_name_id: + mapper.dygraph_name_id["softplus"] += 1 + else: + mapper.dygraph_name_id["softplus"] = 0 + softplus_name = "softplus" + str(mapper.dygraph_name_id["softplus"]) + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [softplus_name, output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%x.31 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + layer_attrs["beta"] = mapper.attrs[inputs_name[1]] + layer_attrs["threshold"] = mapper.attrs[inputs_name[2]] + + graph.add_layer( + "paddle.nn.Softplus", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_sqrt(mapper, graph, node): + """ 构构造sqrt的PaddleLayer。 + + TorchScript示例: + %787 : Tensor = aten::sqrt(%786) + 参数含义: + %787 (Tensor): 输出,取sqrt的Tensor。 + %786 (Tensor): 需要获取sqrt的Tensor。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%786 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "fluid.layers.sqrt", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_squeeze(mapper, graph, node): + """ 构造删除位数为1的维度的PaddleLayer。 + + TorchScript示例: + %12 : Tensor = aten::squeeze(%start_logits.1, %4) + 参数含义: + %12 (Tensor): 输出,删除维度后的Tensor。 + %start_logits.1 (Tensor): 需要删除维度的Tensor。 + %4 (int): 维度。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%start_logits.1 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%4 + if inputs_name[1] in mapper.attrs: + layer_attrs["axis"] = mapper.attrs[inputs_name[1]] + else: + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + layer_inputs["axis"] = inputs_name[1] + current_inputs.append(inputs_name[1]) + graph.add_layer( + "paddle.tensor.squeeze", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_stack(mapper, graph, node): + """ 构造堆叠Tensor的PaddleLayer。 + + TorchScript示例: + %x.222 : Tensor = aten::stack(%32, %7) + 参数含义: + %x.222 (Tensor): 输出,堆叠后的结果。 + %i.12 (Tensor): 需要堆叠的Tensor组成的Tensor。 + %7 (int): 堆叠的轴。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%13 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%12 + if inputs_name[1] in mapper.attrs: + layer_attrs["axis"] = mapper.attrs[inputs_name[1]] + else: + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + layer_inputs["axis"] = inputs_name[1] + current_inputs.append(inputs_name[1]) + graph.add_layer( + "paddle.stack", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_sub(mapper, graph, node): + """ 构造数值相减的PaddleLayer。 + + TorchScript示例: + %840 : int = aten::sub(%839, %836) + 参数含义: + %840 (-): 相减结果。 + %839 (-): 输入数值 x。 + %836 (-): 输入数值 y。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%839 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 处理输入1,即%836 + mapper._check_input( + graph, inputs_node[1], inputs_name[1], current_outputs, add_dim=True) + layer_inputs["y"] = inputs_name[1] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.sub", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_t(mapper, graph, node): + """ 构造矩阵转置的PaddleLayer。 + + TorchScript示例: + %840 : int = aten::sub(%839, %836) + 参数含义: + %109 (Tensor): 输出,转置后的矩阵。 + %102 (Tensor): 需要转置的Tensor。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%x.12 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "fluid.layers.transpose", + inputs=layer_inputs, + outputs=layer_outputs, + perm=[1, 0]) + return current_inputs, current_outputs + + +def aten_tanh(mapper, graph, node): + """ 构造tanh激活的PaddleLayer。 + + TorchScript示例: + %55 : Tensor = aten::tanh(%54) + 参数含义: + %55 (Tensor): 输出,tanh后的结果。 + %54 (Tensor): 需要tanh的Tensor。 + """ + if "tanh" in mapper.dygraph_name_id: + mapper.dygraph_name_id["tanh"] += 1 + else: + mapper.dygraph_name_id["tanh"] = 0 + tanh_name = "tanh" + str(mapper.dygraph_name_id["tanh"]) + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [tanh_name, output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%result.5 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入、输出的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "paddle.nn.Tanh", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_split(mapper, graph, node): + """ 构造分割Tensor的PaddleLayer。 + + TorchScript示例: + %160 : Tensor[] = aten::split(%159, %135, %123) + 参数含义: + %160 (Tensor): 输出,分割后的矩阵。 + %159 (Tensor): 需要分割的Tensor。 + %135 (int): 分割的数量。 + %723 (int): 轴。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%159 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 处理输入2,即%723 + mapper._check_input(graph, inputs_node[2], inputs_name[2], current_outputs) + layer_inputs["dim"] = inputs_name[2] + # 处理输入1,即%135 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + input_type = list(node.inputs())[0].type() + if "[]" in str(input_type): + layer_inputs["num_or_sections"] = inputs_name[1] + else: + layer_attrs["num_or_sections"] = 1 + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "fluid.layers.split", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_transpose(mapper, graph, node): + """ 构造矩阵转置的PaddleLayer。 + + TorchScript示例: + %715 : Tensor = aten::transpose(%x.21, %704, %705) + 参数含义: + %715 (Tensor): 输出,转置后的矩阵。 + %x.21 (Tensor): 需要转置的Tensor。 + %704 (int): 转置的维度1。 + %705 (int): 转置的维度2。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%x.21 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 处理输入1,即%704 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + dim1 = inputs_name[1] + # 处理输入2,即%705 + mapper._check_input(graph, inputs_node[2], inputs_name[2], current_outputs) + dim2 = inputs_name[2] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + graph.add_layer( + "fluid.layers.shape", + inputs={"input": inputs_name[0]}, + outputs=[output_name + "_shape"]) + current_outputs.append(output_name + "_shape") + graph.add_layer( + "prim.len", + inputs={"input": output_name + "_shape"}, + outputs=[output_name + "_len"]) + current_outputs.append(output_name + "_len") + current_inputs.append(output_name + "_shape") + graph.add_layer( + "prim.len2list", + inputs={"len": output_name + "_len"}, + outputs=[output_name + "_list"]) + current_outputs.append(output_name + "_list") + current_inputs.append(output_name + "_len") + graph.add_layer( + "prim.check_dim", + inputs={"len": output_name + "_len", + "dim": dim1}, + outputs=[dim1 + "_new"]) + graph.add_layer( + "prim.check_dim", + inputs={"len": output_name + "_len", + "dim": dim2}, + outputs=[dim2 + "_new"]) + graph.add_layer( + "prim.replaceitem", + inputs={ + "list": output_name + "_list", + "index": dim1 + "_new", + "item": dim2 + "_new" + }, + outputs=[]) + graph.add_layer( + "prim.replaceitem", + inputs={ + "list": output_name + "_list", + "index": dim2 + "_new", + "item": dim1 + "_new" + }, + outputs=[]) + graph.add_layer( + "fluid.layers.transpose", + inputs=layer_inputs, + outputs=layer_outputs, + perm=output_name + "_list") + return current_inputs, current_outputs + + +def aten_to(mapper, graph, node): + """ 构造类型转换的PaddleLayer。 + + TorchScript示例: + %30 : Tensor = aten::to(%extended_attention_mask.1, %12, %5, %5, %4) + 参数含义: + %30 (Tensor): 转换后的Tensor。 + %extended_attention_mask.1 (Tensor): 需要转换的Tensor。 + %12 (int): 转换的类型。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%13 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%12 + if len(inputs_name) == 6: + layer_attrs["dtype"] = dtype_dict[mapper.attrs[inputs_name[2]]] + else: + layer_attrs["dtype"] = dtype_dict[mapper.attrs[inputs_name[1]]] + + graph.add_layer( + "fluid.layers.cast", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_type_as(mapper, graph, node): + """ 构造转换Tensor类型的PaddleLayer。 + + TorchScript示例: + %57 : Tensor = aten::type_as(%56, %mask.1) + 参数含义: + %57 (Tensor): 输出,改变类型后的Tensor。 + %56 (Tensor): 需要改变类型的Tensor。 + %mask.1 (Tensor): 转换成与该Tensor相一致的类型。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%56 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + # 处理输入0,即%mask.1 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + graph.add_layer( + "prim.type", + inputs={"input": inputs_name[1]}, + outputs=[inputs_name[1] + "_type"]) + layer_inputs["dtype"] = inputs_name[1] + "_type" + current_inputs.append(inputs_name[1]) + + graph.add_layer( + "fluid.layers.cast", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_unsqueeze(mapper, graph, node): + """ 构造插入维度的PaddleLayer。 + + TorchScript示例: + %13 : Tensor = aten::unsqueeze(%12, %7) + 参数含义: + %13 (Tensor): 输出,插入维度后的Tensor。 + %12 (Tensor): 需要插入维度的Tensor。 + %7 (int): 维度。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%13 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%12 + if inputs_name[1] in mapper.attrs: + layer_attrs["axis"] = mapper.attrs[inputs_name[1]] + else: + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + layer_inputs["axis"] = inputs_name[1] + current_inputs.append(inputs_name[1]) + graph.add_layer( + "paddle.tensor.unsqueeze", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_upsample_bilinear2d(mapper, graph, node): + """ 构造使用bilinear上采样的PaddleLayer。 + + TorchScript示例: + %4997 : Tensor = aten::upsample_bilinear2d(%x.13, %4963, %5421, %4995, %4996) + 参数含义: + %4997 (Tensor): 输出,上采样后的Tensor。 + %x.13 (Tensor): 需要上采样的Tensor。 + %4963 (list): 上采样后的大小。 + %5421 (bool): 若为True,则将输入和输出张量的4个角落像素的中心对齐,并保留角点像素的值。 + %4995 (float): 高度的乘数因子。 + %4995 (float): 宽度的乘数因子。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%x.13 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%4963 + if inputs_name[1] in mapper.attrs: + layer_attrs["size"] = mapper.attrs[inputs_name[1]] + else: + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + layer_inputs["size"] = inputs_name[1] + current_inputs.append(inputs_name[1]) + graph.add_layer( + "prim.isinstance", + inputs={"input": inputs_name[1]}, + outputs=[inputs_name[1] + "_isinstance"], + cls="paddle.fluid.Variable") + graph.add_layer( + "prim.if", {"input": inputs_name[1] + "_isinstance"}, + outputs=[inputs_name[0] + "_if1"]) + if_layer = graph.layers[list(graph.layers.keys())[-1]] + block = PaddleGraph(if_layer, graph_type="dygraph") + block.add_layer( + "prim.var2list", + inputs={"input": inputs_name[1]}, + outputs=[inputs_name[1]]) + if_layer.add_block(block) + block = PaddleGraph(if_layer, graph_type="dygraph") + if_layer.add_block(block) + if_layer.inputs["input-0"] = inputs_name[1] + # 处理输入2,即%5421 + if inputs_name[2] in mapper.attrs: + layer_attrs["align_corners"] = mapper.attrs[inputs_name[2]] + else: + mapper._check_input(graph, inputs_node[2], inputs_name[2], + current_outputs) + layer_inputs["align_corners"] = inputs_name[2] + current_inputs.append(inputs_name[2]) + # 处理输入3和4,构造assert + list_layer_inputs = {} + mapper._check_input(graph, inputs_node[3], inputs_name[3], current_outputs) + list_layer_inputs["key"] = inputs_name[3] + current_inputs.append(inputs_name[3]) + mapper._check_input(graph, inputs_node[4], inputs_name[4], current_outputs) + list_layer_inputs["value"] = inputs_name[4] + current_inputs.append(inputs_name[4]) + graph.add_layer( + "prim.assert", + inputs=list_layer_inputs, + outputs=[output_name + "_assert"], + type="eq") + layer_inputs["scale_factor"] = inputs_name[3] + layer_attrs["align_mode"] = 0 + layer_attrs["mode"] = string("bilinear") + graph.add_layer( + "paddle.nn.functional.interpolate", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_view(mapper, graph, node): + """ 构造调整大小的PaddleLayer。 + + TorchScript示例: + %input.152 : Tensor = aten::view(%x.20, %430) + 参数含义: + %input.152 (Tensor): 输出,view后的Tensor。 + %x.20 (Tensor): 需要view的Tensor。 + %430 (list): 形状大小组成的list。 + + 【注意】view 函数只能用于contiguous后的Tensor上, + 也就是只能用于内存中连续存储的Tensor。 + 如果对Tensor调用过transpose,permute等操作的话会使该Tensor在内存中变得不再连续, + 此时就不能再调用view函数。因此,需要先使用contiguous来返回一个contiguous copy。 + reshape则不需要依赖目标Tensor是否在内存中是连续的。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%x.20 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入、输出的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%430 + if inputs_name[1] in mapper.attrs: + layer_attrs["shape"] = mapper.attrs[inputs_name[1]] + else: + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + layer_inputs["shape"] = inputs_name[1] + current_inputs.append(inputs_name[1]) + graph.add_layer( + "prim.type", + inputs={"input": inputs_name[0]}, + outputs=[inputs_name[0] + "_type"]) + graph.add_layer( + "prim.str", + inputs={"input": inputs_name[0] + "_type"}, + outputs=[inputs_name[0] + "_type"]) + graph.add_layer( + "prim.eq", + inputs={"x": inputs_name[0] + "_type"}, + outputs=[inputs_name[0] + "_cond"], + y=string("VarType.BOOL")) + graph.add_layer( + "prim.if", {'input': inputs_name[0] + "_cond"}, + outputs=[inputs_name[0] + "_if1"]) + if_layer = graph.layers[list(graph.layers.keys())[-1]] + block = PaddleGraph(if_layer, graph_type="dygraph") + block.add_layer( + "fluid.layers.cast", + inputs={"x": inputs_name[0]}, + outputs=[inputs_name[0]], + dtype=string("int32")) + if_layer.add_block(block) + block = PaddleGraph(if_layer, graph_type="dygraph") + if_layer.add_block(block) + if_layer.inputs["input-0"] = inputs_name[0] + graph.add_layer( + "fluid.layers.reshape", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + graph.add_layer( + "prim.if", {'input': inputs_name[0] + "_cond"}, + outputs=[inputs_name[0] + "_if2"]) + if_layer = graph.layers[list(graph.layers.keys())[-1]] + block = PaddleGraph(if_layer, graph_type="dygraph") + block.add_layer( + "fluid.layers.cast", + inputs={"x": layer_outputs[0]}, + outputs=layer_outputs, + dtype=string("bool")) + if_layer.add_block(block) + block = PaddleGraph(if_layer, graph_type="dygraph") + if_layer.add_block(block) + if_layer.inputs["input-0"] = layer_outputs[0] + return current_inputs, current_outputs + + +def aten_warn(mapper, graph, node): + """ 构造warning的PaddleLayer。 + + TorchScript示例: + = aten::warn(%3, %2) + 参数含义: + %3 (str): warning的提示字符串。 + %2 (int): warning的stacklevel。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%3 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%2 + if inputs_name[1] in mapper.attrs: + layer_attrs["stacklevel"] = mapper.attrs[inputs_name[1]] + else: + mapper._check_input(graph, inputs_node[1], inputs_name[1], + current_outputs) + layer_inputs["stacklevel"] = inputs_name[1] + current_inputs.append(inputs_name[1]) + + graph.add_layer( + "prim.warnings", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_where(mapper, graph, node): + """ 构造返回一个根据输入condition, 选择x或y的元素组成的多维Tensor的PaddleLayer,该节点实现out = x + y。 + + TorchScript示例: + %input.4 : Tensor = aten::where(%209, %w0.2, %210) + 参数含义: + %input.4 (Tensor): 选择的结果。 + %209 (Tensor): 条件。 + %w0.2 (Tensor): 输入数值 x。 + %210 (Tensor): 输入数值 y。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%209 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["condition"] = inputs_name[0] + # 处理输入1,即%w0.2 + mapper._check_input(graph, inputs_node[1], inputs_name[1], current_outputs) + layer_inputs["x"] = inputs_name[1] + # 处理输入1,即%w0.2 + mapper._check_input(graph, inputs_node[2], inputs_name[2], current_outputs) + layer_inputs["y"] = inputs_name[2] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("paddle.where", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def aten_zeros(mapper, graph, node): + """ 构造创建固定形状、数据类型且值全为0的Tensor的PaddleLayer。 + + TorchScript示例: + %input.49 : Tensor = aten::zeros(%23, %8, %6, %24, %5) + 参数含义: + %input.49 (Tensor): 输出,全0的Tensor。 + %23 (list): 形状。 + %8 (int): 类型dtype。 + %6 (int): layout。 + %4995 (Device): 设备。 + %4995 (bool): 是否计算梯度。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + current_inputs = [] + # 处理输入0,即%23,代表end + if inputs_name[0] in mapper.attrs: + layer_attrs["shape"] = mapper.attrs[inputs_name[0]] + else: + mapper._check_input(graph, inputs_node[0], inputs_name[0], + current_outputs) + layer_inputs["shape"] = inputs_name[0] + current_inputs.append(inputs_name[0]) + # 处理输入1,即%8,代表dtype + layer_attrs["dtype"] = dtype_dict[mapper.attrs[inputs_name[1]]] + + graph.add_layer( + "paddle.zeros", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def aten_zeros_like(mapper, graph, node): + """ 构造创建与输入Tensor形状一致的、数据类型且值全为0的Tensor的PaddleLayer。 + + TorchScript示例: + %782 : Tensor = aten::zeros_like(%n.2, %655, %670, %662, %671, %672) + 参数含义: + %782 (Tensor): 输出,全0的Tensor。 + %n.2 (Tensor): 标准Tensor。 + %655 (int): 类型dtype。 + %670 (int): layout。 + %662 (Device): 设备。 + %671 (bool): 是否计算梯度。 + %672 (memory_format): 存储类型。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%n.2 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["x"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + # 处理输入1,即%655,代表dtype + layer_attrs["dtype"] = dtype_dict[mapper.attrs[inputs_name[1]]] + + graph.add_layer( + "paddle.zeros_like", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs diff --git a/x2paddle/op_mapper/pytorch2paddle/prim.py b/x2paddle/op_mapper/pytorch2paddle/prim.py new file mode 100644 index 0000000000000000000000000000000000000000..834a409f1ce9b373541a7253c6e9ca73e17e92de --- /dev/null +++ b/x2paddle/op_mapper/pytorch2paddle/prim.py @@ -0,0 +1,541 @@ +# 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 torch +import numpy as np +from x2paddle.core.util import * + + +def prim_Constant(mapper, graph, node): + """ 构造constant的PaddleLayer,该节点实现常量赋值。 + + TorchScript示例: + %2 : int = prim::Constant[value=-1]() + 参数含义: + %2 (常量类型由赋值类型定义,该示例中为int型): 常量赋值结果输出。 + """ + output_name = mapper._get_outputs_name(node)[0] + output = list(node.outputs())[0] + value = output.toIValue() + output_type = output.type() + if isinstance(value, str): + value = string(value) + if str(output_type) == "Tensor": + value = "{}".format(value) + + if "inf" in str(value): + t = str(type(value)).split("'")[1] + if str(value).startswith("-"): + value = "-{}({})".format(t, string(str(value)[1:])) + else: + value = "{}({})".format(t, string(str(value))) + if "9223372036854775807" in str(value): + import math + value = int(math.pow(2, 31) - 1) + mapper.attrs[output_name] = value + graph.add_layer( + "prim.constant", inputs={}, outputs=[output_name], value=value) + return [], [output_name] + + +def prim_data(mapper, graph, node): + """ 构造Tensor的PaddleLayer。 + + TorchScript示例: + %4336 : Tensor = prim::data(%out.6) + 参数含义: + %4336 (Tensor): 输出Tensor。 + %out.6 (Tensor): 原始Tensor。 + + 【注意】Paddle中无此用法,所以此处翻译成赋值。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%4336 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.equal", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def prim_GetAttr(mapper, graph, node): + """ 获取attribute信息。 + + TorchScript示例: + %27 : Tensor? = prim::GetAttr[name="bias"](%7) + 参数含义: + %7 (Tensor): 输入Tensor。 + %27 (Tensor): 输入Tensor。 + """ + current_node = node + field_name_list = [node.s('name')] + while True: + input_node = list(node.inputs())[0].node() + try: + field_name_list.insert(0, input_node.s('name')) + node = input_node + except Exception: + break + attr_name = ".".join(field_name_list) + output_name = mapper._get_outputs_name(current_node, attr_name)[0] + part_script = mapper.script + for field_name in field_name_list: + if hasattr(part_script, field_name): + param = getattr(part_script, field_name) + if isinstance(param, torch.Tensor): + param = param.detach().numpy() + if len(param.shape) == 0: + param = np.reshape(param, 1) + if str(param.dtype) == "uint8": + param = param.astype("int32") + mapper.pytorch_params[output_name] = param + part_script = param + return [], [output_name] + + +def prim_If(mapper, graph, node): + """ 构造if控制流的PaddleLayer。 + + TorchScript示例: + %input.5 : Tensor = prim::If(%107) + block0(): + %109 : Tensor = aten::t(%102) + %ret.2 : Tensor = aten::addmm(%103, %101, %109, %104, %104) + -> (%ret.2) + block1(): + %111 : Tensor = aten::t(%102) + ... + -> (%output.4) + 参数含义: + %107 (bool): if判断条件。 + %input.5 (Tensor): if控制流的输出,与%output.4对应。 + """ + outputs_name = mapper._get_outputs_name(node) + node_outputs = outputs_name.copy() + current_outputs = outputs_name.copy() + input_node = list(node.inputs())[0].node() + script_input_unique_id = list(node.inputs())[0].unique() + input_node_name = mapper.outputs_info[script_input_unique_id] + mapper._check_input(graph, input_node, input_node_name, current_outputs) + graph.add_layer("prim.if", {'input': input_node_name}, node_outputs) + current_layer = list(graph.layers.values())[-1] + block0 = list(node.blocks())[0] + block0_graph, graph_inputs0 = mapper.traverse(block0, current_layer) + len0 = 0 + for i, input_name in enumerate(graph_inputs0): + current_layer.inputs['input-{}'.format(i)] = input_name + len0 = i + current_layer.add_block(block0_graph) + block1 = list(node.blocks())[1] + block1_graph, graph_inputs1 = mapper.traverse(block1, current_layer) + for i, input_name in enumerate(graph_inputs1): + current_layer.inputs['input-{}'.format(len0 + 1 + i)] = input_name + current_layer.add_block(block1_graph) + return list(current_layer.inputs.values()), current_outputs + + +def prim_ListConstruct(mapper, graph, node): + """ 构造list的PaddleLayer。 + + TorchScript示例: + %86 : int[] = prim::ListConstruct(%84, %85) + 参数含义: + %86 (list): list节点输出。 + %84 (int/其他): list第一个元素信息。 + %85 (int/其他): list第二个元素信息。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理每个输入 + for i, input_name in enumerate(inputs_name): + layer_inputs["input{}".format(i)] = input_name + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.list", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def prim_ListUnpack(mapper, graph, node): + """ 构造获取list中元素的PaddleLayer。 + + TorchScript示例: + %x1.4 : Tensor, %x2.4 : Tensor = prim::ListUnpack(%4354) + 参数含义: + %x1.4 (Tensor): 输出,list的第一个元素。 + %x2.4 (Tensor): 输出,list的第二个元素。 + %4354 (list): 列表。 + """ + outputs_name = mapper._get_outputs_name(node) + layer_outputs = outputs_name.copy() + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = layer_outputs.copy() + # 处理输入0,即%4354 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "prim.list_unpack", inputs=layer_inputs, outputs=layer_outputs) + mapper.split_len[list(layer_inputs.values())[0]] = len(layer_outputs) + return current_inputs, current_outputs + + +def prim_Loop(mapper, graph, node): + """ 构造loop循环的PaddleLayer。 + + TorchScript示例: + %x : Tensor = prim::Loop(%4, %3, %x.3) + block0(%i : int, %x.12 : Tensor): + %72 : int[] = prim::Constant[value=[6, 6]]() + ... + %x.5 : Tensor = aten::adaptive_avg_pool2d(%x.12, %_output_size.1) + -> (%3, %x.5) + 参数含义: + %4 (int): 循环次数。 + %3 (bool): 是否进入退出。 + %x.3 (Tensor): 循环中修改的Tensor。 + %x (Tensor): loop循环的输出,与%x.5对应。 + """ + node_outputs = mapper._get_outputs_name(node) + loop_inputs = {} + block = list(node.blocks())[0] + loop_outputs = node_outputs.copy() + for i, block_input_ivalue in enumerate(block.inputs()): + if i == 0: + block_input_node_name = '_x' + str(mapper.output_index) + else: + block_input_node_name = 'x' + str(mapper.output_index) + unique_id = block_input_ivalue.unique() + if unique_id not in mapper.outputs_info: + mapper.outputs_info[unique_id] = block_input_node_name + mapper.output_index += 1 + if i == 0: + loop_input_node = list(node.inputs())[0].node() + script_loop_input_unique_id = list(node.inputs())[0].unique() + loop_input_node_name = mapper.outputs_info[ + script_loop_input_unique_id] + mapper._check_input(graph, loop_input_node, loop_input_node_name, + node_outputs) + loop_inputs['input'] = loop_input_node_name + loop_outputs.append(block_input_node_name) + node_outputs.append(block_input_node_name) + else: + loop_input_node = list(node.inputs())[i + 1].node() + script_loop_input_unique_id = list(node.inputs())[i + 1].unique() + loop_input_node_name = mapper.outputs_info[ + script_loop_input_unique_id] + mapper._check_input(graph, loop_input_node, loop_input_node_name, + node_outputs) + graph.add_layer( + "prim.equal", + inputs={'input': loop_input_node_name}, + outputs=[block_input_node_name]) + node_outputs.append(block_input_node_name) + + graph.add_layer("prim.loop", inputs=loop_inputs, outputs=loop_outputs) + current_layer = list(graph.layers.values())[-1] + block_graph, graph_inputs = mapper.traverse(block, current_layer) + for i, input_name in enumerate(graph_inputs): + if input_name == loop_outputs[1]: + continue + current_layer.inputs['input-{}'.format(i)] = input_name + current_layer.add_block(block_graph) + return list(current_layer.inputs.values()), node_outputs + + +def prim_min(mapper, graph, node): + """ 构造min的PaddleLayer。 + + TorchScript示例: + %87 : int = prim::min(%86) + 参数含义: + %86 (list): 输入。 + %87 (int): 输出。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%86 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.min", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def prim_NumToTensor(mapper, graph, node): + """ 构造转为Tensor的PaddleLayer。 + + TorchScript示例: + %other.2 : Tensor = prim::NumToTensor(%1736) + 参数含义: + %other.2 (Tensor): 输出。 + %1736 (-): 输入。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%86 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + if inputs_node[0].kind() == "aten::size": + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + graph.add_layer( + "prim_equal", inputs=layer_inputs, outputs=layer_outputs) + else: + layer_inputs["value"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + input_type = list(node.inputs())[0].type() + layer_attrs["dtype"] = input_type + layer_attrs["persistable"] = True + layer_attrs["shape"] = [1] + graph.add_layer( + "fluid.layers.create_global_var", + inputs=layer_inputs, + outputs=layer_outputs, + **layer_attrs) + return current_inputs, current_outputs + + +def prim_RaiseException(mapper, graph, node): + """ 构造抛出异常的PaddleLayer。 + + TorchScript示例: + = prim::RaiseException(%76) + 参数含义: + %76 (str): 异常信息。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%76 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "prim.exception", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def prim_requires_grad(mapper, graph, node): + """ 构造是否计算梯度的PaddleLayer。 + + TorchScript示例: + %356 : bool = prim::requires_grad(%tensor.31) + 参数含义: + %356 (bool): 输出,当前Tensor是否计算梯度。 + %tensor.31 (Tensor): 输入的Tensor。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%86 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "prim.requires_grad", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def prim_SetAttr(mapper, graph, node): + """ 设置attribute信息。 + + TorchScript示例: + = prim::SetAttr[name="num_batches_tracked"](%260, %277) + 参数含义: + %260 (-): 属性名前缀。 + %277 (-): 需要设置的值。 + """ + output_name = mapper._get_outputs_name(node)[0] + field_name_list = [] + tmp_node = node + while True: + input_node = list(tmp_node.inputs())[0].node() + try: + field_name_list.insert(0, input_node.s('name')) + tmp_node = input_node + except Exception: + break + field_name_list.append(node.s('name')) + + inputs_name, inputs_node = mapper._get_inputs_name(node) + param = { + "Tensor": "self." + ".".join(field_name_list).replace(".", "_"), + "parent_layer_id": graph.parent_layer.id + } + mapper.pytorch_params[".".join(field_name_list)] = param + graph.add_layer( + "prim.set_attr", + inputs={"input": inputs_name[1]}, + outputs=["self." + ".".join(field_name_list).replace(".", "_")]) + return [], [output_name] + + +def prim_shape(mapper, graph, node): + """ 构造获取shape的PaddleLayer。 + + TorchScript示例: + %4701 : int[] = prim::shape(%result.1) + 参数含义: + %4701 (list): 输出,shape信息。 + %result.1 (Tensor): 需要获取shape的值。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%input.8 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "fluid.layers.shape", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def prim_TupleConstruct(mapper, graph, node): + """ 构造tuple的PaddleLayer。 + + TorchScript示例: + %4492 : (Tensor, Tensor?) = prim::TupleConstruct(%x.46, %aux) + 参数含义: + %4492 (tuple): 输出,tuple。 + %x.46 (Tensor/其他): tuple第一个元素信息。 + %aux (Tensor/其他): tuple第二个元素信息。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理每个输入 + for i, input_name in enumerate(inputs_name): + layer_inputs["input{}".format(i)] = input_name + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.tuple", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def prim_TupleUnpack(mapper, graph, node): + """ 构造获取tuple元素的PaddleLayer。 + + TorchScript示例: + %x.223 : Tensor, %aux.3 : Tensor? = prim::TupleUnpack(%4492) + 参数含义: + %x.223 (Tensor/其他): 输出,tuple第一个元素信息。 + %aux.3 (Tensor/其他): 输出,tuple第二个元素信息。 + %4492 (tuple): 需要获取元素的tuple。 + """ + outputs_name = mapper._get_outputs_name(node) + layer_outputs = outputs_name + layer_inputs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = outputs_name + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer( + "prim.tuple_unpack", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def prim_unchecked_cast(mapper, graph, node): + """ 构造确认类型的PaddleLayer。 + + TorchScript示例: + %size.64 : int[] = prim::unchecked_cast(%size.63) + 参数含义: + %size.64 (-): 输出。 + %size.63 (-): 输入。 + + 【注意】Paddle中无此用法,所以此处翻译成赋值。 + """ + output_name = mapper._get_outputs_name(node)[0] + layer_outputs = [output_name] + layer_inputs = {} + layer_attrs = {} + inputs_name, inputs_node = mapper._get_inputs_name(node) + # 获取当前节点输出的list + current_outputs = [output_name] + # 处理输入0,即%size.63 + mapper._check_input(graph, inputs_node[0], inputs_name[0], current_outputs) + layer_inputs["input"] = inputs_name[0] + # 获取当前节点输入的list + current_inputs = list(layer_inputs.values()) + + graph.add_layer("prim.equal", inputs=layer_inputs, outputs=layer_outputs) + return current_inputs, current_outputs + + +def prim_Uninitialized(mapper, graph, node): + """ 构造表示编译器永远不会使用的值的PaddleLayer,该节点转换为None。 + + TorchScript示例: + %345 : bool = prim::Uninitialized() + 参数含义: + %345 (bool): 输出,为赋值的bool。 + """ + output_name = mapper._get_outputs_name(node)[0] + output = list(node.outputs())[0] + mapper.attrs[output_name] = None + graph.add_layer( + "prim.constant", inputs={}, outputs=[output_name], value=None) + return [], [output_name] diff --git a/x2paddle/op_mapper/pytorch2paddle/prim2code.py b/x2paddle/op_mapper/pytorch2paddle/prim2code.py new file mode 100644 index 0000000000000000000000000000000000000000..d16197f6793fccc7e236edbc21e5abb01ce98c37 --- /dev/null +++ b/x2paddle/op_mapper/pytorch2paddle/prim2code.py @@ -0,0 +1,392 @@ +# 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. + + +def gen_codes(code_list, indent=0): + indent_blank = " " * indent + codes = [] + for code_line in code_list: + if code_line.strip() == "": + codes.append('\n') + else: + codes.append(indent_blank + code_line + '\n') + return codes + + +def get_value(layer, key): + """ 进行optimizer后可能把inputs的value直接用数值代替(ConstantFuser), + 会把input换成attr,所以需要此处的操作。 + """ + if key in layer.inputs: + return layer.inputs[key] + else: + return str(layer.attrs[key]) + + +def prim_add(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {} + {}".format(layer.outputs[0], + get_value(layer, "x"), get_value(layer, "y")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_add_(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {} + {} * {}".format(layer.outputs[0], + get_value(layer, "x"), + layer.attrs["alpha"], + get_value(layer, "y")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_and(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {} and {}".format(layer.outputs[0], + get_value(layer, "x"), get_value(layer, "y")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_append(layer, indent=1, init_func=[], forward_func=[]): + line = "{}.append({})".format( + get_value(layer, "list"), get_value(layer, "element")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_assert(layer, indent=1, init_func=[], forward_func=[]): + if layer.attrs["type"] == "eq": + values = get_value(layer, "key") + if "value" in layer.attrs: + values = layer.attrs["value"] + if isinstance(values, list): + s = "" + for v in values: + s += "{} == {} or ".format(get_value(layer, "key"), v) + if len(s) > 0: + s = s[:-4] + line = "assert {}, \'The {} must be {}!\'".format( + s, get_value(layer, "key"), get_value(layer, "value")) + else: + line = "assert {} == {}, \'The {} must be {}!\'".format( + get_value(layer, "key"), + get_value(layer, "value"), + get_value(layer, "key"), get_value(layer, "value")) + else: + raise Exception("Not implement yet!") + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_check_dim(layer, indent=1, init_func=[], forward_func=[]): + lines = [] + lines.append("if {} < 0:".format(get_value(layer, "dim"))) + lines.append(" {} = {} + {}".format(layer.outputs[ + 0], get_value(layer, "dim"), get_value(layer, "len"))) + lines.append("else:") + lines.append(" {} = {}".format(layer.outputs[0], get_value(layer, + "dim"))) + forward_func.extend(gen_codes(lines, indent=indent)) + + +def prim_constant(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {}".format(layer.outputs[0], layer.attrs["value"]) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_contain(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {} in {}".format(layer.outputs[0], + get_value(layer, "element"), + get_value(layer, "input")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_dict(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = dict()".format(layer.outputs[0]) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_div(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {} / {}".format(layer.outputs[0], + get_value(layer, "x"), get_value(layer, "y")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_eq(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {} == {}".format(layer.outputs[0], + get_value(layer, "x"), get_value(layer, "y")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_equal(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {}".format(layer.outputs[0], get_value(layer, "input")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_exception(layer, indent=1, init_func=[], forward_func=[]): + line = "raise RaiseException({})".format(get_value(layer, "input")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_float(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = float({})".format(layer.outputs[0], get_value(layer, "input")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_floor(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = math.floor({})".format(layer.outputs[0], + get_value(layer, "input")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_floordiv(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {} // {}".format(layer.outputs[0], + get_value(layer, "x"), get_value(layer, "y")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_getitem(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {}[{}]".format(layer.outputs[0], + get_value(layer, "list"), + get_value(layer, "index")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_gt(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {} > {}".format(layer.outputs[0], + get_value(layer, "x"), get_value(layer, "y")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_if(layer, indent=1, init_func=[], forward_func=[]): + line = "if {} :".format(get_value(layer, "input")) + forward_func.extend(gen_codes([line], indent=indent)) + block = layer.blocks[0] + b_init_lines, b_forward_lines = block.gen_dygraph_code(indent=indent + 1) + init_func.extend(b_init_lines) + forward_func.extend(b_forward_lines) + block = layer.blocks[1] + if len(block.layers) > 0: + b_init_lines, b_forward_lines = block.gen_dygraph_code( + indent=indent + 1) + if len(b_forward_lines) != 0: + line = "else:" + forward_func.extend(gen_codes([line], indent=indent)) + init_func.extend(b_init_lines) + forward_func.extend(b_forward_lines) + + +def prim_int(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = int({})".format(layer.outputs[0], get_value(layer, "input")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_is(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {} is {}".format(layer.outputs[0], + get_value(layer, "x"), get_value(layer, "y")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_isinstance(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = isinstance({}, {})".format(layer.outputs[0], + get_value(layer, "input"), + layer.attrs["cls"]) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_isnot(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {} is not {}".format(layer.outputs[0], + get_value(layer, "x"), + get_value(layer, "y")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_le(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {} <= {}".format(layer.outputs[0], + get_value(layer, "x"), get_value(layer, "y")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_len(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = len({})".format(layer.outputs[0], get_value(layer, "input")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_len2list(layer, indent=1, init_func=[], forward_func=[]): + lines = [] + lines.append("{} = []".format(layer.outputs[0])) + lines.append("for i in range({}):".format(get_value(layer, "len"))) + lines.append(" {}.append(i)".format(layer.outputs[0])) + forward_func.extend(gen_codes(lines, indent=indent)) + + +def prim_lt(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {} < {}".format(layer.outputs[0], + get_value(layer, "x"), get_value(layer, "y")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_list(layer, indent=1, init_func=[], forward_func=[]): + input_len = len(layer.inputs) + len(layer.attrs) + inputs_list = list() + for i in range(input_len): + inputs_list.append(get_value(layer, "input{}".format(i))) + inputs_str = ', '.join(inputs_list) + line = "{} = [{}]".format(layer.outputs[0], inputs_str) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_list_unpack(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {}".format(", ".join(layer.outputs), get_value(layer, "input")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_loop(layer, indent=1, init_func=[], forward_func=[]): + loop_range = get_value(layer, "input") + line = "for {} in range({}):".format(layer.outputs[1], loop_range) + forward_func.extend(gen_codes([line], indent=indent)) + block = layer.blocks[0] + b_init_lines, b_forward_lines = block.gen_dygraph_code(indent=indent + 1) + init_func.extend(b_init_lines) + forward_func.extend(b_forward_lines) + + +def prim_min(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = min({})".format(layer.outputs[0], get_value(layer, "input")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_mul(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {} * {}".format(layer.outputs[0], + get_value(layer, "x"), get_value(layer, "y")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_ne(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {} != {}".format(layer.outputs[0], + get_value(layer, "x"), get_value(layer, "y")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_neg(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = -{}".format(layer.outputs[0], get_value(layer, "input")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_not(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = not {}".format(layer.outputs[0], get_value(layer, "input")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_or(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {} or {}".format(layer.outputs[0], + get_value(layer, "x"), get_value(layer, "y")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_replaceitem(layer, indent=1, init_func=[], forward_func=[]): + line = "{}[{}] = {}".format( + get_value(layer, "list"), + get_value(layer, "index"), get_value(layer, "item")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_requires_grad(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = not {}.stop_gradient".format(layer.outputs[0], + get_value(layer, "input")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_rsub(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {} - {} * {}".format(layer.outputs[0], + get_value(layer, "y"), + get_value(layer, "x"), + get_value(layer, "alpha")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_select(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {}[".format(layer.outputs[0], get_value(layer, "input")) + for dim in range(layer.attrs["dim"]): + line += ":, " + line += (get_value(layer, "index") + "]") + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_set_attr(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {}".format(layer.outputs[0], get_value(layer, "input")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_set_item(layer, indent=1, init_func=[], forward_func=[]): + line = "{}[{}] = {}".format( + get_value(layer, "dict"), + get_value(layer, "key"), get_value(layer, "value")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_shape_dim(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = fluid.layers.shape({})[{}]".format(layer.outputs[0], + get_value(layer, "input"), + get_value(layer, "dim")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_slice(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {}[{}: {}: {}]".format(layer.outputs[0], + get_value(layer, "input"), + get_value(layer, "start"), + get_value(layer, "end"), + get_value(layer, "step")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_str(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = str({})".format(layer.outputs[0], get_value(layer, "input")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_sub(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {} - {}".format(layer.outputs[0], + get_value(layer, "x"), get_value(layer, "y")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_tuple(layer, indent=1, init_func=[], forward_func=[]): + input_len = len(layer.inputs) + len(layer.attrs) + inputs_list = list() + for i in range(input_len): + inputs_list.append(get_value(layer, "input{}".format(i))) + inputs_str = ', '.join(inputs_list) + line = "{} = ({})".format(layer.outputs[0], inputs_str) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_tuple_unpack(layer, indent=1, init_func=[], forward_func=[]): + outputs_str = ', '.join(layer.outputs) + line = "{} = {}".format(outputs_str, get_value(layer, "input")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_type(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {}.dtype".format(layer.outputs[0], get_value(layer, "input")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_var2list(layer, indent=1, init_func=[], forward_func=[]): + line = "{} = {}.numpy().tolist()".format(layer.outputs[0], + get_value(layer, "input")) + forward_func.extend(gen_codes([line], indent=indent)) + + +def prim_warnings(layer, indent=1, init_func=[], forward_func=[]): + lines = ["import warnings"] + line = "warnings.warn({}, stacklevel={})".format( + get_value(layer, "input"), layer.attrs["stacklevel"]) + lines.append(line) + forward_func.extend(gen_codes(lines, indent=indent)) diff --git a/x2paddle/op_mapper/pytorch2paddle/pytorch_op_mapper.py b/x2paddle/op_mapper/pytorch2paddle/pytorch_op_mapper.py new file mode 100644 index 0000000000000000000000000000000000000000..2d63411879009003d80485602ae28e2a498b0035 --- /dev/null +++ b/x2paddle/op_mapper/pytorch2paddle/pytorch_op_mapper.py @@ -0,0 +1,249 @@ +# 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 torch +import numpy as np +from x2paddle.core.op_mapper import OpMapper +from x2paddle.core.util import * +from x2paddle.core.program import PaddleGraph +from x2paddle.op_mapper.pytorch2paddle import prim +from x2paddle.op_mapper.pytorch2paddle import aten + + +class PyTorchOpMapper(OpMapper): + def __init__(self, decoder): + super(PyTorchOpMapper, self).__init__() + self.script = decoder.script + self.paddle_params = dict() + self.outputs_info = {} # key为output unique id,value为当前节点的输出名字 + self.pytorch_params = {} # key为节点名,value为参数 + self.attrs = {} # key为节点名,value为属性值 + self.output_index = 0 + self.dygraph_name_id = {} # 动态图__init__输出名字中的id,key为kernel类型,value为id + self.split_len = {} # split的长度 + # 转换 + self.check_op(decoder.graph) + self.graph, _ = self.traverse(decoder.graph) + + def check_op(self, script_graph): + def _update_op_list(graph): + for node in graph.nodes(): + op_list.append(node.kind()) + for block in node.blocks(): + _update_op_list(block) + + op_list = list() + _update_op_list(script_graph) + op_list = list(set(op_list)) + unsupported_op_list = [] + for op in op_list: + func_name = op.replace('::', '_') + if not (hasattr(prim, func_name) or hasattr(aten, func_name)): + unsupported_op_list.append(op) + if len(unsupported_op_list) > 0: + raise Exception("The kind {} in model is not supported yet.".format( + unsupported_op_list)) + + def traverse(self, script_graph, parent_layer=None): + # 用于获取graph的输入 + def _update_graph_inputs(kind, inputs, outputs): + # extend只能放更新graph_inputs之前的情况: + # 1. loop的输出i也是输入;i是输入的原因是:子图中为父图得到的。 + # 2. 在_check_input中需要使用to_variable。 + # extend只能放更新graph_inputs之后的情况: + # 使用了append。 + if kind != "aten::append": + current_node_outputs.extend(outputs) + for name in inputs: + if name not in current_node_outputs: + graph_inputs.append(name) + if kind == "aten::append": + current_node_outputs.extend(outputs) + + # 初始化 + graph = PaddleGraph(parent_layer, graph_type="dygraph") + current_node_outputs = [] + graph_inputs = [] + # 转换输入节点 + if isinstance(script_graph, torch._C.Graph): + for i, ivalue in enumerate(script_graph.inputs()): + node = ivalue.node() + if str(ivalue.type()) != "Tensor": + graph.set_name(str(ivalue.type()).split(".")[-1]) + continue + inputs, outputs = self.data(graph, node, ivalue.unique()) + # 转换中间节点 + for node in script_graph.nodes(): + kind = node.kind() + func_name = kind.replace('::', '_') + if hasattr(prim, func_name): + func = getattr(prim, func_name) + inputs, outputs = func(self, graph, node) + _update_graph_inputs(kind, inputs, outputs) + elif hasattr(aten, func_name): + func = getattr(aten, func_name) + inputs, outputs = func(self, graph, node) + _update_graph_inputs(kind, inputs, outputs) + + # 转换输出节点 + if hasattr(script_graph, 'returnNode'): + for i, ivalue in enumerate(script_graph.returnNode().inputs()): + if parent_layer.kernel == "prim.loop" and i == 0: + continue + node = ivalue.node() + script_unique_id = ivalue.unique() + inputs, outputs = self.equal( + graph, + node, + uid=script_unique_id, + parent_layer=parent_layer, + index=i) + _update_graph_inputs("equal", inputs, outputs) + + # 设置graph的参数和输出节点 + if isinstance(script_graph, torch._C.Graph): + graph.set_parameters(self.paddle_params) + if hasattr(script_graph, 'return_node'): + inputs_name, inputs_node = self._get_inputs_name( + script_graph.return_node()) + graph.outputs = inputs_name + # 更新split参数 + for layer in graph.layers.values(): + if layer.kernel == "fluid.layers.split" and "num_or_sections" in layer.attrs: + layer.attrs["num_or_sections"] = self.split_len[layer.outputs[ + 0]] + return graph, graph_inputs + + def _get_outputs_name(self, node, attr_name=None): + outputs_name = [] + for output_ivalue in node.outputs(): + script_unique_id = output_ivalue.unique() + if attr_name is None: + output_name = 'x' + str(self.output_index) + if script_unique_id in self.outputs_info: + output_name = self.outputs_info[script_unique_id] + else: + output_name = attr_name.replace(".", "_") + self.outputs_info[script_unique_id] = output_name + self.output_index += 1 + + outputs_name.append(output_name) + # if或loop节点没有输出的情况 + if len(list(node.outputs())) == 0: + output_name = '_x' + str(self.output_index) + self.output_index += 1 + outputs_name.append(output_name) + return outputs_name + + def _check_input(self, + graph, + node, + output_name, + node_outputs, + add_dim=False): + if node.kind() == "prim::GetAttr": + param = self.pytorch_params[output_name] + if isinstance(param, np.ndarray): + if add_dim: + param = param[np.newaxis, :] + self.paddle_params[output_name] = param + graph.add_layer( + "fluid.dygraph.base.to_variable", + inputs={}, + outputs=[output_name], + value="params[{}]".format(string(output_name))) + else: + if isinstance(param, dict) and "Tensor" in param and \ + "parent_layer_id" in param: + if graph.parent_layer is not None: + # 当某个param被2个控制流(if-else)赋值时,else不可以引用if中的赋值结果 + id1 = param["parent_layer_id"] + id2 = graph.parent_layer.id + id1_part = id1.split(".") + id2_part = id2.split(".") + if len(id1_part) >= len(id2_part): + for i in range(len(id1_part)): + if id1_part[i] == id2_part[i]: + continue + else: + if id1_part[i] == "0" and id2_part[ + i] == "1": + if add_dim: + param = param[np.newaxis, :] + self.paddle_params[output_name] = param + graph.add_layer( + "fluid.dygraph.base.to_variable", + inputs={}, + outputs=[output_name], + value="params[{}]".format( + string(output_name))) + node_outputs.append(output_name) + return + # 若if-else外,则可直接引用if-else中的赋值结果 + graph.add_layer( + "prim.constant", + inputs={}, + outputs=[output_name], + value=param["Tensor"]) + else: + graph.add_layer( + "prim.constant", + inputs={}, + outputs=[output_name], + value=string(param) + if isinstance(param, str) else param) + node_outputs.append(output_name) + + def _get_inputs_name(self, node): + inputs_name = [] + inputs_node = [] + for script_input_ivalue in node.inputs(): + script_input_node = script_input_ivalue.node() + script_input_unique_id = script_input_ivalue.unique() + input_name = self.outputs_info[script_input_unique_id] + inputs_node.append(script_input_node) + inputs_name.append(input_name) + return inputs_name, inputs_node + + def data(self, graph, node, uid): + for output_ivalue in node.outputs(): + script_unique_id = output_ivalue.unique() + if script_unique_id in self.outputs_info or script_unique_id != uid: + continue + node_name = 'x' + str(self.output_index) + self.outputs_info[script_unique_id] = node_name + self.output_index += 1 + output_name = self.outputs_info[uid] + graph.add_layer( + "fluid.dygraph.base.to_variable", + inputs={}, + outputs=[node_name], + value=output_name) + return [], [output_name] + + def equal(self, graph, node, uid=None, parent_layer=None, index=None): + if parent_layer is not None and index is not None: + # block的输出 + input_node_name = self.outputs_info[uid] + control_output_id = index + if parent_layer.kernel == "prim.loop": + control_output_id = index - 1 + output_node_name = parent_layer.outputs[control_output_id] + current_outputs = [output_node_name] + self._check_input(graph, node, input_node_name, current_outputs) + graph.add_layer( + "prim.equal", + inputs={'input': input_node_name}, + outputs=[output_node_name]) + return [input_node_name], current_outputs diff --git a/x2paddle/op_mapper/tf_op_mapper.py b/x2paddle/op_mapper/tf_op_mapper.py index 3a88f47330a7d63cff02358aa476d5216c183e9f..d2ed2944fd257df2ef0e5cfc7e5451abde6245aa 100644 --- a/x2paddle/op_mapper/tf_op_mapper.py +++ b/x2paddle/op_mapper/tf_op_mapper.py @@ -15,10 +15,25 @@ from x2paddle.decoder.tf_decoder import TFGraph from x2paddle.core.op_mapper import OpMapper from x2paddle.core.util import * +from x2paddle import program +import traceback +import math import inspect import numpy import sys +name_counter = dict() + + +def gen_name(op_name, var_name): + name = "{}_{}".format(op_name, var_name) + if name not in name_counter: + name_counter[name] = 0 + else: + name_counter[name] += 1 + name = name + '_' + str(name_counter[name]) + return name + # compute padding size for SAME mode def get_same_padding(in_size, kernel_size, stride): @@ -31,45 +46,34 @@ def get_same_padding(in_size, kernel_size, stride): return [pad0, pad1] -def nhwc_dim_to_nchw(node, dim): - tf_data_format = list(node.tf_data_format) - pd_data_format = list(node.pd_data_format) - if isinstance(dim, list): - for i in range(len(dim)): - char = tf_data_format[dim[i]] - dim[i] = pd_data_format.index(char) - else: - char = tf_data_format[dim] - dim = pd_data_format.index(char) - return dim - - if dim < 0: - dim += 4 - if dim > 0: - dim = (dim + 1) % 4 + int((dim + 1) / 4) - return dim - - class TFOpMapper(OpMapper): directly_map_ops = { 'Relu': ['relu'], 'Relu6': ['relu6'], - 'Shape': ['shape'], 'Abs': ['abs'], 'Sigmoid': ['sigmoid'], 'Exp': ['exp'], 'Rsqrt': ['rsqrt'], + 'Sqrt': ['sqrt'], 'swish_f32': ['swish'], 'Tanh': ['tanh'], + 'Softplus': ['softplus'], 'LeakyRelu': ['leaky_relu', { 'alpha': 'alpha' - }] + }], + 'Floor': ['floor'], + 'Erf': ['erf'], + 'Square': ['square'] } elementwise_ops = { 'Add': 'elementwise_add', + 'AddV2': 'elementwise_add', 'RealDiv': 'elementwise_div', 'Sub': 'elementwise_sub', 'Maximum': 'elementwise_max', + 'Minimum': 'elementwise_min', + 'LessEqual': 'less_equal', + 'GreaterEqual': 'greater_equal', 'Mul': 'elementwise_mul', 'FloorDiv': 'elementwise_floordiv' } @@ -78,24 +82,30 @@ class TFOpMapper(OpMapper): super(TFOpMapper, self).__init__() self.decoder = decoder self.graph = decoder.tf_graph - self.batch_node = None self.weights = dict() self.omit_nodes = list() self.used_custom_layers = dict() + program.clear() not_placeholder = list() for name in self.graph.input_nodes: - if self.graph.get_node(name).layer_type != "Placeholder" \ - and self.graph.get_node(name).layer_type != "OneShotIterator": + if self.graph.get_node( + name).layer_type != "Placeholder" and self.graph.get_node( + name + ).layer_type != "OneShotIterator" and self.graph.get_node( + name).layer_type != "IteratorV2": not_placeholder.append(name) for name in not_placeholder: idx = self.graph.input_nodes.index(name) del self.graph.input_nodes[idx] - sys.stderr.write("Total nodes: {}\n".format(len(self.graph.topo_sort))) + program.inputs = self.graph.input_nodes + program.outputs = self.graph.output_nodes + unsupported_ops = set() + sys.stderr.write("Total nodes: {}\n".format(len(self.graph.topo_sort))) for i, node_name in enumerate(self.graph.topo_sort): - sys.stderr.write("\rConverting node {} ... ".format(i + 1)) + sys.stderr.write("\rConverting node {} ... ".format(i + 1)) node = self.graph.get_node(node_name) op = node.layer_type if op in self.directly_map_ops: @@ -110,173 +120,74 @@ class TFOpMapper(OpMapper): if len(unsupported_ops) > 0: continue func = getattr(self, op) - func(node) + try: + func(node) + except Exception as e: + unsupported_ops.add(op) + print("\n{}\n".format(traceback.format_exc())) else: unsupported_ops.add(op) if len(unsupported_ops) > 0: - sys.stderr.write("=========={} Ops are not supported yet======\n". - format(len(unsupported_ops))) + print("\n========= {} OPs are not supported yet ===========".format( + len(unsupported_ops))) for op in unsupported_ops: - sys.stderr.write("========== {} ==========\n".format(op)) + print("========== {} ============".format(op)) sys.exit(-1) - sys.stderr.write('\nDone!\n') - - def add_omit_nodes(self, in_node_name, out_node_name): - in_node = self.graph.get_node(in_node_name) - out_node = self.graph.get_node(out_node_name) - index = in_node.outputs.index(out_node_name) - # del in_node.outputs[index] - index = out_node.inputs.index(in_node_name) - # del out_node.inputs[index] - self.omit_nodes.append(in_node.layer_name) + sys.stderr.write("\nDone!\n") 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_node(node.layer.input[0], copy=True) + input = self.graph.get_node(node.layer.input[0]) attr = dict() for param in op_info[1:]: tf_param_name = list(param.keys())[0] pd_param_name = list(param.values())[0] tf_param = node.get_attr(tf_param_name) attr[pd_param_name] = tf_param - node.fluid_code.add_layer( - op_info[0], inputs=input, output=node, param_attr=attr) + + program.add_layer( + kernel="fluid.layers.{}".format(op_info[0]), + inputs={"x": input.name}, + outputs=[node.name], + **attr) def elementwise_map(self, node): assert node.layer_type in self.elementwise_ops op_type = self.elementwise_ops[node.layer_type] - x = self.graph.get_node(node.layer.input[0], copy=True) - y = self.graph.get_node(node.layer.input[1], copy=True) + x = self.graph.get_node(node.layer.input[0]) + y = self.graph.get_node(node.layer.input[1]) x_shape = x.out_shapes[0] y_shape = y.out_shapes[0] - if len(x_shape) == 0: - x_shape = [1] - if len(y_shape) == 0: - y_shape = [1] - # incomplement broadcasting support for paddle - x_input = x - y_input = y - if len(x_shape) < len(y_shape): - unrevertable_ops = [ - "elementwise_sub", "elementwise_div", "elementwise_floordiv", - "elementwise_mod", "elementwise_pow" - ] - if op_type not in unrevertable_ops: - x_input = y - y_input = x - x_shape = y.out_shapes[0] - if len(x_shape) == 0: - x_shape = [1] - y_shape = x.out_shapes[0] - if len(y_shape) == 0: - y_shape = [1] - else: - if len(x_shape) == 1 and len(y_shape) == 4 and x_shape[ - 0] == y_shape[-1] and y_shape.count(-1) < 1: - shape = [1, x_shape[0], 1, 1] - attr = {"shape": shape} - node.fluid_code.add_layer( - "reshape", - inputs=x_input, - output="reshape_x", - param_attr=attr) - if y_shape[0] != 1: - attr = {"expand_times": [y_shape[0], 1, 1, 1]} - node.fluid_code.add_layer( - "expand", - inputs="reshape_x", - output="reshape_x", - param_attr=attr) - inputs = {"x": "reshape_x", "y": y_input} - node.fluid_code.add_layer( - op_type, inputs=inputs, output=node, param_attr=None) - return - else: - raise Exception("Unexpected situation happend") - - if len(x_shape) == 4 and len(y_shape) == 1: - if x_input.tf_data_format == "NHWC": - axis = 1 - else: - axis = -1 - attr = {"axis": axis} - inputs = {"x": x_input, "y": y_input} - node.fluid_code.add_layer( - op_type, inputs=inputs, output=node, param_attr=attr) - return - - is_sub_seq = True - for i in range(len(y_shape)): - index = -1 * i - 1 - if y_shape[index] != x_shape[index]: - is_sub_seq = False - if not is_sub_seq: - if x_shape.count(-1) > 2: - x_shape = self.decoder.infer_tensor_shape(x_input) - if y_shape.count(-1) > 2: - y_shape = self.decoder.infer_tensor_shape(y_input) - x_expand_times = [1] * len(x_shape) - y_expand_times = [1] * len(y_shape) - x_need_expand = False - y_need_expand = False - for i in range(len(y_shape)): - index = -1 * i - 1 - if y_shape[index] != x_shape[index]: - if y_shape[index] == 1: - y_expand_times[index] = x_shape[index] - y_need_expand = True - elif x_shape[index] == 1: - x_expand_times[index] = y_shape[index] - x_need_expand = True - else: - raise Exception("Unexpected situation happend") - if x_need_expand: - if len(x_expand_times) == 3 and x.tf_data_format == "NHWC": - x_expand_times = [x_expand_times[i] for i in [2, 0, 1]] - if len(x_expand_times) == 4 and x.tf_data_format == "NHWC": - x_expand_times = [x_expand_times[i] for i in [0, 3, 1, 2]] - attr = {"expand_times": x_expand_times} - node.fluid_code.add_layer( - "expand", inputs=x_input, output="x_tmp", param_attr=attr) - x_input = "x_tmp" - if y_need_expand: - if len(y_expand_times) == 3 and y.tf_data_format == "NHWC": - y_expand_times = [y_expand_times[i] for i in [2, 0, 1]] - if len(y_expand_times) == 4 and y.tf_data_format == "NHWC": - y_expand_times = [y_expand_times[i] for i in [0, 3, 1, 2]] - attr = {"expand_times": y_expand_times} - node.fluid_code.add_layer( - "expand", inputs=y_input, output="y_tmp", param_attr=attr) - y_input = "y_tmp" - inputs = {"x": x_input, "y": y_input} - node.fluid_code.add_layer( - op_type, inputs=inputs, output=node, param_attr=None) + layer_id = program.add_layer( + kernel="fluid.layers.{}".format(op_type), + inputs={"x": x.name, + "y": y.name}, + outputs=[node.name]) + program.layers[layer_id].input_shapes = {"x": x_shape, "y": y_shape} + + def NotEqual(self, node): + x = self.graph.get_node(node.layer.input[0]) + y = self.graph.get_node(node.layer.input[1]) + + program.add_layer( + kernel="fluid.layers.not_equal", + inputs={"x": x.name, + "y": y.name}, + outputs=[node.name]) def Placeholder(self, node): shape = node.out_shapes[0] assert len(shape) != 0, "Unknown shape of input nodes[{}].".format( node.layer_name) - if node.tf_data_format == "NHWC" and len(shape) == 4: - shape = [shape[i] for i in [0, 3, 1, 2]] - elif node.tf_data_format == "NCHW" and len(shape) == 4: - self.graph.data_format_propagation(node) dtype = node.dtype - attr = { - 'dtype': string(dtype), - 'shape': shape, - 'name': string(node.layer_name), - 'append_batch_size': False - } - - if shape[0] < 0: - self.batch_node = node - - node.fluid_code.add_layer( - "data", inputs=None, output=node, param_attr=attr) - - def OneShotIterator(self, node): - return self.Placeholder(node) + program.add_layer( + kernel="fluid.data", + inputs={}, + outputs=[node.name], + dtype=string(dtype), + shape=shape, + name=string(node.name)) def Const(self, node): shape = node.out_shapes[0] @@ -286,615 +197,871 @@ class TFOpMapper(OpMapper): if len(shape) == 0: assert value.size == 1, "Unexpected situation happend" shape = [1] - initializer = "Constant({})".format(value) - - self.weights[node.layer_name] = node.value - - if node.tf_data_format == "NHWC": - if len(shape) == 4: - shape = [shape[i] for i in [0, 3, 1, 2]] - if len(shape) == 3: - shape = [shape[i] for i in [2, 0, 1]] - self.weights[node.layer_name] = numpy.transpose(node.value, - (2, 0, 1)) - elif node.tf_data_format == "NCHW": - if len(shape) == 4: - self.graph.data_format_propagation(node) - - attr = { - 'dtype': string(dtype), - 'shape': shape, - 'name': string(node.layer_name), - 'default_initializer': initializer - } - node.fluid_code.add_layer( - "create_parameter", inputs=None, output=node, param_attr=attr) + if value == float('inf'): + value = "float('inf')" + program.add_layer( + kernel="fluid.layers.fill_constant", + inputs={}, + outputs=[node.name], + dtype=string(dtype), + shape=[1], + value=value) + return + + program.parameters[node.name] = node.value + program.add_layer( + kernel="fluid.layers.create_parameter", + inputs={}, + outputs=[node.name], + dtype=string(dtype), + shape=shape, + name=string(node.name), + default_initializer=initializer) def Transpose(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - perm = self.graph.get_node(node.layer.input[1], copy=True) + input = self.graph.get_node(node.layer.input[0]) + perm = self.graph.get_node(node.layer.input[1]) assert perm.layer_type == "Const", "Perm of transpose OP should be Const" - del self.weights[perm.layer_name.replace('/', '_')] - perm.fluid_code.clear() perm = perm.value.tolist() - if perm == [0, 3, 1, 2] and input.data_format == "NHWC": - input_name = input.layer_name - if hasattr(input, "index"): - input_name = input_name + "[{}]".format(input.index) - node.fluid_code.add_layer("{} = {}").format(node.layer_name, - input_name) - node.tf_data_format = "NCHW" - self.graph.data_format_propagation(node) - elif perm == [0, 2, 3, 1] and input.tf_data_format == "NCHW": - input_name = input.layer_name - if hasattr(input, "index"): - input_name = input_name + "[{}]".format(input.index) - node.fluid_code.add_layer("{} = {}").format(node.layer_name, - input_name) - node.tf_data_format = "NHWC" - self.graph.data_format_propagation(node) - elif len(input.out_shapes[0]) > 4: - tf_data_format = list(input.tf_data_format) - pd_data_format = list(input.pd_data_format) - new_perm = [i for i in range(len(perm))] - for i in range(len(perm)): - char0 = tf_data_format[i] - char1 = tf_data_format[perm[i]] - index0 = pd_data_format.index(char0) - index1 = pd_data_format.index(char1) - new_perm[index0] = index1 - node.tf_data_format = [tf_data_format[i] for i in perm] - node.pd_data_format = [pd_data_format[i] for i in perm] - attr = {'perm': new_perm} - node.fluid_code.add_layer( - "transpose", inputs=input, output=node, param_attr=attr) - elif len(node.out_shapes[0]) != 4: - attr = {'perm': perm} - node.fluid_code.add_layer( - "transpose", inputs=input, output=node, param_attr=attr) + program.add_layer( + kernel="fluid.layers.transpose", + inputs={"x": input.name}, + outputs=[node.name], + perm=perm) + + def Fill(self, node): + dims = self.graph.get_node(node.layer.input[0]) + input_value = self.graph.get_node(node.layer.input[1]) + inputs = dict() + attr = dict() + assert input_value.layer_type == "Const", "Value of fill OP should be Const" + if dims.layer_type == "Const": + attr["shape"] = dims.value.tolist() else: - raise Exception("Unexpected situation happend in Transpose OP") + inputs["shape"] = dims.name + attr["dtype"] = string(input_value.dtype) + attr["value"] = input_value.value - def MaxPool(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) + program.add_layer( + "fluid.layers.fill_constant", + inputs=inputs, + outputs=[node.name], + **attr) - in_shape = input.out_shapes[0] - if in_shape.count(-1) > 2: - in_shape = self.decoder.infer_tensor(input).shape + def DepthToSpace(self, node): + input = self.graph.get_node(node.layer.input[0]) + + block_size = node.get_attr("block_size") + data_format = node.get_attr("data_format").decode() + if data_format == "NHWC": + n, h, w, c = input.out_shapes[0] + else: + n, c, h, w = input.out_shapes[0] + + input_name = input.name + if data_format == "NHWC": + transpose_name = gen_name("depth_to_space", "transpose") + program.add_layer( + kernel="fluid.layers.transpose", + inputs={"x": input.name}, + outputs=[transpose_name], + perm=[0, 3, 1, 2]) + input_name = transpose_name + + shape = [0, block_size * block_size, -1, h, w] + reshape_name = gen_name("depth_to_space", "reshape") + program.add_layer( + kernel="fluid.layers.reshape", + inputs={"x": input_name}, + outputs=[reshape_name], + shape=shape) + + transpose_name = gen_name("depth_to_space", "transpose") + program.add_layer( + kernel="fluid.layers.transpose", + inputs={"x": reshape_name}, + outputs=[transpose_name], + perm=[0, 2, 1, 3, 4]) + + reshape_name = gen_name("depth_to_space", "reshape") + program.add_layer( + kernel="fluid.layers.reshape", + inputs={"x": transpose_name}, + outputs=[reshape_name], + shape=[0, c, h, w]) + + program.add_layer( + kernel="fluid.layers.pixel_shuffle", + inputs={"x": reshape_name}, + outputs=[node.name], + upscale_factor=block_size) + + if data_format == "NHWC": + program.add_layer( + kernel="fluid.layers.transpose", + inputs={"x": node.name}, + outputs=[node.name], + perm=[0, 2, 3, 1]) + + def MaxPool(self, node): + input = self.graph.get_node(node.layer.input[0]) k_size = node.get_attr("ksize") strides = node.get_attr("strides") data_format = node.get_attr("data_format").decode() pad_mode = node.get_attr("padding").decode() - channel_first = data_format == "NCHW" - if not channel_first: - in_shape = [in_shape[i] for i in [0, 3, 1, 2]] + input_name = input.name + if data_format == "NHWC": + transpose_name = gen_name("max_pool", "transpose") + program.add_layer( + kernel="fluid.layers.transpose", + inputs={"x": input.name}, + outputs=[transpose_name], + perm=[0, 3, 1, 2]) strides = [strides[i] for i in [0, 3, 1, 2]] k_size = [k_size[i] for i in [0, 3, 1, 2]] - else: - self.graph.data_format_propagation(node) - - attr = { - "pool_size": k_size[2:4], - "pool_type": string("max"), - "pool_padding": string(pad_mode), - "pool_stride": strides[2:4] - } - node.fluid_code.add_layer( - "pool2d", inputs=input, output=node, param_attr=attr) + input_name = transpose_name + + program.add_layer( + kernel="fluid.layers.pool2d", + inputs={"input": input_name}, + outputs=[node.name], + pool_size=k_size[2:4], + pool_type=string("max"), + pool_stride=strides[2:4], + pool_padding=string(pad_mode)) + + if data_format == "NHWC": + program.add_layer( + kernel="fluid.layers.transpose", + inputs={"x": node.name}, + outputs=[node.name], + perm=[0, 2, 3, 1]) def Conv2D(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - kernel = self.graph.get_node(node.layer.input[1], copy=True) - assert kernel.layer_type == "Const", "Kernel of Conv2D should be Const" - self.add_omit_nodes(kernel.layer_name, node.layer_name) + input = self.graph.get_node(node.layer.input[0]) + kernel = self.graph.get_node(node.layer.input[1]) - in_shape = input.out_shapes[0] - if in_shape.count(-1) > 2: - in_shape = self.decoder.infer_tensor(input).shape k_size = kernel.out_shapes[0] - if k_size.count(-1) > 2: - k_size = self.decoder.infer_tensor(kernel).shape - strides = node.get_attr("strides") dilations = node.get_attr("dilations") data_format = node.get_attr("data_format").decode() pad_mode = node.get_attr("padding").decode() - channel_first = data_format == "NCHW" + if data_format == "NHWC": + n, h, w, c = input.out_shapes[0] + else: + n, c, h, w = input.out_shapes[0] - self.weights[kernel.layer_name.replace('/', '_')] = numpy.transpose( - kernel.value, (3, 2, 0, 1)) + if kernel.layer_type == 'Const': + kernel_value = kernel.value + kernel_weight_name = kernel.name.replace('/', '_') + else: + kernel_value = self.decoder.infer_tensor(kernel) + if kernel.layer_type == 'Split': + kernel_weight_name = "{}_{}_kernel".format(node.name, + kernel.name) + else: + kernel_weight_name = kernel.name.replace('/', '_') + program.parameters[kernel_weight_name] = numpy.transpose(kernel_value, + (3, 2, 0, 1)) - if not channel_first: - in_shape = [in_shape[i] for i in [0, 3, 1, 2]] + input_name = input.name + if data_format == "NHWC": strides = [strides[i] for i in [0, 3, 1, 2]] dilations = [dilations[i] for i in [0, 3, 1, 2]] - else: - self.graph.data_format_propagation(node) - - attr = { - "bias_attr": False, - "param_attr": string(kernel.layer_name), - "num_filters": k_size[3], - "filter_size": k_size[0:2], - "stride": strides[2:4], - "dilation": dilations[2:4], - "padding": string(pad_mode) - } - node.fluid_code.add_layer( - "conv2d", inputs=input, output=node, param_attr=attr) + transpose_name = gen_name("conv2d", "transpose") + program.add_layer( + kernel="fluid.layers.transpose", + inputs={"x": input.name}, + outputs=[transpose_name], + perm=[0, 3, 1, 2]) + input_name = transpose_name + + if c == -1: + attr = {"shape": [0, k_size[2], 0, 0]} + node.fluid_code.add_layer( + "reshape", inputs=input, output=input, param_attr=attr) + program.add_layer( + kernel="fluid.layers.reshape", + inputs={"x": input_name}, + outputs=[input_name], + shape=[0, k_size[2], 0, 0]) + + program.add_layer( + kernel="fluid.layers.conv2d", + inputs={"input": input_name}, + outputs=[node.name], + bias_attr=False, + param_attr=string(kernel_weight_name), + num_filters=k_size[3], + filter_size=k_size[0:2], + stride=strides[2:4], + dilation=dilations[2:4], + padding=string(pad_mode)) + + if data_format == "NHWC": + program.add_layer( + kernel="fluid.layers.transpose", + inputs={"x": node.name}, + outputs=[node.name], + perm=[0, 2, 3, 1]) def BiasAdd(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - bias = self.graph.get_node(node.layer.input[1], copy=True) - axis = -1 - if input.tf_data_format == "NHWC" and len(input.out_shapes[0]) == 4: - axis = 1 - inputs = {"x": input, "y": bias} - attr = {"axis": axis} - node.fluid_code.add_layer( - "elementwise_add", inputs=inputs, output=node, param_attr=attr) + input = self.graph.get_node(node.layer.input[0]) + bias = self.graph.get_node(node.layer.input[1]) + program.add_layer( + kernel="fluid.layers.elementwise_add", + inputs={"x": input.name, + "y": bias.name}, + outputs=[node.name]) def FusedBatchNorm(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - gamma = self.graph.get_node(node.layer.input[1], copy=True) - beta = self.graph.get_node(node.layer.input[2], copy=True) - moving_mean = self.graph.get_node(node.layer.input[3], copy=True) - moving_var = self.graph.get_node(node.layer.input[4], copy=True) + input = self.graph.get_node(node.layer.input[0]) + gamma = self.graph.get_node(node.layer.input[1]) + beta = self.graph.get_node(node.layer.input[2]) + moving_mean = self.graph.get_node(node.layer.input[3]) + moving_var = self.graph.get_node(node.layer.input[4]) data_format = node.get_attr("data_format").decode() - channel_first = data_format == "NCHW" assert gamma.layer_type == "Const" assert beta.layer_type == "Const" assert moving_mean.layer_type == "Const" assert moving_var.layer_type == "Const" - self.add_omit_nodes(gamma.layer_name, node.layer_name) - self.add_omit_nodes(beta.layer_name, node.layer_name) - self.add_omit_nodes(moving_mean.layer_name, node.layer_name) - self.add_omit_nodes(moving_var.layer_name, node.layer_name) - if channel_first: - self.data_format_propagation(node) - - attr = { - "epsilon": node.get_attr("epsilon"), - "param_attr": string(gamma.layer_name), - "bias_attr": string(beta.layer_name), - "moving_mean_name": string(moving_mean.layer_name), - "moving_variance_name": string(moving_var.layer_name), - "is_test": True - } - - node.fluid_code.add_layer( - "batch_norm", inputs=input, output=node, param_attr=attr) - - def FusedBatchNormV3(self, node): - return self.FusedBatchNorm(node) + + input_name = input.name + if data_format == "NHWC": + transpose_name = gen_name("batch_norm", "transpose") + program.add_layer( + kernel="fluid.layers.transpose", + inputs={"x": input.name}, + outputs=[transpose_name], + perm=[0, 3, 1, 2]) + input_name = transpose_name + + program.add_layer( + kernel="fluid.layers.batch_norm", + inputs={"input": input_name}, + outputs=[node.name], + epsilon=node.get_attr("epsilon"), + param_attr=string(gamma.name), + bias_attr=string(beta.name), + moving_mean_name=string(moving_mean.name), + moving_variance_name=string(moving_var.name), + is_test=True) + + if data_format == "NHWC": + program.add_layer( + kernel="fluid.layers.transpose", + inputs={"x": node.name}, + outputs=[node.name], + perm=[0, 2, 3, 1]) + + def Mean(self, node): + input = self.graph.get_node(node.layer.input[0]) + reduce_idx = self.graph.get_node(node.layer.input[1]) + assert reduce_idx.layer_type == "Const", "Only support Const parameter[reduce_idx]" + dims = reduce_idx.value.tolist() + keep_dims = node.get_attr("keep_dims") + + program.add_layer( + kernel="fluid.layers.reduce_mean", + inputs={"input": input.name}, + outputs=[node.name], + dim=dims, + keep_dim=keep_dims) + + def Reshape(self, node): + input = self.graph.get_node(node.layer.input[0]) + param = self.graph.get_node(node.layer.input[1]) + + input_name = input.name + if input.dtype == 'bool': + cast_name = gen_name('reshape', 'cast') + program.add_layer( + kernel="fluid.layers.cast", + inputs={"x": input_name}, + outputs=[cast_name], + dtype="'int32'") + input_name = cast_name + + if param.layer_type == "Const": + shape = param.value.tolist() + program.add_layer( + kernel="fluid.layers.reshape", + inputs={"x": input_name}, + outputs=[node.name], + shape=shape) + else: + program.add_layer( + kernel="fluid.layers.reshape", + inputs={"x": input_name, + "shape": param.name}, + outputs=[node.name]) + if param.layer_type != "Const": + out_shape = numpy.array(node.out_shapes[0]) + if (out_shape > 0).any(): + out_shape[out_shape < 0] = 0 + program.add_layer( + kernel="fluid.layers.reshape", + inputs={"x": node.name}, + outputs=[node.name], + shape=out_shape.tolist()) + + if input.dtype == 'bool': + program.add_layer( + kernel="fluid.layers.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]) + assert paddings.layer_type == "Const", "Padding should be Const" + paddings = paddings.value.flatten().tolist() + + if len(input.out_shapes[0]) == 4: + if paddings[0] + paddings[1] + paddings[6] + paddings[7] == 0: + new_padding = paddings[2:6] + transpose_name = gen_name("pad", "transpose") + program.add_layer( + kernel="fluid.layers.transpose", + inputs={"x": input.name}, + outputs=[transpose_name], + perm=[0, 3, 1, 2]) + program.add_layer( + kernel="fluid.layers.pad2d", + inputs={"input": transpose_name}, + outputs=[node.name], + paddings=new_padding) + program.add_layer( + kernel="fluid.layers.transpose", + inputs={"x": node.name}, + outputs=[node.name], + perm=[0, 2, 3, 1]) + return + + program.add_layer( + kernel="fluid.layers.pad", + inputs={"x": input.name}, + outputs=[node.name], + paddings=paddings) + + def Squeeze(self, node): + input = self.graph.get_node(node.layer.input[0]) + squeeze_dims = node.get_attr('squeeze_dims') + program.add_layer( + kernel="fluid.layers.squeeze", + inputs={"input": input.name}, + outputs=[node.name], + axes=squeeze_dims) + + def Softmax(self, node): + input = self.graph.get_node(node.layer.input[0]) + axis = node.get_attr("axis") + program.add_layer( + kernel="fluid.layers.softmax", + inputs={"input": input.name}, + outputs=[node.name], + axis=axis) + + 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') + program.add_layer( + kernel="fluid.layers.cast", + inputs={"x": input.name}, + outputs=[cast_name], + dtype="'int32'") + input_name = cast_name + program.add_layer( + kernel="fluid.layers.shape", + inputs={"input": input_name}, + outputs=[node.name]) + + def ArgMax(self, node): + input = self.graph.get_node(node.layer.input[0]) + axis = self.graph.get_node(node.layer.input[1]) + assert axis.layer_type == "Const", "ArgMax only support Const parameter" + axis = axis.value + program.add_layer( + kernel="fluid.layers.argmax", + inputs={"x": input.name}, + outputs=[node.name], + axis=axis) + + def MatMul(self, node): + x = self.graph.get_node(node.layer.input[0]) + y = self.graph.get_node(node.layer.input[1]) + transpose_a = node.get_attr('transpose_a') + transpose_b = node.get_attr('transpose_b') + if transpose_a is None: + transpose_a = node.get_attr('adj_x') + if transpose_b is None: + transpose_b = node.get_attr('adj_y') + program.add_layer( + kernel="fluid.layers.matmul", + inputs={"x": x.name, + "y": y.name}, + outputs=[node.name], + transpose_x=transpose_a, + transpose_y=transpose_b) + + def BatchMatMul(self, node): + return self.MatMul(node) + + def BatchMatMulV2(self, node): + return self.MatMul(node) def DepthwiseConv2dNative(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - kernel = self.graph.get_node(node.layer.input[1], copy=True) + input = self.graph.get_node(node.layer.input[0]) + kernel = self.graph.get_node(node.layer.input[1]) assert kernel.layer_type == "Const", "Kernel of DepthwiseConv2DNative should be Const" - self.add_omit_nodes(kernel.layer_name, node.layer_name) in_shape = input.out_shapes[0] - if in_shape.count(-1) > 2: - in_shape = self.decoder.infer_tensor(input).shape k_size = kernel.out_shapes[0] - if k_size.count(-1) > 2: - k_size = self.decoder.infer_tensor(kernel).shape - strides = node.get_attr("strides") dilations = node.get_attr("dilations") data_format = node.get_attr("data_format").decode() pad_mode = node.get_attr("padding").decode() - channel_first = data_format == "NCHW" - self.weights[kernel.layer_name.replace('/', '_')] = numpy.transpose( - kernel.value, (2, 3, 0, 1)) + program.parameters[kernel.layer_name.replace( + '/', '_')] = numpy.transpose(kernel.value, (2, 3, 0, 1)) - if not channel_first: + input_name = input.name + if data_format == "NHWC": in_shape = [in_shape[i] for i in [0, 3, 1, 2]] strides = [strides[i] for i in [0, 3, 1, 2]] dilations = [dilations[i] for i in [0, 3, 1, 2]] - else: - self.data_format_propagation(node) - - attr = { - "bias_attr": False, - "param_attr": string(kernel.layer_name), - "num_filters": in_shape[1], - "filter_size": k_size[0:2], - "stride": strides[2:4], - "dilation": dilations[2:4], - "groups": k_size[3] * in_shape[1], - "use_cudnn": False, - "padding": string(pad_mode) - } - node.fluid_code.add_layer( - "conv2d", inputs=input, output=node, param_attr=attr) - - def Reshape(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - param = self.graph.get_node(node.layer.input[1], copy=True) - is_variable = False - if param.layer_type == "Const": - attr = {"shape": param.value.tolist()} - self.add_omit_nodes(param.layer_name, node.layer_name) - else: - # Here is a trick method to solove tensor parameter in tensorflow - shape = self.decoder.infer_shape_tensor(param, node.out_shapes[0]) - if shape.count(-1) <= 1: - attr = {"shape": shape} - self.add_omit_nodes(param.layer_name, node.layer_name) - elif shape.count(-1) == 2 and shape[0] == -1: - shape[0] = 0 - attr = {"shape": shape} - self.add_omit_nodes(param.layer_name, node.layer_name) - else: - assert len(param.out_shapes[ - 0]) == 1, "Unexpected situation of shape parameter" - attr = {"shape": [-1]} - node.fluid_code.add_layer( - "reshape", - inputs=param, - output="shape_param", - param_attr=attr) - attr = {"num_or_sections": param.out_shapes[0][0], "dim": 0} - node.fluid_code.add_layer( - "split", inputs="shape_param", output=node, param_attr=attr) - new_param = "[" - for i in range(param.out_shapes[0][0]): - new_param += (node.layer_name + "[{}]".format(i) + ", ") - new_param = new_param.strip(", ") + "]" - attr = {"shape": new_param} - is_variable = True - - # to change [192, -1]->[-1, 192], allways put -1 in the first dimension - # optimization for Paddle-Lite - in_shape = input.out_shapes[0] - if not is_variable and in_shape.count(-1) < 1: - total_size = 1 - for i in range(len(in_shape)): - total_size *= in_shape[i] - for i in range(len(attr["shape"])): - if attr["shape"][i] == 0: - attr["shape"][i] = in_shape[i] - if attr["shape"][i] != -1: - total_size /= attr["shape"][i] - if attr["shape"].count(-1) > 0: - index = attr["shape"].index(-1) - attr["shape"][index] = int(total_size) - attr["shape"][0] = -1 - - if len(input.out_shapes[0]) == 4 and node.tf_data_format == "NHWC": - if len(attr["shape"]) < 3: - perm = {"perm": [0, 2, 3, 1]} - node.fluid_code.add_layer( - "transpose", inputs=input, output=node, param_attr=perm) - node.fluid_code.add_layer( - "reshape", inputs=node, output=node, param_attr=attr) - return - - if len(attr["shape"]) == 4 and node.tf_data_format == "NHWC": - input_shape = self.decoder.infer_tensor(input).shape - if input_shape[1] == attr["shape"][1]: - attr["shape"] = [attr["shape"][i] for i in [0, 3, 1, 2]] - else: - perm = {"perm": [0, 2, 3, 1]} - node.fluid_code.add_layer( - "transpose", inputs=input, output=node, param_attr=perm) - node.fluid_code.add_layer( - "reshape", inputs=node, output=node, param_attr=attr) - perm = {"perm": [0, 3, 1, 2]} - node.fluid_code.add_layer( - "transpose", inputs=node, output=node, param_attr=perm) - return - if len(attr["shape"]) == 5: - attr["shape"] = [attr["shape"][i] for i in [0, 1, 4, 2, 3]] - - node.fluid_code.add_layer( - "reshape", inputs=input, output=node, param_attr=attr) + transpose_name = gen_name('depthwise_conv2d', 'transpose') + program.add_layer( + kernel="fluid.layers.transpose", + inputs={"x": input.name}, + outputs=[transpose_name], + perm=[0, 3, 1, 2]) + input_name = transpose_name + + program.add_layer( + kernel="fluid.layers.conv2d", + inputs={"input": input_name}, + outputs=[node.name], + num_filters=in_shape[1], + filter_size=k_size[0:2], + stride=strides[2:4], + dilation=dilations[2:4], + groups=k_size[3] * in_shape[1], + padding=string(pad_mode), + param_attr=string(kernel.layer_name), + bias_attr=False) + + if data_format == "NHWC": + program.add_layer( + kernel="fluid.layers.transpose", + inputs={"x": node.name}, + outputs=[node.name], + perm=[0, 2, 3, 1]) def AvgPool(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - - in_shape = input.out_shapes[0] - if in_shape.count(-1) > 2: - in_shape = self.decoder.infer_tensor(input).shape + input = self.graph.get_node(node.layer.input[0]) k_size = node.get_attr("ksize") strides = node.get_attr("strides") data_format = node.get_attr("data_format").decode() pad_mode = node.get_attr("padding").decode() - channel_first = data_format == "NCHW" - if not channel_first: - in_shape = [in_shape[i] for i in [0, 3, 1, 2]] + input_name = input.name + if data_format == "NHWC": + transpose_name = gen_name("avg_pool", "transpose") + program.add_layer( + kernel="fluid.layers.transpose", + inputs={"x": input.name}, + outputs=[transpose_name], + perm=[0, 3, 1, 2]) strides = [strides[i] for i in [0, 3, 1, 2]] k_size = [k_size[i] for i in [0, 3, 1, 2]] - else: - self.graph.data_format_propagation(node) - - attr = { - "pool_size": k_size[2:4], - "pool_type": string("avg"), - "pool_stride": strides[2:4], - "pool_padding": string(pad_mode) - } - node.fluid_code.add_layer( - "pool2d", inputs=input, output=node, param_attr=attr) - - def SplitV(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - num_sections = self.graph.get_node(node.layer.input[1], copy=True) - dim = self.graph.get_node(node.layer.input[2], copy=True) - assert num_sections.layer_type == "Const" - assert dim.layer_type == "Const" - self.add_omit_nodes(num_sections.layer_name, node.layer_name) - self.add_omit_nodes(dim.layer_name, node.layer_name) - dim = dim.value - if input.tf_data_format == "NHWC" and len(input.out_shapes[0]) == 4: - dim = nhwc_dim_to_nchw(input, dim) - attr = { - "num_or_sections": num_sections.value.tolist(), - "dim": dim.value - } - node.fluid_code.add_layer( - "split", inputs=input, output=node, param_attr=attr) - - def ConcatV2(self, node): - inputs = [ - self.graph.get_node( - name, copy=True) for name in node.layer.input[:-1] - ] - axis = self.graph.get_node(node.layer.input[-1], copy=True) - assert axis.layer_type == "Const" - self.add_omit_nodes(axis.layer_name, node.layer_name) - axis = axis.value - if inputs[0].tf_data_format == "NHWC" and len(inputs[0].out_shapes[ - 0]) == 4: - axis = nhwc_dim_to_nchw(inputs[0], axis) - attr = {"axis": axis} - node.fluid_code.add_layer( - "concat", inputs=inputs, output=node, param_attr=attr) - - def Tile(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - expand_times = self.graph.get_node(node.layer.input[1], copy=True) - self.add_omit_nodes(expand_times.layer_name, node.layer_name) - if expand_times.layer_type == "Const": - expand_times = expand_times.value.tolist() - else: - expand_times = self.decoder.infer_shape_tensor(expand_times) - if input.tf_data_format == "NHWC": - if len(input.out_shapes[0]) == 4: - expand_times = [expand_times[i] for i in [0, 3, 1, 2]] - elif len(input.out_shapes[0]) == 3: - expand_times = [expand_times[i] for i in [2, 0, 1]] - for i in range(len(expand_times)): - if expand_times[i] < 0: - expand_times[i] = 1 - - attr = {"expand_times": expand_times} - node.fluid_code.add_layer( - "expand", inputs=input, output=node, param_attr=attr) + input_name = transpose_name + + program.add_layer( + kernel="fluid.layers.pool2d", + inputs={"input": input_name}, + outputs=[node.name], + pool_size=k_size[2:4], + pool_type=string("avg"), + pool_stride=strides[2:4], + pool_padding=string(pad_mode)) + + if data_format == "NHWC": + program.add_layer( + kernel="fluid.layers.transpose", + inputs={"x": node.name}, + outputs=[node.name], + perm=[0, 2, 3, 1]) def Pack(self, node): - inputs = [ - self.graph.get_node( - name, copy=True) for name in node.layer.input - ] + inputs = [self.graph.get_node(name) for name in node.layer.input] + input_names = [i.name for i in inputs] axis = node.get_attr("axis") - if inputs[0].tf_data_format == "NHWC" and len(inputs[0].out_shapes[ - 0]) == 4: - tf_data_format = list(inputs[0].tf_data_format) - tf_data_format.insert(axis, str(len(tf_data_format))) - axis = nhwc_dim_to_nchw(inputs[0], axis) - pd_data_format = list(inputs[0].pd_data_format) - pd_data_format.insert(axis, str(len(pd_data_format))) - node.tf_data_format = "".join(tf_data_format) - node.pd_data_format = "".join(pd_data_format) - - attr = {"axis": axis} - node.fluid_code.add_layer( - "stack", inputs=inputs, output=node, param_attr=attr) - - def Pad(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - paddings = self.graph.get_node(node.layer.input[1], copy=True) - assert paddings.layer_type == "Const", "Padding should be Const" - self.add_omit_nodes(paddings.layer_name, node.layer_name) - paddings = paddings.value.flatten().tolist() - if input.tf_data_format == "NHWC" and len(input.out_shapes[0]) == 4: - paddings = [paddings[i] for i in [0, 1, 6, 7, 2, 3, 4, 5]] + program.add_layer( + kernel="fluid.layers.stack", + inputs={"x": input_names}, + outputs=[node.name], + axis=axis) + if len(node.out_shapes[0]) == 1: + program.add_layer( + kernel="fluid.layers.reshape", + inputs={"x": node.name}, + outputs=[node.name], + shape=[-1]) + + def Unpack(self, node): + input = self.graph.get_node(node.layer.input[0]) + axis = node.get_attr("axis") + num = node.get_attr("num") + shape = input.out_shapes[0] + input_name = input.name + if len(shape) == 1: + if shape[0] > 0 and num == shape[0]: + program.add_layer( + kernel="fluid.layers.unsqueeze", + inputs={"input": input.name}, + outputs=[node.name], + axes=[0]) + input_name = node.name + axis = 1 + else: + raise Exception("Unexpected situation happend in Unpack OP") + program.add_layer( + kernel="fluid.layers.unstack", + inputs={"x": input_name}, + outputs=["{}_p{}".format(node.layer_name, i) for i in range(num)], + axis=axis, + num=num) - pad_op = "pad" - if len(input.out_shapes[0]) == 4: - if paddings[0] + paddings[1] + paddings[2] + paddings[3] == 0: - paddings = paddings[4:] - pad_op = "pad2d" - attr = {"paddings": paddings} - node.fluid_code.add_layer( - pad_op, inputs=input, output=node, param_attr=attr) - - def MirrorPad(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - paddings = self.graph.get_node(node.layer.input[1], copy=True) - assert paddings.layer_type == "Const", "Padding should be Const" - self.add_omit_nodes(paddings.layer_name, node.layer_name) - paddings = paddings.value.flatten().tolist() - mode = node.get_attr("mode").decode() - assert mode == "REFLECT", "Only support 'REFLECT` mode in MirrorPad" - if input.tf_data_format == "NHWC" and len(input.out_shapes[0]) == 4: - paddings = [paddings[i] for i in [0, 1, 6, 7, 2, 3, 4, 5]] + def ConcatV2(self, node): + inputs = [self.graph.get_node(name) for name in node.layer.input[:-1]] + axis = self.graph.get_node(node.layer.input[-1]) + assert axis.layer_type == "Const", "axis for ConcatV2 must be type Const" + axis = axis.value + if axis < 0: + 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') + program.add_layer( + kernel="fluid.layers.cast", + inputs={"x": ipt.name}, + outputs=[cast_name], + dtype="'int32'") + input_names[i] = cast_name + program.add_layer( + kernel="fluid.layers.concat", + inputs={"input": input_names}, + outputs=[node.name], + axis=axis) + if node.dtype == 'bool': + program.add_layer( + kernel="fluid.layers.cast", + inputs={"x": node.name}, + outputs=[node.name], + dtype="'bool'") - pad_op = "pad" - if len(input.out_shapes[0]) == 4: - if paddings[0] + paddings[1] + paddings[2] + paddings[3] == 0: - paddings = paddings[4:] - pad_op = "pad2d" - attr = {"paddings": paddings, "mode": string("reflect")} - node.fluid_code.add_layer( - pad_op, inputs=input, output=node, param_attr=attr) + def StridedSlice(self, node): + input = self.graph.get_node(node.layer.input[0]) + begin = self.graph.get_node(node.layer.input[1]) + end = self.graph.get_node(node.layer.input[2]) + strides = self.graph.get_node(node.layer.input[3]) - def Range(self, node): - start = self.graph.get_node(node.layer.input[0], copy=True) - limit = self.graph.get_node(node.layer.input[1], copy=True) - delta = self.graph.get_node(node.layer.input[2], copy=True) - self.add_omit_nodes(start.layer_name, node.layer_name) - self.add_omit_nodes(limit.layer_name, node.layer_name) - self.add_omit_nodes(delta.layer_name, node.layer_name) - if start.layer_type == "Const": - start = start.value + if strides.layer_type == "Const": + strides = strides.value.tolist() else: - start = self.decoder.infer_tensor(start) - if limit.layer_type == "Const": - limit = limit.value + strides = self.decoder.infer_shape_tensor(strides) + if begin.layer_type == "Const": + begin = begin.value.tolist() else: - limit = self.decoder.infer_tensor(limit) - if delta.layer_type == "Const": - delta = delta.value + begin = self.decoder.infer_shape_tensor(begin) + if end.layer_type == "Const": + end = end.value.tolist() else: - delta = self.decoder.infer_tensor(delta) + end = self.decoder.infer_shape_tensor(end) - inputs = {"start": start, "end": limit, "step": delta} - attr = {"dtype": string(node.dtype)} - node.fluid_code.add_layer( - "range", inputs=inputs, output=node, param_attr=attr) - - def Mean(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - reduce_idx = self.graph.get_node(node.layer.input[1], copy=True) - assert reduce_idx.layer_type == "Const", "Only support Const parameter[reduce_idx]" - dims = reduce_idx.value.tolist() - keep_dims = node.get_attr("keep_dims") - - if input.tf_data_format == "NHWC" and len(input.out_shapes[0]) == 4: - for i in range(len(dims)): - dims[i] = nhwc_dim_to_nchw(input, dims[i]) - - attr = {"dim": dims, "keep_dim": keep_dims} - node.fluid_code.add_layer( - "reduce_mean", inputs=input, output=node, param_attr=attr) - - def MatMul(self, node): - x = self.graph.get_node(node.layer.input[0], copy=True) - y = self.graph.get_node(node.layer.input[1], copy=True) - transpose_a = node.get_attr('transpose_a') - transpose_b = node.get_attr('transpose_b') - inputs = {"x": x, "y": y} - # fix paddle shape infer problem - # should be removed after paddle 1.6 - if x.out_shapes[0][-1] < 0 and y.out_shapes[0][0] > 0: - shape = x.out_shapes[0] - shape[-1] = y.out_shapes[0][0] - attr = {"shape": shape} - node.fluid_code.add_layer( - "reshape", inputs=x, output=x, param_attr=attr) - attr = {"transpose_x": transpose_a, "transpose_y": transpose_b} - node.fluid_code.add_layer( - "matmul", inputs=inputs, output=node, param_attr=attr) - - def ArgMax(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - axis = self.graph.get_node(node.layer.input[1], copy=True) - assert axis.layer_type == "Const", "ArgMax only support Const parameter" - self.add_omit_nodes(axis.layer_name, node.layer_name) - axis = axis.value - if input.tf_data_format == "NHWC" and len(input.out_shapes[0]) == 4: - axis = nhwc_dim_to_nchw(input, axis) - attr = {"axis": axis} - node.fluid_code.add_layer( - "argmax", inputs=input, output=node, param_attr=attr) - - def StridedSlice(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - begin = self.graph.get_node(node.layer.input[1], copy=True) - end = self.graph.get_node(node.layer.input[2], copy=True) - strides = self.graph.get_node(node.layer.input[3], copy=True) - assert begin.layer_type == "Const" - assert end.layer_type == "Const" - assert strides.layer_type == "Const" - self.add_omit_nodes(begin.layer_name, node.layer_name) - self.add_omit_nodes(end.layer_name, node.layer_name) - self.add_omit_nodes(strides.layer_name, node.layer_name) - strides = strides.value.tolist() - assert len(set(strides)) == 1 and strides[0] == 1 - - begin = begin.value.tolist() - end = end.value.tolist() - if input.tf_data_format == "NHWC" and len(input.out_shapes[0]) == 4: - begin = [begin[i] for i in [0, 3, 1, 2]] - end = [end[i] for i in [0, 3, 1, 2]] + assert len(set(strides)) == 1 and strides[ + 0] == 1, "Only support strides be 1 in StridedSlice OP" + if len(begin) < len(input.out_shapes[0]): + begin = begin + [0] * (len(input.out_shapes[0]) - len(begin)) + if len(end) < len(input.out_shapes[0]): + end = end + [0] * (len(input.out_shapes[0]) - len(end)) for i in range(len(end)): if end[i] == 0: end[i] = 999999 - attr = { - "axes": [i for i in range(len(strides))], - "starts": begin, - "ends": end - } - + begin_mask = node.get_attr('begin_mask') + end_mask = node.get_attr('end_mask') + ellipsis_mask = node.get_attr('ellipsis_mask') + new_axis_mask = node.get_attr('new_axis_mask') shrink_axis_mask = node.get_attr('shrink_axis_mask') - squeeze_dims = list() - for i in range(len(begin)): - x = shrink_axis_mask >> i & 1 - if x == 1: - squeeze_dims.append(i) - node.fluid_code.add_layer( - "slice", inputs=input, output=node, param_attr=attr) - if shrink_axis_mask > 0 and len(input.out_shapes[0]) == 5: - attr = {"axes": squeeze_dims} - node.fluid_code.add_layer( - "squeeze", inputs=node, output=node, param_attr=attr) + + assert ellipsis_mask == 0, "(OP:{} Name:{})Only support ellipsis_mask be 0[now: {}] n StridedSlice OP".format( + node.layer_type, node.layer.name, ellipsis_mask) + + # TODO codes without validation + # Use it carefully + new_begin = list() + new_end = list() + new_axes = list() + shrink_axes = list() + for i, item in enumerate(begin): + mask = (new_axis_mask >> i) & 1 + if mask != 0: + new_axes.append(i) + continue + + mask = (shrink_axis_mask >> i) & 1 + if mask != 0: + shrink_axes.append(i) + + mask = (begin_mask >> i) & 1 + if mask != 0: + new_begin.append(0) + else: + new_begin.append(item) + + mask = (end_mask >> i) & 1 + if mask != 0: + new_end.append(999999) + else: + new_end.append(end[i]) + + program.add_layer( + kernel="fluid.layers.slice", + inputs={"input": input.name}, + outputs=[node.name], + axes=[i for i in range(len(new_begin))], + starts=new_begin, + ends=new_end) + if len(new_axes) > 0: + program.add_layer( + kernel="fluid.layers.unsqueeze", + inputs={"input": node.name}, + outputs=[node.name], + axes=new_axes) + if len(shrink_axes) > 0: + if len(input.out_shapes[0]) + len(new_axes) <= 1: + pass + else: + program.add_layer( + kernel="fluid.layers.squeeze", + inputs={"input": node.name}, + outputs=[node.name], + axes=shrink_axes) + + def Split(self, node): + dim = self.graph.get_node(node.layer.input[0]) + input = self.graph.get_node(node.layer.input[1]) + assert dim.layer_type == "Const" + num_split = node.get_attr('num_split') + dim = dim.value + + program.add_layer( + kernel="fluid.layers.split", + inputs={"input": input.name}, + outputs=[ + "{}_p{}".format(node.layer_name, i) for i in range(num_split) + ], + num_or_sections=num_split, + dim=dim) def Slice(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - begin = self.graph.get_node(node.layer.input[1], copy=True) - size = self.graph.get_node(node.layer.input[2], copy=True) - self.add_omit_nodes(begin.layer_name, node.layer_name) - self.add_omit_nodes(size.layer_name, node.layer_name) + input = self.graph.get_node(node.layer.input[0]) + begin = self.graph.get_node(node.layer.input[1]) + size = self.graph.get_node(node.layer.input[2]) + + inputs = {"x": input.name} + attrs = {} if begin.layer_type == "Const": begin = begin.value.tolist() + attrs['offsets'] = begin else: + # shape = begin.out_shapes[0] + # reshape_name = gen_name("slice", "reshape") + # program.add_layer( + # kernel="fluid.layers.reshape", + # inputs={"x": begin.name}, + # outputs=[reshape_name], + # shape=shape) + # inputs['offsets'] = reshape_name begin = self.decoder.infer_tensor(begin).tolist() - if size.layer_type == "const": + attrs['offsets'] = begin + if size.layer_type == "Const": size = size.value.tolist() + attrs['shape'] = size else: - size = self.decoder.infer_tensor(size).tolist() + shape = size.out_shapes[0] + reshape_name = gen_name("slice", "reshape") + program.add_layer( + kernel="fluid.layers.reshape", + inputs={"x": size.name}, + outputs=[reshape_name], + shape=shape) + inputs['shape'] = reshape_name + program.add_layer( + kernel="fluid.layers.crop_tensor", + inputs=inputs, + outputs=[node.name], + **attrs) - if input.tf_data_format == "NHWC" and len(input.out_shapes[0]) == 4: - size = [size[i] for i in [0, 3, 1, 2]] - begin = [begin[i] for i in [0, 3, 1, 2]] + def ResizeNearestNeighbor(self, node): + input = self.graph.get_node(node.layer.input[0]) + resize_shape = self.graph.get_node(node.layer.input[1]) + data_format = "NHWC" + inputs = {"input": input.name} + attrs = {"align_corners": node.get_attr("align_corners")} - for i in range(len(size)): - if size[i] < 0: - size[i] = 99999999 - else: - size[i] = size[i] + begin[i] + if resize_shape.layer_type == "Const": + resize_shape = resize_shape.value.tolist() + attrs["out_shape"] = resize_shape + else: + shape = resize_shape.out_shapes[0] + reshape_name = gen_name("resize_nearest", "reshape") + program.add_layer( + kernel="fluid.layers.reshape", + inputs={"x": resize_shape.name}, + outputs=[reshape_name], + shape=shape) + inputs["out_shape"] = reshape_name + + if data_format == "NHWC": + transpose_name = gen_name("resize_nearest", "reshape") + program.add_layer( + kernel="fluid.layers.transpose", + inputs={"x": input.name}, + outputs=[transpose_name], + perm=[0, 3, 1, 2]) + inputs["input"] = transpose_name + + program.add_layer( + kernel="fluid.layers.resize_nearest", + inputs=inputs, + outputs=[node.name], + **attrs) + + if data_format == "NHWC": + program.add_layer( + kernel="fluid.layers.transpose", + inputs={"x": node.name}, + outputs=[node.name], + perm=[0, 2, 3, 1]) + + def ResizeBilinear(self, node): + input = self.graph.get_node(node.layer.input[0]) + resize_shape = self.graph.get_node(node.layer.input[1]) + data_format = "NHWC" + inputs = {"input": input.name} + attrs = {"align_corners": node.get_attr("align_corners")} + + if resize_shape.layer_type == "Const": + resize_shape = resize_shape.value.tolist() + attrs["out_shape"] = resize_shape + else: + shape = resize_shape.out_shapes[0] + reshape_name = gen_name("resize_bilinear", "reshape") + program.add_layer( + kernel="fluid.layers.reshape", + inputs={"x": resize_shape.name}, + outputs=[reshape_name], + shape=shape) + inputs["out_shape"] = reshape_name + + if data_format == "NHWC": + transpose_name = gen_name("resize_bilinear", "reshape") + program.add_layer( + kernel="fluid.layers.transpose", + inputs={"x": input.name}, + outputs=[transpose_name], + perm=[0, 3, 1, 2]) + inputs["input"] = transpose_name + + program.add_layer( + kernel="fluid.layers.resize_bilinear", + inputs=inputs, + outputs=[node.name], + **attrs) + + if data_format == "NHWC": + program.add_layer( + kernel="fluid.layers.transpose", + inputs={"x": node.name}, + outputs=[node.name], + perm=[0, 2, 3, 1]) + + def Cast(self, node): + input = self.graph.get_node(node.layer.input[0]) + dtype = node.dtype + program.add_layer( + kernel="fluid.layers.cast", + inputs={"x": input.name}, + outputs=[node.name], + dtype=string(dtype)) + + def Sum(self, node): + input = self.graph.get_node(node.layer.input[0]) + reduce_idx = self.graph.get_node(node.layer.input[1]) + assert reduce_idx.layer_type == "Const", "Only support Const parameter[reduce_idx]" + keep_dims = node.get_attr("keep_dims") + dim = reduce_idx.value.tolist() + + program.add_layer( + kernel="fluid.layers.reduce_sum", + inputs={"input": input.name}, + outputs=[node.name], + dim=dim, + keep_dim=keep_dims) + + def Max(self, node): + input = self.graph.get_node(node.layer.input[0]) + reduce_idx = self.graph.get_node(node.layer.input[1]) + assert reduce_idx.layer_type == "Const", "Only support Const parameter[reduce_idx]" + keep_dims = node.get_attr("keep_dims") + dim = reduce_idx.value.tolist() + program.add_layer( + kernel="fluid.layers.reduce_max", + inputs={"input": input.name}, + outputs=[node.name], + dim=dim, + keep_dim=keep_dims) - attr = { - "axes": [i for i in range(len(size))], - "starts": begin, - "ends": size - } - node.fluid_code.add_layer( - "slice", inputs=input, output=node, param_attr=attr) + def RandomUniform(self, node): + shape = self.graph.get_node(node.layer.input[0]) + if shape.layer_type == "Const": + shape = shape.value.tolist() + program.add_layer( + kernel="fluid.layers.uniform_random", + inputs={}, + outputs=[node.name], + shape=shape, + min=0.0, + max=0.9999) + else: + program.add_layer( + kernel="fluid.layers.uniform_random", + inputs={'shape': shape.name}, + outputs=[node.name], + min=0.0, + max=0.9999) def Conv2DBackpropInput(self, node): - out_shape = self.graph.get_node(node.layer.input[0], copy=True) - kernel = self.graph.get_node(node.layer.input[1], copy=True) - input = self.graph.get_node(node.layer.input[2], copy=True) + out_shape = self.graph.get_node(node.layer.input[0]) + kernel = self.graph.get_node(node.layer.input[1]) + input = self.graph.get_node(node.layer.input[2]) assert kernel.layer_type == "Const", "Kernel of Conv2DBackpropInput should be Const" - self.add_omit_nodes(kernel.layer_name, node.layer_name) - self.add_omit_nodes(out_shape.layer_name, node.layer_name) - if out_shape.layer_type == "Const": out_shape = out_shape.value.tolist() else: @@ -912,163 +1079,215 @@ class TFOpMapper(OpMapper): strides = node.get_attr("strides") dilations = node.get_attr("dilations") data_format = node.get_attr("data_format").decode() - channel_first = data_format == "NCHW" - self.weights[kernel.layer_name.replace('/', '_')] = numpy.transpose( - kernel.value, (3, 2, 0, 1)) - if not channel_first: + program.parameters[kernel.layer_name.replace( + '/', '_')] = numpy.transpose(kernel.value, (3, 2, 0, 1)) + + input_name = input.name + if data_format == "NHWC": in_shape = [in_shape[i] for i in [0, 3, 1, 2]] strides = [strides[i] for i in [0, 3, 1, 2]] dilations = [dilations[i] for i in [0, 3, 1, 2]] - else: - self.data_format_propagation(node) - - attr = { - "bias_attr": False, - "param_attr": string(kernel.layer_name), - "num_filters": k_size[2], - "filter_size": k_size[0:2], - "stride": strides[2:4], - "dilation": dilations[2:4], - "padding": string(pad_mode), - "output_size": out_shape[1:3] - } - node.fluid_code.add_layer( - "conv2d_transpose", inputs=input, output=node, param_attr=attr) + transpose_name = gen_name("conv2dbackpropinput", "transpose") + program.add_layer( + kernel="fluid.layers.transpose", + inputs={"x": input.name}, + outputs=[transpose_name], + perm=[0, 3, 1, 2]) + input_name = transpose_name + + program.add_layer( + kernel="fluid.layers.conv2d_transpose", + inputs={"input": input_name}, + outputs=[node.name], + bias_attr=False, + param_attr=string(kernel.layer_name), + num_filters=k_size[2], + filter_size=k_size[0:2], + stride=strides[2:4], + dilation=dilations[2:4], + padding=string(pad_mode), + output_size=out_shape[1:3]) + + if data_format == "NHWC": + program.add_layer( + kernel="fluid.layers.transpose", + inputs={"x": node.name}, + outputs=[node.name], + perm=[0, 2, 3, 1]) - def Max(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - reduce_idx = self.graph.get_node(node.layer.input[1], copy=True) - assert reduce_idx.layer_type == "Const", "Only support Const parameter[reduce_idx]" - keep_dims = node.get_attr("keep_dims") - dim = reduce_idx.value.tolist() - if input.tf_data_format == "NHWC" and len(input.out_shapes[0]) == 4: - dim = nhwc_dim_to_nchw(input, dim) - - attr = {"dim": dim, "keep_dim": keep_dims} - node.fluid_code.add_layer( - "reduce_max", inputs=input, output=node, param_attr=attr) - - def Sum(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - reduce_idx = self.graph.get_node(node.layer.input[1], copy=True) - assert reduce_idx.layer_type == "Const", "Only support Const parameter[reduce_idx]" - keep_dims = node.get_attr("keep_dims") - dim = reduce_idx.value.tolist() - if input.tf_data_format == "NHWC" and len(input.out_shapes[0]) == 4: - dim = nhwc_dim_to_nchw(input, dim) - - attr = {"dim": dim, "keep_dim": keep_dims} - node.fluid_code.add_layer( - "reduce_sum", inputs=input, output=node, param_attr=attr) - - def Cast(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - dtype = node.dtype_map[node.get_attr('DstT')] - attr = {"dtype": string(dtype)} - node.fluid_code.add_layer( - "cast", inputs=input, output=node, param_attr=attr) - - def Split(self, node): - dim = self.graph.get_node(node.layer.input[0], copy=True) - input = self.graph.get_node(node.layer.input[1], copy=True) - self.add_omit_nodes(dim.layer_name, node.layer_name) - num_split = node.get_attr('num_split') - dim = dim.value - if input.tf_data_format == "NHWC" and len(input.out_shapes[0]) == 4: - dim = nhwc_dim_to_nchw(input, dim) - - attr = {"num_or_sections": num_split, "dim": dim} - node.fluid_code.add_layer( - "split", inputs=input, output=node, param_attr=attr) - - def Squeeze(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - squeeze_dims = node.get_attr('squeeze_dims') - if input.tf_data_format == "NHWC" and len(input.out_shapes[0]) == 4: - for i in range(len(squeeze_dims)): - squeeze_dims[i] = nhwc_dim_to_nchw(input, squeeze_dims[i]) - attr = {"axes": squeeze_dims} - node.fluid_code.add_layer( - "squeeze", inputs=input, output=node, param_attr=attr) + def Tile(self, node): + input = self.graph.get_node(node.layer.input[0]) + expand_times = self.graph.get_node(node.layer.input[1]) + inputs = {"x": input.name} + attr = dict() + if expand_times.layer_type == "Const": + expand_times = expand_times.value.tolist() + attr["expand_times"] = expand_times + else: + inputs["expand_times"] = expand_times.name - def Softmax(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - axis = node.get_attr("axis") - if axis is None: - axis = -1 + len(input.out_shapes[0]) - if input.tf_data_format == "NHWC" and len(input.out_shapes[0]) == 4: - axis = nhwc_dim_to_nchw(input, axis) - attr = {"axis": axis} - node.fluid_code.add_layer( - "softmax", inputs=input, output=node, param_attr=attr) + program.add_layer( + kernel="fluid.layers.expand", + inputs=inputs, + outputs=[node.name], + **attr) - def ResizeNearestNeighbor(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - resize_shape = self.graph.get_node(node.layer.input[1], copy=True) - self.add_omit_nodes(resize_shape.layer_name, node.layer_name) - if resize_shape.layer_type == "Const": - resize_shape = resize_shape.value.tolist() - else: - resize_shape = self.decoder.infer_shape_tensor(resize_shape, - node.out_shapes[0]) - align_corners = node.get_attr("align_corners") - attr = {"align_corners": align_corners, "out_shape": resize_shape} - node.fluid_code.add_layer( - "resize_nearest", inputs=input, output=node, param_attr=attr) + def Range(self, node): + start = self.graph.get_node(node.layer.input[0]) + limit = self.graph.get_node(node.layer.input[1]) + delta = self.graph.get_node(node.layer.input[2]) + inputs = dict() + attr = dict() - def ResizeBilinear(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - resize_shape = self.graph.get_node(node.layer.input[1], copy=True) - self.add_omit_nodes(resize_shape.layer_name, node.layer_name) - if resize_shape.layer_type == "Const": - resize_shape = resize_shape.value.tolist() + dtype = 'int32' + if start.dtype.startswith('float'): + dtype = start.dtype + if start.layer_type == "Const": + attr["start"] = start.value else: - resize_shape = self.decoder.infer_shape_tensor(resize_shape, - node.out_shapes[0]) - align_corners = node.get_attr("align_corners") - attr = { - "align_corners": align_corners, - "out_shape": resize_shape, - "align_mode": 1 - } - node.fluid_code.add_layer( - "resize_bilinear", inputs=input, output=node, param_attr=attr) - - def GreaterEqual(self, node): - x = self.graph.get_node(node.layer.input[0], copy=True) - y = self.graph.get_node(node.layer.input[1], copy=True) - inputs = {"x": x, "y": y} - node.fluid_code.add_layer( - "greater_equal", inputs=inputs, output=node, param_attr=None) - - def RandomUniform(self, node): - shape = self.graph.get_node(node.layer.input[0], copy=True) - self.add_omit_nodes(shape.layer_name, node.layer_name) - if shape.layer_type == "Const": - shape = shape.value.tolist() + inputs["start"] = start.name + if limit.dtype.startswith('float'): + dtype = limit.dtype + if limit.layer_type == "Const": + attr["end"] = limit.value else: - shape = self.decoder.infer_shape_tensor(shape) - if len(shape) == 4 and node.tf_data_format == "NHWC": - shape = [shape[i] for i in [0, 3, 1, 2]] - attr = {"shape": shape, "min": 0.0, "max": 0.9999} - if shape[0] < 0: - input = self.batch_node - node.fluid_code.add_layer( - "uniform_random_batch_size_like", - inputs=input, - output=node, - param_attr=attr) + inputs["end"] = limit.name + if delta.dtype.startswith('float'): + dtype = delta.dtype + if delta.layer_type == "Const": + attr["step"] = delta.value else: - node.fluid_code.add_layer( - "uniform_random", inputs=None, output=node, param_attr=attr) + inputs["step"] = delta.name + node.set_dtype(dtype) + attr["dtype"] = string(node.dtype) + + program.add_layer( + kernel="fluid.layers.range", + inputs=inputs, + outputs=[node.name], + **attr) def SquaredDifference(self, node): + x = self.graph.get_node(node.layer.input[0]) + y = self.graph.get_node(node.layer.input[1]) + inputs = {"x": x.name, "y": y.name} + x_shape = x.out_shapes[0] + y_shape = y.out_shapes[0] + layer_id = program.add_layer( + "fluid.layers.elementwise_sub", inputs=inputs, outputs=[node.name]) + program.layers[layer_id].input_shapes = {"x": x_shape, "y": y_shape} + + inputs = {"x": node.name, "y": node.name} + x_shape = node.out_shapes[0] + y_shape = node.out_shapes[0] + layer_id = program.add_layer( + "fluid.layers.elementwise_mul", inputs=inputs, outputs=[node.name]) + program.layers[layer_id].input_shapes = {"x": x_shape, "y": y_shape} + + def OneHot(self, node): + input = self.graph.get_node(node.layer.input[0]) + depth = self.graph.get_node(node.layer.input[1]) + on_value = self.graph.get_node(node.layer.input[2]) + off_value = self.graph.get_node(node.layer.input[3]) + assert depth.layer_type == 'Const', 'Parameter depth should be Const in OneHot' + assert on_value.layer_type == 'Const', 'Parameter on_value should be Const in OneHot' + assert off_value.layer_type == 'Const', 'Parameter off_value should be Const in OneHot' + + attr = {'depth': depth.value} + on_value = on_value.value + off_value = off_value.value + assert math.fabs(on_value - + 1.0) < 1e-06, "on_value should be 1 in OneHot" + assert math.fabs(off_value - + 0.0) < 1e-06, "off_value should be 0 in OneHot" + + program.add_layer( + "fluid.one_hot", + inputs={"input": input.name}, + outputs=[node.name], + depth=depth.value) + + def Pow(self, node): + x = self.graph.get_node(node.layer.input[0]) + factor = self.graph.get_node(node.layer.input[1]) + inputs = {"x": x.name} + attr = dict() + if factor.layer_type == 'Const': + attr["factor"] = factor.value.tolist() + else: + inputs["factor"] = factor.name + program.add_layer( + "fluid.layers.pow", inputs=inputs, outputs=[node.name], **attr) + + def All(self, node): + input = self.graph.get_node(node.layer.input[0]) + reduce_idx = self.graph.get_node(node.layer.input[1]) + assert reduce_idx.layer_type == "Const", "Only support Const parameter[reduce_idx]" + attr = dict() + attr["dim"] = reduce_idx.value.tolist() + attr["keep_dim"] = node.get_attr("keep_dims") + + input_name = input.name + if input.dtype != "bool": + input_name = gen_name("all", "cast") + program.add_layer( + "fluid.layers.cast", + inputs={"x": input.name}, + outputs=[input_name], + dtype=string("bool")) + program.add_layer( + "fluid.layers.reduce_all", + inputs={"input": input_name}, + outputs=[node.name], + **attr) + + node.layer.attr['dtype'].type = 10 + + def GatherV2(self, node): + embeddings = self.graph.get_node(node.layer.input[0]) + index = self.graph.get_node(node.layer.input[1]) + axis = self.graph.get_node(node.layer.input[2]) + assert axis.layer_type == 'Const', "Only support Const parameter[axis]" + axis = axis.value.tolist() + assert axis == 0, "Only support axis=0 in GatherV2 OP" + index_name = index.name + if len(index.out_shapes[0]) != 1: + reshape_name = gen_name("gather", "reshape") + index_name = reshape_name + program.add_layer( + "fluid.layers.reshape", + inputs={"x": index.name}, + outputs=[reshape_name], + shape=[-1]) + inputs = {'input': embeddings.name, 'index': index_name} + program.add_layer( + "fluid.layers.gather", + inputs=inputs, + outputs=[node.name], + overwrite=False) + if len(index.out_shapes[0]) != 1: + out_shape = node.out_shapes[0] + program.add_layer( + kernel="fluid.layers.reshape", + inputs={"x": node.name}, + outputs=[node.name], + shape=out_shape) + + def ExpandDims(self, node): x = self.graph.get_node(node.layer.input[0], copy=True) y = self.graph.get_node(node.layer.input[1], copy=True) - inputs = {"x": x, "y": y} - node.fluid_code.add_layer( - "elementwise_sub", inputs=inputs, output=node, param_attr=None) - inputs = {"x": node, "y": node} - node.fluid_code.add_layer( - "elementwise_mul", inputs=inputs, output=node, param_attr=None) + inputs = {"input": x.name} + attr = dict() + if y.layer_type == 'Const': + dim = y.value.tolist() + if not isinstance(dim, list): + dim = [dim] + attr['axes'] = dim + else: + inputs['axes'] = y.name + program.add_layer( + "fluid.layers.unsqueeze", + inputs=inputs, + outputs=[node.name], + **attr) diff --git a/x2paddle/op_mapper/tf_op_mapper_nhwc.py b/x2paddle/op_mapper/tf_op_mapper_nhwc.py deleted file mode 100644 index a83a303e5f0fe3f21f32b44c06c7c5d44b59bd4d..0000000000000000000000000000000000000000 --- a/x2paddle/op_mapper/tf_op_mapper_nhwc.py +++ /dev/null @@ -1,1115 +0,0 @@ -# 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. - -from x2paddle.decoder.tf_decoder import TFGraph -from x2paddle.core.op_mapper import OpMapper -from x2paddle.core.util import * -import math -import inspect -import numpy -import sys - - -# compute padding size for SAME mode -def get_same_padding(in_size, kernel_size, stride): - new_size = int(math.ceil(in_size * 1.0 / stride)) - pad_size = (new_size - 1) * stride + kernel_size - in_size - if pad_size < 0: - pad_size = 0 - pad0 = int(pad_size / 2) - pad1 = pad_size - pad0 - return [pad0, pad1] - - -class TFOpMapperNHWC(OpMapper): - directly_map_ops = { - 'Relu': ['relu'], - 'Relu6': ['relu6'], - 'Shape': ['shape'], - 'Abs': ['abs'], - 'Sigmoid': ['sigmoid'], - 'Exp': ['exp'], - 'Rsqrt': ['rsqrt'], - 'Sqrt': ['sqrt'], - 'swish_f32': ['swish'], - 'Tanh': ['tanh'], - 'Softplus': ['softplus'], - 'LeakyRelu': ['leaky_relu', { - 'alpha': 'alpha' - }], - 'Floor': ['floor'], - 'Erf': ['erf'] - } - elementwise_ops = { - 'Add': 'elementwise_add', - 'AddV2': 'elementwise_add', - 'RealDiv': 'elementwise_div', - 'Sub': 'elementwise_sub', - 'Maximum': 'elementwise_max', - 'Minimum': 'elementwise_min', - 'LessEqual': 'less_equal', - 'Mul': 'elementwise_mul', - 'FloorDiv': 'elementwise_floordiv' - } - - def __init__(self, decoder): - super(TFOpMapperNHWC, self).__init__() - self.decoder = decoder - self.graph = decoder.tf_graph - self.weights = dict() - self.batch_node = None - self.omit_nodes = list() - self.used_custom_layers = dict() - - not_placeholder = list() - for name in self.graph.input_nodes: - if self.graph.get_node( - name).layer_type != "Placeholder" and self.graph.get_node( - name - ).layer_type != "OneShotIterator" and self.graph.get_node( - name).layer_type != "IteratorV2": - not_placeholder.append(name) - for name in not_placeholder: - idx = self.graph.input_nodes.index(name) - del self.graph.input_nodes[idx] - - unsupported_ops = set() - sys.stderr.write("Total nodes: {}\n".format(len(self.graph.topo_sort))) - for i, node_name in enumerate(self.graph.topo_sort): - sys.stderr.write("\rConverting node {} ... ".format(i + 1)) - node = self.graph.get_node(node_name) - op = node.layer_type - if op in self.directly_map_ops: - if len(unsupported_ops) > 0: - continue - self.directly_map(node) - elif op in self.elementwise_ops: - if len(unsupported_ops) > 0: - continue - self.elementwise_map(node) - elif hasattr(self, op): - if len(unsupported_ops) > 0: - continue - func = getattr(self, op) - try: - func(node) - except Exception as e: - unsupported_ops.add(op) - print(e) - else: - unsupported_ops.add(op) - if len(unsupported_ops) > 0: - print("========= {} OPs are not supported yet ===========".format( - len(unsupported_ops))) - for op in unsupported_ops: - print("========== {} ============".format(op)) - sys.exit(-1) - sys.stderr.write("\nDone!\n") - - def add_omit_nodes(self, in_node_name, out_node_name): - in_node = self.graph.get_node(in_node_name) - out_node = self.graph.get_node(out_node_name) - index = in_node.outputs.index(out_node_name) - del in_node.outputs[index] - index = out_node.inputs.index(in_node_name) - del out_node.inputs[index] - self.omit_nodes.append(in_node.layer_name) - - 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_node(node.layer.input[0], copy=True) - attr = dict() - for param in op_info[1:]: - tf_param_name = list(param.keys())[0] - pd_param_name = list(param.values())[0] - tf_param = node.get_attr(tf_param_name) - attr[pd_param_name] = tf_param - - if len(input.out_shapes[0]) == 4 and op_info[0] != 'shape': - attr1 = {"perm": [0, 3, 1, 2]} - node.fluid_code.add_layer( - 'transpose', inputs=input, output=node, param_attr=attr1) - input = node - node.fluid_code.add_layer( - op_info[0], inputs=input, output=node, param_attr=attr) - input = node - attr2 = {"perm": [0, 2, 3, 1]} - node.fluid_code.add_layer( - 'transpose', inputs=input, output=node, param_attr=attr2) - else: - node.fluid_code.add_layer( - op_info[0], inputs=input, output=node, param_attr=attr) - - def elementwise_map(self, node): - assert node.layer_type in self.elementwise_ops - op_type = self.elementwise_ops[node.layer_type] - x = self.graph.get_node(node.layer.input[0], copy=True) - y = self.graph.get_node(node.layer.input[1], copy=True) - inputs = {"x": x, "y": y} - node.fluid_code.add_layer( - op_type, inputs=inputs, output=node, param_attr=None) - - def Placeholder(self, node): - shape = node.out_shapes[0] - assert len(shape) != 0, "Unknown shape of input nodes[{}].".format( - node.layer_name) - dtype = node.dtype - if shape[0] < 0: - self.batch_node = node - attr = { - 'dtype': string(dtype), - 'shape': shape, - 'name': string(node.layer_name), - 'append_batch_size': False - } - - node.fluid_code.add_layer( - "data", inputs=None, output=node, param_attr=attr) - - def Const(self, node): - shape = node.out_shapes[0] - dtype = node.dtype - value = node.value - initializer = "Constant(0.0)" - if len(shape) == 0: - assert value.size == 1, "Unexpected situation happend" - shape = [1] - initializer = "Constant({})".format(value) - - self.weights[node.layer_name] = node.value - - attr = { - 'dtype': string(dtype), - 'shape': shape, - 'name': string(node.layer_name), - 'default_initializer': initializer - } - node.fluid_code.add_layer( - "create_parameter", inputs=None, output=node, param_attr=attr) - - def Transpose(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - perm = self.graph.get_node(node.layer.input[1], copy=True) - assert perm.layer_type == "Const", "Perm of transpose OP should be Const" - del self.weights[perm.layer_name.replace('/', '_')] - perm.fluid_code.clear() - perm = perm.value.tolist() - - attr = {'perm': perm} - node.fluid_code.add_layer( - "transpose", inputs=input, output=node, param_attr=attr) - - def Fill(self, node): - dims = self.graph.get_node(node.layer.input[0], copy=True) - input_value = self.graph.get_node(node.layer.input[1], copy=True) - - assert input_value.layer_type == "Const", "Value of fill OP should be Const" - - self.add_omit_nodes(input_value.layer_name, node.layer_name) - input_value = input_value.value - input_dtype = string(input_value.dtype) - attr = {'value': input_value, 'dtype': input_dtype} - - node.fluid_code.add_layer( - "fill_constant", inputs=dims, output=node, param_attr=attr) - - def DepthToSpace(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - - block_size = node.get_attr("block_size") - data_format = node.get_attr("data_format").decode() - - if data_format == "NHWC": - attr = {"perm": [0, 3, 1, 2]} - node.fluid_code.add_layer( - "transpose", inputs=input, output=input, param_attr=attr) - n, h, w, c = input.out_shapes[0] - - attr = {'shape': [0, block_size * block_size, -1, h, w]} - node.fluid_code.add_layer( - "reshape", inputs=input, output=input, param_attr=attr) - - attr = {'perm': [0, 2, 1, 3, 4]} - node.fluid_code.add_layer( - "transpose", inputs=input, output=input, param_attr=attr) - attr = {'shape': [0, c, h, w]} - node.fluid_code.add_layer( - "reshape", inputs=input, output=input, param_attr=attr) - - attr = {'upscale_factor': block_size} - node.fluid_code.add_layer( - "pixel_shuffle", inputs=input, output=node, param_attr=attr) - - if data_format == "NHWC": - attr = {"perm": [0, 2, 3, 1]} - node.fluid_code.add_layer( - "transpose", inputs=node, output=node, param_attr=attr) - - def MaxPool(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - - k_size = node.get_attr("ksize") - strides = node.get_attr("strides") - data_format = node.get_attr("data_format").decode() - pad_mode = node.get_attr("padding").decode() - channel_first = data_format == "NCHW" - - if not channel_first: - attr = {"perm": [0, 3, 1, 2]} - node.fluid_code.add_layer( - "transpose", inputs=input, output=node, param_attr=attr) - strides = [strides[i] for i in [0, 3, 1, 2]] - k_size = [k_size[i] for i in [0, 3, 1, 2]] - input = node - - attr = { - "pool_size": k_size[2:4], - "pool_type": string("max"), - "pool_stride": strides[2:4], - "pool_padding": string(pad_mode) - } - node.fluid_code.add_layer( - "pool2d", inputs=input, output=node, param_attr=attr) - - if not channel_first: - attr = {"perm": [0, 2, 3, 1]} - node.fluid_code.add_layer( - "transpose", inputs=node, output=node, param_attr=attr) - - def Conv2D(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - kernel = self.graph.get_node(node.layer.input[1], copy=True) - self.add_omit_nodes(kernel.layer_name, node.layer_name) - - k_size = kernel.out_shapes[0] - strides = node.get_attr("strides") - dilations = node.get_attr("dilations") - data_format = node.get_attr("data_format").decode() - pad_mode = node.get_attr("padding").decode() - channel_first = data_format == "NCHW" - if data_format == "NHWC": - n, h, w, c = input.out_shapes[0] - else: - n, c, h, w = input.out_shapes[0] - - if kernel.layer_type == 'Const': - kernel_value = kernel.value - kernel_weight_name = kernel.layer_name.replace('/', '_') - else: - kernel_value = self.decoder.infer_tensor(kernel) - if kernel.layer_type == 'Split': - kernel_weight_name = "{}_{}_kernel".format(node.layer_name, - kernel.layer_name) - else: - kernel_weight_name = kernel.layer_name.replace('/', '_') - self.weights[kernel_weight_name] = numpy.transpose(kernel_value, - (3, 2, 0, 1)) - - if not channel_first: - strides = [strides[i] for i in [0, 3, 1, 2]] - dilations = [dilations[i] for i in [0, 3, 1, 2]] - attr = {"perm": [0, 3, 1, 2]} - node.fluid_code.add_layer( - "transpose", inputs=input, output=node, param_attr=attr) - input = node - attr = { - "bias_attr": False, - "param_attr": string(kernel_weight_name), - "num_filters": k_size[3], - "filter_size": k_size[0:2], - "stride": strides[2:4], - "dilation": dilations[2:4], - "padding": string(pad_mode) - } - if hasattr(node, 'dilation') and attr['dilation'] == [1, 1]: - if len(node.dilation) == 1: - attr['dilation'] = [1, node.dilation[0]] - - if c == -1: - reshape_attr = {"shape": [0, k_size[2], 0, 0]} - node.fluid_code.add_layer( - "reshape", inputs=input, output=input, param_attr=reshape_attr) - - node.fluid_code.add_layer( - "conv2d", inputs=input, output=node, param_attr=attr) - if not channel_first: - attr = {"perm": [0, 2, 3, 1]} - node.fluid_code.add_layer( - "transpose", inputs=node, output=node, param_attr=attr) - - def BiasAdd(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - bias = self.graph.get_node(node.layer.input[1], copy=True) - inputs = {"x": input, "y": bias} - node.fluid_code.add_layer( - "elementwise_add", inputs=inputs, output=node, param_attr=None) - - def FusedBatchNorm(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - gamma = self.graph.get_node(node.layer.input[1], copy=True) - beta = self.graph.get_node(node.layer.input[2], copy=True) - moving_mean = self.graph.get_node(node.layer.input[3], copy=True) - moving_var = self.graph.get_node(node.layer.input[4], copy=True) - data_format = node.get_attr("data_format").decode() - channel_first = data_format == "NCHW" - - assert gamma.layer_type == "Const" - assert beta.layer_type == "Const" - assert moving_mean.layer_type == "Const" - assert moving_var.layer_type == "Const" - self.add_omit_nodes(gamma.layer_name, node.layer_name) - self.add_omit_nodes(beta.layer_name, node.layer_name) - self.add_omit_nodes(moving_mean.layer_name, node.layer_name) - self.add_omit_nodes(moving_var.layer_name, node.layer_name) - - if not channel_first: - attr = {"perm": [0, 3, 1, 2]} - node.fluid_code.add_layer( - "transpose", inputs=input, output=node, param_attr=attr) - input = node - - attr = { - "epsilon": node.get_attr("epsilon"), - "param_attr": string(gamma.layer_name), - "bias_attr": string(beta.layer_name), - "moving_mean_name": string(moving_mean.layer_name), - "moving_variance_name": string(moving_var.layer_name), - "is_test": True - } - - node.fluid_code.add_layer( - "batch_norm", inputs=input, output=node, param_attr=attr) - - if not channel_first: - attr = {"perm": [0, 2, 3, 1]} - node.fluid_code.add_layer( - "transpose", inputs=node, output=node, param_attr=attr) - - def DepthwiseConv2dNative(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - kernel = self.graph.get_node(node.layer.input[1], copy=True) - assert kernel.layer_type == "Const", "Kernel of DepthwiseConv2DNative should be Const" - self.add_omit_nodes(kernel.layer_name, node.layer_name) - - in_shape = input.out_shapes[0] - k_size = kernel.out_shapes[0] - strides = node.get_attr("strides") - dilations = node.get_attr("dilations") - data_format = node.get_attr("data_format").decode() - pad_mode = node.get_attr("padding").decode() - channel_first = data_format == "NCHW" - - self.weights[kernel.layer_name.replace('/', '_')] = numpy.transpose( - kernel.value, (2, 3, 0, 1)) - - if not channel_first: - in_shape = [in_shape[i] for i in [0, 3, 1, 2]] - strides = [strides[i] for i in [0, 3, 1, 2]] - dilations = [dilations[i] for i in [0, 3, 1, 2]] - attr = {"perm": [0, 3, 1, 2]} - node.fluid_code.add_layer( - "transpose", inputs=input, output=node, param_attr=attr) - input = node - - attr = { - "bias_attr": False, - "param_attr": string(kernel.layer_name), - "num_filters": in_shape[1], - "filter_size": k_size[0:2], - "stride": strides[2:4], - "dilation": dilations[2:4], - "groups": k_size[3] * in_shape[1], - "use_cudnn": False, - "padding": string(pad_mode) - } - node.fluid_code.add_layer( - "conv2d", inputs=input, output=node, param_attr=attr) - - if not channel_first: - attr = {"perm": [0, 2, 3, 1]} - node.fluid_code.add_layer( - "transpose", inputs=node, output=node, param_attr=attr) - - def Reshape(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - param = self.graph.get_node(node.layer.input[1], copy=True) - if param.layer_type == "Const": - self.add_omit_nodes(param.layer_name, node.layer_name) - shape = param.value.tolist() - else: - shape = param - inputs = {"x": input, "shape": shape} - node.fluid_code.add_layer( - "reshape", inputs=inputs, output=node, param_attr=None) - if param.layer_type != "Const": - out_shape = numpy.array(node.out_shapes[0]) - if (out_shape > 0).any(): - out_shape[out_shape < 0] = 0 - attr = {'shape': out_shape.tolist()} - node.fluid_code.add_layer( - "reshape", inputs=node, output=node, param_attr=attr) - - def AvgPool(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - - k_size = node.get_attr("ksize") - strides = node.get_attr("strides") - data_format = node.get_attr("data_format").decode() - pad_mode = node.get_attr("padding").decode() - channel_first = data_format == "NCHW" - - if not channel_first: - strides = [strides[i] for i in [0, 3, 1, 2]] - k_size = [k_size[i] for i in [0, 3, 1, 2]] - attr = {"perm": [0, 3, 1, 2]} - node.fluid_code.add_layer( - "transpose", inputs=input, output=node, param_attr=attr) - input = node - - attr = { - "pool_size": k_size[2:4], - "pool_type": string("avg"), - "pool_stride": strides[2:4], - "pool_padding": string(pad_mode) - } - node.fluid_code.add_layer( - "pool2d", inputs=input, output=node, param_attr=attr) - - if not channel_first: - attr = {"perm": [0, 2, 3, 1]} - node.fluid_code.add_layer( - "transpose", inputs=node, output=node, param_attr=attr) - - def SplitV(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - num_sections = self.graph.get_node(node.layer.input[1], copy=True) - dim = self.graph.get_node(node.layer.input[2], copy=True) - assert num_sections.layer_type == "Const" - assert dim.layer_type == "Const" - self.add_omit_nodes(num_sections.layer_name, node.layer_name) - self.add_omit_nodes(dim.layer_name, node.layer_name) - dim = dim.value - attr = { - "num_or_sections": num_sections.value.tolist(), - "dim": dim.value - } - node.fluid_code.add_layer( - "split", inputs=input, output=node, param_attr=attr) - - def ConcatV2(self, node): - inputs = [ - self.graph.get_node( - name, copy=True) for name in node.layer.input[:-1] - ] - axis = self.graph.get_node(node.layer.input[-1], copy=True) - assert axis.layer_type == "Const" - self.add_omit_nodes(axis.layer_name, node.layer_name) - axis = axis.value - if axis < 0: - axis += len(inputs[0].out_shapes[0]) - attr = {"axis": axis} - node.fluid_code.add_layer( - "concat", inputs=inputs, output=node, param_attr=attr) - - def Tile(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - expand_times = self.graph.get_node(node.layer.input[1], copy=True) - if expand_times.layer_type == "Const": - self.add_omit_nodes(expand_times.layer_name, node.layer_name) - expand_times = expand_times.value.tolist() - else: - expand_times = expand_times - inputs = {"x": input, "expand_times": expand_times} - node.fluid_code.add_layer( - "expand", inputs=inputs, output=node, param_attr=None) - - def Pack(self, node): - inputs = [ - self.graph.get_node( - name, copy=True) for name in node.layer.input - ] - reshape_shape = list() - for input_node in inputs: - k_size = input_node.out_shapes[0] - if len(k_size) and k_size[-1] != -1: - reshape_shape = [0] * len(k_size) - reshape_shape[-1] = k_size[-1] - break - if len(reshape_shape): - for i, input_node in enumerate(inputs): - node.fluid_code.add_layer( - "reshape", - inputs=input_node, - output='tmp_{}'.format(i), - param_attr={"shape": reshape_shape}) - axis = node.get_attr("axis") - attr = {"axis": axis} - if len(reshape_shape): - inputs = ['tmp_{}'.format(i) for i in range(len(inputs))] - node.fluid_code.add_layer( - "stack", inputs=inputs, output=node, param_attr=attr) - - def Pad(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - paddings = self.graph.get_node(node.layer.input[1], copy=True) - assert paddings.layer_type == "Const", "Padding should be Const" - self.add_omit_nodes(paddings.layer_name, node.layer_name) - paddings = paddings.value.flatten().tolist() - data_format = input.tf_data_format - - if len(input.out_shapes[0]) == 4: - new_padding = None - if input.tf_data_format == "NHWC": - if paddings[0] + paddings[1] + paddings[6] + paddings[7] == 0: - new_padding = paddings[2:6] - else: - if paddings[0] + paddings[1] + paddings[2] + paddings[3] == 0: - new_padding = paddings[4:] - if new_padding is not None: - if input.tf_data_format == "NHWC": - attr = {"perm": [0, 3, 1, 2]} - node.fluid_code.add_layer( - "transpose", inputs=input, output=node, param_attr=attr) - input = node - attr = {"paddings": new_padding} - node.fluid_code.add_layer( - "pad2d", inputs=input, output=node, param_attr=attr) - if input.tf_data_format == "NHWC": - attr = {"perm": [0, 2, 3, 1]} - node.fluid_code.add_layer( - "transpose", inputs=node, output=node, param_attr=attr) - - return - - attr = {"paddings": paddings} - node.fluid_code.add_layer( - "pad", inputs=input, output=node, param_attr=attr) - - def Range(self, node): - start = self.graph.get_node(node.layer.input[0], copy=True) - limit = self.graph.get_node(node.layer.input[1], copy=True) - delta = self.graph.get_node(node.layer.input[2], copy=True) - - if start.layer_type == "Const": - self.add_omit_nodes(start.layer_name, node.layer_name) - start = start.value - if limit.layer_type == "Const": - self.add_omit_nodes(limit.layer_name, node.layer_name) - limit = limit.value - if delta.layer_type == "Const": - self.add_omit_nodes(delta.layer_name, node.layer_name) - delta = delta.value - - dtype = node.dtype - inputs = { - "start": start, - "end": limit, - "step": delta, - } - attr = {"dtype": string(node.dtype)} - node.fluid_code.add_layer( - "range", inputs=inputs, output=node, param_attr=attr) - - def Mean(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - reduce_idx = self.graph.get_node(node.layer.input[1], copy=True) - assert reduce_idx.layer_type == "Const", "Only support Const parameter[reduce_idx]" - dims = reduce_idx.value.tolist() - keep_dims = node.get_attr("keep_dims") - - attr = {"dim": dims, "keep_dim": keep_dims} - node.fluid_code.add_layer( - "reduce_mean", inputs=input, output=node, param_attr=attr) - - def MatMul(self, node): - x = self.graph.get_node(node.layer.input[0], copy=True) - y = self.graph.get_node(node.layer.input[1], copy=True) - transpose_a = node.get_attr('transpose_a') - transpose_b = node.get_attr('transpose_b') - inputs = {"x": x, "y": y} - # fix paddle shape infer problem - # should be removed after paddle 1.6 - if x.out_shapes[0][-1] < 0 and y.out_shapes[0][0] > 0: - shape = x.out_shapes[0] - shape[-1] = y.out_shapes[0][0] - attr = {"shape": shape} - node.fluid_code.add_layer( - "reshape", inputs=x, output=x, param_attr=attr) - if transpose_a is None: - transpose_a = node.get_attr('adj_x') - if transpose_b is None: - transpose_b = node.get_attr('adj_y') - attr = {"transpose_x": transpose_a, "transpose_y": transpose_b} - node.fluid_code.add_layer( - "matmul", inputs=inputs, output=node, param_attr=attr) - - def BatchMatMul(self, node): - return self.MatMul(node) - - def BatchMatMulV2(self, node): - return self.MatMul(node) - - def ArgMax(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - axis = self.graph.get_node(node.layer.input[1], copy=True) - assert axis.layer_type == "Const", "ArgMax only support Const parameter" - self.add_omit_nodes(axis.layer_name, node.layer_name) - axis = axis.value - attr = {"axis": axis} - node.fluid_code.add_layer( - "argmax", inputs=input, output=node, param_attr=attr) - - def StridedSlice(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - begin = self.graph.get_node(node.layer.input[1], copy=True) - end = self.graph.get_node(node.layer.input[2], copy=True) - strides = self.graph.get_node(node.layer.input[3], copy=True) - assert begin.layer_type == "Const" - assert end.layer_type == "Const" - assert strides.layer_type == "Const" - self.add_omit_nodes(begin.layer_name, node.layer_name) - self.add_omit_nodes(end.layer_name, node.layer_name) - self.add_omit_nodes(strides.layer_name, node.layer_name) - strides = strides.value.tolist() - assert len(set(strides)) == 1 and strides[ - 0] == 1, "Only support strides be 1 in StridedSlice OP" - - begin = begin.value.tolist() - end = end.value.tolist() - - for i in range(len(end)): - if end[i] == 0: - end[i] = 999999 - - begin_mask = node.get_attr('begin_mask') - end_mask = node.get_attr('end_mask') - ellipsis_mask = node.get_attr('ellipsis_mask') - new_axis_mask = node.get_attr('new_axis_mask') - shrink_axis_mask = node.get_attr('shrink_axis_mask') - - assert ellipsis_mask == 0, "(OP:{} Name:{})Only support ellipsis_mask be 0[now: {}] n StridedSlice OP".format( - node.layer_type, node.layer.name, ellipsis_mask) - - # TODO codes without validation - # Use it carefully - new_begin = list() - new_end = list() - new_axes = list() - shrink_axes = list() - for i, item in enumerate(begin): - mask = (new_axis_mask >> i) & 1 - if mask != 0: - new_axes.append(i) - continue - - mask = (shrink_axis_mask >> i) & 1 - if mask != 0: - shrink_axes.append(i) - - mask = (begin_mask >> i) & 1 - if mask != 0: - new_begin.append(0) - else: - new_begin.append(item) - - mask = (end_mask >> i) & 1 - if mask != 0: - new_end.append(999999) - else: - new_end.append(end[i]) - - attr = { - "axes": [i for i in range(len(new_begin))], - "starts": new_begin, - "ends": new_end - } - node.fluid_code.add_layer( - "slice", inputs=input, output=node, param_attr=attr) - if len(new_axes) > 0: - attr = {"axes": new_axes} - node.fluid_code.add_layer( - "unsqueeze", inputs=node, output=node, param_attr=attr) - if len(shrink_axes) > 0: - if len(input.out_shapes[0]) + len(new_axes) <= 1: - pass - else: - attr = {"axes": shrink_axes} - node.fluid_code.add_layer( - "squeeze", inputs=node, output=node, param_attr=attr) - - def Slice(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - begin = self.graph.get_node(node.layer.input[1], copy=True) - size = self.graph.get_node(node.layer.input[2], copy=True) - if begin.layer_type == "Const": - self.add_omit_nodes(begin.layer_name, node.layer_name) - begin = begin.value.tolist() - else: - begin = self.decoder.infer_tensor(begin).tolist() - -# shape = begin.out_shapes[0] -# attr = {"shape": shape} -# node.fluid_code.add_layer( -# "reshape", inputs=begin, output=begin, param_attr=attr) - if size.layer_type == "Const": - self.add_omit_nodes(size.layer_name, node.layer_name) - size = size.value.tolist() - else: - size = size - shape = size.out_shapes[0] - attr = {"shape": shape} - node.fluid_code.add_layer( - "reshape", inputs=size, output=size, param_attr=attr) - inputs = {"x": input, "offsets": begin, "shape": size} - node.fluid_code.add_layer( - "crop_tensor", inputs=inputs, output=node, param_attr=None) - - def Conv2DBackpropInput(self, node): - out_shape = self.graph.get_node(node.layer.input[0], copy=True) - kernel = self.graph.get_node(node.layer.input[1], copy=True) - input = self.graph.get_node(node.layer.input[2], copy=True) - - assert kernel.layer_type == "Const", "Kernel of Conv2DBackpropInput should be Const" - - self.add_omit_nodes(kernel.layer_name, node.layer_name) - self.add_omit_nodes(out_shape.layer_name, node.layer_name) - - if out_shape.layer_type == "Const": - out_shape = out_shape.value.tolist() - else: - out_shape = self.decoder.infer_shape_tensor(out_shape, - node.out_shapes[0]) - - in_shape = input.out_shapes[0] - if in_shape.count(-1) > 2: - in_shape = self.decoder.infer_tensor(input).shape - k_size = kernel.out_shapes[0] - if k_size.count(-1) > 2: - k_size = self.decoder.infer_tensor(kernel).shape - - pad_mode = node.get_attr("padding").decode() - strides = node.get_attr("strides") - dilations = node.get_attr("dilations") - data_format = node.get_attr("data_format").decode() - channel_first = data_format == "NCHW" - - self.weights[kernel.layer_name.replace('/', '_')] = numpy.transpose( - kernel.value, (3, 2, 0, 1)) - if not channel_first: - in_shape = [in_shape[i] for i in [0, 3, 1, 2]] - strides = [strides[i] for i in [0, 3, 1, 2]] - dilations = [dilations[i] for i in [0, 3, 1, 2]] - attr = {"perm": [0, 3, 1, 2]} - node.fluid_code.add_layer( - "transpose", inputs=input, output=node, param_attr=attr) - input = node - else: - self.graph.data_format_propagation(node) - - attr = { - "bias_attr": False, - "param_attr": string(kernel.layer_name), - "num_filters": k_size[2], - "filter_size": k_size[0:2], - "stride": strides[2:4], - "dilation": dilations[2:4], - "padding": string(pad_mode), - "output_size": out_shape[1:3] - } - node.fluid_code.add_layer( - "conv2d_transpose", inputs=input, output=node, param_attr=attr) - - if not channel_first: - attr = {"perm": [0, 2, 3, 1]} - node.fluid_code.add_layer( - "transpose", inputs=node, output=node, param_attr=attr) - - def Max(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - reduce_idx = self.graph.get_node(node.layer.input[1], copy=True) - assert reduce_idx.layer_type == "Const", "Only support Const parameter[reduce_idx]" - keep_dims = node.get_attr("keep_dims") - dim = reduce_idx.value.tolist() - - attr = {"dim": dim, "keep_dim": keep_dims} - node.fluid_code.add_layer( - "reduce_max", inputs=input, output=node, param_attr=attr) - - def Sum(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - reduce_idx = self.graph.get_node(node.layer.input[1], copy=True) - assert reduce_idx.layer_type == "Const", "Only support Const parameter[reduce_idx]" - keep_dims = node.get_attr("keep_dims") - dim = reduce_idx.value.tolist() - - attr = {"dim": dim, "keep_dim": keep_dims} - node.fluid_code.add_layer( - "reduce_sum", inputs=input, output=node, param_attr=attr) - - def Cast(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - dtype = node.dtype_map[node.get_attr('DstT')] - attr = {"dtype": string(dtype)} - node.fluid_code.add_layer( - "cast", inputs=input, output=node, param_attr=attr) - - def Split(self, node): - dim = self.graph.get_node(node.layer.input[0], copy=True) - input = self.graph.get_node(node.layer.input[1], copy=True) - assert dim.layer_type == "Const" - self.add_omit_nodes(dim.layer_name, node.layer_name) - num_split = node.get_attr('num_split') - dim = dim.value - - attr = {"num_or_sections": num_split, "dim": dim} - node.fluid_code.add_layer( - "split", inputs=input, output=node, param_attr=attr) - - def Squeeze(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - squeeze_dims = node.get_attr('squeeze_dims') - attr = {"axes": squeeze_dims} - node.fluid_code.add_layer( - "squeeze", inputs=input, output=node, param_attr=attr) - - def Softmax(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - axis = node.get_attr("axis") - attr = {"axis": axis} - node.fluid_code.add_layer( - "softmax", inputs=input, output=node, param_attr=attr) - - def ResizeNearestNeighbor(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - resize_shape = self.graph.get_node(node.layer.input[1], copy=True) - if resize_shape.layer_type == "Const": - self.add_omit_nodes(resize_shape.layer_name, node.layer_name) - resize_shape = resize_shape.value.tolist() - else: - resize_shape = resize_shape - shape = resize_shape.out_shapes[0] - attr = {"shape": shape} - node.fluid_code.add_layer( - "reshape", - inputs=resize_shape, - output=resize_shape, - param_attr=attr) - - align_corners = node.get_attr("align_corners") - attr = {"perm": [0, 3, 1, 2]} - node.fluid_code.add_layer( - "transpose", inputs=input, output=node, param_attr=attr) - inputs = {"input": node, "out_shape": resize_shape} - attr = {"align_corners": align_corners} - node.fluid_code.add_layer( - "resize_nearest", inputs=inputs, output=node, param_attr=attr) - attr = {"perm": [0, 2, 3, 1]} - node.fluid_code.add_layer( - "transpose", inputs=node, output=node, param_attr=attr) - - def ResizeBilinear(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - resize_shape = self.graph.get_node(node.layer.input[1], copy=True) - if resize_shape.layer_type == "Const": - self.add_omit_nodes(resize_shape.layer_name, node.layer_name) - resize_shape = resize_shape.value.tolist() - else: - shape = resize_shape.out_shapes[0] - attr = {"shape": shape} - node.fluid_code.add_layer( - "reshape", - inputs=resize_shape, - output=resize_shape, - param_attr=attr) - align_corners = node.get_attr("align_corners") - attr = {"perm": [0, 3, 1, 2]} - node.fluid_code.add_layer( - "transpose", inputs=input, output=node, param_attr=attr) - inputs = {"input": node, "out_shape": resize_shape} - attr = { - #"out_shape": resize_shape, - "align_corners": align_corners, - "align_mode": 1 - } - node.fluid_code.add_layer( - "resize_bilinear", inputs=inputs, output=node, param_attr=attr) - attr = {"perm": [0, 2, 3, 1]} - node.fluid_code.add_layer( - "transpose", inputs=node, output=node, param_attr=attr) - - def GreaterEqual(self, node): - x = self.graph.get_node(node.layer.input[0], copy=True) - y = self.graph.get_node(node.layer.input[1], copy=True) - inputs = {"x": x, "y": y} - node.fluid_code.add_layer( - "greater_equal", inputs=inputs, output=node, param_attr=None) - - def RandomUniform(self, node): - shape = self.graph.get_node(node.layer.input[0], copy=True) - if shape.layer_type == "Const": - self.add_omit_nodes(shape.layer_name, node.layer_name) - shape = shape.value.tolist() - else: - shape = shape - attr = {"min": 0.0, "max": 0.9999} - - node.fluid_code.add_layer( - "uniform_random", inputs=shape, output=node, param_attr=attr) - - def SquaredDifference(self, node): - x = self.graph.get_node(node.layer.input[0], copy=True) - y = self.graph.get_node(node.layer.input[1], copy=True) - inputs = {"x": x, "y": y} - node.fluid_code.add_layer( - "elementwise_sub", inputs=inputs, output=node, param_attr=None) - inputs = {"x": node, "y": node} - node.fluid_code.add_layer( - "elementwise_mul", inputs=inputs, output=node, param_attr=None) - - def ExpandDims(self, node): - x = self.graph.get_node(node.layer.input[0], copy=True) - y = self.graph.get_node(node.layer.input[1], copy=True) - if y.layer_type == 'Const': - self.add_omit_nodes(y.layer_name, node.layer_name) - dim = y.value.tolist() - if not isinstance(dim, list): - dim = [dim] - attr = {'axes': dim} - else: - attr = {'axes': y} - node.fluid_code.add_layer( - "unsqueeze", inputs=x, output=node, param_attr=attr) - - def BatchToSpaceND(self, node): - x = self.graph.get_node(node.layer.input[0], copy=True) - y = self.graph.get_node(node.layer.input[1], copy=True) - if hasattr(node, 'skip') and node.skip: - node.fluid_code.add_layer( - "=", inputs=x, output=node, param_attr=None) - else: - raise Exception("BatchToSpaceND is not supported") - - def SpaceToBatchND(self, node): - x = self.graph.get_node(node.layer.input[0], copy=True) - y = self.graph.get_node(node.layer.input[1], copy=True) - if hasattr(node, 'skip') and node.skip: - node.fluid_code.add_layer( - "=", inputs=x, output=node, param_attr=None) - else: - raise Exception("SpaceToBatchND is not supported") - - def OneHot(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - depth = self.graph.get_node(node.layer.input[1], copy=True) - on_value = self.graph.get_node(node.layer.input[2], copy=True) - off_value = self.graph.get_node(node.layer.input[3], copy=True) - assert depth.layer_type == 'Const', 'Parameter depth should be Const in OneHot' - assert on_value.layer_type == 'Const', 'Parameter on_value should be Const in OneHot' - assert off_value.layer_type == 'Const', 'Parameter off_value should be Const in OneHot' - self.add_omit_nodes(depth.layer_name, node.layer_name) - self.add_omit_nodes(on_value.layer_name, node.layer_name) - self.add_omit_nodes(off_value.layer_name, node.layer_name) - depth = depth.value - on_value = on_value.value - off_value = off_value.value - assert math.fabs(on_value - - 1.0) < 1e-06, "on_value should be 1 in OneHot" - assert math.fabs(off_value - - 0.0) < 1e-06, "off_value should be 0 in OneHot" - attr = {'depth': depth} - node.fluid_code.add_layer( - "one_hot", - inputs=input, - output=node, - param_attr=attr, - use_fluid=True) - - def Pow(self, node): - x = self.graph.get_node(node.layer.input[0], copy=True) - factor = self.graph.get_node(node.layer.input[1], copy=True) - self.add_omit_nodes(factor.layer_name, node.layer_name) - if factor.layer_type == 'Const': - factor = factor.value.tolist() - else: - factor = self.decoder.infer_tensor(factor) - attr = {'factor': factor} - node.fluid_code.add_layer("pow", inputs=x, output=node, param_attr=attr) - - def All(self, node): - input = self.graph.get_node(node.layer.input[0], copy=True) - reduce_idx = self.graph.get_node(node.layer.input[1], copy=True) - self.add_omit_nodes(reduce_idx.layer_name, node.layer_name) - assert reduce_idx.layer_type == "Const", "Only support Const parameter[reduce_idx]" - dims = reduce_idx.value.tolist() - keep_dims = node.get_attr("keep_dims") - - attr = {"dim": dims, "keep_dim": keep_dims} - node.fluid_code.add_layer( - "reduce_all", inputs=input, output=node, param_attr=attr) - - def GatherV2(self, node): - embeddings = self.graph.get_node(node.layer.input[0], copy=True) - index = self.graph.get_node(node.layer.input[1], copy=True) - axis = self.graph.get_node(node.layer.input[2], copy=True) - self.add_omit_nodes(axis.layer_name, node.layer_name) - assert axis.layer_type == 'Const', "Only support Const parameter[axis]" - axis = axis.value.tolist() - assert axis == 0, "Only support axis=0 in GatherV2 OP" - attr = {'overwrite': False} - embeddings_shape = embeddings.out_shapes[0][-1] - reshape_list = list() - reshape_name = index.layer_name - if len(index.out_shapes[0]) != 1: - reshape_list = index.out_shapes[0] - reshape_attr = {"shape": [-1]} - reshape_name = "{}_reshape".format(index.layer_name) - node.fluid_code.add_layer( - "reshape", - inputs=index, - output=reshape_name, - param_attr=reshape_attr) - inputs = {'input': embeddings, 'index': reshape_name} - node.fluid_code.add_layer( - "gather", inputs=inputs, output=node, param_attr=attr) - if len(index.out_shapes[0]) != 1: - reshape_attr = {"shape": reshape_list + [embeddings_shape]} - node.fluid_code.add_layer( - "reshape", inputs=node, output=node, param_attr=reshape_attr) - - def OneShotIterator(self, node): - return self.Placeholder(node) - - def IteratorV2(self, node): - dtype_map = { - 1: "float32", - 3: "int32", - 4: "uint8", - 9: "int64", - 10: "bool" - } - shapes = node.out_shapes - dtypes = node.layer.attr['output_types'].list.type - node.fluid_code.add_note("{} = [0] * {}".format(node.layer_name, - len(shapes))) - for i, shape in enumerate(shapes): - attr = { - 'dtype': string(dtype_map[dtypes[i]]), - 'shape': shape, - 'name': string("{}_{}".format(node.layer_name, i)), - 'append_batch_size': False - } - output = "{}[{}]".format(node.layer_name, i) - node.fluid_code.add_layer( - "data", inputs=None, output=output, param_attr=attr) diff --git a/x2paddle/op_mapper/paddle2onnx/opset10/__init__.py b/x2paddle/optimizer/pytorch_optimizer/__init__.py similarity index 100% rename from x2paddle/op_mapper/paddle2onnx/opset10/__init__.py rename to x2paddle/optimizer/pytorch_optimizer/__init__.py diff --git a/x2paddle/optimizer/pytorch_optimizer/fusion/__init__.py b/x2paddle/optimizer/pytorch_optimizer/fusion/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..f0355401f5357309d21552aef5cf9f54c3a25059 --- /dev/null +++ b/x2paddle/optimizer/pytorch_optimizer/fusion/__init__.py @@ -0,0 +1,28 @@ +# 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 .adaptive_pool2d_fuser import AdaptivePool2dFuser +from .adaptive_pool2d_fuse_pass import AdaptivePool2dFusePass +from .batchnorm2d_fuser import BatchNorm2dFuser +from .batchnorm2d_fuse_pass import BatchNorm2dFusePass +from .constant_fuser import ConstantFuser +from .constant_fuse_pass import ConstantFusePass +from .dropout_fuser import DropoutFuser +from .dropout_fuse_pass import DropoutFusePass +from .fc_fuser import FcFuser +from .fc_fuse_pass import FcFusePass +from .interpolate_bilinear_fuser import InterpolateBilinearFuser +from .interpolate_bilinear_fuse_pass import InterpolateBilinearFusePass +from .reshape_fuser import ReshapeFuser +from .reshape_fuse_pass import ReshapeFusePass diff --git a/x2paddle/optimizer/pytorch_optimizer/fusion/adaptive_pool2d_fuse_pass.py b/x2paddle/optimizer/pytorch_optimizer/fusion/adaptive_pool2d_fuse_pass.py new file mode 100644 index 0000000000000000000000000000000000000000..737ecef25f5fc12f66914edb1b10fec4da7255b3 --- /dev/null +++ b/x2paddle/optimizer/pytorch_optimizer/fusion/adaptive_pool2d_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.pytorch_optimizer.pass_ import Pass +from x2paddle.optimizer.pytorch_optimizer.fusion import AdaptivePool2dFuser +from x2paddle.optimizer.pytorch_optimizer.pass_manager import pass_register + + +@pass_register +class AdaptivePool2dFusePass(Pass): + name = "adaptive_pool2d_fuse_pass" + + def __init__(self): + Pass.__init__(self) + + def apply(self, graph): + fuser = AdaptivePool2dFuser() + fuser.operate(graph, match_kind="topo") + + +# 用于注册 +adaptive_pool2d_fuse_pass = AdaptivePool2dFusePass() diff --git a/x2paddle/optimizer/pytorch_optimizer/fusion/adaptive_pool2d_fuser.py b/x2paddle/optimizer/pytorch_optimizer/fusion/adaptive_pool2d_fuser.py new file mode 100644 index 0000000000000000000000000000000000000000..93085ea7f7f53e516b65234ab6b2d7185f754e3b --- /dev/null +++ b/x2paddle/optimizer/pytorch_optimizer/fusion/adaptive_pool2d_fuser.py @@ -0,0 +1,133 @@ +# 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 numpy as np +from x2paddle.optimizer.pytorch_optimizer.pattern_matcher import FuseBase +from x2paddle.core.program import PaddleGraph, PaddleLayer +from x2paddle.core.util import * + + +class AdaptivePool2dFuser(FuseBase): + def __init__(self): + super(AdaptivePool2dFuser, self).__init__(graph_type="dygraph") + + def build_pattern(self): + """ 描述需要替换的adaptive pool2d图结构。 + adaptive pool2d层模式python实现代码示例: + x68 = fluid.layers.shape(input=x60) + x69 = len(x68) + x70 = x69 <= 2 + if x70 : + raise RaiseException('Exception') + x73 = [] + x74 = x68[-2: 2147483647: 1] + x75 = len(x74) + x76 = [2, x75] + x77 = min(x76) + for _x79 in range(x77): + x80 = [6, 6][_x79] + x73.append(x80) + x81 = fluid.layers.adaptive_pool2d(input=x60, pool_size=x73, pool_type='avg') + """ + + def gen_name(id): + return "x" + str(id) + + self.pattern.add_layer( + "fluid.layers.shape", + inputs={'input': "pool-input-0"}, + outputs=[gen_name(1)]) + self.pattern.add_layer( + "prim.len", inputs={"input": gen_name(1)}, outputs=[gen_name(6)]) + self.pattern.add_layer( + "prim.le", inputs={"x": gen_name(6)}, outputs=[gen_name(8)], y=2) + self.pattern.add_layer("prim.if", {'input': gen_name(8)}, [gen_name(9)]) + if_layer = self.pattern.layers[list(self.pattern.layers.keys())[-1]] + pattern_block0 = PaddleGraph(if_layer, graph_type="dygraph") + pattern_block0.add_layer( + "prim.exception", + inputs={}, + outputs=[gen_name(9)], + input="Exception") + if_layer.add_block(pattern_block0) + pattern_block1 = PaddleGraph(if_layer, graph_type="dygraph") + if_layer.add_block(pattern_block1) + self.pattern.add_layer("prim.list", inputs={}, outputs=[gen_name(10)]) + self.pattern.add_layer( + "prim.slice", + inputs={"input": gen_name(1), }, + outputs=[gen_name(12)], + start=-1, + end=100, + step=1) + self.pattern.add_layer( + "prim.len", inputs={"input": gen_name(12)}, outputs=[gen_name(14)]) + self.pattern.add_layer( + "prim.list", + inputs={"input1": gen_name(14)}, + outputs=[gen_name(15)], + input0=2) + self.pattern.add_layer( + "prim.min", inputs={"input": gen_name(15)}, outputs=[gen_name(16)]) + self.pattern.add_layer("prim.loop", {'input': gen_name(16)}, + [gen_name(17), gen_name(18)]) + loop_layer = self.pattern.layers[list(self.pattern.layers.keys())[-1]] + pattern_block = PaddleGraph(loop_layer, graph_type="dygraph") + pattern_block.add_layer( + "prim.getitem", + inputs={"index": gen_name(18)}, + outputs=[gen_name(19)], + list=[6, 6]) + pattern_block.add_layer( + "prim.append", + inputs={"list": gen_name(10), + "index": gen_name(19)}, + outputs=[gen_name(20)]) + loop_layer.inputs["input-0"] = gen_name(10) + loop_layer.add_block(pattern_block) + pool_attrs = {'pool_type': string("avg")} + self.pattern.add_layer( + "fluid.layers.adaptive_pool2d", + inputs={'input': "pool-input-0", + "pool_size": gen_name(10)}, + outputs=[gen_name(21)], + **pool_attrs) + self.pattern.build(inputs={"input-0": "pool-input-0", }) + + def insert_new_layer(self, graph, parameters, matches): + parameters = graph.parameters + new_layer = self.gen_new_layer(parameters, matches) + new_layer_id = list(matches.keys())[0] + graph.layers[new_layer_id] = new_layer + matches.pop(new_layer_id) + + def gen_new_layer(self, parameters, matches): + layers_id = list(matches.keys()) + layer = matches[layers_id[11]] + pool_size = layer.attrs["list"] + layer = matches[layers_id[0]] + input_name = layer.inputs["input"] + layer = matches[layers_id[-1]] + output_name = layer.outputs[0] + pool_type = layer.attrs["pool_type"] + attrs = dict() + attrs["pool_size"] = pool_size + attrs["pool_type"] = pool_type + new_layer = PaddleLayer( + layers_id[0], + "fluid.layers.adaptive_pool2d", + inputs={"input": input_name}, + outputs=[output_name], + **attrs) + return new_layer diff --git a/x2paddle/optimizer/pytorch_optimizer/fusion/batchnorm2d_fuse_pass.py b/x2paddle/optimizer/pytorch_optimizer/fusion/batchnorm2d_fuse_pass.py new file mode 100644 index 0000000000000000000000000000000000000000..1af1b881020fa35be8c94090b0dd32954993c8c0 --- /dev/null +++ b/x2paddle/optimizer/pytorch_optimizer/fusion/batchnorm2d_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.pytorch_optimizer.pass_ import Pass +from x2paddle.optimizer.pytorch_optimizer.fusion import BatchNorm2dFuser +from x2paddle.optimizer.pytorch_optimizer.pass_manager import pass_register + + +@pass_register +class BatchNorm2dFusePass(Pass): + name = "batchnorm2d_fuse_pass" + + def __init__(self): + Pass.__init__(self) + + def apply(self, graph): + fuser = BatchNorm2dFuser() + fuser.operate(graph, match_kind="topo") + + +# 用于注册 +batchnorm2d_fuse_pass = BatchNorm2dFusePass() diff --git a/x2paddle/optimizer/pytorch_optimizer/fusion/batchnorm2d_fuser.py b/x2paddle/optimizer/pytorch_optimizer/fusion/batchnorm2d_fuser.py new file mode 100644 index 0000000000000000000000000000000000000000..6b6dab45ec8501875e6b9a545d0df2b9ad994308 --- /dev/null +++ b/x2paddle/optimizer/pytorch_optimizer/fusion/batchnorm2d_fuser.py @@ -0,0 +1,158 @@ +# 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 numpy as np +from x2paddle.optimizer.pytorch_optimizer.pattern_matcher import FuseBase +from x2paddle.core.program import PaddleGraph, PaddleLayer +from x2paddle.core.util import * + + +class BatchNorm2dFuser(FuseBase): + def __init__(self): + super(BatchNorm2dFuser, self).__init__(graph_type="dygraph") + + def build_pattern(self): + """ 描述需要替换的batchnorm2d图结构。 + batchnorm2d层模式python实现代码示例: + x336 = fluid.layers.shape(input=x334) + x336 = len(x336) + x337 = x336 != 4 + if x337 : + raise RaiseException('Exception') + if False : + x351 = fluid.layers.shape(input=x334) + x352 = x351[0] + x353 = len(x351) + x354 = x353 - 2 + x357 = x352 + for _x356 in range(x354): + x358 = _x356 + 2 + x359 = x351[x358] + x360 = x357 * x359 + x355 = x360 + x361 = x355 == 1 + if x361 : + raise RaiseException('Exception') + x364 = self.batchnorm7(x334) + """ + + def gen_name(id): + return "x" + str(id) + + self.pattern.add_layer( + "fluid.layers.shape", + inputs={'input': "bn-input-0"}, + outputs=[gen_name(0)]) + self.pattern.add_layer( + "prim.len", inputs={'input': gen_name(0)}, outputs=[gen_name(0)]) + self.pattern.add_layer( + "prim.ne", inputs={"x": gen_name(0)}, outputs=[gen_name(1)], y=4) + self.pattern.add_layer("prim.if", {'input': gen_name(1)}, [gen_name(2)]) + if_layer1 = self.pattern.layers[list(self.pattern.layers.keys())[-1]] + pattern_block0 = PaddleGraph(if_layer1, graph_type="dygraph") + pattern_block0.add_layer( + "prim.exception", + inputs={}, + outputs=[gen_name(3)], + input="Exception") + if_layer1.add_block(pattern_block0) + pattern_block1 = PaddleGraph(if_layer1, graph_type="dygraph") + if_layer1.add_block(pattern_block1) + self.pattern.add_layer("prim.if", {}, [gen_name(4)], input=False) + if_layer2 = self.pattern.layers[list(self.pattern.layers.keys())[-1]] + pattern_block0 = PaddleGraph(if_layer2, graph_type="dygraph") + pattern_block0.add_layer( + "fluid.layers.shape", + inputs={'input': "bn-input-0"}, + outputs=[gen_name(5)]) + pattern_block0.add_layer( + "prim.getitem", + inputs={"list": gen_name(5)}, + outputs=[gen_name(6)], + index=0) + pattern_block0.add_layer( + "prim.len", inputs={"input": gen_name(5)}, outputs=[gen_name(7)]) + pattern_block0.add_layer( + "prim.sub", inputs={"x": gen_name(7)}, outputs=[gen_name(8)], y=2) + pattern_block0.add_layer( + "prim.equal", inputs={"input": gen_name(6)}, outputs=[gen_name(9)]) + pattern_block0.add_layer( + "prim.loop", + inputs={"input": gen_name(8)}, + outputs=[gen_name(8.1), gen_name(10)]) + loop_layer = pattern_block0.layers[list(pattern_block0.layers.keys())[ + -1]] + pattern_block0_block0 = PaddleGraph(loop_layer, graph_type="dygraph") + pattern_block0_block0.add_layer( + "prim.add", inputs={"x": gen_name(10)}, outputs=[gen_name(11)], y=2) + pattern_block0_block0.add_layer( + "prim.getitem", + inputs={"list": gen_name(5), + "index": gen_name(11)}, + outputs=[gen_name(12)]) + pattern_block0_block0.add_layer( + "prim.mul", + inputs={"x": gen_name(9), + "y": gen_name(12)}, + outputs=[gen_name(13)]) + pattern_block0_block0.add_layer( + "prim.equal", + inputs={"input": gen_name(13)}, + outputs=[gen_name(8.1)]) + loop_layer.inputs["input-1"] = gen_name(5) + loop_layer.inputs["input-2"] = gen_name(9) + loop_layer.add_block(pattern_block0_block0) + pattern_block0.add_layer( + "prim.eq", inputs={"x": gen_name(8.1)}, outputs=[gen_name(14)], y=1) + pattern_block0.add_layer( + "prim.if", inputs={"input": gen_name(14)}, outputs=[gen_name(15)]) + if_layer21 = pattern_block0.layers[list(pattern_block0.layers.keys())[ + -1]] + pattern_block0_block0 = PaddleGraph(if_layer21, graph_type="dygraph") + pattern_block0_block0.add_layer( + "prim.exception", + inputs={}, + outputs=[gen_name(15)], + input="Exception") + if_layer21.add_block(pattern_block0_block0) + pattern_block0_block1 = PaddleGraph(if_layer21, graph_type="dygraph") + if_layer21.add_block(pattern_block0_block1) + if_layer2.add_block(pattern_block0) + pattern_block1 = PaddleGraph(if_layer2, graph_type="dygraph") + if_layer2.add_block(pattern_block1) + if_layer2.inputs["input-0"] = "bn-input-0" + self.pattern.add_layer( + "paddle.nn.BatchNorm", + inputs={"input": "bn-input-0"}, + outputs=[gen_name(16), gen_name(17)], + is_test=True, + num_channels=160, + momentum=0.1, + epsilon=0.001) + self.pattern.build(inputs={"input-0": "bn-input-0"}) + + def insert_new_layer(self, graph, parameters, matches): + new_layer = self.gen_new_layer(parameters, matches) + new_layer_id = list(matches.keys())[0] + graph.layers[new_layer_id] = new_layer + matches.pop(new_layer_id) + +# for layer in matches.values(): +# print(layer.outputs) +# print("-------") + + def gen_new_layer(self, parameters, matches): + layers_id = list(matches.keys()) + layer = matches[layers_id[-1]] + return layer diff --git a/x2paddle/optimizer/pytorch_optimizer/fusion/constant_fuse_pass.py b/x2paddle/optimizer/pytorch_optimizer/fusion/constant_fuse_pass.py new file mode 100644 index 0000000000000000000000000000000000000000..c006284d0b4c55e4e0ec4b5aca4c571858bb5dba --- /dev/null +++ b/x2paddle/optimizer/pytorch_optimizer/fusion/constant_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.pytorch_optimizer.pass_ import Pass +from x2paddle.optimizer.pytorch_optimizer.fusion import ConstantFuser +from x2paddle.optimizer.pytorch_optimizer.pass_manager import pass_register + + +@pass_register +class ConstantFusePass(Pass): + name = "constant_fuse_pass" + + def __init__(self): + Pass.__init__(self) + + def apply(self, graph): + fuser = ConstantFuser() + fuser.operate(graph, match_kind="topo") + + +# 用于注册 +constant_fuse_pass = ConstantFuser() diff --git a/x2paddle/optimizer/pytorch_optimizer/fusion/constant_fuser.py b/x2paddle/optimizer/pytorch_optimizer/fusion/constant_fuser.py new file mode 100644 index 0000000000000000000000000000000000000000..f036212fcb264f7963eb6fe35aa803f21689d6aa --- /dev/null +++ b/x2paddle/optimizer/pytorch_optimizer/fusion/constant_fuser.py @@ -0,0 +1,63 @@ +# 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 numpy as np +from x2paddle.optimizer.pytorch_optimizer.pattern_matcher import FuseBase +from x2paddle.core.program import PaddleGraph, PaddleLayer +from x2paddle.core.util import * + + +class ConstantFuser(FuseBase): + def __init__(self): + super(ConstantFuser, self).__init__(graph_type="dygraph") + + def build_pattern(self): + """ 描述需要替换的constant图结构。 + constant层模式python实现代码示例: + x3 = 10 + for _x70 in range(x3): + ... + """ + self.pattern.add_layer( + "prim.constant", inputs={}, outputs=["x1"], value=2) + self.pattern.build() + self.pattern.outputs = ["x1"] + + def insert_new_layer(self, graph, parameters, matches): + def replace_value(layer_connect, match_name, match_value): + for k, v in layer_connect.inputs.items(): + if v == match_name: + layer_connect.inputs.pop(k) + layer_connect.attrs[k] = match_value + break + for k, v in layer_connect.attrs.items(): + if v == match_name: + layer_connect.attrs[k] = match_value + break + if layer_connect.kernel == "prim.loop" or \ + layer_connect.kernel == "prim.if": + for block in layer_connect.blocks: + for b_layer_id, b_layer in block.layers.items(): + if block.edges_in.get(b_layer_id, 0) != 0 and \ + -1 in block.edges_in[b_layer_id]: + replace_value(b_layer, match_name, match_value) + + layer_id = list(matches.keys())[0] + layer = list(matches.values())[0] + layer_output_name = layer.outputs[0] + layer_value = layer.attrs["value"] + if graph.edges_out.get(layer_id, 0) != 0: + for layer_id_out in graph.edges_out[layer_id]: + layer_connect = graph.layers[layer_id_out] + replace_value(layer_connect, layer_output_name, layer_value) diff --git a/x2paddle/optimizer/pytorch_optimizer/fusion/dropout_fuse_pass.py b/x2paddle/optimizer/pytorch_optimizer/fusion/dropout_fuse_pass.py new file mode 100644 index 0000000000000000000000000000000000000000..5c4cce4065dcb268ae7f4f73977756c69027f5af --- /dev/null +++ b/x2paddle/optimizer/pytorch_optimizer/fusion/dropout_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.pytorch_optimizer.pass_ import Pass +from x2paddle.optimizer.pytorch_optimizer.fusion import DropoutFuser +from x2paddle.optimizer.pytorch_optimizer.pass_manager import pass_register + + +@pass_register +class DropoutFusePass(Pass): + name = "dropout_fuse_pass" + + def __init__(self): + Pass.__init__(self) + + def apply(self, graph): + fuser = DropoutFuser() + fuser.operate(graph, match_kind="topo") + + +# 用于注册 +dropout_fuse_pass = DropoutFuser() diff --git a/x2paddle/optimizer/pytorch_optimizer/fusion/dropout_fuser.py b/x2paddle/optimizer/pytorch_optimizer/fusion/dropout_fuser.py new file mode 100644 index 0000000000000000000000000000000000000000..bfece3fb4a6bd4f814e0a009167e4a4f9a9d38be --- /dev/null +++ b/x2paddle/optimizer/pytorch_optimizer/fusion/dropout_fuser.py @@ -0,0 +1,60 @@ +# 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 numpy as np +from x2paddle.optimizer.pytorch_optimizer.pattern_matcher import FuseBase +from x2paddle.core.program import PaddleGraph, PaddleLayer +from x2paddle.core.util import * + + +class DropoutFuser(FuseBase): + def __init__(self): + super(DropoutFuser, self).__init__(graph_type="dygraph") + + def build_pattern(self): + """ 描述需要替换的constant图结构。 + constant层模式python实现代码示例: + x3 = 10 + for _x70 in range(x3): + ... + """ + self.pattern.add_layer( + "paddle.nn.Dropout", + inputs={"input": "dropout-input-0"}, + outputs=["dropout0", "x1"]) + self.pattern.build(inputs={"input-0": "dropout-input-0"}) + self.pattern.outputs = ["dropout0", "x1"] + + def insert_new_layer(self, graph, parameters, matches): + def replace_value(layer_connect, match_name, match_input): + for k, v in layer_connect.inputs.items(): + if v == match_name: + layer_connect.inputs[k] = match_input + break + if layer_connect.kernel == "prim.loop" or \ + layer_connect.kernel == "prim.if": + for block in layer_connect.blocks: + for b_layer_id, b_layer in block.layers.items(): + if block.edges_in.get(b_layer_id, 0) != 0 and \ + -1 in block.edges_in[b_layer_id]: + replace_value(b_layer, match_name, match_input) + + layer_id = list(matches.keys())[0] + layer = list(matches.values())[0] + layer_output_name = layer.outputs[1] + layer_input = layer.inputs["input"] + if graph.edges_out.get(layer_id, 0) != 0: + for layer_id_out in graph.edges_out[layer_id]: + layer_connect = graph.layers[layer_id_out] + replace_value(layer_connect, layer_output_name, layer_input) diff --git a/x2paddle/optimizer/pytorch_optimizer/fusion/fc_fuse_pass.py b/x2paddle/optimizer/pytorch_optimizer/fusion/fc_fuse_pass.py new file mode 100644 index 0000000000000000000000000000000000000000..c94b67b1b122473a8311fa0b3406061076af2944 --- /dev/null +++ b/x2paddle/optimizer/pytorch_optimizer/fusion/fc_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.pytorch_optimizer.pass_ import Pass +from x2paddle.optimizer.pytorch_optimizer.fusion import FcFuser +from x2paddle.optimizer.pytorch_optimizer.pass_manager import pass_register + + +@pass_register +class FcFusePass(Pass): + name = "fc_fuse_pass" + + def __init__(self): + Pass.__init__(self) + + def apply(self, graph): + fuser = FcFuser() + fuser.operate(graph, match_kind="topo") + + +# 用于注册 +fc_fuse_pass = FcFusePass() diff --git a/x2paddle/optimizer/pytorch_optimizer/fusion/fc_fuser.py b/x2paddle/optimizer/pytorch_optimizer/fusion/fc_fuser.py new file mode 100644 index 0000000000000000000000000000000000000000..079ab6fa260edb1938b9b495744f586686c311f4 --- /dev/null +++ b/x2paddle/optimizer/pytorch_optimizer/fusion/fc_fuser.py @@ -0,0 +1,158 @@ +# 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 numpy as np +from x2paddle.optimizer.pytorch_optimizer.pattern_matcher import FuseBase +from x2paddle.core.program import PaddleGraph, PaddleLayer +from x2paddle.core.util import * + + +class FcFuser(FuseBase): + def __init__(self): + self.linear_index = 0 + super(FcFuser, self).__init__(graph_type="dygraph") + + def build_pattern(self): + """ 描述需要替换的fc图结构。 + fc层模式python实现代码示例: + x133 = x128.shape + x133 = len(x133) + x134 = x133 == 2 + if x134 : + classifier_6_weight = self.classifier_6_weight + x136 = fluid.layers.transpose(x=classifier_6_weight, perm=[1, 0]) + classifier_6_bias = self.classifier_6_bias + x137 = paddle.addmm(input=classifier_6_bias, x=x128, y=x136, beta=1, alpha=1) + x135 = x137 + else: + classifier_6_weight = self.classifier_6_weight + x138 = fluid.layers.transpose(x=classifier_6_weight, perm=[1, 0]) + x139 = fluid.layers.matmul(x=x128, y=x138) + classifier_6_bias = self.classifier_6_bias + x140 = x139 + 1 * classifier_6_bias + x135 = x140 + """ + + def gen_name(id): + return "x" + str(id) + + self.pattern.add_layer( + "fluid.layers.shape", + inputs={'input': "fc-input-0"}, + outputs=[gen_name(2)]) + self.pattern.add_layer( + "prim.len", inputs={'input': gen_name(2)}, outputs=[gen_name(2)]) + self.pattern.add_layer( + "prim.eq", + inputs={"eq0": gen_name(2)}, + outputs=[gen_name(3)], + eq1=2) + self.pattern.add_layer("prim.if", {'input': gen_name(3)}, [gen_name(4)]) + self.pattern.outputs.append(gen_name(4)) + if_layer1 = self.pattern.layers[list(self.pattern.layers.keys())[-1]] + pattern_block0 = PaddleGraph(if_layer1, graph_type="dygraph") + pattern_block0.add_layer( + "fluid.dygraph.base.to_variable", + inputs={}, + outputs=[gen_name(5)], + value="params[{}]".format(string(gen_name(5)))) + pattern_block0.add_layer( + "fluid.layers.transpose", + inputs={"x": gen_name(5)}, + outputs=[gen_name(6)], + perm=[1, 0]) + pattern_block0.add_layer( + "fluid.dygraph.base.to_variable", + inputs={}, + outputs=[gen_name(7)], + value="params[{}]".format(string(gen_name(7)))) + pattern_block0.add_layer( + "paddle.addmm", + inputs={"input": gen_name(7), + "x": "fc-input-0", + "y": gen_name(6)}, + outputs=[gen_name(8)], + beta=1, + alpha=1) + if_layer1.inputs["input-0"] = "fc-input-0" + self.pattern.inputs.append("fc-input-0") + pattern_block0.add_layer( + "prim.equal", inputs={'input': gen_name(8)}, outputs=[gen_name(4)]) + if_layer1.add_block(pattern_block0) + pattern_block1 = PaddleGraph(if_layer1, graph_type="dygraph") + pattern_block1.add_layer( + "fluid.dygraph.base.to_variable", + inputs={}, + outputs=[gen_name(5)], + value="params[{}]".format(string(gen_name(5)))) + pattern_block1.add_layer( + "fluid.layers.transpose", + inputs={"x": gen_name(5)}, + outputs=[gen_name(6)], + perm=[1, 0]) + pattern_block1.add_layer( + "paddle.matmul", + inputs={"x": "fc-input-0", + "y": gen_name(6)}, + outputs=[gen_name(9)]) + if_layer1.inputs["input-1"] = "fc-input-0" + pattern_block1.add_layer( + "fluid.dygraph.base.to_variable", + inputs={}, + outputs=[gen_name(12)], + value="params[{}]".format(string(gen_name(12)))) + pattern_block1.add_layer( + "prim.add_", + inputs={"x": gen_name(9), + "y": gen_name(12)}, + outputs=[gen_name(13)], + alpha=1) + pattern_block1.add_layer( + "prim.equal", inputs={'input': gen_name(13)}, + outputs=[gen_name(4)]) + if_layer1.add_block(pattern_block1) + self.pattern.build(inputs={"input-0": "fc-input-0"}) + + def insert_new_layer(self, graph, parameters, matches): + new_layer = self.gen_new_layer(parameters, matches) + new_layer_id = list(matches.keys())[0] + graph.layers[new_layer_id] = new_layer + matches.pop(new_layer_id) + + def gen_new_layer(self, parameters, matches): + layers_id = list(matches.keys()) + layer = matches[layers_id[0]] + input_name = layer.inputs["input"] + layer = matches[layers_id[3]] + output_name = layer.outputs[0] + layer = matches[layers_id[4]] + weight_name = layer.attrs["value"][8:-2] + layer = matches[layers_id[6]] + bias_name = layer.attrs["value"][8:-2] + attrs = dict() + attrs["in_features"] = parameters[weight_name].shape[1] + attrs["out_features"] = parameters[weight_name].shape[0] + linear_name = "linear{}".format(self.linear_index) + self.linear_index += 1 + parameters["{}.weight".format(linear_name)] = parameters[ + weight_name].transpose((1, 0)) + parameters["{}.bias".format(linear_name)] = np.squeeze(parameters[ + bias_name]) + new_layer = PaddleLayer( + layers_id[0], + "paddle.nn.Linear", + inputs={"input": input_name}, + outputs=[linear_name, output_name], + **attrs) + return new_layer diff --git a/x2paddle/optimizer/pytorch_optimizer/fusion/interpolate_bilinear_fuse_pass.py b/x2paddle/optimizer/pytorch_optimizer/fusion/interpolate_bilinear_fuse_pass.py new file mode 100644 index 0000000000000000000000000000000000000000..328e055307394a68a6a068948fa1d71d3f902237 --- /dev/null +++ b/x2paddle/optimizer/pytorch_optimizer/fusion/interpolate_bilinear_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.pytorch_optimizer.pass_ import Pass +from x2paddle.optimizer.pytorch_optimizer.fusion import InterpolateBilinearFuser +from x2paddle.optimizer.pytorch_optimizer.pass_manager import pass_register + + +@pass_register +class InterpolateBilinearFusePass(Pass): + name = "interpolate_bilinear_fuse_pass" + + def __init__(self): + Pass.__init__(self) + + def apply(self, graph): + fuser = InterpolateBilinearFuser() + fuser.operate(graph, match_kind="topo") + + +# 用于注册 +interpolate_bilinear_fuse_pass = InterpolateBilinearFusePass() diff --git a/x2paddle/optimizer/pytorch_optimizer/fusion/interpolate_bilinear_fuser.py b/x2paddle/optimizer/pytorch_optimizer/fusion/interpolate_bilinear_fuser.py new file mode 100644 index 0000000000000000000000000000000000000000..a39ffb49e771a925f96b587bb3062fe282a39580 --- /dev/null +++ b/x2paddle/optimizer/pytorch_optimizer/fusion/interpolate_bilinear_fuser.py @@ -0,0 +1,1552 @@ +# 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 numpy as np +from x2paddle.optimizer.pytorch_optimizer.pattern_matcher import FuseBase +from x2paddle.core.program import PaddleGraph, PaddleLayer +from x2paddle.core.util import * + + +class InterpolateBilinearFuser(FuseBase): + def __init__(self): + super(InterpolateBilinearFuser, self).__init__(graph_type="dygraph") + import torch + torch_version = torch.__version__ + torch_version_part = torch_version.split(".") + if int(torch_version_part[0]) == 1 and int(torch_version_part[1]) > 5: + self.version_gt_150 = True + else: + self.version_gt_150 = False + + def build_pattern(self): + """ 描述需要替换的双线性插值图结构。 + interpolate_bilinear层模式python实现代码示例: + x3016 = fluid.layers.shape(input=x3005) + x3016 = len(x3016) + x3017 = x3016 - 2 + x3018 = [] + for _x3020 in range(x3017): + x3018.append(None) + x3021 = (x3005, x8, None, None) + x3022 = fluid.layers.shape(input=x3005) + x3022 = len(x3022) + x3023 = x3022 == 3 + if x3023 : + raise RaiseException('Exception') + x3024 = None + else: + x3026 = fluid.layers.shape(input=x3005) + x3026 = len(x3026) + x3027 = x3026 == 4 + if x3027 : + x3044, x3045, x3046, x3047 = x3021 + x3048 = x3045 is None + if x3048 : + x3051 = x3046 is None + x3049 = x3051 + x3050 = x3045 + else: + x3052 = x3045 + x3049 = False + x3050 = x3052 + if x3049 : + raise RaiseException('Exception') + x3055 = x3050 is not None + if x3055 : + x3058 = x3050 + x3059 = x3046 is not None + x3056 = x3059 + x3057 = x3058 + else: + x3056 = False + x3057 = x3050 + if x3056 : + raise RaiseException('Exception') + x3060 = None + x3061 = None + else: + x3060 = x3046 + x3061 = x3057 + x3063 = x3060 is not None + if x3063 : + x3065 = x3060 + x3066 = len(x3065) + x3067 = x3066 != 2 + if x3067 : + raise RaiseException('Exception') + x3064 = x3065 + else: + x3064 = x3060 + x3070 = x3061 is not None + if x3070 : + x3072 = x3061 + x3071 = x3072 + else: + x3071 = None + if x3070 : + x3073 = x3071 + else: + x3074 = x3064 is not None + if x3074 : + x3076 = x3064 + x3075 = x3076 + else: + raise RaiseException('Exception') + x3075 = None + x3078 = x3047 is None + if x3078 : + x3080 = len(x3075) + x3081 = x3080 > 0 + x3086 = 0 + for x3083 in range(2147483647): + x3087 = x3075[x3086] + x3088 = math.floor(x3087) + x3089 = x3088 != x3087 + if x3089 : + x3090 = False + x3091 = x3089 + else: + x3090 = None + x3091 = None + if x3089 : + x3092 = x3090 + x3093 = x3091 + else: + x3092 = True + x3093 = x3089 + x3094 = x3086 + 1 + x3095 = x3094 < x3080 + x3096 = x3095 and x3092 + x3082 = x3093 + x3083 = x3094 + if x3082 : + import warnings + warnings.warn('The default behavior for interpolate/upsample with float scale_factor will change in 1.6.0 to align with other frameworks/libraries, and use scale_factor directly, instead of relying on the computed output size. If you wish to keep the old behavior, please set recompute_scale_factor=True. See the documentation of nn.Upsample for details. ', stacklevel=2) + x3099 = [] + for _x3101 in range(2): + x3102 = _x3101 + 2 + x3103 = fluid.layers.shape(x3044)[x3102] + x3104 = float(x3103) + x3105 = x3075[_x3101] + x3106 = x3104 * x3105 + x3107 = math.floor(x3106) + x3099.append(x3107) + x3073 = x3099 + x3108 = x3018[0] + x3109 = x3018[1] + x3073_isinstance = isinstance(x3073, paddle.fluid.Variable) + if x3073_isinstance : + x3073 = x3073.numpy().tolist() + assert x3108 == x3109, 'The x3108 must be x3109!' + x3110 = paddle.nn.functional.interpolate(x=x3005, size=x3073, scale_factor=x3108, align_corners=False, align_mode=0) + x3028 = x3110 + else: + x3111 = fluid.layers.shape(input=x3005) + x3111 = len(x3111) + x3112 = x3111 == 5 + if x3112 : + raise RaiseException('Exception') + else: + raise RaiseException('Exception') + x3028 = None + x3024 = x3028 + """ + + def gen_name(id): + return "x" + str(id) + + if self.version_gt_150: + self.pattern.add_layer( + "fluid.layers.shape", + inputs={"input": "interpolate-input-0"}, + outputs=[gen_name(9)]) + self.pattern.add_layer( + "prim.len", + inputs={"input": gen_name(9)}, + outputs=[gen_name(9)]) + self.pattern.add_layer( + "prim.sub", + inputs={"x": gen_name(9)}, + outputs=[gen_name(10)], + y=2) + self.pattern.add_layer( + "prim.list", inputs={}, outputs=[gen_name(11)]) + self.pattern.add_layer( + "prim.loop", + inputs={"input": gen_name(10)}, + outputs=[gen_name(12.1), gen_name(12.2)]) + loop_layer = self.pattern.layers[list(self.pattern.layers.keys())[ + -1]] + pattern_block = PaddleGraph(loop_layer, graph_type="dygraph") + pattern_block.add_layer( + "prim.append", + inputs={"list": gen_name(11)}, + outputs=[], + element=None) + loop_layer.inputs["input-0"] = gen_name(11) + loop_layer.add_block(pattern_block) + self.pattern.add_layer( + "prim.tuple", + inputs={ + "input0": "interpolate-input-0", + "input1": "interpolate-input-1", + }, + outputs=[gen_name(13)], + input2=None, + input3=None) + self.pattern.add_layer( + "fluid.layers.shape", + inputs={"input": "interpolate-input-0"}, + outputs=[gen_name(14)]) + self.pattern.add_layer( + "prim.len", + inputs={"input": gen_name(14)}, + outputs=[gen_name(14)]) + self.pattern.add_layer( + "prim.eq", + inputs={"x": gen_name(14)}, + outputs=[gen_name(15)], + y=3) + self.pattern.add_layer( + "prim.if", + inputs={"input": gen_name(15)}, + outputs=[gen_name(16)]) + if_layer1 = self.pattern.layers[list(self.pattern.layers.keys())[ + -1]] + pattern_block = PaddleGraph(if_layer1, graph_type="dygraph") + pattern_block.add_layer( + "prim.exception", + inputs={}, + outputs=[gen_name(17)], + input="Exception") + pattern_block.add_layer( + "prim.equal", inputs={}, outputs=[gen_name(16)], input=None) + if_layer1.add_block(pattern_block) + pattern_block = PaddleGraph(if_layer1, graph_type="dygraph") + pattern_block.add_layer( + "fluid.layers.shape", + inputs={"input": "interpolate-input-0"}, + outputs=[gen_name(18)]) + pattern_block.add_layer( + "prim.len", + inputs={"input": gen_name(18)}, + outputs=[gen_name(18)]) + pattern_block.add_layer( + "prim.eq", + inputs={"x": gen_name(18)}, + outputs=[gen_name(19)], + y=4) + pattern_block.add_layer( + "prim.if", + inputs={"input": gen_name(19)}, + outputs=[gen_name(20)]) + if_layer2 = pattern_block.layers[list(pattern_block.layers.keys())[ + -1]] + pattern_block_block = PaddleGraph(if_layer2, graph_type="dygraph") + pattern_block_block.add_layer( + "prim.tuple_unpack", + inputs={"input": gen_name(13)}, + outputs=[ + gen_name(34), gen_name(35), gen_name(36), gen_name(37) + ]) + pattern_block_block.add_layer( + "prim.is", + inputs={"x": gen_name(35)}, + outputs=[gen_name(38)], + y=None) + pattern_block_block.add_layer( + "prim.if", + inputs={"input": gen_name(38)}, + outputs=[gen_name(39), gen_name(40)]) + if_layer3 = pattern_block_block.layers[list( + pattern_block_block.layers.keys())[-1]] + pattern_block_block_block = PaddleGraph( + if_layer3, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.is", + inputs={"x": gen_name(36)}, + outputs=[gen_name(41)], + y=None) + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(41)}, + outputs=[gen_name(39)]) + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(35)}, + outputs=[gen_name(40)]) + if_layer3.add_block(pattern_block_block_block) + pattern_block_block_block = PaddleGraph( + if_layer3, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(35)}, + outputs=[gen_name(42)]) + pattern_block_block_block.add_layer( + "prim.equal", inputs={}, outputs=[gen_name(39)], input=False) + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(35)}, + outputs=[gen_name(40)]) + if_layer3.add_block(pattern_block_block_block) + if_layer3.inputs.update({ + "input-0": gen_name(36), + 'input-1': gen_name(35), + 'input-2': gen_name(35), + }) + pattern_block_block.add_layer( + "prim.if", + inputs={"input": gen_name(39)}, + outputs=[gen_name(43)]) + if_layer4 = pattern_block_block.layers[list( + pattern_block_block.layers.keys())[-1]] + pattern_block_block_block = PaddleGraph( + if_layer4, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.exception", + inputs={}, + outputs=[gen_name(44)], + input="Exception") + if_layer4.add_block(pattern_block_block_block) + pattern_block_block_block = PaddleGraph( + if_layer4, graph_type="dygraph") + if_layer4.add_block(pattern_block_block_block) + pattern_block_block.add_layer( + "prim.isnot", + inputs={"x": gen_name(40)}, + outputs=[gen_name(45)], + y=None) + pattern_block_block.add_layer( + "prim.if", + inputs={"input": gen_name(45)}, + outputs=[gen_name(46), gen_name(47)]) + if_layer5 = pattern_block_block.layers[list( + pattern_block_block.layers.keys())[-1]] + pattern_block_block_block = PaddleGraph( + if_layer5, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(40)}, + outputs=[gen_name(48)]) + pattern_block_block_block.add_layer( + "prim.isnot", + inputs={"x": gen_name(36)}, + outputs=[gen_name(49)], + y=None) + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(49)}, + outputs=[gen_name(46)]) + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(48)}, + outputs=[gen_name(47)]) + if_layer5.add_block(pattern_block_block_block) + pattern_block_block_block = PaddleGraph( + if_layer5, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.equal", inputs={}, outputs=[gen_name(46)], input=False) + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(40)}, + outputs=[gen_name(47)]) + if_layer5.add_block(pattern_block_block_block) + if_layer5.inputs.update({ + "input-0": gen_name(40), + "input-1": gen_name(36), + "input-3": gen_name(40) + }) + pattern_block_block.add_layer( + "prim.if", + inputs={"input": gen_name(46)}, + outputs=[gen_name(50), gen_name(51)]) + if_layer6 = pattern_block_block.layers[list( + pattern_block_block.layers.keys())[-1]] + pattern_block_block_block = PaddleGraph( + if_layer6, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.exception", + inputs={}, + outputs=[gen_name(52)], + input="Exception") + pattern_block_block_block.add_layer( + "prim.equal", inputs={}, outputs=[gen_name(50)], input=None) + pattern_block_block_block.add_layer( + "prim.equal", inputs={}, outputs=[gen_name(51)], input=None) + if_layer6.add_block(pattern_block_block_block) + pattern_block_block_block = PaddleGraph( + if_layer6, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(36)}, + outputs=[gen_name(50)]) + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(47)}, + outputs=[gen_name(51)]) + if_layer6.add_block(pattern_block_block_block) + if_layer6.inputs.update({ + "input-0": gen_name(36), + "input-1": gen_name(47) + }) + pattern_block_block.add_layer( + "prim.isnot", + inputs={"x": gen_name(50)}, + outputs=[gen_name(53)], + y=None) + pattern_block_block.add_layer( + "prim.if", + inputs={"input": gen_name(53)}, + outputs=[gen_name(54)]) + if_layer7 = pattern_block_block.layers[list( + pattern_block_block.layers.keys())[-1]] + pattern_block_block_block = PaddleGraph( + if_layer7, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(50)}, + outputs=[gen_name(55)]) + pattern_block_block_block.add_layer( + "prim.len", + inputs={"input": gen_name(55)}, + outputs=[gen_name(56)]) + pattern_block_block_block.add_layer( + "prim.ne", + inputs={"x": gen_name(56)}, + outputs=[gen_name(57)], + y=2) + pattern_block_block_block.add_layer( + "prim.if", + inputs={"input": gen_name(57)}, + outputs=[gen_name(58)]) + if_layer8 = pattern_block_block_block.layers[list( + pattern_block_block_block.layers.keys())[-1]] + pattern_block_block_block_block = PaddleGraph( + if_layer8, graph_type="dygraph") + pattern_block_block_block_block.add_layer( + "prim.exception", + inputs={}, + outputs=[gen_name(59)], + input="Exception") + if_layer8.add_block(pattern_block_block_block_block) + pattern_block_block_block_block = PaddleGraph( + if_layer8, graph_type="dygraph") + if_layer8.add_block(pattern_block_block_block_block) + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(55)}, + outputs=[gen_name(54)]) + if_layer7.add_block(pattern_block_block_block) + pattern_block_block_block = PaddleGraph( + if_layer7, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(50)}, + outputs=[gen_name(54)]) + if_layer7.add_block(pattern_block_block_block) + if_layer7.inputs.update({ + "input-0": gen_name(50), + "input-1": gen_name(50) + }) + pattern_block_block.add_layer( + "prim.isnot", + inputs={"x": gen_name(51)}, + outputs=[gen_name(60)], + y=None) + pattern_block_block.add_layer( + "prim.if", + inputs={"input": gen_name(60)}, + outputs=[gen_name(61)]) + if_layer9 = pattern_block_block.layers[list( + pattern_block_block.layers.keys())[-1]] + pattern_block_block_block = PaddleGraph( + if_layer9, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(51)}, + outputs=[gen_name(62)]) + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(62)}, + outputs=[gen_name(61)]) + if_layer9.add_block(pattern_block_block_block) + pattern_block_block_block = PaddleGraph( + if_layer9, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.isnot", + inputs={"x": gen_name(54)}, + outputs=[gen_name(64)], + y=None) + pattern_block_block_block.add_layer( + "prim.if", + inputs={"input": gen_name(64)}, + outputs=[gen_name(65)]) + if_layer11 = pattern_block_block_block.layers[list( + pattern_block_block_block.layers.keys())[-1]] + pattern_block_block_block_block = PaddleGraph( + if_layer11, graph_type="dygraph") + pattern_block_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(54)}, + outputs=[gen_name(66)]) + pattern_block_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(66)}, + outputs=[gen_name(65)]) + if_layer11.add_block(pattern_block_block_block_block) + pattern_block_block_block_block = PaddleGraph( + if_layer11, graph_type="dygraph") + pattern_block_block_block_block.add_layer( + "prim.exception", + inputs={}, + outputs=[gen_name(67)], + input="Exception") + pattern_block_block_block_block.add_layer( + "prim.equal", inputs={}, outputs=[gen_name(65)], input=None) + if_layer11.add_block(pattern_block_block_block_block) + if_layer11.inputs.update({"input-0": gen_name(54), }) + pattern_block_block_block.add_layer( + "prim.is", + inputs={"x": gen_name(37)}, + outputs=[gen_name(68)], + y=None) + pattern_block_block_block.add_layer( + "prim.if", + inputs={"input": gen_name(68)}, + outputs=[gen_name(69)]) + if_layer12 = pattern_block_block_block.layers[list( + pattern_block_block_block.layers.keys())[-1]] + pattern_block_block_block_block = PaddleGraph( + if_layer12, graph_type="dygraph") + pattern_block_block_block_block.add_layer( + "prim.len", + inputs={"input": gen_name(65)}, + outputs=[gen_name(70)]) + pattern_block_block_block_block.add_layer( + "prim.gt", + inputs={"x": gen_name(70)}, + outputs=[gen_name(71)], + y=0) + pattern_block_block_block_block.add_layer( + "prim.equal", inputs={}, outputs=[gen_name(72)], input=0) + pattern_block_block_block_block.add_layer( + "prim.loop", + inputs={}, + outputs=[gen_name(74), gen_name(75), gen_name(76.1)], + input=2147483647) + loop_layer = pattern_block_block_block_block.layers[list( + pattern_block_block_block_block.layers.keys())[-1]] + pattern_loop_block = PaddleGraph(loop_layer, graph_type="dygraph") + pattern_loop_block.add_layer( + "prim.getitem", + inputs={"list": gen_name(65), + "element": gen_name(72)}, + outputs=[gen_name(74.1)]) + pattern_loop_block.add_layer( + "prim.floor", + inputs={"input": gen_name(74.1)}, + outputs=[gen_name(75.1)]) + pattern_loop_block.add_layer( + "prim.ne", + inputs={"x": gen_name(75.1), + "y": gen_name(74.1)}, + outputs=[gen_name(76)]) + pattern_loop_block.add_layer( + "prim.if", + inputs={"input": gen_name(76)}, + outputs=[gen_name(77)]) + if_layer13 = pattern_loop_block.layers[list( + pattern_loop_block.layers.keys())[-1]] + pattern_loop_block_block = PaddleGraph( + if_layer13, graph_type="dygraph") + pattern_loop_block_block.add_layer( + "prim.equal", inputs={}, outputs=[gen_name(77)], input=False) + if_layer13.add_block(pattern_loop_block_block) + pattern_loop_block_block = PaddleGraph( + if_layer13, graph_type="dygraph") + pattern_loop_block_block.add_layer( + "prim.equal", inputs={}, outputs=[gen_name(77)], input=True) + if_layer13.add_block(pattern_loop_block_block) + pattern_loop_block.add_layer( + "prim.add", + inputs={"x": gen_name(72)}, + outputs=[gen_name(81)], + y=1) + pattern_loop_block.add_layer( + "prim.lt", + inputs={"x": gen_name(81), + "y": gen_name(70)}, + outputs=[gen_name(82)]) + pattern_loop_block.add_layer( + "prim.and", + inputs={"x": gen_name(82), + "y": gen_name(77)}, + outputs=[gen_name(83)]) + pattern_loop_block.add_layer( + "prim.equal", + inputs={"input": gen_name(76)}, + outputs=[gen_name(74)]) + pattern_loop_block.add_layer( + "prim.equal", + inputs={"input": gen_name(81)}, + outputs=[gen_name(75)]) + loop_layer.add_block(pattern_loop_block) + loop_layer.inputs.update({ + "input-0": gen_name(65), + "input-1": gen_name(72), + "input-2": gen_name(72), + "input-3": gen_name(70) + }) + pattern_block_block_block_block.add_layer( + "prim.if", + inputs={"input": gen_name(74)}, + outputs=[gen_name(84)]) + if_layer15 = pattern_block_block_block_block.layers[list( + pattern_block_block_block_block.layers.keys())[-1]] + pattern_block_block_block_block_block = PaddleGraph( + if_layer15, graph_type="dygraph") + pattern_block_block_block_block_block.add_layer( + "prim.warnings", + inputs={}, + outputs=[gen_name(85)], + stacklevel=2, + input="...") + if_layer15.add_block(pattern_block_block_block_block_block) + pattern_block_block_block_block_block = PaddleGraph( + if_layer15, graph_type="dygraph") + if_layer15.add_block(pattern_block_block_block_block_block) + if_layer12.add_block(pattern_block_block_block_block) + pattern_block_block_block_block = PaddleGraph( + if_layer12, graph_type="dygraph") + if_layer12.add_block(pattern_block_block_block_block) + if_layer12.inputs.update({ + "input-0": gen_name(65), + "input-1": gen_name(65), + }) + pattern_block_block_block.add_layer( + "prim.list", inputs={}, outputs=[gen_name(86)]) + pattern_block_block_block.add_layer( + "prim.loop", + inputs={}, + outputs=[gen_name(87), gen_name(88)], + input=2) + loop_layer = pattern_block_block_block.layers[list( + pattern_block_block_block.layers.keys())[-1]] + pattern_loop_block = PaddleGraph(loop_layer, graph_type="dygraph") + pattern_loop_block.add_layer( + "prim.add", + inputs={"x": gen_name(88)}, + outputs=[gen_name(89)], + y=2) + pattern_loop_block.add_layer( + "prim.shape_dim", + inputs={"input": gen_name(34), + "dim": gen_name(89)}, + outputs=[gen_name(90)]) + pattern_loop_block.add_layer( + "prim.float", + inputs={"input": gen_name(90)}, + outputs=[gen_name(91)]) + pattern_loop_block.add_layer( + "prim.getitem", + inputs={"list": gen_name(65), + "element": gen_name(88)}, + outputs=[gen_name(92)]) + pattern_loop_block.add_layer( + "prim.mul", + inputs={"x": gen_name(91), + "y": gen_name(92)}, + outputs=[gen_name(93)]) + pattern_loop_block.add_layer( + "prim.floor", + inputs={"input": gen_name(93)}, + outputs=[gen_name(94)]) + pattern_loop_block.add_layer( + "prim.append", + inputs={"list": gen_name(86), + "element": gen_name(94)}, + outputs=[]) + loop_layer.add_block(pattern_loop_block) + loop_layer.inputs.update({ + "input-0": gen_name(34), + "input-1": gen_name(65), + "input-2": gen_name(86) + }) + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(86)}, + outputs=[gen_name(61)]) + if_layer9.add_block(pattern_block_block_block) + if_layer9.inputs.update({ + "input-0": gen_name(51), + "input-1": gen_name(54), + "input-2": gen_name(54), + "input-3": gen_name(37), + "input-4": gen_name(34) + }) + pattern_block_block.add_layer( + "prim.getitem", + inputs={"list": gen_name(11)}, + outputs=[gen_name(95)], + element=0) + pattern_block_block.add_layer( + "prim.getitem", + inputs={"list": gen_name(11)}, + outputs=[gen_name(96)], + element=1) + pattern_block_block.add_layer( + "prim.isinstance", + inputs={"input": gen_name(61)}, + outputs=["interpolate-input-0_isinstance"], + cls="paddle.fluid.Variable") + pattern_block_block.add_layer( + "prim.if", {"input": "interpolate-input-0_isinstance"}, + outputs=["interpolate-input-0_if1"]) + if_layer_isinstance = pattern_block_block.layers[list( + pattern_block_block.layers.keys())[-1]] + pattern_block_block_block = PaddleGraph( + if_layer_isinstance, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.var2list", + inputs={"input": gen_name(61)}, + outputs=[gen_name(61)]) + if_layer_isinstance.add_block(pattern_block_block_block) + pattern_block_block_block = PaddleGraph( + if_layer_isinstance, graph_type="dygraph") + if_layer_isinstance.add_block(pattern_block_block_block) + if_layer_isinstance.inputs["input-0"] = gen_name(61) + pattern_block_block.add_layer( + "prim.assert", + inputs={"key": gen_name(95), + "value": gen_name(96)}, + outputs=[gen_name(97) + "_assert"], + type="eq") + pattern_block_block.add_layer( + "paddle.nn.functional.interpolate", + inputs={ + "input": "interpolate-input-0", + "size": gen_name(61), + "scale_factor": gen_name(95) + }, + outputs=[gen_name(97)], + align_corners=False, + align_mode=0) + pattern_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(97)}, + outputs=[gen_name(20)]) + if_layer2.add_block(pattern_block_block) + pattern_block_block = PaddleGraph(if_layer2, graph_type="dygraph") + pattern_block_block.add_layer( + "fluid.layers.shape", + inputs={"input": "interpolate-input-0"}, + outputs=[gen_name(98)]) + pattern_block_block.add_layer( + "prim.len", + inputs={"input": gen_name(98)}, + outputs=[gen_name(98)]) + pattern_block_block.add_layer( + "prim.eq", + inputs={"x": gen_name(98)}, + outputs=[gen_name(99)], + y=5) + pattern_block_block.add_layer( + "prim.if", + inputs={"input": gen_name(99)}, + outputs=[gen_name(100)]) + if_layer16 = pattern_block_block.layers[list( + pattern_block_block.layers.keys())[-1]] + pattern_block_block_block = PaddleGraph( + if_layer16, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.exception", + inputs={}, + outputs=[gen_name(101)], + input="Exception") + if_layer16.add_block(pattern_block_block_block) + pattern_block_block_block = PaddleGraph( + if_layer16, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.exception", + inputs={}, + outputs=[gen_name(102)], + input="Exception") + if_layer16.add_block(pattern_block_block_block) + pattern_block_block.add_layer( + "prim.equal", inputs={}, outputs=[gen_name(20)], input=None) + if_layer2.add_block(pattern_block_block) + if_layer2.inputs.update({ + "input-0": gen_name(13), + "input-1": gen_name(13), + "input-2": "interpolate-input-0", + "input-3": gen_name(11), + "input-5": gen_name(11), + }) + pattern_block.add_layer( + "prim.equal", + inputs={"input": gen_name(20)}, + outputs=[gen_name(16)]) + if_layer1.add_block(pattern_block) + if_layer1.inputs.update({ + "input-2": "interpolate-input-0", + "input-4": gen_name(13), + "input-7": gen_name(11), + "input-9": gen_name(11), + "input-11": "interpolate-input-0", + "input-12": "interpolate-input-0", + }) + self.pattern.build(inputs={ + "input-0": "interpolate-input-0", + "input-1": "interpolate-input-1" + }) + else: + self.pattern.add_layer( + "fluid.layers.shape", + inputs={"input": "interpolate-input-0"}, + outputs=[gen_name(9)]) + self.pattern.add_layer( + "prim.len", + inputs={"input": gen_name(9)}, + outputs=[gen_name(9)]) + self.pattern.add_layer( + "prim.sub", + inputs={"x": gen_name(9)}, + outputs=[gen_name(10)], + y=2) + self.pattern.add_layer( + "prim.list", inputs={}, outputs=[gen_name(11)]) + self.pattern.add_layer( + "prim.loop", + inputs={"input": gen_name(10)}, + outputs=[gen_name(12.1), gen_name(12.2)]) + loop_layer = self.pattern.layers[list(self.pattern.layers.keys())[ + -1]] + pattern_block = PaddleGraph(loop_layer, graph_type="dygraph") + pattern_block.add_layer( + "prim.append", + inputs={"list": gen_name(11)}, + outputs=[], + element=None) + loop_layer.inputs["input-0"] = gen_name(11) + loop_layer.add_block(pattern_block) + self.pattern.add_layer( + "prim.tuple", + inputs={ + "input0": "interpolate-input-0", + "input1": "interpolate-input-1", + }, + outputs=[gen_name(13)], + input2=None, + input3=None) + self.pattern.add_layer( + "fluid.layers.shape", + inputs={"input": "interpolate-input-0"}, + outputs=[gen_name(14)]) + self.pattern.add_layer( + "prim.len", + inputs={"input": gen_name(14)}, + outputs=[gen_name(14)]) + self.pattern.add_layer( + "prim.eq", + inputs={"x": gen_name(14)}, + outputs=[gen_name(15)], + y=3) + self.pattern.add_layer( + "prim.if", + inputs={"input": gen_name(15)}, + outputs=[gen_name(16)]) + if_layer1 = self.pattern.layers[list(self.pattern.layers.keys())[ + -1]] + pattern_block = PaddleGraph(if_layer1, graph_type="dygraph") + pattern_block.add_layer( + "prim.exception", + inputs={}, + outputs=[gen_name(17)], + input="Exception") + pattern_block.add_layer( + "prim.equal", inputs={}, outputs=[gen_name(16)], input=None) + if_layer1.add_block(pattern_block) + pattern_block = PaddleGraph(if_layer1, graph_type="dygraph") + pattern_block.add_layer( + "fluid.layers.shape", + inputs={"input": "interpolate-input-0"}, + outputs=[gen_name(18)]) + pattern_block.add_layer( + "prim.len", + inputs={"input": gen_name(18)}, + outputs=[gen_name(18)]) + pattern_block.add_layer( + "prim.eq", + inputs={"x": gen_name(18)}, + outputs=[gen_name(19)], + y=4) + pattern_block.add_layer( + "prim.if", + inputs={"input": gen_name(19)}, + outputs=[gen_name(20)]) + if_layer2 = pattern_block.layers[list(pattern_block.layers.keys())[ + -1]] + pattern_block_block = PaddleGraph(if_layer2, graph_type="dygraph") + pattern_block_block.add_layer( + "prim.tuple_unpack", + inputs={"input": gen_name(13)}, + outputs=[ + gen_name(34), gen_name(35), gen_name(36), gen_name(37) + ]) + pattern_block_block.add_layer( + "prim.is", + inputs={"x": gen_name(35)}, + outputs=[gen_name(38)], + y=None) + pattern_block_block.add_layer( + "prim.if", + inputs={"input": gen_name(38)}, + outputs=[gen_name(39), gen_name(40)]) + if_layer3 = pattern_block_block.layers[list( + pattern_block_block.layers.keys())[-1]] + pattern_block_block_block = PaddleGraph( + if_layer3, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.is", + inputs={"x": gen_name(36)}, + outputs=[gen_name(41)], + y=None) + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(41)}, + outputs=[gen_name(39)]) + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(35)}, + outputs=[gen_name(40)]) + if_layer3.add_block(pattern_block_block_block) + pattern_block_block_block = PaddleGraph( + if_layer3, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(35)}, + outputs=[gen_name(42)]) + pattern_block_block_block.add_layer( + "prim.equal", inputs={}, outputs=[gen_name(39)], input=False) + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(35)}, + outputs=[gen_name(40)]) + if_layer3.add_block(pattern_block_block_block) + if_layer3.inputs.update({ + "input-0": gen_name(36), + 'input-1': gen_name(35), + 'input-2': gen_name(35), + }) + pattern_block_block.add_layer( + "prim.if", + inputs={"input": gen_name(39)}, + outputs=[gen_name(43)]) + if_layer4 = pattern_block_block.layers[list( + pattern_block_block.layers.keys())[-1]] + pattern_block_block_block = PaddleGraph( + if_layer4, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.exception", + inputs={}, + outputs=[gen_name(44)], + input="Exception") + if_layer4.add_block(pattern_block_block_block) + pattern_block_block_block = PaddleGraph( + if_layer4, graph_type="dygraph") + if_layer4.add_block(pattern_block_block_block) + pattern_block_block.add_layer( + "prim.isnot", + inputs={"x": gen_name(40)}, + outputs=[gen_name(45)], + y=None) + pattern_block_block.add_layer( + "prim.if", + inputs={"input": gen_name(45)}, + outputs=[gen_name(46), gen_name(47)]) + if_layer5 = pattern_block_block.layers[list( + pattern_block_block.layers.keys())[-1]] + pattern_block_block_block = PaddleGraph( + if_layer5, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(40)}, + outputs=[gen_name(48)]) + pattern_block_block_block.add_layer( + "prim.isnot", + inputs={"x": gen_name(36)}, + outputs=[gen_name(49)], + y=None) + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(49)}, + outputs=[gen_name(46)]) + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(48)}, + outputs=[gen_name(47)]) + if_layer5.add_block(pattern_block_block_block) + pattern_block_block_block = PaddleGraph( + if_layer5, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.equal", inputs={}, outputs=[gen_name(46)], input=False) + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(40)}, + outputs=[gen_name(47)]) + if_layer5.add_block(pattern_block_block_block) + if_layer5.inputs.update({ + "input-0": gen_name(40), + "input-1": gen_name(36), + "input-3": gen_name(40) + }) + pattern_block_block.add_layer( + "prim.if", + inputs={"input": gen_name(46)}, + outputs=[gen_name(50), gen_name(51)]) + if_layer6 = pattern_block_block.layers[list( + pattern_block_block.layers.keys())[-1]] + pattern_block_block_block = PaddleGraph( + if_layer6, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.exception", + inputs={}, + outputs=[gen_name(52)], + input="Exception") + pattern_block_block_block.add_layer( + "prim.equal", inputs={}, outputs=[gen_name(50)], input=None) + pattern_block_block_block.add_layer( + "prim.equal", inputs={}, outputs=[gen_name(51)], input=None) + if_layer6.add_block(pattern_block_block_block) + pattern_block_block_block = PaddleGraph( + if_layer6, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(36)}, + outputs=[gen_name(50)]) + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(47)}, + outputs=[gen_name(51)]) + if_layer6.add_block(pattern_block_block_block) + if_layer6.inputs.update({ + "input-0": gen_name(36), + "input-1": gen_name(47) + }) + pattern_block_block.add_layer( + "prim.isnot", + inputs={"x": gen_name(50)}, + outputs=[gen_name(53)], + y=None) + pattern_block_block.add_layer( + "prim.if", + inputs={"input": gen_name(53)}, + outputs=[gen_name(54)]) + if_layer7 = pattern_block_block.layers[list( + pattern_block_block.layers.keys())[-1]] + pattern_block_block_block = PaddleGraph( + if_layer7, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(50)}, + outputs=[gen_name(55)]) + pattern_block_block_block.add_layer( + "prim.len", + inputs={"input": gen_name(55)}, + outputs=[gen_name(56)]) + pattern_block_block_block.add_layer( + "prim.ne", + inputs={"x": gen_name(56)}, + outputs=[gen_name(57)], + y=2) + pattern_block_block_block.add_layer( + "prim.if", + inputs={"input": gen_name(57)}, + outputs=[gen_name(58)]) + if_layer8 = pattern_block_block_block.layers[list( + pattern_block_block_block.layers.keys())[-1]] + pattern_block_block_block_block = PaddleGraph( + if_layer8, graph_type="dygraph") + pattern_block_block_block_block.add_layer( + "prim.exception", + inputs={}, + outputs=[gen_name(59)], + input="Exception") + if_layer8.add_block(pattern_block_block_block_block) + pattern_block_block_block_block = PaddleGraph( + if_layer8, graph_type="dygraph") + if_layer8.add_block(pattern_block_block_block_block) + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(55)}, + outputs=[gen_name(54)]) + if_layer7.add_block(pattern_block_block_block) + pattern_block_block_block = PaddleGraph( + if_layer7, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(50)}, + outputs=[gen_name(54)]) + if_layer7.add_block(pattern_block_block_block) + if_layer7.inputs.update({ + "input-0": gen_name(50), + "input-1": gen_name(50) + }) + pattern_block_block.add_layer( + "prim.isnot", + inputs={"x": gen_name(51)}, + outputs=[gen_name(60)], + y=None) + pattern_block_block.add_layer( + "prim.if", + inputs={"input": gen_name(60)}, + outputs=[gen_name(61)]) + if_layer9 = pattern_block_block.layers[list( + pattern_block_block.layers.keys())[-1]] + pattern_block_block_block = PaddleGraph( + if_layer9, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(51)}, + outputs=[gen_name(62)]) + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(62)}, + outputs=[gen_name(61)]) + if_layer9.add_block(pattern_block_block_block) + pattern_block_block_block = PaddleGraph( + if_layer9, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.equal", inputs={}, outputs=[gen_name(61)], input=None) + if_layer9.add_block(pattern_block_block_block) + if_layer9.inputs.update({"input-0": gen_name(51)}) + pattern_block_block.add_layer( + "prim.if", + inputs={"input": gen_name(60)}, + outputs=[gen_name(63)]) + if_layer10 = pattern_block_block.layers[list( + pattern_block_block.layers.keys())[-1]] + pattern_block_block_block = PaddleGraph( + if_layer10, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(61)}, + outputs=[gen_name(63)]) + if_layer10.add_block(pattern_block_block_block) + pattern_block_block_block = PaddleGraph( + if_layer10, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.isnot", + inputs={"x": gen_name(54)}, + outputs=[gen_name(64)], + y=None) + pattern_block_block_block.add_layer( + "prim.if", + inputs={"input": gen_name(64)}, + outputs=[gen_name(65)]) + if_layer11 = pattern_block_block_block.layers[list( + pattern_block_block_block.layers.keys())[-1]] + pattern_block_block_block_block = PaddleGraph( + if_layer11, graph_type="dygraph") + pattern_block_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(54)}, + outputs=[gen_name(66)]) + pattern_block_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(66)}, + outputs=[gen_name(65)]) + if_layer11.add_block(pattern_block_block_block_block) + pattern_block_block_block_block = PaddleGraph( + if_layer11, graph_type="dygraph") + pattern_block_block_block_block.add_layer( + "prim.exception", + inputs={}, + outputs=[gen_name(67)], + input="Exception") + pattern_block_block_block_block.add_layer( + "prim.equal", inputs={}, outputs=[gen_name(65)], input=None) + if_layer11.add_block(pattern_block_block_block_block) + if_layer11.inputs.update({"input-0": gen_name(54), }) + pattern_block_block_block.add_layer( + "prim.is", + inputs={"x": gen_name(37)}, + outputs=[gen_name(68)], + y=None) + pattern_block_block_block.add_layer( + "prim.if", + inputs={"input": gen_name(68)}, + outputs=[gen_name(69)]) + if_layer12 = pattern_block_block_block.layers[list( + pattern_block_block_block.layers.keys())[-1]] + pattern_block_block_block_block = PaddleGraph( + if_layer12, graph_type="dygraph") + pattern_block_block_block_block.add_layer( + "prim.len", + inputs={"input": gen_name(65)}, + outputs=[gen_name(70)]) + pattern_block_block_block_block.add_layer( + "prim.gt", + inputs={"x": gen_name(70)}, + outputs=[gen_name(71)], + y=0) + pattern_block_block_block_block.add_layer( + "prim.equal", inputs={}, outputs=[gen_name(72)], input=0) + pattern_block_block_block_block.add_layer( + "prim.loop", + inputs={}, + outputs=[gen_name(74), gen_name(75), gen_name(76.1)], + input=2147483647) + loop_layer = pattern_block_block_block_block.layers[list( + pattern_block_block_block_block.layers.keys())[-1]] + pattern_loop_block = PaddleGraph(loop_layer, graph_type="dygraph") + pattern_loop_block.add_layer( + "prim.getitem", + inputs={"list": gen_name(65), + "element": gen_name(72)}, + outputs=[gen_name(74.1)]) + pattern_loop_block.add_layer( + "prim.floor", + inputs={"input": gen_name(74.1)}, + outputs=[gen_name(75.1)]) + pattern_loop_block.add_layer( + "prim.ne", + inputs={"x": gen_name(75.1), + "y": gen_name(74.1)}, + outputs=[gen_name(76)]) + pattern_loop_block.add_layer( + "prim.if", + inputs={"input": gen_name(76)}, + outputs=[gen_name(77), gen_name(78)]) + if_layer13 = pattern_loop_block.layers[list( + pattern_loop_block.layers.keys())[-1]] + pattern_loop_block_block = PaddleGraph( + if_layer13, graph_type="dygraph") + pattern_loop_block_block.add_layer( + "prim.equal", inputs={}, outputs=[gen_name(77)], input=False) + pattern_loop_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(76)}, + outputs=[gen_name(78)]) + if_layer13.add_block(pattern_loop_block_block) + pattern_loop_block_block = PaddleGraph( + if_layer13, graph_type="dygraph") + pattern_loop_block_block.add_layer( + "prim.equal", inputs={}, outputs=[gen_name(77)], input=None) + pattern_loop_block_block.add_layer( + "prim.equal", inputs={}, outputs=[gen_name(78)], input=None) + if_layer13.add_block(pattern_loop_block_block) + if_layer13.inputs.update({"input-0": gen_name(76), }) + pattern_loop_block.add_layer( + "prim.if", + inputs={"input": gen_name(76)}, + outputs=[gen_name(79), gen_name(80)]) + if_layer14 = pattern_loop_block.layers[list( + pattern_loop_block.layers.keys())[-1]] + pattern_loop_block_block = PaddleGraph( + if_layer14, graph_type="dygraph") + pattern_loop_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(77)}, + outputs=[gen_name(79)]) + pattern_loop_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(78)}, + outputs=[gen_name(80)]) + if_layer14.add_block(pattern_loop_block_block) + pattern_loop_block_block = PaddleGraph( + if_layer14, graph_type="dygraph") + pattern_loop_block_block.add_layer( + "prim.equal", inputs={}, outputs=[gen_name(79)], input=True) + pattern_loop_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(76)}, + outputs=[gen_name(80)]) + if_layer14.add_block(pattern_loop_block_block) + if_layer14.inputs.update({ + "input-0": gen_name(77), + "input-1": gen_name(78), + "input-2": gen_name(76) + }) + pattern_loop_block.add_layer( + "prim.add", + inputs={"x": gen_name(72)}, + outputs=[gen_name(81)], + y=1) + pattern_loop_block.add_layer( + "prim.lt", + inputs={"x": gen_name(81), + "y": gen_name(70)}, + outputs=[gen_name(82)]) + pattern_loop_block.add_layer( + "prim.and", + inputs={"x": gen_name(82), + "y": gen_name(79)}, + outputs=[gen_name(83)]) + pattern_loop_block.add_layer( + "prim.equal", + inputs={"input": gen_name(80)}, + outputs=[gen_name(74)]) + pattern_loop_block.add_layer( + "prim.equal", + inputs={"input": gen_name(81)}, + outputs=[gen_name(75)]) + loop_layer.add_block(pattern_loop_block) + loop_layer.inputs.update({ + "input-0": gen_name(65), + "input-1": gen_name(72), + "input-2": gen_name(72), + "input-3": gen_name(70) + }) + pattern_block_block_block_block.add_layer( + "prim.if", + inputs={"input": gen_name(74)}, + outputs=[gen_name(84)]) + if_layer15 = pattern_block_block_block_block.layers[list( + pattern_block_block_block_block.layers.keys())[-1]] + pattern_block_block_block_block_block = PaddleGraph( + if_layer15, graph_type="dygraph") + pattern_block_block_block_block_block.add_layer( + "prim.warnings", + inputs={}, + outputs=[gen_name(85)], + stacklevel=2, + input="...") + if_layer15.add_block(pattern_block_block_block_block_block) + pattern_block_block_block_block_block = PaddleGraph( + if_layer15, graph_type="dygraph") + if_layer15.add_block(pattern_block_block_block_block_block) + if_layer12.add_block(pattern_block_block_block_block) + pattern_block_block_block_block = PaddleGraph( + if_layer12, graph_type="dygraph") + if_layer12.add_block(pattern_block_block_block_block) + if_layer12.inputs.update({ + "input-0": gen_name(65), + "input-1": gen_name(65), + }) + pattern_block_block_block.add_layer( + "prim.list", inputs={}, outputs=[gen_name(86)]) + pattern_block_block_block.add_layer( + "prim.loop", + inputs={}, + outputs=[gen_name(87), gen_name(88)], + input=2) + loop_layer = pattern_block_block_block.layers[list( + pattern_block_block_block.layers.keys())[-1]] + pattern_loop_block = PaddleGraph(loop_layer, graph_type="dygraph") + pattern_loop_block.add_layer( + "prim.add", + inputs={"x": gen_name(88)}, + outputs=[gen_name(89)], + y=2) + pattern_loop_block.add_layer( + "prim.shape_dim", + inputs={"input": gen_name(34), + "dim": gen_name(89)}, + outputs=[gen_name(90)]) + pattern_loop_block.add_layer( + "prim.float", + inputs={"input": gen_name(90)}, + outputs=[gen_name(91)]) + pattern_loop_block.add_layer( + "prim.getitem", + inputs={"list": gen_name(65), + "element": gen_name(88)}, + outputs=[gen_name(92)]) + pattern_loop_block.add_layer( + "prim.mul", + inputs={"x": gen_name(91), + "y": gen_name(92)}, + outputs=[gen_name(93)]) + pattern_loop_block.add_layer( + "prim.floor", + inputs={"input": gen_name(93)}, + outputs=[gen_name(94)]) + pattern_loop_block.add_layer( + "prim.append", + inputs={"list": gen_name(86), + "element": gen_name(94)}, + outputs=[]) + loop_layer.add_block(pattern_loop_block) + loop_layer.inputs.update({ + "input-0": gen_name(34), + "input-1": gen_name(65), + "input-2": gen_name(86) + }) + pattern_block_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(86)}, + outputs=[gen_name(63)]) + if_layer10.add_block(pattern_block_block_block) + if_layer10.inputs.update({ + "input-0": gen_name(61), + "input-1": gen_name(54), + "input-2": gen_name(54), + "input-3": gen_name(37), + "input-4": gen_name(34) + }) + pattern_block_block.add_layer( + "prim.getitem", + inputs={"list": gen_name(11)}, + outputs=[gen_name(95)], + element=0) + pattern_block_block.add_layer( + "prim.getitem", + inputs={"list": gen_name(11)}, + outputs=[gen_name(96)], + element=1) + pattern_block_block.add_layer( + "prim.isinstance", + inputs={"input": gen_name(63)}, + outputs=["interpolate-input-0_isinstance"], + cls="paddle.fluid.Variable") + pattern_block_block.add_layer( + "prim.if", {"input": "interpolate-input-0_isinstance"}, + outputs=["interpolate-input-0_if1"]) + if_layer_isinstance = pattern_block_block.layers[list( + pattern_block_block.layers.keys())[-1]] + pattern_block_block_block = PaddleGraph( + if_layer_isinstance, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.var2list", + inputs={"input": gen_name(63)}, + outputs=[gen_name(63)]) + if_layer_isinstance.add_block(pattern_block_block_block) + pattern_block_block_block = PaddleGraph( + if_layer_isinstance, graph_type="dygraph") + if_layer_isinstance.add_block(pattern_block_block_block) + if_layer_isinstance.inputs["input-0"] = gen_name(63) + pattern_block_block.add_layer( + "prim.assert", + inputs={"key": gen_name(95), + "value": gen_name(96)}, + outputs=[gen_name(97) + "_assert"], + type="eq") + pattern_block_block.add_layer( + "paddle.nn.functional.interpolate", + inputs={ + "input": "interpolate-input-0", + "size": gen_name(63), + "scale_factor": gen_name(95) + }, + outputs=[gen_name(97)], + align_corners=False, + align_mode=0) + pattern_block_block.add_layer( + "prim.equal", + inputs={"input": gen_name(97)}, + outputs=[gen_name(20)]) + if_layer2.add_block(pattern_block_block) + pattern_block_block = PaddleGraph(if_layer2, graph_type="dygraph") + pattern_block_block.add_layer( + "fluid.layers.shape", + inputs={"input": "interpolate-input-0"}, + outputs=[gen_name(98)]) + pattern_block_block.add_layer( + "prim.len", + inputs={"input": gen_name(98)}, + outputs=[gen_name(98)]) + pattern_block_block.add_layer( + "prim.eq", + inputs={"x": gen_name(98)}, + outputs=[gen_name(99)], + y=5) + pattern_block_block.add_layer( + "prim.if", + inputs={"input": gen_name(99)}, + outputs=[gen_name(100)]) + if_layer16 = pattern_block_block.layers[list( + pattern_block_block.layers.keys())[-1]] + pattern_block_block_block = PaddleGraph( + if_layer16, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.exception", + inputs={}, + outputs=[gen_name(101)], + input="Exception") + if_layer16.add_block(pattern_block_block_block) + pattern_block_block_block = PaddleGraph( + if_layer16, graph_type="dygraph") + pattern_block_block_block.add_layer( + "prim.exception", + inputs={}, + outputs=[gen_name(102)], + input="Exception") + if_layer16.add_block(pattern_block_block_block) + pattern_block_block.add_layer( + "prim.equal", inputs={}, outputs=[gen_name(20)], input=None) + if_layer2.add_block(pattern_block_block) + if_layer2.inputs.update({ + "input-0": gen_name(13), + "input-1": gen_name(13), + "input-2": "interpolate-input-0", + "input-3": gen_name(11), + "input-5": gen_name(11), + }) + pattern_block.add_layer( + "prim.equal", + inputs={"input": gen_name(20)}, + outputs=[gen_name(16)]) + if_layer1.add_block(pattern_block) + if_layer1.inputs.update({ + "input-2": "interpolate-input-0", + "input-4": gen_name(13), + "input-7": gen_name(11), + "input-9": gen_name(11), + "input-11": "interpolate-input-0", + "input-12": "interpolate-input-0", + }) + self.pattern.build(inputs={ + "input-0": "interpolate-input-0", + "input-1": "interpolate-input-1" + }) + + def insert_new_layer(self, graph, parameters, matches): + new_layers = self.gen_new_layer(parameters, matches) + new_layer_id = list(matches.keys())[0] + graph.layers[new_layer_id] = new_layers[0] + matches.pop(new_layer_id) + new_layer_id = list(matches.keys())[0] + graph.layers[new_layer_id] = new_layers[1] + block_layer = new_layers[1].blocks[0].layers.pop( + list(new_layers[1].blocks[0].layers.keys())[-1]) + new_layers[1].blocks[0].layers[new_layer_id + ".0.0"] = block_layer + matches.pop(new_layer_id) + new_layer_id = list(matches.keys())[0] + graph.layers[new_layer_id] = new_layers[2] + matches.pop(new_layer_id) + + def gen_new_layer(self, parameters, matches): + layers = list() + layers_id = list(matches.keys()) + layer = matches[layers_id[6]] + size = layer.inputs["input1"] + layer = matches[layers_id[92]] + layer.inputs["input"] = size + layers.append(layer) + layer = matches[layers_id[93]] + block_layer = layer.blocks[0].layers[list(layer.blocks[0].layers.keys()) + [0]] + block_layer.inputs["input"] = size + block_layer.outputs[0] = size + layer.inputs["input-0"] = size + layers.append(layer) + layer = matches[layers_id[-1]] + outputs = layer.outputs + layer = matches[layers_id[96]] + layer.inputs.pop("scale_factor") + layer.inputs["size"] = size + layer.outputs = outputs + layers.append(layer) + return layers diff --git a/x2paddle/optimizer/pytorch_optimizer/fusion/reshape_fuse_pass.py b/x2paddle/optimizer/pytorch_optimizer/fusion/reshape_fuse_pass.py new file mode 100644 index 0000000000000000000000000000000000000000..375b50b6bd5c9e02ad7ed988938ee9452f306716 --- /dev/null +++ b/x2paddle/optimizer/pytorch_optimizer/fusion/reshape_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.pytorch_optimizer.pass_ import Pass +from x2paddle.optimizer.pytorch_optimizer.fusion import ReshapeFuser +from x2paddle.optimizer.pytorch_optimizer.pass_manager import pass_register + + +@pass_register +class ReshapeFusePass(Pass): + name = "reshape_fuse_pass" + + def __init__(self): + Pass.__init__(self) + + def apply(self, graph): + fuser = ReshapeFuser() + fuser.operate(graph, match_kind="edge") + + +# 用于注册 +reshape_fuse_pass = ReshapeFusePass() diff --git a/x2paddle/optimizer/pytorch_optimizer/fusion/reshape_fuser.py b/x2paddle/optimizer/pytorch_optimizer/fusion/reshape_fuser.py new file mode 100644 index 0000000000000000000000000000000000000000..b489f9706293fc2c31907bbff5d0eb6f7564c145 --- /dev/null +++ b/x2paddle/optimizer/pytorch_optimizer/fusion/reshape_fuser.py @@ -0,0 +1,73 @@ +# 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 numpy as np +from x2paddle.optimizer.pytorch_optimizer.pattern_matcher import FuseBase +from x2paddle.core.program import PaddleGraph, PaddleLayer +from x2paddle.core.util import * + + +class ReshapeFuser(FuseBase): + def __init__(self): + super(ReshapeFuser, self).__init__(graph_type="dygraph") + + def build_pattern(self): + """ 描述需要替换的reshape图结构。 + reshape层模式python实现代码示例: + x165 = int(x164) + x166 = [x158, x159, x165] + x167 = fluid.layers.reshape(x=x157, shape=x166) + """ + + def gen_name(id): + return "x" + str(id) + + self.pattern.add_layer( + "prim.int", + inputs={"input": "reshape-input-0"}, + outputs=[gen_name(0)]) + self.pattern.add_layer( + "prim.list", + inputs={ + "input0": "reshape-input-1", + "input1": "reshape-input-2", + "input2": gen_name(0) + }, + outputs=[gen_name(1)]) + self.pattern.add_layer( + "fluid.layers.reshape", + inputs={"x": "reshape-input-3", + "shape": gen_name(1)}, + outputs=[gen_name(2)]) + self.pattern.build(inputs={ + "input-0": "reshape-input-0", + "input-1": "reshape-input-1", + "input-2": "reshape-input-2", + "input-3": "reshape-input-3", + }) + + def insert_new_layer(self, graph, parameters, matches): + self.update_layer(matches) + matches.pop(list(matches.keys())[1]) + matches.pop(list(matches.keys())[1]) + + def update_layer(self, matches): + layers_id = list(matches.keys()) + layer = matches[layers_id[0]] + int_input_name = layer.inputs["input"] + output_name = layer.outputs[0] + layer = matches[layers_id[1]] + for key, input_name in layer.inputs.items(): + if input_name == output_name: + layer.inputs[key] = int_input_name diff --git a/x2paddle/optimizer/pytorch_optimizer/optimizer.py b/x2paddle/optimizer/pytorch_optimizer/optimizer.py new file mode 100644 index 0000000000000000000000000000000000000000..3ca3b4a9f7bc6ed46c1649cadb076f51f56dab65 --- /dev/null +++ b/x2paddle/optimizer/pytorch_optimizer/optimizer.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.pytorch_optimizer.fusion import * +from x2paddle.optimizer.pytorch_optimizer.pass_manager import PassManager + + +class GraphOptimizer(object): + def __init__(self): + self.passes = [ + "constant_fuse_pass", "batchnorm2d_fuse_pass", + "interpolate_bilinear_fuse_pass", "fc_fuse_pass", + "adaptive_pool2d_fuse_pass", "reshape_fuse_pass", + "dropout_fuse_pass" + ] + + def optimize(self, graph): + for pass_name in self.passes: + pass_ = PassManager.lookup(pass_name)() + pass_.apply(graph) + print("{} done!".format(pass_name)) + return graph diff --git a/x2paddle/decoder/paddle_decoder.py b/x2paddle/optimizer/pytorch_optimizer/pass_.py similarity index 52% rename from x2paddle/decoder/paddle_decoder.py rename to x2paddle/optimizer/pytorch_optimizer/pass_.py index c915c4da19429e0998d8807a16cf7116da59cbe5..0bfa2ff888d69bf2f78beb57d9994d00d8027727 100644 --- a/x2paddle/decoder/paddle_decoder.py +++ b/x2paddle/optimizer/pytorch_optimizer/pass_.py @@ -1,4 +1,4 @@ -# Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved. +# 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. @@ -12,17 +12,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -import paddle.fluid as fluid +class Pass(object): + name = "pass" -class PaddleDecoder(object): - def __init__(self, - model_dir, - model_filename='__model__', - params_filename=None): - exe = fluid.Executor(fluid.CPUPlace()) - [self.program, feed, fetchs] = fluid.io.load_inference_model( - model_dir, - exe, - model_filename=model_filename, - params_filename=params_filename) + def __init__(self): + pass + + def apply(self, graph): + raise NotImplementedError("The apply function must be implemented!") + + @classmethod + def get_name(cls): + return cls.name diff --git a/x2paddle/optimizer/pytorch_optimizer/pass_manager.py b/x2paddle/optimizer/pytorch_optimizer/pass_manager.py new file mode 100644 index 0000000000000000000000000000000000000000..8653f62b3a415c1a4db4a95d0a185a28028d75c9 --- /dev/null +++ b/x2paddle/optimizer/pytorch_optimizer/pass_manager.py @@ -0,0 +1,42 @@ +# 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. + + +class PassManager(object): + """ pass管理器。 + """ + # pass_map存储name与其对应的pass + pass_map = dict() + + def __init__(self): + pass + + @staticmethod + def add_new_pass(name, pass_): + if name not in PassManager.pass_map: + PassManager.pass_map[name] = pass_ + + @staticmethod + def clear(): + PassManager.passes = list() + + @staticmethod + def lookup(name): + return PassManager.pass_map[name] + + +def pass_register(cls): + name = cls.get_name() + PassManager.add_new_pass(name, cls) + return cls diff --git a/x2paddle/optimizer/pytorch_optimizer/pattern_matcher.py b/x2paddle/optimizer/pytorch_optimizer/pattern_matcher.py new file mode 100644 index 0000000000000000000000000000000000000000..c5b38b0f34242b0d1e462eeb5e9a55210432dc37 --- /dev/null +++ b/x2paddle/optimizer/pytorch_optimizer/pattern_matcher.py @@ -0,0 +1,293 @@ +# 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.core.program import PaddleGraph + + +class PatternMatcher(object): + def __init__(self, pattern): + self.pattern = pattern + # matches的每个match是按照拓扑排序组成layer的dict + self.matches = list() + + def operate(self, graph, match_kind="topo"): + if match_kind == "topo": + self.detect_patterns_by_topo(graph) + elif match_kind == "edge": + self.detect_patterns_by_edge(graph) + self.remove_overlapped_match() + return self.matches + + def detect_patterns_by_topo(self, graph): + """ 找到与模式匹配的子图, + 并将子图的id以拓扑排序存放到subgraph_id2layers。 + """ + + def get_subgraph(pattern, graph, start_index, is_subblock=False): + pattern_index = 0 + pattern_id2layers = pattern.get_global_layers() + pattern_ids = list(pattern_id2layers.keys()) + subgraph_id2layers = dict() + graph_layers = dict(list(graph.layers.items())[start_index:]) + for layer_id, layer in graph_layers.items(): + pattern_layer = pattern.layers[list(pattern.layers.keys())[ + pattern_index]] + if layer.kernel == pattern_layer.kernel: + subgraph_id2layers[layer_id] = layer + pattern_layer_id = pattern_layer.id + # 判断输入连接是否一致 + if layer_id in graph.edges_in: + if pattern_layer_id not in pattern.edges_in: + if pattern_index == 0 or is_subblock: + return False + else: + subgraph_id2layers.pop(layer_id) + continue + else: + if len(graph.edges_in[layer_id]) != len( + pattern.edges_in[pattern_layer_id]): + if pattern_index == 0 or is_subblock: + return False + else: + subgraph_id2layers.pop(layer_id) + continue + layer_in = graph.edges_in[layer_id] + pattern_layer_in = pattern.edges_in[pattern_layer_id] + for i in range(len(layer_in)): + layer_id_in = layer_in[i] + pattern_layer_id_in = pattern_layer_in[i] + if pattern_layer_id_in != -1: + subgraph_ids = list(subgraph_id2layers.keys()) + if layer_id_in not in subgraph_ids: + return False + if pattern_ids.index(pattern_layer_id_in) == \ + subgraph_ids.index(layer_id_in): + # 判断pattern输入在pattern_ids的索引 + # 和graph输入在subgraph_ids的索引一致 + continue + if pattern_index == 0 or is_subblock: + return False + else: + subgraph_id2layers.pop(layer_id) + continue + # 判断subgraph中的节点是否被外部图使用到(如若被使用到则无效) + if layer_id in graph.edges_out: + if pattern_layer_id not in pattern.edges_out: + if not set(pattern_layer.outputs).issubset( + pattern.outputs): + # 若pattern当前layer的输出是pattern的输出,则是正确的 + if pattern_index == 0 or is_subblock: + return False + else: + subgraph_id2layers.pop(layer_id) + continue + else: + if len(graph.edges_out[layer_id]) != len( + pattern.edges_out[pattern_layer_id]): + # 如果在每个节点edges_in相同的情况下,edges_out数目相同则说明无节点在subgraph外被用到 + if not set(pattern_layer.outputs).issubset( + pattern.outputs): + # 若pattern当前layer的输出是pattern的输出,则是正确的 + if pattern_index == 0 or is_subblock: + return False + else: + subgraph_id2layers.pop(layer_id) + continue + # 当为控制流时的处理 + if layer.kernel == "prim.if" or layer.kernel == "prim.loop": + if len(pattern_layer.blocks) != len(layer.blocks): + if pattern_index == 0 or is_subblock: + return False + else: + subgraph_id2layers.pop(layer_id) + continue + is_subblock_match = True + for i, b in enumerate(pattern_layer.blocks): + match_info = get_subgraph( + pattern_layer.blocks[i], + layer.blocks[i], + 0, + is_subblock=True) + if match_info is not False: + subgraph_id2layers.update(match_info) + else: + is_subblock_match = False + break + if not is_subblock_match: + if pattern_index == 0 or is_subblock: + return False + else: + index = list(subgraph_id2layers.keys()).index( + layer_id) + for key in list(subgraph_id2layers.keys())[ + index:]: + subgraph_id2layers.pop(key) + continue + pattern_index += 1 + if pattern_index == len(pattern.layers): + return subgraph_id2layers + else: + if pattern_index == 0 or is_subblock: + return False + else: + continue + if pattern_index == len(pattern.layers): + return subgraph_id2layers + return False + + for i, (layer_id, layer) in enumerate(graph.layers.items()): + match_info = get_subgraph(self.pattern, graph, i) + if match_info: + self.matches.append(match_info) + for j, block in enumerate(layer.blocks): + if len(block.layers) > 0: + self.detect_patterns_by_topo(layer.blocks[j]) + + def detect_patterns_by_edge(self, graph, ignore_list_inputs=True): + """当遇见顺序没有强制规定的pattern时使用该方式 + """ + + def get_subgraph(pattern, graph, start_index): + pattern_id2layers = pattern.get_global_layers() + 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] + + def update(layer_id, pattern_layer_id): + layer = graph_layers[layer_id] + pattern_layer = pattern_id2layers[pattern_layer_id] + 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: + return False + if pattern.edges_out.get(pattern_layer_id, 0) != 0: + if len(pattern.edges_out[pattern_layer_id]) != \ + len(graph.edges_out[layer_id]): + return False + for i, pattern_layer_id_out in enumerate(pattern.edges_out[ + 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) + update(new_layer_id_out, pattern_layer_id_out) + + while len(subgraph_id2layers) != len(pattern_id2layers): + out = update(layer_id, pattern_layer_id) + if out == False: + return False + else: + if len(subgraph_id2layers) == len(pattern_id2layers): + return subgraph_id2layers + else: + return False + + for i, (layer_id, layer) in enumerate(graph.layers.items()): + match_info = get_subgraph(self.pattern, graph, i) + if match_info: + self.matches.append(match_info) + for j, block in enumerate(layer.blocks): + if len(block.layers) > 0: + self.detect_patterns_by_edge(layer.blocks[j]) + + def remove_overlapped_match(self): + """ 如果2个子图有重叠,只取前一个子图。 + """ + match_ids = [] + for i, match in enumerate(self.matches): + is_overlapped = False + for id in match.keys(): + if id in match_ids: + self.matches.pop(i) + is_overlapped = True + break + if not is_overlapped: + match_ids.extend(list(match.keys())) + + +def get_subgraph(prefix_layer_id, suffix_layer_id, graph): + """ 根据prefix_layer_id和suffix_layer_id获取需要子图。 + Args: + prefix_layer_id (str): 起初为一个空字符串,之后为suffix_layer_id分割出来的前缀。 + suffix_layer_id (str): 起初为以一个layer的id,之后将分割部分给prefix_layer_id;例如”57.0.1“; + graph (x2paddle.core.program.PaddleGraph): 需要进行pass的子图。 + """ + id_part = suffix_layer_id.split(".") + if len(id_part) == 1: + return graph + if prefix_layer_id == "": + layer_id = id_part[0] + prefix_layer_id += ".".join(id_part[:2]) + else: + layer_id = prefix_layer_id + "." + id_part[0] + prefix_layer_id += ("." + ".".join(id_part[:2])) + subgraph = graph.layers[layer_id].blocks[int(id_part[1])] + suffix_layer_id = ".".join(id_part[2:]) + return get_subgraph(prefix_layer_id, suffix_layer_id, subgraph) + + +class FuseBase(object): + def __init__(self, graph_type): + self.pattern = PaddleGraph(graph_type=graph_type) + + def operate(self, graph, match_kind="topo"): + parameters = graph.parameters + self.build_pattern() + self.perform_pattern_matcher(graph, match_kind) + for match in self.matches: + 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) + graph.build() + + def perform_pattern_matcher(self, graph, match_kind="topo"): + """ 执行模式匹配,找到匹配的子图。 + """ + pattern_matcher = PatternMatcher(self.pattern) + self.matches = pattern_matcher.operate(graph, match_kind) + + def delete_inter_layer(self, graph): + """ 删除不需要的中间layer及其对应参数。 + """ + for match in self.matches: + first_layer_id = list(match.keys())[0] + subgraph = get_subgraph("", first_layer_id, graph) + for layer_id, layer in match.items(): + if layer.kernel == "fluid.dygraph.base.to_variable" and \ + layer.attrs["value"].startswith("params["): + param_name = layer.attrs["value"][8:-2] + if param_name in graph.parameters: + graph.parameters.pop(param_name) + if layer_id in subgraph.layers: + # layer_id可能是属于子图的,此时删除父layer,即删除整个子图 + subgraph.layers.pop(layer_id) diff --git a/x2paddle/op_mapper/paddle2onnx/opset10/paddle_custom_layer/__init__.py b/x2paddle/optimizer/tensorflow/__init__.py similarity index 100% rename from x2paddle/op_mapper/paddle2onnx/opset10/paddle_custom_layer/__init__.py rename to x2paddle/optimizer/tensorflow/__init__.py diff --git a/x2paddle/optimizer/tensorflow/batch_norm.py b/x2paddle/optimizer/tensorflow/batch_norm.py new file mode 100644 index 0000000000000000000000000000000000000000..3e3d81360598c2b66a00735cd23059998f3bef2d --- /dev/null +++ b/x2paddle/optimizer/tensorflow/batch_norm.py @@ -0,0 +1,180 @@ +import copy +from collections import OrderedDict +from x2paddle.core.program import PaddleLayer + + +class BatchNormOpt: + def __init__(self): + pass + + def run(self, graph): + print("Optimize: BatchNormOpt...") + 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] + 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 + axis = sub_layer0.attrs.get('axis', -1) + if axis != -1 and axis != 0: + 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 = graph.edges_in[input_ids0[0]] + nhwc_input = graph.layers[input_ids1[0]] + mul_layer1 = graph.layers[input_ids1[1]] + 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], [])) != 2: + continue + + input_ids2 = graph.edges_in[input_ids0[1]] + beta = graph.layers[input_ids2[0]] + mul_layer2 = graph.layers[input_ids2[1]] + if beta.kernel != "fluid.layers.create_parameter": + continue + axis = mul_layer2.attrs.get('axis', -1) + if axis != -1 and axis != 0: + continue + if len(graph.edges_out.get(input_ids2[0], [])) != 1: + continue + if len(graph.edges_out.get(input_ids2[1], [])) != 1: + continue + if beta.outputs[0] not in graph.parameters: + continue + beta_shape = graph.parameters[beta.outputs[0]].shape + if len(beta_shape) != 1: + continue + + input_ids3 = graph.edges_in[input_ids2[1]] + mean = graph.layers[input_ids3[0]] + mul_layer3 = graph.layers[input_ids3[1]] + if mean.kernel != "fluid.layers.create_parameter": + continue + axis = mul_layer3.attrs.get('axis', -1) + if axis != -1 and axis != 0: + continue + if len(graph.edges_out.get(input_ids3[0], [])) != 1: + continue + if len(graph.edges_out.get(input_ids3[1], [])) != 2: + continue + if mul_layer3.id != mul_layer1.id: + continue + if mean.outputs[0] not in graph.parameters: + continue + mean_shape = graph.parameters[mean.outputs[0]].shape + if mean_shape != beta_shape: + continue + + input_ids4 = graph.edges_in[input_ids3[1]] + rsqrt_layer = graph.layers[input_ids4[0]] + gamma = graph.layers[input_ids4[1]] + if rsqrt_layer.kernel != "fluid.layers.rsqrt": + continue + if gamma.kernel != "fluid.layers.create_parameter": + continue + if len(graph.edges_out.get(input_ids4[0], [])) != 1: + continue + if len(graph.edges_out.get(input_ids4[1], [])) != 1: + continue + if gamma.outputs[0] not in graph.parameters: + continue + gamma_shape = graph.parameters[gamma.outputs[0]].shape + if gamma_shape != beta_shape: + continue + + input_ids5 = graph.edges_in[input_ids4[0]] + add_layer = graph.layers[input_ids5[0]] + if add_layer.kernel != "fluid.layers.elementwise_add": + continue + axis = add_layer.attrs.get('axis', -1) + if axis != -1 and axis != 0: + continue + if len(graph.edges_out.get(input_ids5[0], [])) != 1: + continue + + input_ids6 = graph.edges_in[input_ids5[0]] + variance = graph.layers[input_ids6[0]] + other = graph.layers[input_ids6[1]] + if variance.kernel != "fluid.layers.create_parameter": + continue + if other.kernel != "fluid.layers.create_parameter": + continue + if len(graph.edges_out.get(input_ids6[0], [])) != 1: + continue + if len(graph.edges_out.get(input_ids6[1], [])) != 1: + continue + if variance.outputs[0] not in graph.parameters: + continue + 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, + mul_layer2.id, mean.id, mul_layer2.id, rsqrt_layer.id, gamma.id, + add_layer.id, variance.id, other.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 != nhwc_input.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_bn"], + perm=[0, 3, 1, 2]) + bn = PaddleLayer( + id='{}_2'.format(k), + kernel="fluid.layers.batch_norm", + inputs={"input": "transpose_for_bn"}, + outputs=layer.outputs, + epsilon=graph.parameters[other.outputs[0]], + param_attr="'{}'".format(gamma.outputs[0]), + bias_attr="'{}'".format(beta.outputs[0]), + moving_mean_name="'{}'".format(mean.outputs[0]), + moving_variance_name="'{}'".format(variance.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[bn.id] = bn + graph.layers[transpose1.id] = transpose1 + graph.build() diff --git a/x2paddle/optimizer/tensorflow/bias.py b/x2paddle/optimizer/tensorflow/bias.py new file mode 100644 index 0000000000000000000000000000000000000000..593095127b5729f3ef6aae52af41341132b9e73b --- /dev/null +++ b/x2paddle/optimizer/tensorflow/bias.py @@ -0,0 +1,75 @@ +import copy + + +class BiasOpt: + def __init__(self): + 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...") + layers = copy.deepcopy(graph.layers) + for layer_id, layer in layers.items(): + if layer.kernel in self.conv_layers or layer.kernel == "fluid.layers.transpose": + if len(graph.edges_out.get(layer_id, [])) > 1: + continue + if layer.outputs[0] in graph.outputs: + continue + + out_layer_id = graph.edges_out[layer_id][0] + if graph.layers[ + out_layer_id].kernel != "fluid.layers.elementwise_add": + continue + if graph.layers[out_layer_id].attrs.get('axis', -1) != -1: + continue + + in_layer_id = graph.edges_in[out_layer_id] + bias_layer_id = in_layer_id[1 - in_layer_id.index(layer_id)] + if graph.layers[ + bias_layer_id].kernel != "fluid.layers.create_parameter": + continue + + bias_layer = graph.layers[bias_layer_id] + if len(bias_layer.attrs['shape']) != 1: + continue + if len(graph.edges_out[bias_layer_id]) != 1: + continue + + if layer.kernel == "fluid.layers.transpose": + if layer.attrs['perm'] != [0, 2, 3, 1]: + continue + in_layer_id = graph.edges_in[layer_id][0] + if graph.layers[in_layer_id].kernel not in self.conv_layers: + continue + if graph.layers[in_layer_id].attrs['bias_attr'] != False: + continue + if graph.layers[in_layer_id].outputs[0] in graph.outputs: + continue + if len(graph.edges_out[in_layer_id]) != 1: + continue + graph.layers[in_layer_id].attrs[ + 'bias_attr'] = bias_layer.attrs['name'] + else: + graph.layers[layer_id].attrs[ + 'bias_attr'] = bias_layer.attrs['name'] + bias_add_outs = graph.edges_out.get(out_layer_id, []) + bias_add_output = graph.layers[out_layer_id].outputs[0] + graph.del_layer(bias_layer_id) + graph.del_layer(out_layer_id) + + for out in bias_add_outs: + for k, v in graph.layers[out].inputs.items(): + if v == layer.outputs[0]: + graph.layers[out].inputs[k] = bias_add_output + graph.layers[layer_id].outputs[0] = bias_add_output + + if layer.kernel == "fluid.layers.transpose": + in_layer_id = graph.edges_in[layer_id][0] + graph.layers[in_layer_id].outputs[0] = bias_add_output + graph.layers[layer_id].inputs['x'] = bias_add_output diff --git a/x2paddle/optimizer/tensorflow/transpose.py b/x2paddle/optimizer/tensorflow/transpose.py new file mode 100644 index 0000000000000000000000000000000000000000..fbd10ab230d81e3463a74c64a7eda7a9fba6d93d --- /dev/null +++ b/x2paddle/optimizer/tensorflow/transpose.py @@ -0,0 +1,262 @@ +import copy +import sys + + +class TransposeOpt: + def __init__(self): + self.image_layers = [ + 'fluid.layers.conv2d', 'fluid.layers.batch_norm', + 'fluid.layers.conv2d_transpose', 'fluid.layers.resize_nearest', + 'fluid.layers.resize_bilinear', 'fluid.layers.pool2d', + 'fluid.layers.pad2d' + ] + self.direct_layers = [ + 'fluid.layers.relu', 'fluid.layers.relu6', 'fluid.layers.abs', + 'fluid.layers.sigmoid', 'fluid.layers.exp', 'fluid.layers.rsqrt', + 'fluid.layers.swish_f32', 'fluid.layers.tanh', + 'fluid.layers.softplus', 'fluid.layers.leaky_relu', + 'fluid.layers.floor', 'fluid.layers.erf', 'fluid.layers.swish' + ] + self.elementwise_layers = [ + 'fluid.layers.elementwise_add', 'fluid.layers.elementwise_sub', + 'fluid.layers.elementwise_mul', 'fluid.layers.elementwise_div' + ] + # self.reduce_layers = [] + self.reduce_layers = [ + 'fluid.layers.reduce_mean', 'fluid.layers.reduce_all', + 'fluid.layers.reduce_max', 'fluid.layers.reduce_any', + 'fluid.layers.reduce_sum', 'fluid.layers.reduce_prod' + ] + + def get_transpose_num(self, graph): + count = 0 + for layer_id, layer in graph.layers.items(): + if layer.kernel == "fluid.layers.transpose": + count += 1 + return count + + def run(self, graph): + print("Optimize: TransposeOpt...") + 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) + sys.stderr.write("\rOptimize Transpose Layers...{}%".format( + percent)) + + if layer.kernel != "fluid.layers.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 == "fluid.layers.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: + if _graph.layers[out].outputs[0] 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('keep_dim', False): + can_be_optimized = False + break + propagate_layers.append(out) + reduce_layers.append(out) + elif _graph.layers[out].kernel == "fluid.layers.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 == "fluid.layers.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: + 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.reduce_layers: + if _graph.layers[out].outputs[0] in _graph.outputs: + can_be_optimized = False + break + if not _graph.layers[out].attrs.get('keep_dim', + 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 == "fluid.layers.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 == "fluid.layers.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: + 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.reduce_layers: + if _graph.layers[ipt].outputs[0] in _graph.outputs: + can_be_optimized = False + break + if not _graph.layers[ipt].attrs.get('keep_dim', + 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 == "fluid.layers.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: + _graph.del_layer(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)): + graph.del_layer(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/tf_optimizer.py b/x2paddle/optimizer/tf_optimizer.py deleted file mode 100644 index 7847219b10532e8efaabaf3fc11d57429646b789..0000000000000000000000000000000000000000 --- a/x2paddle/optimizer/tf_optimizer.py +++ /dev/null @@ -1,1084 +0,0 @@ -# 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. - -# TODO useless node remove -from x2paddle.op_mapper.tf_op_mapper import TFOpMapper -from x2paddle.core.fluid_code import Layer -from x2paddle.core.util import * -import six -import numpy -import copy as cp - - -def exist_act(node): - for layer in node.fluid_code.layers: - if layer.param_attr is not None: - act = layer.param_attr.get("act", None) - if act is not None: - return True - return False - - -class TFOptimizer(object): - activation_ops = { - 'Relu': 'relu', - 'Sigmoid': 'sigmoid', - 'Relu6': 'relu6', - 'swish_f32': 'swish' - } - layers_with_act = [ - 'Conv2D', 'BiasAdd', 'DepthwiseConv2dNative', 'Conv2DBackpropInput', - 'FusedBatchNorm', 'conv2d', 'elementwise_add', 'conv2d_transpose', - 'batch_norm' - ] - layers_with_bias = [ - 'Conv2D', 'DepthwiseConv2dNative', 'Conv2DBackpropInput', 'conv2d', - 'conv2d_transpose' - ] - - def __init__(self, op_mapper): - self.op_mapper = op_mapper - self.graph = op_mapper.graph - - def delete_redundance_code(self): - for node_name in self.graph.topo_sort: - if node_name in self.op_mapper.omit_nodes: - node = self.graph.get_node(node_name) - if node is None: - continue - omit_freq = self.op_mapper.omit_nodes.count(node_name) - if len(node.outputs) <= omit_freq: - node.fluid_code.clear() - - # remove node from graph - input_names = node.inputs - output_names = node.outputs - for in_name in input_names: - in_node = self.graph.get_node(in_name) - index = in_node.outputs.index(node_name) - del in_node.outputs[index] - for out_name in output_names: - out_node = self.graph.get_node(out_name) - index = out_node.inputs.index(node_name) - del out_node.inputs[index] - del self.graph.node_map[node_name] - - def strip_graph(self): - visited_nodes = set() - - def visit(node_name): - if node_name in visited_nodes: - return - visited_nodes.add(node_name) - input_names = self.graph.get_node(node_name).inputs - for in_name in input_names: - visit(in_name) - - for node_name in self.graph.output_nodes: - visit(node_name) - - for i, node_name in enumerate(self.graph.topo_sort): - if node_name not in visited_nodes: - node = self.graph.get_node(node_name) - if node is None: - continue - input_names = node.inputs - output_names = node.outputs - for in_name in input_names: - in_node = self.graph.get_node(in_name) - index = in_node.outputs.index(node_name) - del in_node.outputs[index] - for out_name in output_names: - out_node = self.graph.get_node(out_name) - index = out_node.inputs.index(node_name) - del out_node.inputs[index] - del self.graph.node_map[node_name] - - def optimize_elementwise_op(self): - elementwise_ops = [ - 'Sub', 'Add', 'RealDiv', 'Maximum', 'Mul', 'FloorDiv', - 'GreaterEqual' - ] - revertable_ops = ['Add', 'Mul'] - for node_name in self.graph.topo_sort: - node = self.graph.get_node(node_name) - if node is None: - continue - if node.layer_type in elementwise_ops: - if len(node.fluid_code.layers) != 2: - continue - if node.fluid_code.layers[0].op != "expand": - continue - expand_out = node.fluid_code.layers[0].output - expand_in = node.fluid_code.layers[0].inputs - expand_times = node.fluid_code.layers[0].param_attr[ - "expand_times"] - - x = node.fluid_code.layers[1].inputs["x"] - y = node.fluid_code.layers[1].inputs["y"] - if isinstance( - x, - six.string_types) and node.layer_type in revertable_ops: - node.fluid_code.layers[1].inputs["y"] = x - node.fluid_code.layers[1].inputs["x"] = y - x = node.fluid_code.layers[1].inputs["x"] - y = expand_in - elif isinstance(y, six.string_types): - y = expand_in - else: - continue - - x_shape = x.out_shapes[0] - y_shape = y.out_shapes[0] - if len(x_shape) != len(y_shape): - continue - if len(x_shape) == 4: - x_shape = [x_shape[i] for i in [0, 3, 1, 2]] - y_shape = [y_shape[i] for i in [0, 3, 1, 2]] - - continue_flag = True - for i in range(len(x_shape)): - if y_shape[-1 * (i + 1)] == 1 and continue_flag: - expand_times[-1 * (i + 1)] = 1 - else: - continue_flag = False - - if expand_times.count(1) == len(expand_times): - node.fluid_code.layers[1].inputs["y"] = expand_in - del node.fluid_code.layers[0] - - def merge_activation(self): - act_nodes = list() - for node_name in self.graph.topo_sort: - node = self.graph.get_node(node_name) - if node is None: - continue - if node.layer_type in self.activation_ops: - act_nodes.append(node_name) - - for act_node_name in act_nodes: - node = self.graph.get_node(act_node_name) - input = self.graph.get_node(node.inputs[0]) - if input.layer_type not in self.layers_with_act: - continue - if len(input.fluid_code.layers) == 0: - continue - if 'act' in input.fluid_code.layers[ - -1].param_attr and input.fluid_code.layers[-1].param_attr[ - 'act'] is not None: - continue - if len(input.outputs) != 1: - continue - index = -1 - for i in range(len(input.fluid_code.layers)): - if input.fluid_code.layers[i].op in self.layers_with_act: - index = i - break - input.fluid_code.layers[index].param_attr['act'] = string( - self.activation_ops[node.layer_type]) - input.fluid_code.layers[-1].output = node.fluid_code.layers[ - 0].output - self.graph.remove_node(act_node_name) - - def merge_bias(self): - for node_name in self.graph.topo_sort: - node = self.graph.get_node(node_name) - if node is None: - continue - if node.layer_type == "BiasAdd": - input = self.graph.get_node(node.inputs[0]) - if input.layer_type not in self.layers_with_bias: - continue - if len(input.outputs) != 1: - continue - if len(input.fluid_code.layers) == 0: - continue - bias_with_act = False - if 'act' in node.fluid_code.layers[-1].param_attr: - bias_with_act = True - layer_with_act = False - index = -1 - for i in range(len(input.fluid_code.layers)): - if input.fluid_code.layers[i].op in self.layers_with_bias: - index = i - break - if 'act' in input.fluid_code.layers[ - index].param_attr and input.fluid_code.layers[ - index].param_attr['act'] is not None: - layer_with_act = True - - if bias_with_act and layer_with_act: - continue - if not input.fluid_code.layers[index].param_attr['bias_attr']: - bias_name = node.inputs[1] - input.fluid_code.layers[index].param_attr[ - 'bias_attr'] = string(bias_name) - input.fluid_code.layers[-1].output = node.fluid_code.layers[ - 0].output - if bias_with_act: - input.fluid_code.layers[index].param_attr[ - 'act'] = node.fluid_code.layers[-1].param_attr[ - 'act'] - node.fluid_code.clear() - self.graph.remove_node(node.layer_name) - self.graph.identity_map[node.layer_name] = input.layer_name - - def remove_transpose(self): - graph_copy = cp.deepcopy(self.graph) - elementwise_ops = [ - 'Sub', 'Add', 'RealDiv', 'Maximum', 'Mul', 'FloorDiv', - 'GreateerEqual' - ] - can_be_optimized_ops = [ - 'Conv2D', 'MaxPool', 'FusedBatchNorm', 'DepthwiseConv2dNative', - 'AvgPool', 'Pad', 'Conv2DBackpropInput', 'ResizeNearestNeighbor', - 'Placeholder', 'Relu', 'Relu6', 'Abs', 'Sigmoid', 'Exp', 'Rsqrt', - 'swish_f32', 'LeakyRelu', 'Cast', 'Tanh' - ] - # These ops may have one more Variable input - can_be_optimized_special_ops = ['ResizeBilinear'] - for node_name in self.graph.topo_sort: - node = graph_copy.get_node(node_name) - if node is None: - continue - if node.layer_type in can_be_optimized_ops: - if node.fluid_code.layers[ - -1].op != "transpose" or node.fluid_code.layers[ - -1].param_attr["perm"] != [0, 2, 3, 1]: - continue - can_be_removed = True - output_names = node.outputs - for out_name in output_names: - out_node = graph_copy.get_node(out_name) - if hasattr(out_node, "can_be_removed"): - if not out_node.can_be_removed: - can_be_removed = False - break - elif out_node.fluid_code.layers[ - 0].op != "transpose" or out_node.fluid_code.layers[ - 0].param_attr["perm"] != [0, 3, 1, 2]: - can_be_removed = False - break - elif out_node.layer_type in elementwise_ops or out_node.layer_type in can_be_optimized_special_ops: - can_be_removed = False - break - - if can_be_removed and len(node.fluid_code.layers) > 1: - true_node = self.graph.get_node(node_name) - if true_node.layer_type == "Placeholder": - index = self.graph.input_nodes.index( - true_node.fluid_code.layers[-2].output) - if isinstance(true_node.fluid_code.layers[-1].output, - str): - self.graph.input_nodes[ - index] = true_node.fluid_code.layers[-1].output - else: - self.graph.input_nodes[ - index] = true_node.fluid_code.layers[ - -1].output.layer_name - true_node.fluid_code.layers[ - -2].output = true_node.fluid_code.layers[-1].output - node.removed = True - del true_node.fluid_code.layers[-1] - - for out_name in output_names: - out_node = self.graph.get_node(out_name) - out_node.fluid_code.layers[ - 1].inputs = out_node.fluid_code.layers[0].inputs - del out_node.fluid_code.layers[0] - - for node_name in self.graph.topo_sort: - node = graph_copy.get_node(node_name) - if node is None: - continue - if node.layer_type in elementwise_ops: - can_be_removed = True - if node.fluid_code.layers[ - -1].op != "transpose" or node.fluid_code.layers[ - -1].param_attr["perm"] != [0, 2, 3, 1]: - continue - can_be_removed = True - - output_names = node.outputs - for out_name in output_names: - out_node = graph_copy.get_node(out_name) - if len(out_node.fluid_code.layers) < 3: - can_be_removed = False - break - if hasattr(out_node, "can_be_removed"): - if not out_node.can_be_removed: - can_be_removed = False - break - if out_node.layer_type in can_be_optimized_ops: - if out_node.fluid_code.layers[ - 0].op != "transpose" or out_node.fluid_code.layers[ - 0].param_attr["perm"] != [0, 3, 1, 2]: - can_be_removed = False - break - elif out_node.layer_type in elementwise_ops: - if out_node.fluid_code.layers[ - 0].op != "transpose" and out_node.fluid_code.layers[ - 1].op != "transpose": - can_be_removed = False - break - if out_node.fluid_code.layers[0].op == "transpose": - if out_node.fluid_code.layers[0].param_attr[ - "perm"] != [0, 3, 1, 2]: - can_be_removed = False - break - if out_node.fluid_code.layers[1].op == "transpose": - if out_node.fluid_code.layers[1].param_attr[ - "perm"] != [0, 3, 1, 2]: - can_be_removed = False - break - - if can_be_removed and len(node.fluid_code.layers) > 1: - true_node = self.graph.get_node(node_name) - true_node.fluid_code.layers[ - -2].output = true_node.fluid_code.layers[-1].output - del true_node.fluid_code.layers[-1] - for out_name in output_names: - out_node = self.graph.get_node(out_name) - if out_node.layer_type in can_be_optimized_ops: - out_node.fluid_code.layers[ - 1].inputs = out_node.fluid_code.layers[0].inputs - del out_node.fluid_code.layers[0] - elif out_node.layer_type in elementwise_ops: - if out_node.inputs[0] in node.layer_name: - if out_node.fluid_code.layers[ - 1].op == 'transpose': - out_node.fluid_code.layers[2].inputs[ - 'x'] = out_node.fluid_code.layers[ - 0].inputs - del out_node.fluid_code.layers[0] - else: - out_node.fluid_code.layers[1].inputs[ - 'x'] = out_node.fluid_code.layers[ - 0].inputs - del out_node.fluid_code.layers[0] - elif out_node.inputs[1] in node.layer_name: - if out_node.fluid_code.layers[ - 1].op == 'transpose': - out_node.fluid_code.layers[2].inputs[ - 'y'] = out_node.fluid_code.layers[ - 1].inputs - del out_node.fluid_code.layers[1] - else: - out_node.fluid_code.layers[1].inputs[ - 'y'] = out_node.fluid_code.layers[ - 0].inputs - del out_node.fluid_code.layers[0] - graph_copy = cp.deepcopy(self.graph) - for node_name in self.graph.topo_sort: - node = graph_copy.get_node(node_name) - if node is None or len(node.fluid_code.layers) < 2: - continue - if node.layer_type in can_be_optimized_ops and node.layer_type != "Placeholder": - if node.fluid_code.layers[ - -1].op != "transpose" or node.fluid_code.layers[ - -1].param_attr["perm"] != [0, 2, 3, 1]: - continue - can_be_removed = True - output_names = node.outputs - for out_name in output_names: - out_node = graph_copy.get_node(out_name) - if hasattr(out_node, "can_be_removed"): - if not out_node.can_be_removed: - can_be_removed = False - break - if len(out_node.fluid_code.layers) < 2: - can_be_removed = False - break - if out_node.layer_type in can_be_optimized_ops: - if out_node.fluid_code.layers[ - 0].op != "transpose" or out_node.fluid_code.layers[ - 0].param_attr["perm"] != [0, 3, 1, 2]: - can_be_removed = False - break - elif out_node.layer_type in elementwise_ops: - if out_node.fluid_code.layers[ - 0].op != "transpose" and out_node.fluid_code.layers[ - 1].op != "transpose": - can_be_removed = False - break - if out_node.fluid_code.layers[ - 0].op == "expand" or out_node.fluid_code.layers[ - 1].op == "expand": - can_be_removed = False - break - if out_node.fluid_code.layers[0].op == "transpose": - if out_node.fluid_code.layers[0].param_attr[ - "perm"] != [0, 3, 1, 2]: - can_be_removed = False - break - if out_node.fluid_code.layers[1].op == "transpose": - if out_node.fluid_code.layers[1].param_attr[ - "perm"] != [0, 3, 1, 2]: - can_be_removed = False - break - elif out_node.layer_type not in elementwise_ops and out_node.layer_type not in can_be_optimized_ops: - can_be_removed = False - break - - if can_be_removed: - true_node = self.graph.get_node(node_name) - if len(true_node.fluid_code.layers) < 2: - continue - true_node.fluid_code.layers[ - -2].output = true_node.fluid_code.layers[-1].output - del true_node.fluid_code.layers[-1] - for out_name in output_names: - out_node = self.graph.get_node(out_name) - if out_node.layer_type in can_be_optimized_ops: - out_node.fluid_code.layers[ - 1].inputs = out_node.fluid_code.layers[0].inputs - del out_node.fluid_code.layers[0] - elif out_node.layer_type in elementwise_ops: - if out_node.inputs[0] in node.layer_name: - if out_node.fluid_code.layers[ - 1].op == 'transpose': - if out_node.fluid_code.layers[ - 2].op == 'transpose': - out_node.fluid_code.layers[3].inputs[ - 'x'] = out_node.fluid_code.layers[ - 0].inputs - else: - out_node.fluid_code.layers[2].inputs[ - 'x'] = out_node.fluid_code.layers[ - 0].inputs - del out_node.fluid_code.layers[0] - else: - out_node.fluid_code.layers[1].inputs[ - 'x'] = out_node.fluid_code.layers[ - 0].inputs - del out_node.fluid_code.layers[0] - elif out_node.inputs[1] in node.layer_name: - if out_node.fluid_code.layers[ - 1].op == 'transpose': - out_node.fluid_code.layers[2].inputs[ - 'y'] = out_node.fluid_code.layers[ - 1].inputs - del out_node.fluid_code.layers[1] - else: - out_node.fluid_code.layers[1].inputs[ - 'y'] = out_node.fluid_code.layers[ - 0].inputs - del out_node.fluid_code.layers[0] - - graph_copy = cp.deepcopy(self.graph) - for node_name in self.graph.topo_sort: - node = graph_copy.get_node(node_name) - if node is None: - continue - if node.layer_type in elementwise_ops: - can_be_removed = True - if len(node.fluid_code.layers) < 3: - continue - - numTranspose = 0 - numNotTranspose = 0 - - for i in range(len(node.fluid_code.layers)): - if node.fluid_code.layers[i].op == 'transpose': - numTranspose += 1 - elif node.fluid_code.layers[i].op != 'expand': - numNotTranspose += 1 - if numTranspose > numNotTranspose: - if node.fluid_code.layers[0].op == 'expand': - if node.fluid_code.layers[ - 1].op != 'transpose' or node.fluid_code.layers[ - 2].op != 'transpose': - continue - else: - true_node = self.graph.get_node(node_name) - true_node.fluid_code.layers[3].inputs[ - 'x'] = true_node.fluid_code.layers[1].inputs - true_node.fluid_code.layers[3].inputs[ - 'y'] = true_node.fluid_code.layers[2].inputs - - l = Layer() - l.op = 'transpose' - l.inputs = true_node.fluid_code.layers[3].output - l.param_attr = {'perm': [0, 3, 1, 2]} - if isinstance(l.inputs, six.string_types): - l.output = l.inputs - else: - l.output = l.inputs.layer_name - true_node.fluid_code.layers.append(l) - del true_node.fluid_code.layers[1] - del true_node.fluid_code.layers[1] - else: - if node.fluid_code.layers[ - 0].op != 'transpose' or node.fluid_code.layers[ - 1].op != 'transpose': - continue - else: - true_node = self.graph.get_node(node_name) - true_node.fluid_code.layers[2].inputs[ - 'x'] = true_node.fluid_code.layers[0].inputs - true_node.fluid_code.layers[2].inputs[ - 'y'] = true_node.fluid_code.layers[1].inputs - - l = Layer() - l.op = 'transpose' - l.inputs = true_node.fluid_code.layers[2].output - l.param_attr = {'perm': [0, 3, 1, 2]} - l.output = l.inputs.layer_name - true_node.fluid_code.layers.append(l) - del true_node.fluid_code.layers[0] - del true_node.fluid_code.layers[0] - - def make_nchw_input_output(self): - for i, name in enumerate(self.graph.input_nodes): - node = self.graph.get_node(name) - if len(node.out_shapes[0]) == 4 and node.tf_data_format == "NHWC": - shape = node.fluid_code.layers[0].param_attr["shape"] - shape = [shape[j] for j in [0, 3, 1, 2]] - node.fluid_code.layers[0].param_attr["shape"] = shape - node.fluid_code.layers[0].output = "nhwc_" + name - attr = {"perm": [0, 2, 3, 1]} - node.fluid_code.add_layer( - "transpose", - inputs="nhwc_" + name, - output=node, - param_attr=attr) - self.graph.input_nodes[i] = "nhwc_" + name - for i, name in enumerate(self.graph.output_nodes): - node = self.graph.get_node(name) - if node.layer_type != "transpose": - if node.fluid_code.layers[-1].op == "transpose": - node.fluid_code.layers[-2].output = name - del node.fluid_code.layers[-1] - - def optimize_sub_graph(self): - self.merge_batch_norm() - self.merge_prelu() - self.merge_scale() - self.merge_affine_channel() - - def merge_batch_norm(self): - for i, name in enumerate(self.graph.topo_sort): - node = self.graph.get_node(name) - if node is None: - continue - is_batch_norm = True - if node.layer_type == "Add": - in_nodes0 = [ - self.graph.get_node(in_name) for in_name in node.inputs - ] - if in_nodes0[0].layer_type != "Mul" or in_nodes0[ - 1].layer_type != "Sub": - is_batch_norm = False - continue - - if exist_act(in_nodes0[0]) or exist_act(in_nodes0[1]): - is_batch_norm = False - continue - - in_nodes1 = [ - self.graph.get_node(in_name) - for in_name in in_nodes0[0].inputs - ] - in_nodes2 = [ - self.graph.get_node(in_name) - for in_name in in_nodes0[1].inputs - ] - if len(in_nodes1[0].out_shapes[0]) != 4: - is_batch_norm = False - continue - if in_nodes1[1].layer_type != "Mul": - is_batch_norm = False - continue - if exist_act(in_nodes1[1]): - is_batch_norm = False - continue - - if in_nodes2[0].layer_type != "Const" or in_nodes2[ - 1].layer_type != "Mul": - is_batch_norm = False - continue - if exist_act(in_nodes2[1]): - is_batch_norm = False - continue - - in_nodes3 = [ - self.graph.get_node(in_name) - for in_name in in_nodes1[1].inputs - ] - if in_nodes3[0].layer_type != "Rsqrt" or in_nodes3[ - 1].layer_type != "Const": - is_batch_norm = False - continue - - in_nodes4 = [ - self.graph.get_node(in_name) - for in_name in in_nodes2[1].inputs - ] - if in_nodes4[0].layer_type != "Const" or in_nodes4[ - 1].layer_name != in_nodes1[1].layer_name: - is_batch_norm = False - continue - - in_nodes5 = self.graph.get_node(in_nodes3[0].inputs[0]) - if in_nodes5.layer_type != "Add": - is_batch_norm = False - continue - if exist_act(in_nodes5): - is_batch_norm = False - continue - - in_nodes6 = [ - self.graph.get_node(in_name) for in_name in in_nodes5.inputs - ] - if in_nodes6[0].layer_type != "Const" or in_nodes6[ - 1].layer_type != "Const": - is_batch_norm = False - continue - - if len(in_nodes0[0].outputs) != 1: - is_batch_norm = False - continue - if len(in_nodes0[1].outputs) != 1: - is_batch_norm = False - continue - if len(in_nodes1[1].outputs) != 2: - is_batch_norm = False - continue - if len(in_nodes2[0].outputs) != 1: - is_batch_norm = False - continue - if len(in_nodes2[1].outputs) != 1: - is_batch_norm = False - continue - if len(in_nodes3[0].outputs) != 1: - is_batch_norm = False - continue - if len(in_nodes3[1].outputs) != 1: - is_batch_norm = False - continue - if len(in_nodes4[0].outputs) != 1: - is_batch_norm = False - continue - if len(in_nodes5.outputs) != 1: - is_batch_norm = False - continue - if len(in_nodes6[0].outputs) != 1: - is_batch_norm = False - continue - if len(in_nodes6[1].outputs) != 1: - is_batch_norm = False - continue - - conv_shape = in_nodes1[0].out_shapes[0] - if conv_shape[3] < 0: - is_batch_norm = False - continue - - # moving_variance - if in_nodes6[0].value.size != conv_shape[3]: - is_batch_norm = False - continue - - # epsilon - if in_nodes6[1].value.size != 1: - is_batch_norm = False - continue - - # gamma - if in_nodes3[1].value.size != conv_shape[3]: - is_batch_norm = False - continue - - # moving_mean - if in_nodes4[0].value.size != conv_shape[3]: - is_batch_norm = False - continue - - # beta - if in_nodes2[0].value.size != conv_shape[3]: - is_batch_norm = False - continue - - if is_batch_norm: - index = in_nodes1[0].outputs.index(in_nodes0[0].layer_name) - in_nodes1[0].outputs[index] = node.layer_name - node.layer_type = "FusedBatchNorm" - node.inputs = [in_nodes1[0].layer_name] - act = node.fluid_code.layers[-1].param_attr.get("act", None) - node.fluid_code.clear() - attr = { - "epsilon": in_nodes6[1].value, - "param_attr": string(in_nodes3[1].layer_name), - "bias_attr": string(in_nodes2[0].layer_name), - "moving_mean_name": string(in_nodes4[0].layer_name), - "moving_variance_name": string(in_nodes6[0].layer_name), - "is_test": True, - "act": act - } - - node.fluid_code.add_layer( - "batch_norm", - inputs=in_nodes1[0].fluid_code.layers[-1].output, - output=node, - param_attr=attr) - - del self.graph.node_map[in_nodes0[0].layer_name] - del self.graph.node_map[in_nodes0[1].layer_name] - del self.graph.node_map[in_nodes1[1].layer_name] - del self.graph.node_map[in_nodes2[1].layer_name] - del self.graph.node_map[in_nodes3[0].layer_name] - del self.graph.node_map[in_nodes4[0].layer_name] - del self.graph.node_map[in_nodes5.layer_name] - - def merge_prelu(self): - for i, name in enumerate(self.graph.topo_sort): - node = self.graph.get_node(name) - if node is None: - continue - is_prelu = True - if node.layer_type == "Add": - if exist_act(node): - is_prelu = False - continue - in_nodes0 = [ - self.graph.get_node(in_name) for in_name in node.inputs - ] - if in_nodes0[0].layer_type != "Relu" or in_nodes0[ - 1].layer_type != "Mul": - is_prelu = False - continue - if exist_act(in_nodes0[1]): - is_prelu = False - continue - - if len(in_nodes0[0].outputs) != 1 or len(in_nodes0[1] - .outputs) != 1: - is_prelu = False - continue - - in_nodes1 = self.graph.get_node(in_nodes0[0].inputs[0]) - in_nodes2 = [ - self.graph.get_node(in_name) - for in_name in in_nodes0[1].inputs - ] - if in_nodes2[1].layer_type != "Const" or numpy.fabs(in_nodes2[ - 1].value - 0.5) > 1e-06: - is_prelu = False - continue - if in_nodes2[0].layer_type != "Mul": - is_prelu = False - continue - if exist_act(in_nodes2[0]): - is_prelu = False - continue - if len(in_nodes2[1].outputs) != 1 or len(in_nodes2[0] - .outputs) != 1: - is_prelu = False - continue - - in_nodes3 = [ - self.graph.get_node(in_name) - for in_name in in_nodes2[0].inputs - ] - if in_nodes3[0].layer_type != "Const" or in_nodes3[ - 1].layer_type != "Sub": - is_prelu = False - continue - if exist_act(in_nodes3[1]): - is_prelu = False - continue - if len(in_nodes3[0].outputs) != 1 or len(in_nodes3[1] - .outputs) != 1: - is_prelu = False - continue - - in_nodes4 = [ - self.graph.get_node(in_name) - for in_name in in_nodes3[1].inputs - ] - if in_nodes4[0].layer_name != in_nodes1.layer_name or in_nodes4[ - 1].layer_type != "Abs": - is_prelu = False - continue - if len(in_nodes4[1].outputs) != 1: - is_prelu = False - continue - - in_nodes5 = self.graph.get_node(in_nodes4[1].inputs[0]) - if in_nodes5.layer_name != in_nodes1.layer_name: - is_prelu = False - continue - - if len(in_nodes0[0].outputs) != 1: - is_prelu = false - continue - if len(in_nodes0[1].outputs) != 1: - is_prelu = False - continue - if len(in_nodes1.outputs) < 3: - is_prelu = False - continue - if len(in_nodes2[0].outputs) != 1: - is_prelu = false - continue - if len(in_nodes2[1].outputs) != 1: - is_prelu = False - continue - if len(in_nodes3[0].outputs) != 1: - is_prelu = False - continue - if len(in_nodes3[1].outputs) != 1: - is_prelu = false - continue - if len(in_nodes4[1].outputs) != 1: - is_prelu = False - continue - - mode = None - in_shape = in_nodes1.out_shapes[0] - if in_shape == list(in_nodes3[0].value.shape): - mode = "element" - elif len(in_nodes3[0].value.shape) == 0: - mode = "all" - elif len(in_nodes3[0].value.shape) == 1 and in_nodes3[ - 0].value.shape[0] == 1: - mode = "all" - elif len(in_shape) == 4 and len(in_nodes3[ - 0].value.shape) == 1 and in_nodes3[0].value.shape[ - 0] == in_shape[-1]: - mode = "channel" - weight = self.op_mapper.weights[in_nodes3[0].layer_name] - weight = numpy.expand_dims(weight, 0) - weight = numpy.expand_dims(weight, 2) - weight = numpy.expand_dims(weight, 3) - self.op_mapper.weights[in_nodes3[0].layer_name] = weight - # fix bug in Paddle1.8.3 and may change in next version. - # self.op_mapper.weights[in_nodes3[0].layer_name + - # '_1'] = weight.reshape(1, -1) - in_nodes3[0].fluid_code.layers[0].param_attr["shape"] = [ - 1, in_shape[-1], 1, 1 - ] - else: - is_prelu = False - continue - - if is_prelu: - index = in_nodes1.outputs.index(in_nodes0[0].layer_name) - del in_nodes1.outputs[index] - index = in_nodes1.outputs.index(in_nodes3[1].layer_name) - del in_nodes1.outputs[index] - index = in_nodes1.outputs.index(in_nodes4[1].layer_name) - del in_nodes1.outputs[index] - in_nodes1.outputs.append(node.layer_name) - - node.layer_type = "Prelu" - node.inputs = [in_nodes1.layer_name] - act = node.fluid_code.layers[-1].param_attr.get("act", None) - node.fluid_code.clear() - attr = { - "mode": string(mode), - "param_attr": string(in_nodes3[0].layer_name) - } - - node.fluid_code.add_layer( - "prelu", - inputs=in_nodes1.fluid_code.layers[-1].output, - output=node, - param_attr=attr) - del self.graph.node_map[in_nodes0[0].layer_name] - del self.graph.node_map[in_nodes0[1].layer_name] - del self.graph.node_map[in_nodes2[0].layer_name] - del self.graph.node_map[in_nodes2[1].layer_name] - del self.graph.node_map[in_nodes3[1].layer_name] - del self.graph.node_map[in_nodes4[1].layer_name] - - def merge_scale(self): - for i, name in enumerate(self.graph.topo_sort): - node = self.graph.get_node(name) - if node is None: - continue - is_scale = True - if node.layer_type == "Sub": - in_nodes0 = [ - self.graph.get_node(in_name) for in_name in node.inputs - ] - if in_nodes0[0].layer_type != "Mul" or in_nodes0[ - 1].layer_type != "Const" or in_nodes0[ - 1].value.size != 1: - is_scale = False - continue - if exist_act(in_nodes0[0]): - is_scale = False - continue - if len(in_nodes0[0].outputs) != 1 or len(in_nodes0[1] - .outputs) != 1: - is_scale = False - continue - - in_nodes1 = [ - self.graph.get_node(in_name) - for in_name in in_nodes0[0].inputs - ] - if in_nodes1[0].layer_type != "Const" or in_nodes1[ - 1].layer_type != "RealDiv" or in_nodes1[ - 0].value.size != 1: - is_scale = False - continue - if exist_act(in_nodes1[1]): - is_scale = False - continue - if len(in_nodes1[0].outputs) != 1 or len(in_nodes1[1] - .outputs) != 1: - is_scale = False - continue - - in_nodes2 = [ - self.graph.get_node(in_name) - for in_name in in_nodes1[1].inputs - ] - if in_nodes2[1].layer_type != "Const" or in_nodes2[ - 1].value.size != 1: - is_scale = False - continue - - if is_scale: - in_node = self.graph.get_node(in_nodes1[1].inputs[0]) - index = in_node.outputs.index(in_nodes1[1].layer_name) - in_node.outputs[index] = node.layer_name - node.layer_type = "Scale" - node.inputs = [in_node.layer_name] - scale = 1.0 / in_nodes2[1].value * in_nodes1[0].value - act = None - if node.fluid_code.layers[0].param_attr is not None: - act = node.fluid_code.layers[0].param_attr.get("act", - None) - node.fluid_code.clear() - - attr = { - "scale": scale, - "bias": in_nodes0[1].value, - "bias_after_scale": True, - "act": act - } - node.fluid_code.add_layer( - "scale", inputs=in_node, output=node, param_attr=attr) - - del self.graph.node_map[in_nodes0[0].layer_name] - del self.graph.node_map[in_nodes0[1].layer_name] - del self.graph.node_map[in_nodes1[0].layer_name] - del self.graph.node_map[in_nodes1[1].layer_name] - del self.graph.node_map[in_nodes2[1].layer_name] - - def merge_affine_channel(self): - for i, name in enumerate(self.graph.topo_sort): - node = self.graph.get_node(name) - if node is None: - continue - is_affine_channel = True - if node.layer_type == "RealDiv": - in_nodes0 = [ - self.graph.get_node(in_name) for in_name in node.inputs - ] - bias_add = True - if (in_nodes0[0].layer_type != "Sub" and in_nodes0[0].layer_type - != "Add") or in_nodes0[1].layer_type != "Const" or len( - in_nodes0[1].value.shape) != 3: - is_affine_channel = False - continue - if in_nodes0[0].layer_type == "Sub": - bias_add = False - if exist_act(in_nodes0[0]): - is_affine_channel = False - continue - if len(in_nodes0[0].outputs) != 1 or len(in_nodes0[1] - .outputs) != 1: - is_affine_channel = False - continue - in_nodes1 = [ - self.graph.get_node(in_name) - for in_name in in_nodes0[0].inputs - ] - if len(in_nodes1[0].out_shapes[0]) != 4 or in_nodes1[ - 1].layer_type != "Const" or len(in_nodes1[1] - .value.shape) != 3: - is_affine_channel = False - continue - if len(in_nodes1[1].outputs) != 1: - is_affine_channel = False - continue - channel = in_nodes1[0].out_shapes[0][-1] - if channel < 0 or channel != in_nodes0[ - 1].value.size or channel != in_nodes1[1].value.size: - is_affine_channel = False - continue - if in_nodes0[1].out_shapes[0][-1] != in_nodes0[ - 1].value.size or in_nodes1[1].out_shapes[0][ - -1] != in_nodes1[1].value.size: - is_affine_channel = False - continue - if is_affine_channel: - in_node = in_nodes1[0] - index = in_node.outputs.index(in_nodes0[0].layer_name) - in_node.outputs[index] = node.layer_name - node.layer_type = "AffineChannel" - node.inputs = [in_node.layer_name] - scale = 1.0 / in_nodes0[1].value.flatten() - bias = in_nodes1[1].value.flatten() / in_nodes0[ - 1].value.flatten() - if not bias_add: - bias *= -1.0 - self.op_mapper.weights[node.layer_name + "_scale"] = scale - self.op_mapper.weights[node.layer_name + "_bias"] = bias - - act = None - if node.fluid_code.layers[0].param_attr is not None: - act = node.fluid_code.layers[0].param_attr.get("act", - None) - node.fluid_code.clear() - - attr = { - "dtype": string(scale.dtype), - "shape": [channel], - "name": string(node.layer_name + "_scale") - } - node.fluid_code.add_layer( - "create_parameter", - inputs=None, - output=node.layer_name + "_scale", - param_attr=attr) - attr = { - "dtype": string(scale.dtype), - "shape": [channel], - "name": string(node.layer_name + "_bias") - } - node.fluid_code.add_layer( - "create_parameter", - inputs=None, - output=node.layer_name + "_bias", - param_attr=attr) - inputs = { - "x": in_node, - "scale": node.layer_name + "_scale", - "bias": node.layer_name + "_bias" - } - attr = {"act": act} - node.fluid_code.add_layer( - "affine_channel", - inputs=inputs, - output=node, - param_attr=attr) - - del self.graph.node_map[in_nodes0[0].layer_name] - del self.graph.node_map[in_nodes0[1].layer_name] - del self.graph.node_map[in_nodes1[1].layer_name] diff --git a/x2paddle_model_zoo.md b/x2paddle_model_zoo.md index 464abdf547b1c9c7a3698c05579131426c44b59e..871b8c327003e577b976eabc9eee55293fda8fbd 100644 --- a/x2paddle_model_zoo.md +++ b/x2paddle_model_zoo.md @@ -21,7 +21,7 @@ | ResNet_V2_101 | [code](https://github.com/tensorflow/models/tree/master/research/slim/nets) |-| | UNet | [code1](https://github.com/jakeret/tf_unet )/[code2](https://github.com/lyatdawn/Unet-Tensorflow) |-| | MTCNN | [code](https://github.com/AITTSMD/MTCNN-Tensorflow) |-| -| YOLO-V3| [code](https://github.com/YunYang1994/tensorflow-yolov3) | 转换需要关闭NHWC->NCHW的优化,见[文档Q2](FAQ.md) | +| YOLO-V3| [code](https://github.com/YunYang1994/tensorflow-yolov3) | -| | FALSR | [code](https://github.com/xiaomi-automl/FALSR) | 需使用参数without_data_format_optimization | | DCSCN | [code](https://modelzoo.co/model/dcscn-super-resolution) | 需使用参数without_data_format_optimization | | Bert(albert) | [code](https://github.com/google-research/albert#pre-trained-models) | 需使用参数without_data_format_optimization |