"fs/vscode:/vscode.git/clone" did not exist on "30fb7e19f806c1b0f0fce19d088dbb126b36acaa"
server.md 9.53 KB
Newer Older
yuguo-Jack's avatar
yuguo-Jack committed
1
2
3
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# PaddleNLP SimpleSevring

PaddleNLP SimpleServing 是基于 unicorn 封装的模型部署服务化工具,该服务化工具具备灵活、易用的特性,可以简易部署预训练模型和预训练模型工具Taskflow,PaddleNLP SimpleServing 具备以下两个特性:
  - 易用:一行代码即可部署预训练模型和预训练工具Taskflow
  - 灵活:Handler机制可以快速定制化服务化部署方式


## Tasflow部署

Taskflow 是 PaddleNLP 预训练模型工具,具备开箱即用的特性,同时 Taskflow 可以支持加载微调后的模型,基于 Taskflow 的服务化方式可以进一步降低使用者的部署难度。PaddleNLP SimpleServing 基于这样的设计需求,设计了一套基于Taskflow的快速部署方式。下面从 server 搭建,client 发送请求来详细介绍使用方式。

### server 搭建

下面是 Taskflow 搭建服务的简易代码

```python
schema = ['出发地', '目的地', '费用', '时间']
uie = Taskflow("information_extraction", schema=schema)
app = SimpleServer()
app.register_taskflow('taskflow/uie', uie)
```
这里主要是使用 `SimpleServer` 服务类来注册 Taskflow Server,下面我们具体介绍一下 `register_taskflow` 相关参数

```text
def register_taskflow(
    task_name,
    task,
    taskflow_handler=None)

task_name(str):
      服务化的名称,最终的服务化的URL: https://host:port/{task_name}
task(paddlenlp.Taskflow or list(paddlenlp.Taskflow)):
      Taskflow的实例对象,将想要注册的Taskflow任务注册进去,可以是多个Taskflow实例来支持多卡服务化
taskflow_handler(paddlenlp.server.BaseTaskflowHandler, 可选):
      Taskflow句柄处理类,可以自定义处理类来定制化Taskflow服务,默认为None,是默认的TaskflowHandler
```
### 多卡服务化(可选)
在机器环境里面如果有多卡,那就可以register taskflow服务化时,可以注册多个Taskflow实例,在服务化处理请求的过程中做了负载均衡,保证机器设备利用率充分利用,下面是具体的使用例子
```python
schema = ['出发地', '目的地', '费用', '时间']
uie1 = Taskflow("information_extraction", schema=schema, device_id=0)
uie2 = Taskflow("information_extraction", schema=schema, device_id=1)
app = SimpleServer()
app.register_taskflow('taskflow/uie', [uie1, uie2])
```
### 启动服务化
执行代码的即可启动服务
```
paddlenlp server server:app --host 0.0.0.0 --port 8189 --workers 1
```
服务化整体参数配置如下:
```text
--host: 启动服务化的IP地址,通常可以设置成 0.0.0.0
--port:启动服务化的网络端口
--workers: 接收服务化的进程数,默认为1
--log_level:服务化输出日志的级别,默认为 info 级别
--limit_concurrency:服务化能接受的并发数目,默认为None, 没有限制
--timeout_keep_alive:保持服务化连接的时间,默认为15s
--app_dir:服务化本地的路径,默认为服务化启动的位置
--reload: 当 app_dir的服务化相关配置和代码发生变化时,是否重启server,默认为False
```

### client 发送
```python
import requests
import json

url = "http://0.0.0.0:8189/taskflow/uie"
headers = {"Content-Type": "application/json"}
texts = ["城市内交通费7月5日金额114广州至佛山", "5月9日交通费29元从北苑到望京搜后"]
data = {
    "data": {
        "text": texts,
    }
}
r = requests.post(url=url, headers=headers, data=json.dumps(data))
datas = json.loads(r.text)
print(datas)
```
通过上述代码配置即可发送POST请求,同时注意在`data`这个key填入相关请求

同时可以支持定义 `schema` 传入到client请求中,可以快速切换 `schema`

```python
import requests
import json

url = "http://0.0.0.0:8189/taskflow/uie"
headers = {"Content-Type": "application/json"}
texts = ["城市内交通费7月5日金额114广州至佛山", "5月9日交通费29元从北苑到望京搜后"]
data = {
    "data": {
        "text": texts,
    },
    "parameters": {
        "schema": [] # 自定义schema
    }
}
r = requests.post(url=url, headers=headers, data=json.dumps(data))
datas = json.loads(r.text)
print(datas)
```

## 预训练模型部署
PaddleNLP SimpleServing 除了能支持Taskflow的服务化部署,也能支持预训练模型的部署,通过简单的配置即可加载预训练模型来进行服务化,同时在接口层面也能支持服务化的扩展,支持模型前后处理的定制化需求。

## server 搭建

下面是预训练模型的搭建的简易代码
```python
from paddlenlp import SimpleServer
from paddlenlp.server import CustomModelHandler, MultiClassificationPostHandler

app = SimpleServer()
app.register('cls_multi_class',
             model_path="./export",
             tokenizer_name='ernie-3.0-medium-zh',
             model_handler=CustomModelHandler,
             post_handler=MultiClassificationPostHandler)
```

