diff --git a/README.md b/README.md index 11e101225f262c9a21af3d4d338ce4e3664726bd..3bd8061115e0c073edc0894b8c59be862b4009b0 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ X2Paddle是飞桨生态下的模型转换工具,致力于帮助其它深度学 - tensorflow == 1.14 (如需转换TensorFlow模型) - onnx >= 1.6.0 (如需转换ONNX模型) - torch >= 1.5.0 (如需转换PyTorch模型) +- paddlelite == 2.9.0 (如需一键转换成Paddle-Lite支持格式) ### pip安装(推荐) @@ -100,6 +101,12 @@ x2paddle --framework=caffe --prototxt=deploy.prototxt --weight=deploy.caffemodel | --model | 当framework为tensorflow/onnx时,该参数指定tensorflow的pb模型文件或onnx模型路径 | | --caffe_proto | **[可选]** 由caffe.proto编译成caffe_pb2.py文件的存放路径,当存在自定义Layer时使用,默认为None | | --define_input_shape | **[可选]** For TensorFlow, 当指定该参数时,强制用户输入每个Placeholder的shape,见[文档Q2](./docs/inference_model_convertor/FAQ.md) | +| --to_lite | **[可选]** 是否使用opt工具转成Paddle-Lite支持格式,默认为False | +| --lite_valid_places | **[可选]** 指定转换类型,可以同时指定多个backend(以逗号分隔),opt将会自动选择最佳方式,默认为arm | +| --lite_model_type | **[可选]** 指定模型转化类型,目前支持两种类型:protobuf和naive_buffer,默认为naive_buffer | + +#### 一键转换Paddle-Lite支持格式 +可参考[使用X2paddle导出Padde-Lite支持格式](docs/inference_model_convertor/convert2lite_api.md) ### 功能二:PyTorch模型训练迁移 diff --git a/docs/inference_model_convertor/convert2lite_api.md b/docs/inference_model_convertor/convert2lite_api.md new file mode 100644 index 0000000000000000000000000000000000000000..aa96911cfe30b432942092a2352afe132bc4d543 --- /dev/null +++ b/docs/inference_model_convertor/convert2lite_api.md @@ -0,0 +1,110 @@ +# X2paddle Convert2Lite API + + +## 目录 +* [x2paddle.convert.tf2paddle](#1) +* [x2paddle.convert.caffe2paddle](#2) +* [x2paddle.convert.onnx2paddle](#3) +* [x2paddle.convert.pytorch2paddle](#4) + + +## 使用X2paddle导出Padde-Lite支持格式 + +**背景**:如果想用Paddle-Lite运行第三方来源(TensorFlow、Caffe、ONNX、PyTorch)模型,一般需要经过两次转化。即使用X2paddle工具将第三方模型转化为PaddlePaddle格式,再使用opt将PaddlePaddle模型转化为Padde-Lite可支持格式。 + +**使用方法**:为了简化这一过程,X2Paddle集成了opt工具,提供一键转换功能,包括API以及命令行,以ONNX为例: + +***API方式*** + ```python +from x2paddle.convert import onnx2paddle + +onnx2paddle(model_path, save_dir, + convert_to_lite=True, + lite_valid_places="arm", + lite_model_type="naive_buffer") +# model_path(str)为ONNX模型路径 +# save_dir(str)为转换后模型保存路径 +# convert_to_lite(bool)表示是否使用opt工具,默认为False +# lite_valid_places(str)指定转换类型,默认为arm +# lite_model_type(str)指定模型转化类型,默认为naive_buffer +``` + +***命令行方式*** +```shell +x2paddle --framework=onnx --model=onnx_model.onnx --save_dir=pd_model --to_lite=True --lite_valid_places=arm --lite_model_type=naive_buffer +``` + +TensorFlow、Caffe以及Pytorch模型转换参考如下API + + +##

x2paddle.convert.tf2paddle

+ +```python +x2paddle.convert.tf2paddle(model_path, save_dir, define_input_shape=False, convert_to_lite=False, lite_valid_places="arm", lite_model_type="naive_buffer") +``` + +> 转换TensorFlow模型。 + +> **参数** +> +> > - **model_path** (str): TensorFlow pb模型路径 +> > - **save_dir** (str): 转换后模型保存路径 +> > - **define_input_shape** (bool): 是否指定输入大小,默认为False +> > - **convert_to_lite** (bool): 是否使用opt工具转成Paddle-Lite支持格式,默认为False +> > - **lite_valid_places** (str): 指定转换类型,可以同时指定多个backend(以逗号分隔),opt将会自动选择最佳方式,默认为arm +> > - **lite_model_type** (str): 指定模型转化类型,目前支持两种类型:protobuf和naive_buffer,默认为naive_buffer + + +##

