serving.py 8.9 KB
Newer Older
走神的阿圆's avatar
走神的阿圆 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
# coding:utf-8
# Copyright (c) 2019  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.

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import argparse
import os
走神的阿圆's avatar
走神的阿圆 已提交
22 23
import platform
import socket
走神的阿圆's avatar
走神的阿圆 已提交
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
import json
import paddlehub as hub
from paddlehub.commands.base_command import BaseCommand, ENTRY


class ServingCommand(BaseCommand):
    name = "serving"
    module_list = []

    def __init__(self, name):
        super(ServingCommand, self).__init__(name)
        self.show_in_help = True
        self.description = "Start a service for online predicting by using PaddleHub."
        self.parser = argparse.ArgumentParser(
            description=self.__class__.__doc__,
            prog='%s %s [COMMAND]' % (ENTRY, name),
            usage='%(prog)s',
            add_help=True)
        self.parser.add_argument("command")
走神的阿圆's avatar
走神的阿圆 已提交
43
        self.parser.add_argument("sub_command")
走神的阿圆's avatar
走神的阿圆 已提交
44
        self.parser.add_argument("bert_service", nargs="?")
走神的阿圆's avatar
走神的阿圆 已提交
45 46 47 48
        self.sub_parse = self.parser.add_mutually_exclusive_group(
            required=False)
        self.parser.add_argument(
            "--use_gpu", action="store_true", default=False)
走神的阿圆's avatar
走神的阿圆 已提交
49 50
        self.parser.add_argument(
            "--use_multiprocess", action="store_true", default=False)
走神的阿圆's avatar
走神的阿圆 已提交
51
        self.parser.add_argument("--modules", "-m", nargs="+")
走神的阿圆's avatar
走神的阿圆 已提交
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
        self.parser.add_argument("--config", "-c", nargs="?")
        self.parser.add_argument("--port", "-p", nargs="?", default=8866)
        self.parser.add_argument("--gpu", "-i", nargs="?", default=0)

    @staticmethod
    def start_bert_serving(args):
        if platform.system() != "Linux":
            print("Error. Bert-Service only support linux.")
            return False

        if ServingCommand.is_port_occupied("127.0.0.1", args.port) is True:
            print("Port %s is occupied, please change it." % args.port)
            return False

        from paddle_gpu_serving.run import BertServer
        bs = BertServer(with_gpu=args.use_gpu)
        bs.with_model(model_name=args.modules[0])
        bs.run(gpu_index=args.gpu, port=args.port)
走神的阿圆's avatar
走神的阿圆 已提交
70 71 72 73 74 75 76 77 78 79

    @staticmethod
    def is_port_occupied(ip, port):
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            s.connect((ip, int(port)))
            s.shutdown(2)
            return True
        except:
            return False
走神的阿圆's avatar
走神的阿圆 已提交
80 81 82 83

    @staticmethod
    def preinstall_modules(modules):
        configs = []
走神的阿圆's avatar
走神的阿圆 已提交
84
        module_exist = {}
走神的阿圆's avatar
走神的阿圆 已提交
85 86 87 88 89 90
        if modules is not None:
            for module in modules:
                module_name = module if "==" not in module else \
                module.split("==")[0]
                module_version = None if "==" not in module else \
                module.split("==")[1]
走神的阿圆's avatar
走神的阿圆 已提交
91 92 93 94 95
                if module_exist.get(module_name, "") != "":
                    print(module_name, "==", module_exist.get(module_name),
                          " will be ignored cause new version is specified.")
                    configs.pop()
                module_exist.update({module_name: module_version})
走神的阿圆's avatar
走神的阿圆 已提交
96 97
                try:
                    m = hub.Module(name=module_name, version=module_version)
走神的阿圆's avatar
走神的阿圆 已提交
98 99 100 101
                    method_name = m.desc.attr.map.data['default_signature'].s
                    if method_name == "":
                        raise RuntimeError("{} cannot be use for "
                                           "predicting".format(module_name))
走神的阿圆's avatar
走神的阿圆 已提交
102 103 104 105 106 107
                    configs.append({
                        "module": module_name,
                        "version": m.version,
                        "category": str(m.type).split("/")[0].upper()
                    })
                except Exception as err:
走神的阿圆's avatar
走神的阿圆 已提交
108 109
                    print(err, ", start Hub-Serving unsuccessfully.")
                    exit(1)
走神的阿圆's avatar
走神的阿圆 已提交
110 111 112 113 114 115 116 117 118
            return configs

    @staticmethod
    def start_serving(args):
        config_file = args.config
        if config_file is not None:
            if os.path.exists(config_file):
                with open(config_file, "r") as fp:
                    configs = json.load(fp)
