From 3ce9dd26c6f0b1b77263669ff3552b77c230ef15 Mon Sep 17 00:00:00 2001 From: xiaoting <31891223+tink2123@users.noreply.github.com> Date: Tue, 24 May 2022 21:57:14 +0800 Subject: [PATCH] update serving tipc (#5529) * update serving tipc * rm python version * rm python version * Update serving_python.md * mv unset to prepare.sh --- .../Step6/deploy/serving_python/config.yml | 2 +- .../deploy/serving_python/web_service.py | 63 +++++++++++++- .../serving_infer_python.txt | 3 +- .../Step6/test_tipc/prepare.sh | 2 + .../test_tipc/test_serving_infer_python.sh | 56 ++++++++----- tutorials/tipc/serving_cpp/serving_cpp.md | 82 +++++++++++++------ .../template/code/serving_client.py | 13 +-- .../tipc/serving_python/serving_python.md | 14 ++-- 8 files changed, 170 insertions(+), 65 deletions(-) diff --git a/tutorials/mobilenetv3_prod/Step6/deploy/serving_python/config.yml b/tutorials/mobilenetv3_prod/Step6/deploy/serving_python/config.yml index 88957745..469dca5b 100755 --- a/tutorials/mobilenetv3_prod/Step6/deploy/serving_python/config.yml +++ b/tutorials/mobilenetv3_prod/Step6/deploy/serving_python/config.yml @@ -22,7 +22,7 @@ op: model_config: "./serving_server" #计算硬件类型: 空缺时由devices决定(CPU/GPU),0=cpu, 1=gpu, 2=tensorRT, 3=arm cpu, 4=kunlun xpu - device_type: 1 + device_type: #计算硬件ID,当devices为""或不写时为CPU预测;当devices为"0", "0,1,2"时为GPU预测,表示使用的GPU卡 devices: "0" # "0,1" diff --git a/tutorials/mobilenetv3_prod/Step6/deploy/serving_python/web_service.py b/tutorials/mobilenetv3_prod/Step6/deploy/serving_python/web_service.py index 94beb893..4d8102d6 100755 --- a/tutorials/mobilenetv3_prod/Step6/deploy/serving_python/web_service.py +++ b/tutorials/mobilenetv3_prod/Step6/deploy/serving_python/web_service.py @@ -21,6 +21,62 @@ from PIL import Image import io from preprocess_ops import ResizeImage, CenterCropImage, NormalizeImage, ToCHW, Compose +from argparse import ArgumentParser, RawDescriptionHelpFormatter +import yaml + + +class ArgsParser(ArgumentParser): + def __init__(self): + super(ArgsParser, self).__init__( + formatter_class=RawDescriptionHelpFormatter) + self.add_argument("-c", "--config", help="configuration file to use") + self.add_argument( + "-o", "--opt", nargs='+', help="set configuration options") + + def parse_args(self, argv=None): + args = super(ArgsParser, self).parse_args(argv) + assert args.config is not None, \ + "Please specify --config=configure_file_path." + args.conf_dict = self._parse_opt(args.opt, args.config) + print("args config:", args.conf_dict) + return args + + def _parse_helper(self, v): + if v.isnumeric(): + if "." in v: + v = float(v) + else: + v = int(v) + elif v == "True" or v == "False": + v = (v == "True") + return v + + def _parse_opt(self, opts, conf_path): + f = open(conf_path) + config = yaml.load(f, Loader=yaml.Loader) + if not opts: + return config + for s in opts: + s = s.strip() + k, v = s.split('=') + v = self._parse_helper(v) + if "devices" in k: + v = str(v) + print(k, v, type(v)) + cur = config + parent = cur + for kk in k.split("."): + if kk not in cur: + cur[kk] = {} + parent = cur + cur = cur[kk] + else: + parent = cur + cur = cur[kk] + parent[k.split(".")[-1]] = v + return config + + class MobileNetV3Op(Op): def init_op(self): self.seq = Compose([ @@ -53,16 +109,17 @@ class MobileNetV3Op(Op): result["prob"] = str(result["prob"]) return result, None, "" + class MobileNetV3Service(WebService): def get_pipeline_response(self, read_op): - mobilenetv3_op = MobileNetV3Op( - name="imagenet", input_ops=[read_op]) + mobilenetv3_op = MobileNetV3Op(name="imagenet", input_ops=[read_op]) return mobilenetv3_op # define the service class uci_service = MobileNetV3Service(name="imagenet") # load config and prepare the service -uci_service.prepare_pipeline_config("config.yml") +FLAGS = ArgsParser().parse_args() +uci_service.prepare_pipeline_config(yml_dict=FLAGS.conf_dict) # start the service uci_service.run_service() diff --git a/tutorials/mobilenetv3_prod/Step6/test_tipc/configs/mobilenet_v3_small/serving_infer_python.txt b/tutorials/mobilenetv3_prod/Step6/test_tipc/configs/mobilenet_v3_small/serving_infer_python.txt index e59a41e3..c59180eb 100644 --- a/tutorials/mobilenetv3_prod/Step6/test_tipc/configs/mobilenet_v3_small/serving_infer_python.txt +++ b/tutorials/mobilenetv3_prod/Step6/test_tipc/configs/mobilenet_v3_small/serving_infer_python.txt @@ -8,6 +8,7 @@ trans_model:-m paddle_serving_client.convert --serving_server:./deploy/serving_python/serving_server/ --serving_client:./deploy/serving_python/serving_client/ serving_dir:./deploy/serving_python -web_service:web_service.py +web_service:web_service.py --config=config.yml +--opt op.imagenet.local_service_conf.devices:"0"|null pipline:pipeline_http_client.py --image_dir:../../lite_data/test/ \ No newline at end of file diff --git a/tutorials/mobilenetv3_prod/Step6/test_tipc/prepare.sh b/tutorials/mobilenetv3_prod/Step6/test_tipc/prepare.sh index bc175830..e013ec5d 100644 --- a/tutorials/mobilenetv3_prod/Step6/test_tipc/prepare.sh +++ b/tutorials/mobilenetv3_prod/Step6/test_tipc/prepare.sh @@ -54,6 +54,8 @@ elif [ ${MODE} = "serving_infer" ];then wget -nc -P ./inference https://paddle-model-ecology.bj.bcebos.com/model/mobilenetv3_reprod/mobilenet_v3_small_infer.tar --no-check-certificate cd ./inference && tar xf mobilenet_v3_small_infer.tar && cd ../ fi + unset https_proxy + unset http_proxy elif [ ${MODE} = "cpp_infer" ];then PADDLEInfer=$3 # wget model diff --git a/tutorials/mobilenetv3_prod/Step6/test_tipc/test_serving_infer_python.sh b/tutorials/mobilenetv3_prod/Step6/test_tipc/test_serving_infer_python.sh index 8e79e257..344352f1 100644 --- a/tutorials/mobilenetv3_prod/Step6/test_tipc/test_serving_infer_python.sh +++ b/tutorials/mobilenetv3_prod/Step6/test_tipc/test_serving_infer_python.sh @@ -25,9 +25,11 @@ serving_client_key=$(func_parser_key "${lines[8]}") serving_client_value=$(func_parser_value "${lines[8]}") serving_dir_value=$(func_parser_value "${lines[9]}") web_service_py=$(func_parser_value "${lines[10]}") -pipeline_py=$(func_parser_value "${lines[11]}") -image_dir_key=$(func_parser_key "${lines[12]}") -image_dir_value=$(func_parser_value "${lines[12]}") +web_use_gpu_key=$(func_parser_key "${lines[11]}") +web_use_gpu_list=$(func_parser_value "${lines[11]}") +pipeline_py=$(func_parser_value "${lines[12]}") +image_dir_key=$(func_parser_key "${lines[13]}") +image_dir_value=$(func_parser_value "${lines[13]}") LOG_PATH="./log/${model_name}/${MODE}" @@ -53,24 +55,38 @@ function func_serving(){ cd ${serving_dir_value} status_check $last_status "${trans_model_cmd}" "${status_log}" "${model_name}" echo $PWD - unset https_proxy - unset http_proxy - _save_log_path="../../log/${model_name}/${MODE}/serving_infer_python_gpu_batchsize_1.log" - web_service_cmd="${python} ${web_service_py} &" - eval $web_service_cmd - last_status=${PIPESTATUS[0]} - status_check $last_status "${web_service_cmd}" "${status_log}" "${model_name}" - sleep 5s - _save_log_path="../../log/${model_name}/${MODE}/server_infer_gpu_batchsize_1.log" - set_image_dir=$(func_set_params "${image_dir_key}" "${image_dir_value}") - pipeline_cmd="${python} ${pipeline_py} ${set_image_dir} > ${_save_log_path} 2>&1 " - eval $pipeline_cmd - last_status=${PIPESTATUS[0]} - status_check $last_status "${pipeline_cmd}" "${status_log}" "${model_name}" - eval "cat ${_save_log_path}" - cd ../../ - ps ux | grep -E 'web_service|pipeline' | awk '{print $2}' | xargs kill -s 9 + for use_gpu in ${web_use_gpu_list[*]}; do + if [ ${use_gpu} = "null" ]; then + _save_log_path="../../log/${model_name}/${MODE}/serving_infer_python_cpu_batchsize_1.log" + web_service_cmd="${python} ${web_service_py} ${web_use_gpu_key}="" &" + eval $web_service_cmd + last_status=${PIPESTATUS[0]} + status_check $last_status "${web_service_cmd}" "${status_log}" "${model_name}" + sleep 5s + set_image_dir=$(func_set_params "${image_dir_key}" "${image_dir_value}") + pipeline_cmd="${python} ${pipeline_py} ${set_image_dir} > ${_save_log_path} 2>&1 " + eval $pipeline_cmd + last_status=${PIPESTATUS[0]} + status_check $last_status "${pipeline_cmd}" "${status_log}" "${model_name}" + eval "cat ${_save_log_path}" + ps ux | grep -E 'web_service|pipeline' | awk '{print $2}' | xargs kill -s 9 + else + _save_log_path="../../log/${model_name}/${MODE}/serving_infer_python_gpu_batchsize_1.log" + web_service_cmd="${python} ${web_service_py} ${web_use_gpu_key}=${use_gpu} &" + eval $web_service_cmd + last_status=${PIPESTATUS[0]} + status_check $last_status "${web_service_cmd}" "${status_log}" "${model_name}" + sleep 5s + set_image_dir=$(func_set_params "${image_dir_key}" "${image_dir_value}") + pipeline_cmd="${python} ${pipeline_py} ${set_image_dir} > ${_save_log_path} 2>&1 " + eval $pipeline_cmd + last_status=${PIPESTATUS[0]} + status_check $last_status "${pipeline_cmd}" "${status_log}" "${model_name}" + eval "cat ${_save_log_path}" + ps ux | grep -E 'web_service|pipeline' | awk '{print $2}' | xargs kill -s 9 + fi + done } diff --git a/tutorials/tipc/serving_cpp/serving_cpp.md b/tutorials/tipc/serving_cpp/serving_cpp.md index 3d4901c1..f560a28c 100644 --- a/tutorials/tipc/serving_cpp/serving_cpp.md +++ b/tutorials/tipc/serving_cpp/serving_cpp.md @@ -71,15 +71,13 @@ Paddle Serving服务化部署主要包括以下步骤: nvidia-docker exec -it test bash ``` -(2)安装Paddle Serving四个安装包,分别是:paddle-serving-server(CPU/GPU版本二选一), paddle-serving-client, paddle-serving-app和paddlepaddle(CPU/GPU版本二选一)。 +(2)安装Paddle Serving三个安装包,分别是:paddle-serving-server(CPU/GPU版本二选一), paddle-serving-client, paddle-serving-app和paddlepaddle(CPU/GPU版本二选一)。 ```bash - pip3 install paddle-serving-client==0.8.3 - #pip3 install paddle-serving-server==0.8.3 # CPU - pip3 install paddle-serving-server-gpu==0.8.3.post102 # GPU with CUDA10.2 + TensorRT6 - pip3 install paddle-serving-app==0.8.3 - #pip3 install paddlepaddle==2.2.2 # CPU - pip3 install paddlepaddle-gpu==2.2.2 + pip install paddle-serving-client + pip install paddle-serving-app + #pip install paddlepaddle # CPU + pip install paddlepaddle-gpu ``` 您可能需要使用国内镜像源(例如百度源, 在pip命令中添加`-i https://mirror.baidu.com/pypi/simple`)来加速下载。 Paddle Serving Server更多不同运行环境的whl包下载地址,请参考:[下载页面](https://github.com/PaddlePaddle/Serving/blob/v0.8.3/doc/Latest_Packages_CN.md) @@ -105,7 +103,7 @@ cd models/tutorials/tipc/serving_cpp 为了便于模型服务化部署,需要将静态图模型(模型结构文件:\*.pdmodel和模型参数文件:\*.pdiparams)使用paddle_serving_client.convert按如下命令转换为服务化部署模型: ```bash -python3 -m paddle_serving_client.convert --dirname {静态图模型路径} --model_filename {模型结构文件} --params_filename {模型参数文件} --serving_server {转换后的服务器端模型和配置文件存储路径} --serving_client {转换后的客户端模型和配置文件存储路径} +python -m paddle_serving_client.convert --dirname {静态图模型路径} --model_filename {模型结构文件} --params_filename {模型参数文件} --serving_server {转换后的服务器端模型和配置文件存储路径} --serving_client {转换后的客户端模型和配置文件存储路径} ``` 上面命令中 "转换后的服务器端模型和配置文件" 将用于后续服务化部署。其中`paddle_serving_client.convert`命令是`paddle_serving_client` whl包内置的转换函数,无需修改。 @@ -114,7 +112,7 @@ python3 -m paddle_serving_client.convert --dirname {静态图模型路径} --mod 针对MobileNetV3网络,将inference模型转换为服务化部署模型的示例命令如下,转换完后在本地生成**serving_server**和**serving_client**两个文件夹。本教程后续主要使用serving_server文件夹中的模型。 ```bash -python3 -m paddle_serving_client.convert \ +python -m paddle_serving_client.convert \ --dirname ./mobilenet_v3_small_infer/ \ --model_filename inference.pdmodel \ --params_filename inference.pdiparams \ @@ -133,7 +131,6 @@ python3 -m paddle_serving_client.convert \ - serving_client.py:用于**客户端**访问服务的程序,开发者需要设置url(服务地址)、logid(日志ID)和测试图像。 -- preprocess_ops.py:用户图片前项处理的一些工具类 **【实战】** @@ -145,7 +142,40 @@ cp -r ./template/code/* ./ ### 2.5 服务端修改 -服务端无需进行代码修改。 +需要将前后处理部分以自定义OP的形式与 Serving 服务端编译在一起,推荐复用 cpp_infer 中的代码。 + +**【基本流程】** + +具体开发流程可参考[新增op](https://github.com/PaddlePaddle/Serving/blob/v0.8.3/doc/C%2B%2B_Serving/2%2B_model.md) + +**【实战】** + +针对MobileNet网络, 新增三类文件: + +* [General_Clas_op.*](../../mobilenetv3_prod/Step6/deploy/serving_cpp/preprocess/general_clas_op.cpp) 包含自定义op部分,读取 client 端传输数据并进行推理预测; + +* [preprocess_op.*](../../mobilenetv3_prod/Step6/deploy/serving_cpp/preprocess/preprocess_op.cpp) 是可能会用到的工具类函数,复用 cpp_infer 中的代码; + +* [serving_client_conf.prototxt](../../mobilenetv3_prod/Step6/deploy/serving_cpp/preprocess/serving_client_conf.prototxt) 由于clint端输入的是原始图像,可能与推理时需要的输入数据类型不同,建议将输入数据类型统一修改成string,tipc测试时每次copy该文件,覆盖自动生成的`serving_client_conf.prototxt`。 具体将 feed_var 中的 feed_type 修改为20,shape修改为1。 + +``` +feed_var { + name: "input" + alias_name: "input" + is_lod_tensor: false + feed_type: 20 + shape: 1 +} +``` + +完成代码开发后,将相关代码cp到Serving源码中并进行编译[编译](https://github.com/PaddlePaddle/Serving/blob/v0.8.3/doc/Compile_CN.md): + +``` +cp deploy/serving_cpp/preprocess/general_clas_op.* ${Serving_repo_path}/core/general-server/op +cp deploy/serving_cpp/preprocess/preprocess_op.* ${Serving_repo_path}/core/predictor/tools/pp_shitu_tools +``` + + ### 2.6 客户端修改 @@ -170,13 +200,11 @@ img_path = "./images/demo.jpg" **【基本流程】** -serving_client.py文件中的preprocess函数用于开发数据预处理程序,包含输入、处理流程和输出三部分。 +serving_client.py文件中的preprocess函数用于开发数据处理程序,包含输入和输出两部分。 **(1)输入:** 一般开发者使用时,需要自行定义读取数据的方式。 -**(2)处理流程:** 数据预处理流程和基于Paddle Inference的模型预处理流程相同。 - -**(3)输出:** 需要返回两个参数,第一个参数为模型预测的输入字典,第二个参数为需要获取的模型输出列表 +**(2)输出:** 需要返回两个参数,第一个参数为模型预测的输入字典,第二个参数为需要获取的模型输出列表 ``` {"input": input_data}, ["output"] @@ -196,20 +224,20 @@ import numpy as np import base64 from PIL import Image import io -from preprocess_ops import ResizeImage, CenterCropImage, NormalizeImage, ToCHW, Compose from paddle_serving_client import Client ``` -添加数据读取相关代码: +添加数据读取相关代码,将输入图片转换成string类型: ```py -def preprocess(): - image_file = img_path - image = Image.open(image_file) - seq = Compose([ - ResizeImage(256), CenterCropImage(224), NormalizeImage(), ToCHW() - ]) - input_data=seq(image) - feed = {"input": input_data} +def cv2_to_base64(image): + return base64.b64encode(image).decode( + 'utf8') + +def preprocess(img_file): + with open(img_file, 'rb') as file: + image_data = file.read() + image = cv2_to_base64(image_data) + feed = {"input": image} fetch = ["softmax_1.tmp_0"] return feed, fetch ``` @@ -253,7 +281,7 @@ def postprocess(fetch_map): 可以按如下命令启动模型预测服务: ```bash -python3 -m paddle_serving_server.serve --model serving_server --port 9993 +python -m paddle_serving_server.serve --model serving_server --op GeneralClasOp --port 9993 ``` **【实战】** @@ -273,7 +301,7 @@ python3 -m paddle_serving_server.serve --model serving_server --port 9993 客户端访问服务的命令如下: ```bash -python3 serving_client.py +python serving_client.py ``` 访问成功的界面如下图: diff --git a/tutorials/tipc/serving_cpp/template/code/serving_client.py b/tutorials/tipc/serving_cpp/template/code/serving_client.py index 765efa20..a9fa861a 100755 --- a/tutorials/tipc/serving_cpp/template/code/serving_client.py +++ b/tutorials/tipc/serving_cpp/template/code/serving_client.py @@ -13,11 +13,13 @@ # limitations under the License. from paddle_serving_client import Client +import os url = "127.0.0.1:9993" logid = 10000 img_path = "./images/demo.jpg" + def preprocess(): """preprocess @@ -30,6 +32,7 @@ def preprocess(): """ pass + def postprocess(fetch_map): """postprocess @@ -42,14 +45,12 @@ def postprocess(fetch_map): """ pass + client = Client() -client.load_client_config( - "serving_client/serving_client_conf.prototxt") +client.load_client_config("serving_client/serving_client_conf.prototxt") client.connect([url]) -feed, fetch = preprocess() - +feed, fetch = preprocess(img_path) fetch_map = client.predict(feed=feed, fetch=fetch) - result = postprocess(fetch_map) -print(result) \ No newline at end of file +print(result) diff --git a/tutorials/tipc/serving_python/serving_python.md b/tutorials/tipc/serving_python/serving_python.md index 1249304a..b67a7391 100644 --- a/tutorials/tipc/serving_python/serving_python.md +++ b/tutorials/tipc/serving_python/serving_python.md @@ -76,15 +76,15 @@ Paddle Serving服务化部署主要包括以下步骤: nvidia-docker exec -it test bash ``` -(2)安装Paddle Serving四个安装包,分别是:paddle-serving-server(CPU/GPU版本二选一), paddle-serving-client, paddle-serving-app和paddlepaddle(CPU/GPU版本二选一)。 +(2)安装Paddle Serving四个安装包的最新版本,分别是:paddle-serving-server(CPU/GPU版本二选一), paddle-serving-client, paddle-serving-app和paddlepaddle(CPU/GPU版本二选一)。 ```bash - pip3 install paddle-serving-client==0.7.0 - #pip3 install paddle-serving-server==0.7.0 # CPU - pip3 install paddle-serving-server-gpu==0.7.0.post102 # GPU with CUDA10.2 + TensorRT6 - pip3 install paddle-serving-app==0.7.0 - #pip3 install paddlepaddle==2.2.1 # CPU - pip3 install paddlepaddle-gpu==2.2.1 + pip install paddle-serving-client + #pip install paddle-serving-server # CPU + pip install paddle-serving-server-gpu # GPU 默认 CUDA10.2 + TensorRT6,其他环境需手动指定版本号 + pip install paddle-serving-app + #pip install paddlepaddle # CPU + pip install paddlepaddle-gpu ``` 您可能需要使用国内镜像源(例如百度源, 在pip命令中添加`-i https://mirror.baidu.com/pypi/simple`)来加速下载。 Paddle Serving Server更多不同运行环境的whl包下载地址,请参考:[下载页面](https://github.com/PaddlePaddle/Serving/blob/v0.7.0/doc/Latest_Packages_CN.md) -- GitLab