export_model.py 11.9 KB
Newer Older
D
dyning 已提交
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

D
dyning 已提交
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
W
WenmuZhou 已提交
31
from tools.program import load_config, merge_config, ArgsParser
D
dyning 已提交
32 33


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"]
T
tink2123 已提交
42
        other_shape = [
T
tink2123 已提交
43
            paddle.static.InputSpec(
44
                shape=[None, 1, 64, 256], dtype="float32"), [
T
tink2123 已提交
45 46 47
                    paddle.static.InputSpec(
                        shape=[None, 256, 1],
                        dtype="int64"), paddle.static.InputSpec(
W
WenmuZhou 已提交
48
                            shape=[None, max_text_length, 1], dtype="int64"),
T
tink2123 已提交
49
                    paddle.static.InputSpec(
W
WenmuZhou 已提交
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")
T
tink2123 已提交
54 55 56
                ]
        ]
        model = to_static(model, input_spec=other_shape)
T
Topdu 已提交
57 58 59 60
    elif arch_config["algorithm"] == "SAR":
        other_shape = [
            paddle.static.InputSpec(
                shape=[None, 3, 48, 160], dtype="float32"),
A
andyjpaddle 已提交
61 62
            [paddle.static.InputSpec(
                shape=[None], dtype="float32")]
T
Topdu 已提交
63 64
        ]
        model = to_static(model, input_spec=other_shape)
T
topduke 已提交
65
    elif arch_config["algorithm"] in ["SVTR_LCNet", "SVTR_HGNet"]:
66 67 68 69 70
        other_shape = [
            paddle.static.InputSpec(
                shape=[None, 3, 48, -1], dtype="float32"),
        ]
        model = to_static(model, input_spec=other_shape)
A
andyjpaddle 已提交
71
    elif arch_config["algorithm"] == "SVTR":
72 73 74 75
        other_shape = [
            paddle.static.InputSpec(
                shape=[None] + input_shape, dtype="float32"),
        ]
A
andyjpaddle 已提交
76
        model = to_static(model, input_spec=other_shape)
77 78 79
    elif arch_config["algorithm"] == "PREN":
        other_shape = [
            paddle.static.InputSpec(
80
                shape=[None, 3, 64, 256], dtype="float32"),
81 82
        ]
        model = to_static(model, input_spec=other_shape)
X
xiaoting 已提交
83
    elif arch_config["model_type"] == "sr":
xuyang2233's avatar
xuyang2233 已提交
84 85
        other_shape = [
            paddle.static.InputSpec(
X
xiaoting 已提交
86
                shape=[None, 3, 16, 64], dtype="float32")
xuyang2233's avatar
xuyang2233 已提交
87 88
        ]
        model = to_static(model, input_spec=other_shape)
89 90 91 92 93 94 95 96 97 98 99 100 101
    elif arch_config["algorithm"] == "ViTSTR":
        other_shape = [
            paddle.static.InputSpec(
                shape=[None, 1, 224, 224], dtype="float32"),
        ]
        model = to_static(model, input_spec=other_shape)
    elif arch_config["algorithm"] == "ABINet":
        other_shape = [
            paddle.static.InputSpec(
                shape=[None, 3, 32, 128], dtype="float32"),
        ]
        # print([None, 3, 32, 128])
        model = to_static(model, input_spec=other_shape)
102
    elif arch_config["algorithm"] in ["NRTR", "SPIN", 'RFL']:
103 104 105 106
        other_shape = [
            paddle.static.InputSpec(
                shape=[None, 1, 32, 100], dtype="float32"),
        ]
Z
zhiminzhang0830 已提交
107 108 109 110 111 112
        model = to_static(model, input_spec=other_shape)
    elif arch_config["algorithm"] == 'SATRN':
        other_shape = [
            paddle.static.InputSpec(
                shape=[None, 3, 32, 100], dtype="float32"),
        ]
113
        model = to_static(model, input_spec=other_shape)
A
andyjpaddle 已提交
114 115 116 117 118 119
    elif arch_config["algorithm"] == "VisionLAN":
        other_shape = [
            paddle.static.InputSpec(
                shape=[None, 3, 64, 256], dtype="float32"),
        ]
        model = to_static(model, input_spec=other_shape)
xuyang2233's avatar
xuyang2233 已提交
120 121 122 123
    elif arch_config["algorithm"] == "RobustScanner":
        max_text_length = arch_config["Head"]["max_text_length"]
        other_shape = [
            paddle.static.InputSpec(
文幕地方's avatar
文幕地方 已提交
124 125 126 127 128 129
                shape=[None, 3, 48, 160], dtype="float32"), [
                    paddle.static.InputSpec(
                        shape=[None, ], dtype="float32"),
                    paddle.static.InputSpec(
                        shape=[None, max_text_length], dtype="int64")
                ]
xuyang2233's avatar
xuyang2233 已提交
130 131
        ]
        model = to_static(model, input_spec=other_shape)
D
dorren 已提交
132 133 134 135 136 137 138 139 140 141 142
    elif arch_config["algorithm"] == "CAN":
        other_shape = [[
            paddle.static.InputSpec(
                shape=[None, 1, None, None],
                dtype="float32"), paddle.static.InputSpec(
                    shape=[None, 1, None, None], dtype="float32"),
            paddle.static.InputSpec(
                shape=[None, arch_config['Head']['max_text_length']],
                dtype="int64")
        ]]
        model = to_static(model, input_spec=other_shape)
143
    elif arch_config["algorithm"] in ["LayoutLM", "LayoutLMv2", "LayoutXLM"]:
文幕地方's avatar
文幕地方 已提交
144
        input_spec = [
145 146 147 148 149 150 151 152 153 154 155
            paddle.static.InputSpec(
                shape=[None, 512], dtype="int64"),  # input_ids
            paddle.static.InputSpec(
                shape=[None, 512, 4], dtype="int64"),  # bbox
            paddle.static.InputSpec(
                shape=[None, 512], dtype="int64"),  # attention_mask
            paddle.static.InputSpec(
                shape=[None, 512], dtype="int64"),  # token_type_ids
            paddle.static.InputSpec(
                shape=[None, 3, 224, 224], dtype="int64"),  # image
        ]
文幕地方's avatar
文幕地方 已提交
156 157 158 159 160 161 162
        if 'Re' in arch_config['Backbone']['name']:
            input_spec.extend([
                paddle.static.InputSpec(
                    shape=[None, 512, 3], dtype="int64"),  # entities
                paddle.static.InputSpec(
                    shape=[None, None, 2], dtype="int64"),  # relations
            ])
littletomatodonkey's avatar
littletomatodonkey 已提交
163
        if model.backbone.use_visual_backbone is False:
164 165
            input_spec.pop(4)
        model = to_static(model, input_spec=[input_spec])
T
tink2123 已提交
166
    else:
167
        infer_shape = [3, -1, -1]
168
        if arch_config["model_type"] == "rec":
T
tink2123 已提交
169
            infer_shape = [3, 32, -1]  # for rec model, H must be 32
170 171 172
            if "Transform" in arch_config and arch_config[
                    "Transform"] is not None and arch_config["Transform"][
                        "name"] == "TPS":
173
                logger.info(
174
                    "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"
175 176
                )
                infer_shape[-1] = 100
M
refine  
MissPenguin 已提交
177 178
        elif arch_config["model_type"] == "table":
            infer_shape = [3, 488, 488]
文幕地方's avatar
文幕地方 已提交
179 180
            if arch_config["algorithm"] == "TableMaster":
                infer_shape = [3, 480, 480]
文幕地方's avatar
文幕地方 已提交
181 182
            if arch_config["algorithm"] == "SLANet":
                infer_shape = [3, -1, -1]
T
tink2123 已提交
183 184 185 186
        model = to_static(
            model,
            input_spec=[
                paddle.static.InputSpec(
187
                    shape=[None] + infer_shape, dtype="float32")
T
tink2123 已提交
188 189
            ])

T
topduke 已提交
190 191 192 193 194 195
    if arch_config["Backbone"]["name"] == "LCNetv3":
        # for rep lcnetv3
        for layer in model.sublayers():
            if hasattr(layer, "rep") and not getattr(layer, "is_repped"):
                layer.rep()

littletomatodonkey's avatar
littletomatodonkey 已提交
196 197 198 199
    if quanter is None:
        paddle.jit.save(model, save_path)
    else:
        quanter.save_quantized_model(model, save_path)
200 201 202 203 204 205 206
    logger.info("inference model is saved to {}".format(save_path))
    return


def main():
    FLAGS = ArgsParser().parse_args()
    config = load_config(FLAGS.config)
文幕地方's avatar
文幕地方 已提交
207
    config = merge_config(config, FLAGS.opt)
208 209 210 211 212 213 214 215 216 217 218 219 220
    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"]:
A
andyjpaddle 已提交
221 222 223 224 225 226
                if config["Architecture"]["Models"][key]["Head"][
                        "name"] == 'MultiHead':  # multi head
                    out_channels_list = {}
                    if config['PostProcess'][
                            'name'] == 'DistillationSARLabelDecode':
                        char_num = char_num - 2
T
topduke 已提交
227 228 229
                    if config['PostProcess'][
                            'name'] == 'DistillationNRTRLabelDecode':
                        char_num = char_num - 3
A
andyjpaddle 已提交
230 231
                    out_channels_list['CTCLabelDecode'] = char_num
                    out_channels_list['SARLabelDecode'] = char_num + 2
T
topduke 已提交
232
                    out_channels_list['NRTRLabelDecode'] = char_num + 3
A
andyjpaddle 已提交
233 234 235 236 237
                    config['Architecture']['Models'][key]['Head'][
                        'out_channels_list'] = out_channels_list
                else:
                    config["Architecture"]["Models"][key]["Head"][
                        "out_channels"] = char_num
238
                # just one final tensor needs to exported for inference
239 240
                config["Architecture"]["Models"][key][
                    "return_all_feats"] = False
A
andyjpaddle 已提交
241 242 243 244 245 246
        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
T
topduke 已提交
247 248
            if config['PostProcess']['name'] == 'NRTRLabelDecode':
                char_num = char_num - 3
A
andyjpaddle 已提交
249 250
            out_channels_list['CTCLabelDecode'] = char_num
            out_channels_list['SARLabelDecode'] = char_num + 2
T
topduke 已提交
251
            out_channels_list['NRTRLabelDecode'] = char_num + 3
A
andyjpaddle 已提交
252 253
            config['Architecture']['Head'][
                'out_channels_list'] = out_channels_list
254 255
        else:  # base rec model
            config["Architecture"]["Head"]["out_channels"] = char_num
A
andyjpaddle 已提交
256

X
xiaoting 已提交
257 258 259
    # for sr algorithm
    if config["Architecture"]["model_type"] == "sr":
        config['Architecture']["Transform"]['infer_mode'] = True
260
    model = build_model(config["Architecture"])
261
    load_model(config, model, model_type=config['Architecture']["model_type"])
262 263 264 265 266 267
    model.eval()

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

    arch_config = config["Architecture"]

268 269 270 271 272 273 274
    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

275 276 277 278 279 280 281 282
    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")
283 284
        export_single_model(
            model, arch_config, save_path, logger, input_shape=input_shape)
D
dyning 已提交
285 286 287


if __name__ == "__main__":
A
andyjpaddle 已提交
288
    main()