走神的阿圆's avatar
走神的阿圆 已提交
119 120 121 122 123 124 125 126 127 128 129 130
                    use_multiprocess = configs.get("use_multiprocess", False)
                    if use_multiprocess is True:
                        if platform.system() == "Windows":
                            print(
                                "Warning: Windows cannot use multiprocess working "
                                "mode, Hub-Serving will switch to single process mode"
                            )
                            from paddlehub.serving import app_single as app
                        else:
                            from paddlehub.serving import app
                    else:
                        from paddlehub.serving import app_single as app
走神的阿圆's avatar
走神的阿圆 已提交
131
                    use_gpu = configs.get("use_gpu", False)
走神的阿圆's avatar
走神的阿圆 已提交
132 133 134
                    port = configs.get("port", 8866)
                    if ServingCommand.is_port_occupied("127.0.0.1",
                                                       port) is True:
走神的阿圆's avatar
走神的阿圆 已提交
135
                        print("Port %s is occupied, please change it." % port)
走神的阿圆's avatar
走神的阿圆 已提交
136
                        return False
走神的阿圆's avatar
走神的阿圆 已提交
137 138 139 140 141 142 143 144 145 146 147 148
                    configs = configs.get("modules_info")
                    module = [
                        str(i["module"]) + "==" + str(i["version"])
                        for i in configs
                    ]
                    module_info = ServingCommand.preinstall_modules(module)
                    for index in range(len(module_info)):
                        configs[index].update(module_info[index])
                    app.run(use_gpu, configs=configs, port=port)
            else:
                print("config_file ", config_file, "not exists.")
        else:
走神的阿圆's avatar
走神的阿圆 已提交
149 150 151 152 153 154 155 156 157 158
            if args.use_multiprocess is True:
                if platform.system() == "Windows":
                    print(
                        "Warning: Windows cannot use multiprocess working "
                        "mode, Hub-Serving will switch to single process mode")
                    from paddlehub.serving import app_single as app
                else:
                    from paddlehub.serving import app
            else:
                from paddlehub.serving import app_single as app
走神的阿圆's avatar
走神的阿圆 已提交
159 160 161
            module = args.modules
            if module is not None:
                use_gpu = args.use_gpu
162
                port = args.port
走神的阿圆's avatar
走神的阿圆 已提交
163 164 165
                if ServingCommand.is_port_occupied("127.0.0.1", port) is True:
                    print("Port %s is occupied, please change it." % (port))
                    return False
走神的阿圆's avatar
走神的阿圆 已提交
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
                module_info = ServingCommand.preinstall_modules(module)
                [
                    item.update({
                        "batch_size": 1,
                        "queue_size": 20
                    }) for item in module_info
                ]
                app.run(use_gpu, configs=module_info, port=port)
            else:
                print("Lack of necessary parameters!")

    @staticmethod
    def show_help():
        str = "serving <option>\n"
        str += "\tManage PaddleHub-Serving.\n"
走神的阿圆's avatar
走神的阿圆 已提交
181 182
        str += "sub command:\n"
        str += "start\n"
走神的阿圆's avatar
走神的阿圆 已提交
183
        str += "\tStart PaddleHub-Serving if specifies this parameter.\n"
走神的阿圆's avatar
走神的阿圆 已提交
184 185
        str += "start bert_service\n"
        str += "\tStart Bert Service if specifies this parameter.\n"
走神的阿圆's avatar
走神的阿圆 已提交
186
        str += "option:\n"
走神的阿圆's avatar
走神的阿圆 已提交
187 188 189 190 191 192
        str += "--modules/-m [module1==version, module2==version...]\n"
        str += "\tPre-install modules via this parameter list.\n"
        str += "--port/-p XXXX\n"
        str += "\tUse port XXXX for serving.\n"
        str += "--use_gpu\n"
        str += "\tUse gpu for predicting if specifies this parameter.\n"
走神的阿圆's avatar
走神的阿圆 已提交
193 194
        str += "--gpu\n"
        str += "\tSpecify the graphics card to use, only work for Bert as Service\n"
走神的阿圆's avatar
走神的阿圆 已提交
195 196 197 198 199 200
        str += "--config/-c file_path\n"
        str += "\tUse configs in file to starting paddlehub serving."
        str += "Other parameter will be ignored if specifies this parameter.\n"
        print(str)

    def execute(self, argv):
走神的阿圆's avatar
走神的阿圆 已提交
201 202 203 204 205 206
        try:
            args = self.parser.parse_args()
        except:
            ServingCommand.show_help()
            return False
        if args.sub_command == "start":
走神的阿圆's avatar
走神的阿圆 已提交
207
            if args.bert_service == "bert_service":
走神的阿圆's avatar
走神的阿圆 已提交
208
                ServingCommand.start_bert_serving(args)
209
            elif args.bert_service is None:
走神的阿圆's avatar
走神的阿圆 已提交
210
                ServingCommand.start_serving(args)
211 212
            else:
                ServingCommand.show_help()
走神的阿圆's avatar
走神的阿圆 已提交
213 214 215 216 217
        else:
            ServingCommand.show_help()


command = ServingCommand.instance()