convert.py 11.3 KB
Newer Older
1
# Copyright (c) 2020  PaddlePaddle Authors. All Rights Reserved.
J
jiangjiajun 已提交
2 3 4 5 6 7 8 9 10 11 12 13
#
# 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.
S
SunAhong1993 已提交
14

15 16
from six import text_type as _text_type
import argparse
J
jiangjiajun 已提交
17
import sys
18

J
jiangjiajun 已提交
19

20 21
def arg_parser():
    parser = argparse.ArgumentParser()
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
    parser.add_argument(
        "--model",
        "-m",
        type=_text_type,
        default=None,
        help="define model file path for tensorflow or onnx")
    parser.add_argument(
        "--prototxt",
        "-p",
        type=_text_type,
        default=None,
        help="prototxt file of caffe model")
    parser.add_argument(
        "--weight",
        "-w",
        type=_text_type,
        default=None,
        help="weight file of caffe model")
    parser.add_argument(
        "--save_dir",
        "-s",
        type=_text_type,
        default=None,
        help="path to save translated model")
J
upgrade  
jiangjiajun 已提交
46 47 48 49 50
    parser.add_argument(
        "--framework",
        "-f",
        type=_text_type,
        default=None,
51 52
        help="define which deeplearning framework(tensorflow/caffe/onnx/paddle2onnx)"
    )
S
SunAhong1993 已提交
53 54 55 56 57
    parser.add_argument(
        "--caffe_proto",
        "-c",
        type=_text_type,
        default=None,
J
upgrade  
jiangjiajun 已提交
58 59
        help="optional: the .py file compiled by caffe proto file of caffe model"
    )
60 61 62 63 64 65
    parser.add_argument(
        "--version",
        "-v",
        action="store_true",
        default=False,
        help="get version of x2paddle")
66 67 68
    parser.add_argument(
        "--without_data_format_optimization",
        "-wo",
S
SunAhong1993 已提交
69 70
        type=_text_type,
        default="True",
71
        help="tf model conversion without data format optimization")
72 73 74 75 76 77
    parser.add_argument(
        "--define_input_shape",
        "-d",
        action="store_true",
        default=False,
        help="define input shape for tf model")
C
Channingss 已提交
78 79 80 81 82 83
    parser.add_argument(
        "--onnx_opset",
        "-oo",
        type=int,
        default=10,
        help="when paddle2onnx set onnx opset version to export")
84 85 86 87 88 89
    parser.add_argument(
        "--params_merge",
        "-pm",
        action="store_true",
        default=False,
        help="define whether merge the params")
S
SunAhong1993 已提交
90 91 92 93 94 95
    parser.add_argument(
        "--input_shapes",
        "-is",
        action='append',
        default=None,
        help="define the inputs' shape")
96
    return parser
J
jiangjiajun 已提交
97

C
Channingss 已提交
98

99 100
def tf2paddle(model_path,
              save_dir,
S
SunAhong1993 已提交
101
              without_data_format_optimization,
M
mamingjie-China 已提交
102
              define_input_shape=False,
M
mamingjie-China 已提交
103
              params_merge=False):
J
jiangjiajun 已提交
104 105
    # check tensorflow installation and version
    try:
106 107
        import os
        os.environ["TF_CPP_MIN_LOG_LEVEL"] = '3'
J
jiangjiajun 已提交
108 109 110 111
        import tensorflow as tf
        version = tf.__version__
        if version >= '2.0.0' or version < '1.0.0':
            print(
J
jiangjiajun@baidu.com 已提交
112
                "[ERROR] 1.0.0<=tensorflow<2.0.0 is required, and v1.14.0 is recommended"
J
jiangjiajun 已提交
113 114 115
            )
            return
    except:
J
jiangjiajun@baidu.com 已提交
116 117 118
        print(
            "[ERROR] Tensorflow is not installed, use \"pip install tensorflow\"."
        )
J
jiangjiajun 已提交
119 120
        return

J
jiangjiajun 已提交
121
    from x2paddle.decoder.tf_decoder import TFDecoder
J
jiangjiajun 已提交
122
    from x2paddle.op_mapper.tf_op_mapper import TFOpMapper
123
    from x2paddle.op_mapper.tf_op_mapper_nhwc import TFOpMapperNHWC