这里主要是使用 `SimpleServer` 服务类来注册 Transformers Server,下面我们具体介绍一下 `register` 相关参数

```text
def register(task_name,
             model_path,
             tokenizer_name,
             model_handler,
             post_handler,
             precision='fp32',
             device_id=0)
task_name(str):
      服务化的名称,最终的服务化的URL: https://host:port/{task_name}
model_path(str):
      需要部署的模型路径,这里的路径必须是动转静后的模型路径
model_handler(paddlenlp.server.BaseModelHandler):
      模型前置处理以及模型预测的Handler类别名字,这里可以继承 BaseModelHandler 自定义处理逻辑
 post_handler(paddlenlp.server.BasePostHandler):
      模型后置处理的Handler类别名字,这里可以继承 BasePostHandler 自定义处理逻辑
precision(str):
      模型的预测精度,默认为fp32;可选fp16,fp16的支持需要以下条件 1) **硬件**: V100、T4、A10、A100/GA100、Jetson AGX Xavier 、3080、3080、2080、2090 等显卡 2)**CUDA环境**:确保 CUDA >= 11.2,cuDNN >= 8.1.1 3) **安装依赖**:安装 onnx、 onnxruntime-gpu
device_id(int, list(int)):
       GPU设备,device_id默认为0,同时如果有多张显卡,可以设置成list,例如[0, 1]就可以支持多卡服务化;CPU设备,不用设置。
```
- BaseModelHandler继承类:主要是 `CustomModelHandler`,该类的实现可以参考[链接](https://github.com/PaddlePaddle/PaddleNLP/blob/develop/paddlenlp/server/handlers/custom_model_handler.py), 绝大多数语义理解模型均可使用该继承类
- BasePostHandler继承类:主要是文本分类 `MultiClassificationPostHandler``MultiLabelClassificationPostHandler` 来支持多分类、多标签分类,实现代码部分可以参考[链接](https://github.com/PaddlePaddle/PaddleNLP/blob/develop/paddlenlp/server/handlers/cls_post_handler.py)`TokenClsModelHandler` 支持 序列标注任务,实现代码部分可以参考[链接](https://github.com/PaddlePaddle/PaddleNLP/blob/develop/paddlenlp/server/handlers/token_model_handler.py)

### 启动服务化
执行代码的即可启动服务
```
paddlenlp server server:app --host 0.0.0.0 --port 8189 --workers 1
```
服务化整体参数配置如下:
```text
--host: 启动服务化的IP地址,通常可以设置成 0.0.0.0
--port:启动服务化的网络端口,注意和已有网络端口冲突
--workers: 接收服务化的进程数,默认为1
--log_level:服务化输出日志的级别,默认为 info 级别
--limit_concurrency:服务化能接受的并发数目,默认为None, 没有限制
--timeout_keep_alive:保持服务化连接的时间,默认为15s
--app_dir:服务化本地的路径,默认为服务化启动的位置
--reload: 当 app_dir的服务化相关配置和代码发生变化时,是否重启server,默认为False
```

### 多卡服务化(可选)
在机器环境里面如果有多卡,通过简单设置 device_id 即可实现多卡服务化,保证机器设备利用率充分利用,下面是具体的使用例子
```python
from paddlenlp import SimpleServer
from paddlenlp.server import CustomModelHandler, MultiClassificationPostHandler

app = SimpleServer()
app.register('models/cls_multi_class',
             model_path="../../export",
             tokenizer_name='ernie-3.0-medium-zh',
             model_handler=CustomModelHandler,
             post_handler=MultiClassificationPostHandler
             device_id=[0,1]) # device_id是0,1 两张卡
```
### client 发送
```python

import requests
import json

texts = [
        '黑苦荞茶的功效与作用及食用方法', '交界痣会凸起吗', '检查是否能怀孕挂什么科', '鱼油怎么吃咬破吃还是直接咽下去',
        '幼儿挑食的生理原因是'
    ]
    data = {
        'data': {
            'text': texts,
        },
        'parameters': {
            'max_seq_len': 128,
            'batch_size': 2
        }
    }
    r = requests.post(url=url, headers=headers, data=json.dumps(data))
    result_json = json.loads(r.text)
    print(result_json)
```
在Client发送请求的过程中可以一些参数来控制服务化处理逻辑,例如上面的 `max_seq_len``batch_size` 均可以控制服务化处理时的序列长度和处理batch_size 。

## 参考示例
- [UIE 服务化部署](https://github.com/PaddlePaddle/PaddleNLP/tree/develop/model_zoo/uie/deploy/serving/simple_serving)
- [文本分类服务化部署](https://github.com/PaddlePaddle/PaddleNLP/tree/develop/applications/text_classification/multi_class/deploy/simple_serving)
- [预训练模型定制化post_handler](https://github.com/PaddlePaddle/PaddleNLP/tree/develop/model_zoo/ernie-health/cblue/deploy/serving/simple_serving)