serving_python.md 14.3 KB
Newer Older
D
dyning 已提交
1 2
# Linux GPU/CPU PYTHON 服务化部署功能开发文档

3

D
dyning 已提交
4 5
# 目录

6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
- [1. 简介](#1)
- [2. Paddle Serving服务化部署](#2)
    - [2.1 准备测试数据](#2.1)
    - [2.2 准备环境](#2.2)
    - [2.3 准备服务化部署模型](#2.3)
    - [2.4 复制部署样例程序](#2.4)
    - [2.5 服务端修改](#2.5)
    - [2.6 客户端修改](#2.6)
    - [2.7 启动服务端模型预测服务](#2.7)
    - [2.8 启动客服端](#2.7)
- [3. FAQ](#3)

<a name="1"></a>
## 1. 简介

Paddle Serving是飞桨开源的**服务化部署**框架,提供了C++ Serving和Python Pipeline两套框架,C++ Serving框架更倾向于追求极致性能,Python Pipeline框架倾向于二次开发的便捷性。旨在帮助深度学习开发者和企业提供高性能、灵活易用的工业级在线推理服务,助力人工智能落地应用。


更多关于Paddle Serving的介绍,可以参考[Paddle Serving官网repo](https://github.com/PaddlePaddle/Serving)

本文档主要介绍利用Paddle Serving Pipeline框架实现飞桨模型(以MobilenetV3为例)的服务化部署。

**【注意】**:本项目仅支持Python3.6/3.7/3.8,接下来所有的与Python/Pip相关的操作都需要选择正确的Python版本。

<a name="2"></a>
## 2. Paddle Serving服务化部署
Paddle Serving服务化部署主要包括以下步骤:
littletomatodonkey's avatar
littletomatodonkey 已提交
33 34 35 36

<div align="center">
    <img src="../images/serving_guide.png" width="800">
</div>
37 38 39 40 41 42 43

其中设置了2个核验点,分别为:
* 启动服务端
* 启动客户端

<a name="2.1"></a>
### 2.1 准备测试数据
44 45 46 47 48

为方便快速验证推理预测过程,需要准备一个小数据集(训练集和验证集各8~16张图像即可,压缩后数据大小建议在`20M`以内,确保基础训练推理总时间不超过十分钟),放在`lite_data`文件夹下。

    相关文档可以参考[论文复现赛指南3.2章节](../../../docs/lwfx/ArticleReproduction_CV.md),代码可以参考`基于ImageNet准备小数据集的脚本`:[prepare.py](https://github.com/littletomatodonkey/AlexNet-Prod/blob/tipc/pipeline/Step2/prepare.py)。

49 50 51 52 53 54 55 56 57 58 59 60 61

本教程以`./images/demo.jpg`作为测试用例。

<a name="2.2"></a>
### 2.2 准备环境

**docker**是一个开源的应用容器引擎,可以让应用程序更加方便地被打包和移植。Paddle Serving容器化部署建议在docker中进行Serving服务化部署。本教程在docker环境运行。

**【注意】**:推荐使用docker进行Serving部署。如果您已经准备好了docker环境,那么可以跳过此步骤。

(1)以下安装docker的Paddle Serving环境,CPU/GPU版本二选一即可。

 1)docker环境安装(CPU版本)
littletomatodonkey's avatar
littletomatodonkey 已提交
62

63 64 65 66 67 68
  ```bash
  # 拉取并进入 Paddle Serving的 CPU Docker
  docker pull paddlepaddle/serving:0.7.0-devel
  docker run -p 9292:9292 --name test -dit paddlepaddle/serving:0.7.0-devel bash
  docker exec -it test bash
  ````
littletomatodonkey's avatar
littletomatodonkey 已提交
69

70
  2)docker环境安装(GPU版本)
littletomatodonkey's avatar
littletomatodonkey 已提交
71

72 73 74 75 76 77
  ```bash
  # 拉取并进入 Paddle Serving的GPU Docker
  docker pull paddlepaddle/serving:0.7.0-cuda10.2-cudnn7-devel
  nvidia-docker run -p 9292:9292 --name test -dit paddlepaddle/serving:0.7.0-cuda10.2-cudnn7-devel bash
  nvidia-docker exec -it test bash
  ```
littletomatodonkey's avatar
littletomatodonkey 已提交
78

79 80 81 82 83 84 85 86
(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
littletomatodonkey's avatar
littletomatodonkey 已提交
87
  pip3 install paddlepaddle-gpu==2.2.1
88 89 90 91 92 93 94 95 96 97 98 99 100 101
  ```
  您可能需要使用国内镜像源(例如百度源, 在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)
  PaddlePaddle更多版本请参考[官网](https://www.paddlepaddle.org.cn/install/quick?docurl=/documentation/docs/zh/install/pip/linux-pip.html)

(3)在docker中下载工程

```bash
git clone https://github.com/PaddlePaddle/models.git
cd models/tutorials/tipc/serving_python
```

<a name="2.3"></a>
### 2.3 准备服务化部署模型
102
#### 2.3.1 准备MobilenetV3 inference模型
103

104
参考[MobilenetV3](../../mobilenetv3_prod/Step6/README.md#2),确保 inference 模型在当前目录下。
105 106 107 108 109 110 111 112

#### 2.3.2 准备服务化部署模型

【基本流程】

为了便于模型服务化部署,需要将静态图模型(模型结构文件:\*.pdmodel和模型参数文件:\*.pdiparams)使用paddle_serving_client.convert按如下命令转换为服务化部署模型:

```bash
113
python -m paddle_serving_client.convert --dirname {静态图模型路径} --model_filename {模型结构文件} --params_filename {模型参数文件} --serving_server {转换后的服务器端模型和配置文件存储路径} --serving_client {转换后的客户端模型和配置文件存储路径}
114 115 116 117 118 119 120 121
```
上面命令中 "转换后的服务器端模型和配置文件" 将用于后续服务化部署。其中`paddle_serving_client.convert`命令是`paddle_serving_client` whl包内置的转换函数,无需修改。

【实战】

针对MobileNetV3网络,将inference模型转换为服务化部署模型的示例命令如下,转换完后在本地生成**serving_server**和**serving_client**两个文件夹。本教程后续主要使用serving_server文件夹中的模型。

```bash
122
python -m paddle_serving_client.convert \
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
    --dirname ./mobilenet_v3_small_infer/ \
    --model_filename inference.pdmodel \
    --params_filename inference.pdiparams \
    --serving_server serving_server \
    --serving_client serving_client
```
**【注意】**:0.7.0版本的 PaddleServing 需要和PaddlePaddle 2.2之后的版本搭配进行模型转换。

<a name="2.4"></a>
### 2.4 复制部署样例程序
**【基本流程】**

服务化部署的样例程序的目录地址为:`./template/code`

该目录下面包含3个文件,具体如下:

- web_service.py:用于开发**服务端模型预测**相关程序。由于使用多卡或者多机部署预测服务,设计高效的服务调度策略比较复杂,Paddle Serving将网络预测进行了封装,在这个程序里面开发者只需要关心部署服务引擎的初始化,模型预测的前处理和后处理开发,不用关心模型预测调度问题。

- config.yml:服务端模型预测相关**配置文件**,里面有各参数的详细说明。开发者只需要关注如下配置:http_port(服务的http端口),model_config(服务化部署模型的路径),device_type(计算硬件类型),devices(计算硬件ID)。

- pipeline_http_client.py:用于**客户端**访问服务的程序,开发者需要设置url(服务地址)、logid(日志ID)和测试图像。

- preprocess_ops.py:用户图片前项处理的一些工具类

**【实战】**

如果服务化部署MobileNetV3网络,拷贝上述三个文件到当前目录,以便做进一步修改。
```bash
cp -r ./template/code/*  ./

```

<a name="2.5"></a>
### 2.5 服务端修改

服务端修改包括服务端代码修改(即对web_service.py代码进行修改)和服务端配置文件(即对config.yml代码进行修改)修改。
服务端代码修改主要修改:初始化部署引擎、开发数据预处理程序、开发预测结果后处理程序三个模块。
服务端配置文件主要修改:
**【注意】**:后续代码修改,主要修改包含`TIPC`字段的代码模块。

#### 2.5.1 初始化服务端部署配置引擎
**【基本流程】**

针对模型名称,修改web_service.py中类TIPCExampleService、TIPCExampleOp的名称,以及这些类初始化中任务名称name。


**【实战】**

针对MobileNetV3网络

(1)修改web_service.py文件后的代码如下:

```python
from paddle_serving_server.web_service import WebService, Op
class MobileNetV3Op(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
littletomatodonkey's avatar
littletomatodonkey 已提交
184

185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
class MobileNetV3Service(WebService):
    def get_pipeline_response(self, read_op):
        mobilenetv3_op = MobileNetV3Op(name="imagenet", input_ops=[read_op])
        return mobilenetv3_op
uci_service = MobileNetV3Service(name="imagenet")
uci_service.prepare_pipeline_config("config.yml")
uci_service.run_service()
```

#### 2.5.2 开发数据预处理程序

**【基本流程】**

web_service.py文件中的TIPCExampleOp类的preprocess函数用于开发数据预处理程序,包含输入、处理流程和输出三部分。

**(1)输入:** 一般开发者使用时,只需要关心input_dicts和log_id两个输入参数。这两个参数与客户端访问服务程序tipc_pipeline_http_client.py中的请求参数相对应,即:
```
    data = {"key": ["image"], "value": [image], "logid":logid}
```
其中key和value的数据类型都是列表,并且一一对应。input_dicts是一个字典,它的key和value和data中的key和value是一致的。log_id和data中的logid一致。

**(2)处理流程:** 数据预处理流程和基于Paddle Inference的模型预处理流程相同。

**(3)输出:** 需要返回四个参数,一般开发者使用时只关心第一个返回值,网络输入字典,其余返回值使用默认的即可。

```
{"input": input_imgs}, False, None, ""
```
上述网络输入字典的key可以通过服务化模型配置文件serving_server/serving_server_conf.prototxt中的feed_var字典的name字段获取。

**【实战】**

针对MobileNetV3网络的数据预处理开发,修改web_service.py文件中代码如下:

添加头文件:

```py
import sys
import numpy as np
import base64
from PIL import Image
import io
from preprocess_ops import ResizeImage, CenterCropImage, NormalizeImage, ToCHW, Compose
littletomatodonkey's avatar
littletomatodonkey 已提交
228
```  
229 230 231 232 233 234 235 236
修改MobileNetV3Op中的init_op和preprocess函数相关代码:

```py
class MobileNetV3Op(Op):
    def init_op(self):
        self.seq = Compose([
            ResizeImage(256), CenterCropImage(224), NormalizeImage(), ToCHW()
        ])
littletomatodonkey's avatar
littletomatodonkey 已提交
237

238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
    def preprocess(self, input_dicts, data_id, log_id):
        (_, input_dict), = input_dicts.items()
        batch_size = len(input_dict.keys())
        imgs = []
        for key in input_dict.keys():
            data = base64.b64decode(input_dict[key].encode('utf8'))
            byte_stream = io.BytesIO(data)
            img = Image.open(byte_stream)
            img = img.convert("RGB")
            img = self.seq(img)
            imgs.append(img[np.newaxis, :].copy())
        input_imgs = np.concatenate(imgs, axis=0)
        return {"input": input_imgs}, False, None, ""
```

#### 2.5.3 开发预测结果后处理程序

【基本流程】

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字段获取。

**(2)处理流程:** 数据预处理流程和基于Paddle Inference的预测结果后处理一致。

**(3)输出:** 需要返回三个参数,一般开发者使用时只关心第一个返回值,预测结果字典,其余返回值使用默认的即可。

```
result, None, ""
```

【实战】

针对MobileNet网络的预测结果后处理开发,修改web_service.py文件中MobileNetOp中的postprocess函数相关代码如下:

```py
    def postprocess(self, input_dicts, fetch_dict, data_id, log_id):
        score_list = fetch_dict["softmax_1.tmp_0"]
        result = {"class_id": [], "prob": []}
        for score in score_list:
            score = score.tolist()
            max_score = max(score)
            result["class_id"].append(score.index(max_score))
            result["prob"].append(max_score)
        result["class_id"] = str(result["class_id"])
        result["prob"] = str(result["prob"])
        return result, None, ""
```
#### 2.5.4 修改服务配置文件config.yml

- http_port:使用默认的端口号18080
- OP名称:第14行修改成imagenet
- model_config:与2.4转换后服务化部署模型文件夹路径一致,这里使用默认配置 "./serving_server"
- device_type:使用默认配置1,基于GPU预测;使用参数0,基于CPU预测。
littletomatodonkey's avatar
littletomatodonkey 已提交
292
- devices:使用默认配置"0",0号卡预测  
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308

<a name="2.6"></a>
### 2.6 客户端修改

修改pipeline_http_client.py程序,用于访问2.6中的服务端服务。

**【基本流程】**
主要设置客户端代码中的url(服务地址)、logid(日志ID)和测试图像。其中服务地址的url的样式为 "http://127.0.0.1:18080/tipc_example/prediction" ,url的设置需要将url中的tipc_example更新为TIPCExampleService类初始化的name。

**【实战】**

针对MobileNet网络, 修改pipeline_http_client.py程序中的url(服务地址)、logid(日志ID)和测试图像地址,其中url改为:

```
url = "http://127.0.0.1:18080/imagenet/prediction"
img_path = "./images/demo.jpg"
littletomatodonkey's avatar
littletomatodonkey 已提交
309
```
310 311 312 313 314 315 316 317 318

<a name="2.7"></a>
### 2.7 启动服务端模型预测服务

**【基本流程】**

当完成服务化部署引擎初始化、数据预处理和预测结果后处理开发,则可以按如下命令启动模型预测服务:

```bash
319
python web_service.py &
littletomatodonkey's avatar
littletomatodonkey 已提交
320
```  
321 322 323 324 325
**【实战】**

针对MobileNet网络, 启动成功的界面如下:

![图片](./images/py_serving_startup_visualization.jpg)
littletomatodonkey's avatar
littletomatodonkey 已提交
326

327 328 329 330 331 332 333 334
<a name="2.8"></a>
#### 2.8 启动客户端

**【基本流程】**

当成功启动了模型预测服务,可以启动客户端代码,访问服务。

**【实战】**
littletomatodonkey's avatar
littletomatodonkey 已提交
335

336 337 338
客户端访问服务的命令如下:

```bash
339
python pipeline_http_client.py
littletomatodonkey's avatar
littletomatodonkey 已提交
340
```  
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
访问成功的界面如下图:

![图片](./images/serving_client_result.png)

与基于Paddle Inference的推理结果一致,结果正确。

【注意事项】
如果访问不成功,可能设置了代理影响的,可以用下面命令取消代理设置。

```
unset http_proxy
unset https_proxy
```



## 3. FAQ

如果您在使用该文档完成Paddle Serving服务化部署的过程中遇到问题,可以给在[这里](https://github.com/PaddlePaddle/Serving/issues)提一个ISSUE,我们会高优跟进。