J
jiangjiajun 已提交
124
    from x2paddle.optimizer.tf_optimizer import TFOptimizer
J
jiangjiajun 已提交
125 126

    print("Now translating model from tensorflow to paddle.")
127
    model = TFDecoder(model_path, define_input_shape=define_input_shape)
S
SunAhong1993 已提交
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
    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)
151 152


M
mamingjie-China 已提交
153
def caffe2paddle(proto, weight, save_dir, caffe_proto, params_merge=False):
J
jiangjiajun 已提交
154 155
    from x2paddle.decoder.caffe_decoder import CaffeDecoder
    from x2paddle.op_mapper.caffe_op_mapper import CaffeOpMapper
156
    from x2paddle.optimizer.caffe_optimizer import CaffeOptimizer
S
SunAhong1993 已提交
157
    import google.protobuf as gpb
S
SunAhong1993 已提交
158 159 160 161 162
    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):
        version_satisfy = True
J
jiangjiajun@baidu.com 已提交
163
    assert version_satisfy, '[ERROR] google.protobuf >= 3.6.0 is required'
J
jiangjiajun 已提交
164
    print("Now translating model from caffe to paddle.")
S
SunAhong1993 已提交
165
    model = CaffeDecoder(proto, weight, caffe_proto)
J
jiangjiajun 已提交
166
    mapper = CaffeOpMapper(model)
167 168 169
    optimizer = CaffeOptimizer(mapper)
    optimizer.merge_bn_scale()
    optimizer.merge_op_activation()
M
mamingjie-China 已提交
170
    mapper.save_inference_model(save_dir, params_merge)
171 172


M
mamingjie-China 已提交
173
def onnx2paddle(model_path, save_dir, params_merge=False):
C
update  
channingss 已提交
174 175 176 177
    # check onnx installation and version
    try:
        import onnx
        version = onnx.version.version
S
SunAhong1993 已提交
178 179
        if version < '1.6.0':
            print("[ERROR] onnx>=1.6.0 is required")
C
update  
channingss 已提交
180 181
            return
    except:
J
jiangjiajun@baidu.com 已提交
182
        print("[ERROR] onnx is not installed, use \"pip install onnx==1.6.0\".")
C
update  
channingss 已提交
183
        return
C
channingss 已提交
184
    print("Now translating model from onnx to paddle.")
C
update  
channingss 已提交
185

C
Channingss 已提交
186
    from x2paddle.op_mapper.onnx2paddle.onnx_op_mapper import ONNXOpMapper
C
update  
channingss 已提交
187
    from x2paddle.decoder.onnx_decoder import ONNXDecoder
R
root 已提交
188 189
    from x2paddle.optimizer.onnx_optimizer import ONNXOptimizer
    model = ONNXDecoder(model_path)
C
Channingss 已提交
190
    mapper = ONNXOpMapper(model)
191
    print("Model optimizing ...")
C
update  
channingss 已提交
192
    optimizer = ONNXOptimizer(mapper)
193
    print("Model optimized.")
C
channingss 已提交
194

195
    print("Paddle model and code generating ...")
M
mamingjie-China 已提交
196
    mapper.save_inference_model(save_dir, params_merge)
197
    print("Paddle model and code generated.")
C
Channingss 已提交
198 199


S
SunAhong1993 已提交
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
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)


J
Jason 已提交
239
def paddle2onnx(model_path, save_dir, opset_version=10):
S
SunAhong1993 已提交
240
    import paddle.fluid as fluid
C
Channingss 已提交
241
    try:
C
Channingss 已提交
242
        import paddle2onnx
C
Channingss 已提交
243 244 245
    except:
        print(
            "[ERROR] paddle2onnx not installed, use \"pip install paddle2onnx\"")
C
Channingss 已提交
246 247 248 249 250 251

    import paddle2onnx as p2o
    model = p2o.PaddleDecoder(model_path, '__model__', '__params__')
    mapper = p2o.PaddleOpMapper()
    mapper.convert(
        model.program,
S
SunAhong1993 已提交
252 253 254
        save_dir,
        scope=fluid.global_scope(),
        opset_version=opset_version)
C
update  
channingss 已提交
255 256


257
def main():
J
jiangjiajun 已提交
258
    if len(sys.argv) < 2:
