PaddleNLP SimpleServing 是基于 unicorn 封装的模型部署服务化工具,该服务化工具具备灵活、易用的特性,可以简易部署预训练模型和预训练模型工具Taskflow,PaddleNLP SimpleServing 具备以下两个特性:
- 易用:一行代码即可部署预训练模型和预训练工具Taskflow
- 灵活:Handler机制可以快速定制化服务化部署方式
Taskflow 是 PaddleNLP 预训练模型工具,具备开箱即用的特性,同时 Taskflow 可以支持加载微调后的模型,基于 Taskflow 的服务化方式可以进一步降低使用者的部署难度。PaddleNLP SimpleServing 基于这样的设计需求,设计了一套基于Taskflow的快速部署方式。下面从 server 搭建,client 发送请求来详细介绍使用方式。
下面是 Taskflow 搭建服务的简易代码
schema = ['出发地', '目的地', '费用', '时间']
uie = Taskflow("information_extraction", schema=schema)
app = SimpleServer()
app.register_taskflow('taskflow/uie', uie)
这里主要是使用 SimpleServer
服务类来注册 Taskflow Server,下面我们具体介绍一下 register_taskflow
相关参数
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实例,在服务化处理请求的过程中做了负载均衡,保证机器设备利用率充分利用,下面是具体的使用例子
schema = ['出发地', '目的地', '费用', '时间']
uie1 = Taskflow("information_extraction", schema=schema, device_id=0)
uie2 = Taskflow("information_extraction", schema=schema, device_id=1)
app = SimpleServer()
app.register_taskflow('uie', [uie1, uie2])
执行代码的即可启动服务
paddlenlp server server:app --host 0.0.0.0 --port 8189 --workers 1
服务化整体参数配置如下:
--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
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
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的服务化部署,也能支持预训练模型的部署,通过简单的配置即可加载预训练模型来进行服务化,同时在接口层面也能支持服务化的扩展,支持模型前后处理的定制化需求。
下面是预训练模型的搭建的简易代码
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
相关参数
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
,该类的实现可以参考链接, 绝大多数语义理解模型均可使用该继承类 - BasePostHandler继承类:主要是文本分类
MultiClassificationPostHandler
、MultiLabelClassificationPostHandler
来支持多分类、多标签分类,实现代码部分可以参考链接;TokenClsModelHandler
支持 序列标注任务,实现代码部分可以参考链接
执行代码的即可启动服务
paddlenlp server server:app --host 0.0.0.0 --port 8189 --workers 1
服务化整体参数配置如下:
--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 即可实现多卡服务化,保证机器设备利用率充分利用,下面是具体的使用例子
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 两张卡
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 。