x2paddle.convert.caffe2paddle

+ +```python +x2paddle.convert.caffe2paddle(proto_file, weight_file, save_dir, caffe_proto, convert_to_lite=False, lite_valid_places="arm", lite_model_type="naive_buffer") +``` + +> 转换Caffe模型。 + +> **参数** +> +> > - **proto_file** (str): caffe模型的prototxt文件 +> > - **weight_file** (str): caffe模型的权重文件 +> > - **save_dir** (str): 转换后模型保存路径 +> > - **caffe_proto** (str): 可选:由caffe.proto编译成caffe_pb2.py文件的存放路径,当存在自定义Layer时使用,默认为None +> > - **convert_to_lite** (bool): 是否使用opt工具转成Paddle-Lite支持格式,默认为False +> > - **lite_valid_places** (str): 指定转换类型,可以同时指定多个backend(以逗号分隔),opt将会自动选择最佳方式,默认为arm +> > - **lite_model_type** (str): 指定模型转化类型,目前支持两种类型:protobuf和naive_buffer,默认为naive_buffer + + +##

x2paddle.convert.onnx2paddle

+ +```python +x2paddle.convert.onnx2paddle(model_path, save_dir, convert_to_lite=False, lite_valid_places="arm", lite_model_type="naive_buffer") +``` + +> 转换ONNX模型。 + +> **参数** +> +> > - **model_path** (str): TensorFlow pb模型路径 +> > - **save_dir** (str): 转换后模型保存路径 +> > - **convert_to_lite** (bool): 是否使用opt工具转成Paddle-Lite支持格式,默认为False +> > - **lite_valid_places** (str): 指定转换类型,可以同时指定多个backend(以逗号分隔),opt将会自动选择最佳方式,默认为arm +> > - **lite_model_type** (str): 指定模型转化类型,目前支持两种类型:protobuf和naive_buffer,默认为naive_buffer + + +##

x2paddle.convert.pytorch2paddle

