export_model.py 7.46 KB
Newer Older
dyning's avatar
dyning committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 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.

15
16
17
18
19
import os
import sys

__dir__ = os.path.dirname(os.path.abspath(__file__))
sys.path.append(__dir__)
20
sys.path.insert(0, os.path.abspath(os.path.join(__dir__, "..")))
21

dyning's avatar
dyning committed
22
23
24
25
26
27
28
import argparse

import paddle
from paddle.jit import to_static

from ppocr.modeling.architectures import build_model
from ppocr.postprocess import build_post_process
29
from ppocr.utils.save_load import load_model
30
from ppocr.utils.logging import get_logger
WenmuZhou's avatar
WenmuZhou committed
31
from tools.program import load_config, merge_config, ArgsParser
dyning's avatar
dyning committed
32
33


topduke's avatar
topduke committed
34
35
36
37
38
39
def export_single_model(model,
                        arch_config,
                        save_path,
                        logger,
                        input_shape=None,
                        quanter=None):
40
41
    if arch_config["algorithm"] == "SRN":
        max_text_length = arch_config["Head"]["max_text_length"]
tink2123's avatar
tink2123 committed
42
        other_shape = [
tink2123's avatar
tink2123 committed
43
            paddle.static.InputSpec(
44
                shape=[None, 1, 64, 256], dtype="float32"), [
tink2123's avatar
tink2123 committed
45
46
47
                    paddle.static.InputSpec(
                        shape=[None, 256, 1],
                        dtype="int64"), paddle.static.InputSpec(
48
                            shape=[None, max_text_length, 1], dtype="int64"),
tink2123's avatar
tink2123 committed
49
                    paddle.static.InputSpec(
50
51
52
53
                        shape=[None, 8, max_text_length, max_text_length],
                        dtype="int64"), paddle.static.InputSpec(
                            shape=[None, 8, max_text_length, max_text_length],
                            dtype="int64")
tink2123's avatar
tink2123 committed
54
55
56
                ]
        ]
        model = to_static(model, input_spec=other_shape)
Topdu's avatar
Topdu committed
57
58
59
60
    elif arch_config["algorithm"] == "SAR":
        other_shape = [
            paddle.static.InputSpec(
                shape=[None, 3, 48, 160], dtype="float32"),
andyjpaddle's avatar
andyjpaddle committed
61
62
            [paddle.static.InputSpec(
                shape=[None], dtype="float32")]
Topdu's avatar
Topdu committed
63
64
        ]
        model = to_static(model, input_spec=other_shape)
andyjpaddle's avatar
andyjpaddle committed
65
66
67
68
69
70
    elif arch_config["algorithm"] == "SVTR":
        if arch_config["Head"]["name"] == 'MultiHead':
            other_shape = [
                paddle.static.InputSpec(
                    shape=[None, 3, 48, -1], dtype="float32"),
            ]
Topdu's avatar
Topdu committed
71
72
73
        else:
            other_shape = [
                paddle.static.InputSpec(
topduke's avatar
topduke committed
74
                    shape=[None] + input_shape, dtype="float32"),
Topdu's avatar
Topdu committed
75
            ]
andyjpaddle's avatar
andyjpaddle committed
76
        model = to_static(model, input_spec=other_shape)
77
78
79
80
81
82
    elif arch_config["algorithm"] == "PREN":
        other_shape = [
            paddle.static.InputSpec(
                shape=[None, 3, 64, 512], dtype="float32"),
        ]
        model = to_static(model, input_spec=other_shape)
tink2123's avatar
tink2123 committed
83
    else:
84
        infer_shape = [3, -1, -1]
85
        if arch_config["model_type"] == "rec":
tink2123's avatar
tink2123 committed
86
            infer_shape = [3, 32, -1]  # for rec model, H must be 32
87
88
89
            if "Transform" in arch_config and arch_config[
                    "Transform"] is not None and arch_config["Transform"][
                        "name"] == "TPS":
90
                logger.info(
91
                    "When there is tps in the network, variable length input is not supported, and the input size needs to be the same as during training"
92
93
                )
                infer_shape[-1] = 100
Topdu's avatar
Topdu committed
94
95
            if arch_config["algorithm"] == "NRTR":
                infer_shape = [1, 32, 100]
