diff --git a/README.md b/README.md index ba811966bbc03e44b4e3eb5a0c177922866fe624..fc3fea0e8d56e56b69a6029c90e4c1776fef1cc3 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ X2Paddle在多个主流的CV模型上,测试过TensorFlow/Caffe/ONNX模型的 ## 环境依赖 python == 2.7 | python >= 3.5 -paddlepaddle >= 1.8.0 +paddlepaddle >= 2.0.0 **按需安装以下依赖** tensorflow : tensorflow == 1.14.0 @@ -49,11 +49,14 @@ x2paddle --framework=onnx --model=onnx_model.onnx --save_dir=pd_model ### PyTorch > PyTorch不支持命令行使用方式,详见[PyTorch2Paddle](pytorch2paddle.md) +### Paddle2ONNX +> 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 | 指定转换后的模型保存目录路径 | @@ -61,7 +64,6 @@ x2paddle --framework=onnx --model=onnx_model.onnx --save_dir=pd_model |--caffe_proto | **[可选]** 由caffe.proto编译成caffe_pb2.py文件的存放路径,当存在自定义Layer时使用,默认为None | |--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/tools/README.md b/tools/README.md index bdd26d3659246780b3dc9cf52fab1f54fa38a55c..1a507890bc18ea85906812dec28ad5aea4fec373 100644 --- a/tools/README.md +++ b/tools/README.md @@ -4,7 +4,7 @@ ``` python tools/check_for_lite.py paddle_model/inference_model/__model__ ``` - +> 附:check_for_lite工具并不能完全判断模型是否被支持,PaddleLite详细支持的算子请参考[PaddleLite支持算子集](https://github.com/PaddlePaddle/Paddle-Lite/blob/develop/docs/introduction/support_operation_list.md) ### 二、模型参数合并 X2Paddle转换后产出的路径下包括两个目录, diff --git a/x2paddle/convert.py b/x2paddle/convert.py index 0f51a2f79664070b8f490124c2ba8acaba5e5529..7b38f2702c1d5e56bb4559639adcd8d6fc6bdf6e 100644 --- a/x2paddle/convert.py +++ b/x2paddle/convert.py @@ -64,24 +64,12 @@ def arg_parser(): action="store_true", default=False, help="get version of x2paddle") - parser.add_argument( - "--without_data_format_optimization", - "-wo", - type=_text_type, - default="True", - help="tf model conversion without data format optimization") parser.add_argument( "--define_input_shape", "-d", 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", @@ -95,6 +83,12 @@ def arg_parser(): default="dygraph", help="define the paddle model type after converting(dygraph/static)" ) + parser.add_argument( + "--without_data_format_optimization", + "-wo", + type=_text_type, + default="True", + help="tf model conversion without data format optimization") return parser @@ -246,24 +240,6 @@ def pytorch2paddle(module, save_dir, jit_type="trace", input_examples=None): mapper.paddle_graph.gen_model(save_dir, jit_type=jit_type) -def paddle2onnx(model_path, save_dir, opset_version=10): - import paddle.fluid as fluid - try: - import paddle2onnx - except: - print( - "[ERROR] paddle2onnx not installed, use \"pip install paddle2onnx\"") - - import paddle2onnx as p2o - model = p2o.PaddleDecoder(model_path, '__model__', '__params__') - mapper = p2o.PaddleOpMapper() - mapper.convert( - model.program, - save_dir, - scope=fluid.global_scope(), - opset_version=opset_version) - - def main(): if len(sys.argv) < 2: print("Use \"x2paddle -h\" to print the help information") @@ -328,12 +304,11 @@ def main(): params_merge = True onnx2paddle(args.model, args.save_dir, args.paddle_type, 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 de72d0f5453e711fee6c54667bc3b73ac4f6207e..1dc4267b0579bd0ee1de0c22add1df527da21f98 100644 --- a/x2paddle/core/program.py +++ b/x2paddle/core/program.py @@ -1,3 +1,4 @@ +# -*- coding:UTF-8 -*- # Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License" diff --git a/x2paddle/decoder/caffe_decoder.py b/x2paddle/decoder/caffe_decoder.py index ccb09b0d8206c4fc8e80e08db09238d80e27986b..28bc6ce38b8139eabbcde536d66673c28d319a11 100644 --- a/x2paddle/decoder/caffe_decoder.py +++ b/x2paddle/decoder/caffe_decoder.py @@ -110,6 +110,8 @@ class CaffeGraph(Graph): if not exclude: filtered_layers.append(layer) # Guard against dupes. + if layer.name in filtered_layer_names: + layer.name += "_0" assert layer.name not in filtered_layer_names filtered_layer_names.add(layer.name) else: @@ -230,7 +232,7 @@ class CaffeGraph(Graph): assert input_node_name in self.node_map, 'The {} isn\'t a valid node'.format( name) input_node = self.node_map[input_node_name] - if len(input_node.layer.top) > 1: + if len(input_node.layer.top) > 1 and input_node.layer_type != "Input": need_idx = list(input_node.layer.top).index(node.layer.bottom[idx]) name = input_node_name + ':' + str(need_idx) else: diff --git a/x2paddle/decoder/onnx_decoder.py b/x2paddle/decoder/onnx_decoder.py index 3a1ba920efb20184bcf35dccd142da784a285192..5aa52dc03f719c3db27c3426b5552fdefc5703fc 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() diff --git a/x2paddle/decoder/onnx_shape_inference.py b/x2paddle/decoder/onnx_shape_inference.py index 7b08be9db4729a047123dc59b471e74288d94a8a..358bf76fc7e63b5ea9913f899c2afc4761841fbf 100644 --- a/x2paddle/decoder/onnx_shape_inference.py +++ b/x2paddle/decoder/onnx_shape_inference.py @@ -1588,7 +1588,7 @@ class SymbolicShapeInference: 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('Only support models of onnx opset 7 and above.') + 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) @@ -1605,7 +1605,7 @@ class SymbolicShapeInference: symbolic_shape_inference.out_mp_ = shape_inference.infer_shapes( symbolic_shape_inference.out_mp_) except: - print('Stopping at incomplete symbolic 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/op_mapper/dygraph/pytorch2paddle/aten.py b/x2paddle/op_mapper/dygraph/pytorch2paddle/aten.py index d65e14b8d7eb3eebe32177853cec4c1799edc365..c63603eb13054d26b757bb070b2ad2dabe6f2794 100644 --- a/x2paddle/op_mapper/dygraph/pytorch2paddle/aten.py +++ b/x2paddle/op_mapper/dygraph/pytorch2paddle/aten.py @@ -1,3 +1,4 @@ +# -*- coding:UTF-8 -*- # Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License" diff --git a/x2paddle/op_mapper/dygraph/pytorch2paddle/prim.py b/x2paddle/op_mapper/dygraph/pytorch2paddle/prim.py index a0b7c4a9907de511ee05e6b90799e647514b84a2..fb47a31e13fd7169f2ca297ca62ec9a5198f798c 100644 --- a/x2paddle/op_mapper/dygraph/pytorch2paddle/prim.py +++ b/x2paddle/op_mapper/dygraph/pytorch2paddle/prim.py @@ -1,3 +1,4 @@ +# -*- coding:UTF-8 -*- # Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License" diff --git a/x2paddle/op_mapper/dygraph/pytorch2paddle/prim2code.py b/x2paddle/op_mapper/dygraph/pytorch2paddle/prim2code.py index ec323aece9c780f0977e74b5ba31d8dc6829b844..3001f3cf599d05af9e1918ea166979d85f5f34f4 100644 --- a/x2paddle/op_mapper/dygraph/pytorch2paddle/prim2code.py +++ b/x2paddle/op_mapper/dygraph/pytorch2paddle/prim2code.py @@ -1,3 +1,4 @@ +# -*- coding:UTF-8 -*- # Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License" diff --git a/x2paddle/op_mapper/dygraph/pytorch2paddle/pytorch_op_mapper.py b/x2paddle/op_mapper/dygraph/pytorch2paddle/pytorch_op_mapper.py index 0ebec0f17e561ffeb2d1d49d48c9d697783680c8..cb210956b7804fd76fd9ec1bc54a8c43c0bf6dac 100644 --- a/x2paddle/op_mapper/dygraph/pytorch2paddle/pytorch_op_mapper.py +++ b/x2paddle/op_mapper/dygraph/pytorch2paddle/pytorch_op_mapper.py @@ -1,3 +1,4 @@ +# -*- coding:UTF-8 -*- # Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License" diff --git a/x2paddle/op_mapper/dygraph/tf2paddle/tf_op_mapper.py b/x2paddle/op_mapper/dygraph/tf2paddle/tf_op_mapper.py index ad4206e13faf522fe53f388e2e4850c18811cce9..f495b2b5582a7f5e48ef148de648a046bbe0cf12 100644 --- a/x2paddle/op_mapper/dygraph/tf2paddle/tf_op_mapper.py +++ b/x2paddle/op_mapper/dygraph/tf2paddle/tf_op_mapper.py @@ -561,7 +561,7 @@ class TFOpMapper(OpMapper): self.paddle_graph.add_layer( kernel="paddle.nn.functional.pad", - inputs={"input": input.name}, + inputs={"x": input.name}, outputs=[node.name], pad=paddings) diff --git a/x2paddle/op_mapper/static/tf2paddle/tf_op_mapper.py b/x2paddle/op_mapper/static/tf2paddle/tf_op_mapper.py index e135735a679c37b1dbd0d32a1716690f3b0c2baa..da294f8decb223fdc8afe089f385090a9d296455 100644 --- a/x2paddle/op_mapper/static/tf2paddle/tf_op_mapper.py +++ b/x2paddle/op_mapper/static/tf2paddle/tf_op_mapper.py @@ -546,7 +546,7 @@ class TFOpMapper(OpMapper): self.paddle_graph.add_layer( kernel="fluid.layers.pad", - inputs={"input": input.name}, + inputs={"x": input.name}, outputs=[node.name], paddings=paddings)