diff --git a/docs/tipc/py_serving/images/py_serving_deploy_pipeline.jpg b/docs/tipc/py_serving/images/py_serving_deploy_pipeline.jpg index 883f9580b0824aff2f6c4f5943b6a18346c1d30a..7ad5f4851b6423cea217b1dfdf434c050c6511d7 100644 Binary files a/docs/tipc/py_serving/images/py_serving_deploy_pipeline.jpg and b/docs/tipc/py_serving/images/py_serving_deploy_pipeline.jpg differ diff --git a/docs/tipc/py_serving/py_serving.md b/docs/tipc/py_serving/py_serving.md index acecbe8944d6962a2a12dd2455f9b60cdd411a9c..3c893432838a0bbf3ba0a50316472d0d7a7d1823 100644 --- a/docs/tipc/py_serving/py_serving.md +++ b/docs/tipc/py_serving/py_serving.md @@ -1,15 +1,15 @@ # Linux GPU/CPU 服务化部署开发文档 - [1 简介](#1---) -- [2 服务化部署能力开发](#2---) +- [2 服务化部署开发](#2---) * [2.1 准备测试数据和部署环境](#21---) - * [2.2 准备部署模型](#22---) - * [2.3 修改样例程序文件名](#23---) + * [2.2 准备服务化部署模型](#22---) + * [2.3 复制部署样例程序](#23---) * [2.4 初始化部署引擎](#24---) * [2.5 开发数据预处理程序](#25---) * [2.6 开发预测结果后处理程序](#26---) * [2.7 启动模型预测服务](#27---) * [2.8 开发客户端访问服务的程序](#28---) - * [2.9 验证服务化部署能力的正确性](#29---) + * [2.9 验证服务化部署功能的正确性](#29---) - [3 FAQ](#3---) @@ -40,7 +40,7 @@ Paddle Serving依托深度学习框架PaddlePaddle旨在帮助深度学习开发 【基本流程】 -**(1)准备测试数据:** 从验证集或者测试集中抽出至少一张图像,用于后续推理过程验证。后续文档中将使用测试图像 ./demo.jpg 进行说明。 +**(1)准备测试数据:** 从验证集或者测试集中抽出至少一张图像,用于后续推理过程验证。 **(2)准备部署环境** @@ -59,10 +59,10 @@ wget https://paddle-serving.bj.bcebos.com/test-dev/whl/paddle_serving_app-0.7.0- pip3 install paddle_serving_app-0.7.0-py3-none-any.whl ``` -Paddle Serving Server更多不同环境的whl包请参考:[下载页面](https://github.com/PaddlePaddle/Serving/blob/v0.7.0/doc/Latest_Packages_CN.md) +Paddle Serving Server更多不同运行环境的whl包下载地址,请参考:[下载页面](https://github.com/PaddlePaddle/Serving/blob/v0.7.0/doc/Latest_Packages_CN.md) -### 2.2 准备部署模型 +### 2.2 准备服务化部署模型 【基本流程】 @@ -75,49 +75,46 @@ python3 -m paddle_serving_client.convert --dirname {静态图模型路径} --mod 【实战】 -针对AlexNet网络,将静态图模型转换为服务化部署模型的示例命令如下,转换完后在本地生成serving_server和serving_client两个文件夹。 +针对AlexNet网络,将静态图模型([模型下载地址,待补充])转换为服务化部署模型的示例命令如下,转换完后在本地生成serving_server和serving_client两个文件夹。本教程后续主要使用serving_server文件夹中的模型。 ```python -python3 -m paddle_serving_client.convert --dirname ../alexnet_infer/ --model_filename inference.pdmodel --params_filename inference.pdiparams --serving_server serving_server --serving_client serving_client +python3 -m paddle_serving_client.convert --dirname ./alexnet_infer/ --model_filename inference.pdmodel --params_filename inference.pdiparams --serving_server serving_server --serving_client serving_client ``` -### 2.3 修改样例程序文件名 +### 2.3 复制部署样例程序 【基本流程】 -目录 pdserving/example 下面包含3个用于服务化部署的样例程序,具体如下: +服务化部署的样例程序的目录地址为:[tipc/py_serving/template/code/, 待补充地址] +该目录下面包含3个文件,具体如下: -- tipc_web_service.py:用于开发服务端模型预测相关程序。由于使用多卡或者多机部署预测服务,设计高效的服务调度策略比较复杂,Paddle Serving将网络预测进行了封装,在这个程序里面开发者只需要关心部署服务引擎的初始化,模型预测的前处理和后处理开发,不用关心模型预测调度问题。 +- web_service.py:用于开发服务端模型预测相关程序。由于使用多卡或者多机部署预测服务,设计高效的服务调度策略比较复杂,Paddle Serving将网络预测进行了封装,在这个程序里面开发者只需要关心部署服务引擎的初始化,模型预测的前处理和后处理开发,不用关心模型预测调度问题。 - config.yml:服务端模型预测相关配置文件,里面有各参数的详细说明。开发者只需要关注如下配置:http_port(服务的http端口),model_config(服务化部署模型的路径),device_type(计算硬件类型),devices(计算硬件ID)。 -- tipc_pipeline_http_client.py:用于客户端访问服务的程序,开发者需要设置url(服务地址)、logid(日志ID)和测试图像。 +- pipeline_http_client.py:用于客户端访问服务的程序,开发者需要设置url(服务地址)、logid(日志ID)和测试图像。 【实战】 -如果服务化部署AlexNet网络,需要拷贝上述三个文件到运行目录,并修改名称如下: - -- tipc_web_service.py ---> alex_web_service.py - -- config.yml ---> alex_config.yml - -- tipc_pipeline_http_client.py ---> alex_pipeline_http_client.py +如果服务化部署AlexNet网络,需要拷贝上述三个文件到运行目录。 ### 2.4 初始化部署引擎 【基本流程】 -针对模型名称,修改tipc_web_service.py中类TIPCExampleService、TIPCExampleOp的名称,以及这些类初始化中任务名称name,同时通过uci_service.prepare_pipeline_config设置配置参数。 +针对模型名称,修改web_service.py中类TIPCExampleService、TIPCExampleOp的名称,以及这些类初始化中任务名称name,同时通过uci_service.prepare_pipeline_config设置配置参数。 -同时修改服务配置文件中的配置:http_port(服务的http端口),model_config(服务化部署模型的路径),device_type(计算硬件类型),devices(计算硬件ID) +同时修改服务配置文件中的配置:OP名称,http_port(服务的http端口),model_config(服务化部署模型的路径),device_type(计算硬件类型),devices(计算硬件ID) 【实战】 -针对AlexNet网络,修改alex_web_service.py文件后的代码如下: +针对AlexNet网络,(1)修改web_service.py文件后的代码如下: ``` +from paddle_serving_server.web_service import WebService, Op + class AlexNetOp(Op): def init_op(self): pass @@ -135,18 +132,23 @@ class AlexNetService(WebService): return alexnet_op uci_service = AlexNetService(name="alexnet") -uci_service.prepare_pipeline_config("alex_config.yml") +uci_service.prepare_pipeline_config("config.yml") uci_service.run_service() ``` -服务配置文件alex_config.yml 这里我们使用默认配置,开发者可以根据具体运行环境情况进行修改。 +(2)修改服务配置文件config.yml。 +- http_port:使用默认的端口号18080 +- OP名称:第14行更新为alexnet +- model_config:与2.2转换后服务化部署模型文件夹路径一致,这里使用默认配置 "./serving_server" +- device_type:使用默认配置1,基于GPU预测 +- devices:使用默认配置"0",0号卡预测 ### 2.5 开发数据预处理程序 【基本流程】 -tipc_web_service.py文件中的TIPCExampleOp类的preprocess函数用于开发数据预处理程序,包含输入、处理流程和输出三部分。 +web_service.py文件中的TIPCExampleOp类的preprocess函数用于开发数据预处理程序,包含输入、处理流程和输出三部分。 **(1)输入:** 一般开发者使用时,只需要关心input_dicts和log_id两个输入参数。这两个参数与客户端访问服务程序tipc_pipeline_http_client.py中的请求参数相对应,即: ``` @@ -165,15 +167,17 @@ tipc_web_service.py文件中的TIPCExampleOp类的preprocess函数用于开发 【实战】 -针对AlexNet网络的数据预处理开发,需要将Paddle Inference中的preprocess.py 复制到Paddle Serving的目录下,修改alex_web_service.py文件中代码如下: +针对AlexNet网络的数据预处理开发,需要将[Paddle Inference中的preprocess_ops.py, 待补充文件路径] 复制到Paddle Serving的目录下,修改alex_web_service.py文件中代码如下: 添加头文件: ```py +import numpy as np +import sys import base64 from PIL import Image import io -from preprocess import ResizeImage, CenterCropImage, NormalizeImage, ToCHW, Compose +from preprocess_ops import ResizeImage, CenterCropImage, NormalizeImage, ToCHW, Compose ``` 修改AlexNetOp中的init_op和preprocess函数相关代码: @@ -204,7 +208,7 @@ class AlexNetOp(Op): 【基本流程】 -tipc_web_service.py文件中的TIPCExampleOp类的 postprocess 函数用于开发预测结果后处理程序,包含输入、处理流程和输出三部分。 +web_service.py文件中的TIPCExampleOp类的 postprocess 函数用于开发预测结果后处理程序,包含输入、处理流程和输出三部分。 **(1)输入:** 包含四个参数,其中参数input_dicts、log_id和数据预处理函数preprocess中一样,data_id可忽略,fetch_dict 是网络预测输出字典,其中输出的key可以通过服务化模型配置文件serving_server/serving_server_conf.prototxt中的fetch_var字典的name字段获取。 @@ -218,11 +222,11 @@ result, None, "" 【实战】 -针对AlexNet网络的预测结果后处理开发,修改alex_web_service.py文件中AlexNetOp中的postprocess函数相关代码如下: +针对AlexNet网络的预测结果后处理开发,修改web_service.py文件中AlexNetOp中的postprocess函数相关代码如下: ``` def postprocess(self, input_dicts, fetch_dict, data_id, log_id): - score_list = fetch_dict["conv2d_5.tmp_0"] + score_list = fetch_dict["save_infer_model/scale_0.tmp_1"] result = {"class_id": [], "prob": []} for score in score_list: score = score.flatten() @@ -243,34 +247,31 @@ result, None, "" 当完成服务化部署引擎初始化、数据预处理和预测结果后处理开发,则可以按如下命令启动模型预测服务: ```bash -python3 tipc_web_service.py & +python3 web_service.py & ``` 【实战】 -针对AlexNet网络, 模型预测服务启动命令如下: - -```bash -python3 alex_web_service.py & -``` - -启动成功的界面如下: - +针对AlexNet网络, 启动成功的界面如下: ![](./images/py_serving_startup_visualization.jpg) - ### 2.8 开发客户端访问服务的程序 【基本流程】 -当成功启动了模型预测服务,可以修改tipc_pipeline_http_client.py程序,访问该服务。主要设置url(服务地址)、logid(日志ID)和测试图像。其中服务地址的url设置如下: - +当成功启动了模型预测服务,可以修改pipeline_http_client.py程序,访问该服务。主要设置url(服务地址)、logid(日志ID)和测试图像。其中服务地址的url的样式为 "http://127.0.0.1:18080/tipc_example/prediction" ,url的设置需要将url中的tipc_example更新为TIPCExampleService类初始化的name。 【实战】 -针对AlexNet网络, 客户端访问服务的命令如下: +针对AlexNet网络, 修改pipeline_http_client.py程序中的url(服务地址)、logid(日志ID)和测试图像地址,其中url改为: + +``` +url = "http://127.0.0.1:18080/alexnet/prediction" +``` + +客户端访问服务的命令如下: ``` python3 alex_pipeline_http_client.py @@ -289,7 +290,7 @@ unset https_proxy ``` -### 2.9 验证服务化部署能力的正确性 +### 2.9 验证服务化部署功能的正确性([待若愚完善]) ``` python3 infer.py --model-dir ../alexnet_infer/ --benchmark False --img-path ../pdserving/demo.jpg --use-gpu True diff --git a/docs/tipc/py_serving/template/code/config.yml b/docs/tipc/py_serving/template/code/config.yml new file mode 100755 index 0000000000000000000000000000000000000000..fff89519bac0b8eca1ef1a86967aa8dd145b782b --- /dev/null +++ b/docs/tipc/py_serving/template/code/config.yml @@ -0,0 +1,32 @@ +#worker_num, 最大并发数。当build_dag_each_worker=True时, 框架会创建worker_num个进程,每个进程内构建grpcSever和DAG +##当build_dag_each_worker=False时,框架会设置主线程grpc线程池的max_workers=worker_num +worker_num: 20 + +#http端口, rpc_port和http_port不允许同时为空。当rpc_port可用且http_port为空时,不自动生成http_port +http_port: 18080 +rpc_port: 9993 + +dag: + #op资源类型, True, 为线程模型;False,为进程模型 + is_thread_op: False +op: + #op名称,与web_service中的TIPCExampleService初始化name参数一致 + tipc_example: + #并发数,is_thread_op=True时,为线程并发;否则为进程并发 + concurrency: 1 + + #当op配置没有server_endpoints时,从local_service_conf读取本地服务配置 + local_service_conf: + + #uci模型路径 + model_config: "./serving_server" + + #计算硬件类型: 空缺时由devices决定(CPU/GPU),0=cpu, 1=gpu, 2=tensorRT, 3=arm cpu, 4=kunlun xpu + device_type: 1 + + #计算硬件ID,当devices为""或不写时为CPU预测;当devices为"0", "0,1,2"时为GPU预测,表示使用的GPU卡 + devices: "0" # "0,1" + + #client类型,包括brpc, grpc和local_predictor.local_predictor不启动Serving服务,进程内预测 + client_type: local_predictor + diff --git a/docs/tipc/py_serving/template/code/pipeline_http_client.py b/docs/tipc/py_serving/template/code/pipeline_http_client.py new file mode 100755 index 0000000000000000000000000000000000000000..fa67762c0fbdd550e41091d27c1e8d7b34f83ffd --- /dev/null +++ b/docs/tipc/py_serving/template/code/pipeline_http_client.py @@ -0,0 +1,21 @@ +import numpy as np +import requests +import json +import cv2 +import base64 +import os + +def cv2_to_base64(image): + return base64.b64encode(image).decode('utf8') + +if __name__ == "__main__": + url = "http://127.0.0.1:18080/tipc_example/prediction" + logid = 10000 + img_path = "../../images/demo.jpg" + with open(img_path, 'rb') as file: + image_data1 = file.read() + image = cv2_to_base64(image_data1) + data = {"key": ["image"], "value": [image], "logid":logid} + for i in range(5): + r = requests.post(url=url, data=json.dumps(data)) + print(r.json()) diff --git a/docs/tipc/py_serving/template/code/web_service.py b/docs/tipc/py_serving/template/code/web_service.py new file mode 100755 index 0000000000000000000000000000000000000000..6a2eb542c12695dd1288034ae4e39a2ec4fb0e2d --- /dev/null +++ b/docs/tipc/py_serving/template/code/web_service.py @@ -0,0 +1,35 @@ +# Copyright (c) 2021 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 paddle_serving_server.web_service import WebService, Op + +class TIPCExampleOp(Op): + def init_op(self): + pass + + def preprocess(self, input_dicts, data_id, log_id): + pass + + def postprocess(self, input_dicts, fetch_dict, data_id, log_id): + pass + + +class TIPCExampleService(WebService): + def get_pipeline_response(self, read_op): + tipc_example_op = TIPCExampleOp(name="tipc_example", input_ops=[read_op]) + return tipc_example_op + +uci_service = TIPCExampleService(name="tipc_example") +uci_service.prepare_pipeline_config("config.yml") +uci_service.run_service() diff --git a/docs/tipc/py_serving/template/model_linux_gpu_normal_normal_serving_python_linux_gpu_cpu_params.txt b/docs/tipc/py_serving/template/model_linux_gpu_normal_normal_serving_python_linux_gpu_cpu_params.txt deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000