MissPenguin's avatar
refine  
MissPenguin committed
96
97
        elif arch_config["model_type"] == "table":
            infer_shape = [3, 488, 488]
tink2123's avatar
tink2123 committed
98
99
100
101
        model = to_static(
            model,
            input_spec=[
                paddle.static.InputSpec(
102
                    shape=[None] + infer_shape, dtype="float32")
tink2123's avatar
tink2123 committed
103
104
            ])

littletomatodonkey's avatar
littletomatodonkey committed
105
106
107
108
    if quanter is None:
        paddle.jit.save(model, save_path)
    else:
        quanter.save_quantized_model(model, save_path)
109
110
111
112
113
114
115
    logger.info("inference model is saved to {}".format(save_path))
    return


def main():
    FLAGS = ArgsParser().parse_args()
    config = load_config(FLAGS.config)
WenmuZhou's avatar
WenmuZhou committed
116
    config = merge_config(config, FLAGS.opt)
117
118
119
120
121
122
123
124
125
126
127
128
129
    logger = get_logger()
    # build post process

    post_process_class = build_post_process(config["PostProcess"],
                                            config["Global"])

    # build model
    # for rec algorithm
    if hasattr(post_process_class, "character"):
        char_num = len(getattr(post_process_class, "character"))
        if config["Architecture"]["algorithm"] in ["Distillation",
                                                   ]:  # distillation model
            for key in config["Architecture"]["Models"]:
andyjpaddle's avatar
andyjpaddle committed
130
131
132
133
134
135
136
137
138
139
140
141
142
                if config["Architecture"]["Models"][key]["Head"][
                        "name"] == 'MultiHead':  # multi head
                    out_channels_list = {}
                    if config['PostProcess'][
                            'name'] == 'DistillationSARLabelDecode':
                        char_num = char_num - 2
                    out_channels_list['CTCLabelDecode'] = char_num
                    out_channels_list['SARLabelDecode'] = char_num + 2
                    config['Architecture']['Models'][key]['Head'][
                        'out_channels_list'] = out_channels_list
                else:
                    config["Architecture"]["Models"][key]["Head"][
                        "out_channels"] = char_num
143
                # just one final tensor needs to exported for inference
144
145
                config["Architecture"]["Models"][key][
                    "return_all_feats"] = False
andyjpaddle's avatar
andyjpaddle committed
146
147
148
149
150
151
152
153
154
155
        elif config['Architecture']['Head'][
                'name'] == 'MultiHead':  # multi head
            out_channels_list = {}
            char_num = len(getattr(post_process_class, 'character'))
            if config['PostProcess']['name'] == 'SARLabelDecode':
                char_num = char_num - 2
            out_channels_list['CTCLabelDecode'] = char_num
            out_channels_list['SARLabelDecode'] = char_num + 2
            config['Architecture']['Head'][
                'out_channels_list'] = out_channels_list
156
157
        else:  # base rec model
            config["Architecture"]["Head"]["out_channels"] = char_num
andyjpaddle's avatar
andyjpaddle committed
158

159
    model = build_model(config["Architecture"])
160
    load_model(config, model)
161
162
163
164
165
166
    model.eval()

    save_path = config["Global"]["save_inference_dir"]

    arch_config = config["Architecture"]

topduke's avatar
topduke committed
167
168
169
170
171
172
173
    if arch_config["algorithm"] == "SVTR" and arch_config["Head"][
            "name"] != 'MultiHead':
        input_shape = config["Eval"]["dataset"]["transforms"][-2][
            'SVTRRecResizeImg']['image_shape']
    else:
        input_shape = None

174
175
176
177
178
179
180
181
    if arch_config["algorithm"] in ["Distillation", ]:  # distillation model
        archs = list(arch_config["Models"].values())
        for idx, name in enumerate(model.model_name_list):
            sub_model_save_path = os.path.join(save_path, name, "inference")
            export_single_model(model.model_list[idx], archs[idx],
                                sub_model_save_path, logger)
    else:
        save_path = os.path.join(save_path, "inference")
topduke's avatar
topduke committed
182
183
        export_single_model(
            model, arch_config, save_path, logger, input_shape=input_shape)
dyning's avatar
dyning committed
184
185
186
187


if __name__ == "__main__":
    main()