+ +```python +x2paddle.convert.pytorch2paddle(module, save_dir, jit_type="trace", input_examples=None, convert_to_lite=False, lite_valid_places="arm", lite_model_type="naive_buffer") +``` + +> 转换Pytorch模型。 + +> **参数** +> +> > - **module** (torch.nn.Module): PyTorch的Module +> > - **save_dir** (str): 转换后模型保存路径 +> > - **jit_type** (str): 转换方式。目前有两种:trace和script,默认为trace +> > - **input_examples** (list[torch.tensor]): torch.nn.Module的输入示例,list的长度必须与输入的长度一致。默认为None。 +> > - **convert_to_lite** (bool): 是否使用opt工具转成Paddle-Lite支持格式,默认为False +> > - **lite_valid_places** (str): 指定转换类型,可以同时指定多个backend(以逗号分隔),opt将会自动选择最佳方式,默认为arm +> > - **lite_model_type** (str): 指定模型转化类型,目前支持两种类型:protobuf和naive_buffer,默认为naive_buffer diff --git a/x2paddle/convert.py b/x2paddle/convert.py index 24dd0fc837980d5397ef2d7a5d4bbac12b83809f..89268b6ba4e8e2fc7ec1731229eeb45b8947e22e 100644 --- a/x2paddle/convert.py +++ b/x2paddle/convert.py @@ -87,11 +87,44 @@ def arg_parser(): type=_text_type, default=None, help="pretrain model file of pytorch model") + parser.add_argument( + "--to_lite", "-tl", default=False, help="convert to Paddle-Lite format") + parser.add_argument( + "--lite_valid_places", + "-vp", + type=_text_type, + default="arm", + help="Specify the executable backend of the model") + parser.add_argument( + "--lite_model_type", + "-mt", + type=_text_type, + default="naive_buffer", + help="The type of lite model") return parser -def tf2paddle(model_path, save_dir, define_input_shape=False): +def convert2lite(save_dir, + lite_valid_places="arm", + lite_model_type="naive_buffer"): + """Convert to Paddle-Lite format.""" + + from paddlelite.lite import Opt + opt = Opt() + opt.set_model_dir(save_dir + "/inference_model") + opt.set_valid_places(lite_valid_places) + opt.set_model_type(lite_model_type) + opt.set_optimize_out(save_dir + "/opt") + opt.run() + + +def tf2paddle(model_path, + save_dir, + define_input_shape=False, + convert_to_lite=False, + lite_valid_places="arm", + lite_model_type="naive_buffer"): # check tensorflow installation and version try: import os @@ -120,20 +153,28 @@ def tf2paddle(model_path, save_dir, define_input_shape=False): graph_opt = GraphOptimizer(source_frame="tf") graph_opt.optimize(mapper.paddle_graph) mapper.paddle_graph.gen_model(save_dir) + if convert_to_lite: + convert2lite(save_dir, lite_valid_places, lite_model_type) -def caffe2paddle(proto, weight, save_dir, caffe_proto): +def caffe2paddle(proto_file, + weight_file, + save_dir, + caffe_proto, + convert_to_lite=False, + lite_valid_places="arm", + lite_model_type="naive_buffer"): from x2paddle.decoder.caffe_decoder import CaffeDecoder from x2paddle.op_mapper.caffe2paddle.caffe_op_mapper import CaffeOpMapper import google.protobuf as gpb ver_part = gpb.__version__.split('.') version_satisfy = False if (int(ver_part[0]) == 3 and int(ver_part[1]) >= 6) \ - or (int(ver_part[0]) > 3): + or (int(ver_part[0]) > 3): version_satisfy = True assert version_satisfy, '[ERROR] google.protobuf >= 3.6.0 is required' print("Now translating model from caffe to paddle.") - model = CaffeDecoder(proto, weight, caffe_proto) + model = CaffeDecoder(proto_file, weight_file, caffe_proto) mapper = CaffeOpMapper(model) mapper.paddle_graph.build() print("Model optimizing ...") @@ -142,9 +183,15 @@ def caffe2paddle(proto, weight, save_dir, caffe_proto): graph_opt.optimize(mapper.paddle_graph) print("Model optimized.") mapper.paddle_graph.gen_model(save_dir) + if convert_to_lite: + convert2lite(save_dir, lite_valid_places, lite_model_type) -def onnx2paddle(model_path, save_dir): +def onnx2paddle(model_path, + save_dir, + convert_to_lite=False, + lite_valid_places="arm", + lite_model_type="naive_buffer"): # check onnx installation and version try: import onnx @@ -165,9 +212,17 @@ def onnx2paddle(model_path, save_dir): mapper = ONNXOpMapper(model) mapper.paddle_graph.build() mapper.paddle_graph.gen_model(save_dir) + if convert_to_lite: + convert2lite(save_dir, lite_valid_places, lite_model_type) -def pytorch2paddle(module, save_dir, jit_type="trace", input_examples=None): +def pytorch2paddle(module, + save_dir, + jit_type="trace", + input_examples=None, + convert_to_lite=False, + lite_valid_places="arm", + lite_model_type="naive_buffer"): # check pytorch installation and version try: import torch @@ -199,6 +254,8 @@ def pytorch2paddle(module, save_dir, jit_type="trace", input_examples=None): graph_opt.optimize(mapper.paddle_graph) print("Model optimized.") mapper.paddle_graph.gen_model(save_dir, jit_type=jit_type) + if convert_to_lite: + convert2lite(save_dir, lite_valid_places, lite_model_type) def main(): @@ -250,15 +307,32 @@ def main(): define_input_shape = False if args.define_input_shape: define_input_shape = True - tf2paddle(args.model, args.save_dir, define_input_shape) + tf2paddle( + args.model, + args.save_dir, + define_input_shape, + convert_to_lite=args.to_lite, + lite_valid_places=args.lite_valid_places, + lite_model_type=args.lite_model_type) elif args.framework == "caffe": assert args.prototxt is not None and args.weight is not None, "--prototxt and --weight should be defined while translating caffe model" - caffe2paddle(args.prototxt, args.weight, args.save_dir, - args.caffe_proto) + caffe2paddle( + args.prototxt, + args.weight, + args.save_dir, + args.caffe_proto, + convert_to_lite=args.to_lite, + lite_valid_places=args.lite_valid_places, + lite_model_type=args.lite_model_type) elif args.framework == "onnx": assert args.model is not None, "--model should be defined while translating onnx model" - onnx2paddle(args.model, args.save_dir) + onnx2paddle( + args.model, + args.save_dir, + convert_to_lite=args.to_lite, + lite_valid_places=args.lite_valid_places, + lite_model_type=args.lite_model_type) elif args.framework == "paddle2onnx": print( "Paddle to ONNX tool has been migrated to the new github: https://github.com/PaddlePaddle/paddle2onnx"