C
update  
channingss 已提交
259
        print("Use \"x2paddle -h\" to print the help information")
J
jiangjiajun 已提交
260 261
        print("For more information, please follow our github repo below:)")
        print("\nGithub: https://github.com/PaddlePaddle/X2Paddle.git\n")
J
jiangjiajun 已提交
262 263
        return

264 265 266
    parser = arg_parser()
    args = parser.parse_args()

J
jiangjiajun 已提交
267
    if args.version:
J
jiangjiajun 已提交
268
        import x2paddle
M
mamingjie-China 已提交
269
        print("x2paddle-{} with python>=3.5, paddlepaddle>=1.6.0\n".format(
J
jiangjiajun 已提交
270
            x2paddle.__version__))
J
jiangjiajun 已提交
271 272
        return

J
Jason 已提交
273
    assert args.framework is not None, "--framework is not defined(support tensorflow/caffe/onnx)"
274
    assert args.save_dir is not None, "--save_dir is not defined"
M
mamingjie-China 已提交
275

M
mamingjie-China 已提交
276 277 278
    try:
        import paddle
        v0, v1, v2 = paddle.__version__.split('.')
279 280 281 282
        print("paddle.__version__ = {}".format(paddle.__version__))
        if v0 == '0' and v1 == '0' and v2 == '0':
            print("[WARNING] You are use develop version of paddlepaddle")
        elif int(v0) != 1 or int(v1) < 6:
J
jiangjiajun@baidu.com 已提交
283
            print("[ERROR] paddlepaddle>=1.6.0 is required")
M
mamingjie-China 已提交
284 285
            return
    except:
J
jiangjiajun@baidu.com 已提交
286 287 288
        print(
            "[ERROR] paddlepaddle not installed, use \"pip install paddlepaddle\""
        )
289 290

    if args.framework == "tensorflow":
J
jiangjiajun 已提交
291
        assert args.model is not None, "--model should be defined while translating tensorflow model"
S
SunAhong1993 已提交
292 293 294
        assert args.without_data_format_optimization in [
            "True", "False"
        ], "--the param without_data_format_optimization should be defined True or False"
295
        define_input_shape = False
M
mamingjie-China 已提交
296
        params_merge = False
S
SunAhong1993 已提交
297
        without_data_format_optimization = True if args.without_data_format_optimization == "True" else False
298 299
        if args.define_input_shape:
            define_input_shape = True
M
mamingjie-China 已提交
300 301
        if args.params_merge:
            params_merge = True
302
        tf2paddle(args.model, args.save_dir, without_data_format_optimization,
M
mamingjie-China 已提交
303
                  define_input_shape, params_merge)
304 305

    elif args.framework == "caffe":
S
SunAhong1993 已提交
306
        assert args.prototxt is not None and args.weight is not None, "--prototxt and --weight should be defined while translating caffe model"
M
mamingjie-China 已提交
307 308 309
        params_merge = False
        if args.params_merge:
            params_merge = True
S
SunAhong1993 已提交
310
        caffe2paddle(args.prototxt, args.weight, args.save_dir,
M
mamingjie-China 已提交
311
                     args.caffe_proto, params_merge)
C
update  
channingss 已提交
312 313
    elif args.framework == "onnx":
        assert args.model is not None, "--model should be defined while translating onnx model"
M
mamingjie-China 已提交
314
        params_merge = False
315

M
mamingjie-China 已提交
316 317 318
        if args.params_merge:
            params_merge = True
        onnx2paddle(args.model, args.save_dir, params_merge)
C
Channingss 已提交
319

S
SunAhong1993 已提交
320 321 322
    elif args.framework == "pytorch":
        assert args.model is not None, "--model should be defined while translating pytorch model"
        pytorch2paddle(args.model, args.save_dir, args.input_shapes)
323 324 325

    elif args.framework == "paddle2onnx":
        assert args.model is not None, "--model should be defined while translating paddle model to onnx"
S
SunAhong1993 已提交
326
        paddle2onnx(args.model, args.save_dir, opset_version=args.onnx_opset)
327

328
    else:
329 330
        raise Exception(
            "--framework only support tensorflow/caffe/onnx/paddle2onnx now")
331 332 333


if __name__ == "__main__":
C
Channingss 已提交
334
    main()