服务器端高性能部署:将模型部署在服务器上,利用服务器的高性能帮助用户处理推理业务;
服务化部署:将模型以线上服务的形式部署在服务器或者云端,用户通过客户端或浏览器发送需要推理的输入内容,服务器或者云通过响应报文将推理结果返回给用户;
移动端部署:将模型部署在移动端上,例如手机或者物联网的嵌入式端;
Web 端部署:将模型部署在网页上,用户通过网页完成推理业务。
今天我们就来讲讲如何使用飞桨的服务化部署框架 Paddle Serving 来实现第二种部署方式。
这时可能会有读者说了:部署?算了吧,我直接用 python 也能做推理,而且部署太复杂了,都是企业才能干的事情,与我无关。
这位客官慢走!今天咱们说的 Paddle Serving 用起来可是非常简单,而且部署成功后,那可是在线服务,可谓「独乐乐不如众乐乐!」,不仅自己可以使用它做推理,而且还可以让其他人使用手机、电脑等设备通过客户端或浏览器一起使用推理服务,瞬间让你人气值爆棚!下面我们就先介绍一种最基础的用法,0 代码完成在线服务部署!
0 代码完成在线服务部署
使用 Paddle Serving 部署在线推理服务的过程非常简单,主要分为 3 个步骤,获取可用于部署在线服务的模型、启动服务端和使用客户端访问服务端进行推理,也就是说最多 3 步就可以完成部署,是不是和把大象关到冰箱里一样简单?
具体怎么操作,咱们以常用的波士顿房价预测模型为例来快速体验一下如何将这个模型部署到服务器上。为了方便用户使用,飞桨已经把波士顿房价预测等比较常用的模型文件保存在 GitHub 或 Gitee 上,欢迎大家下载体验。
Paddle Serving 部署用例的下载地址:
https://github.com/PaddlePaddle/Serving/tree/develop/python/examples
如果用户想了解如何训练或保存用于部署的模型,可以参考如下地址:
https://github.com/PaddlePaddle/Serving/blob/develop/doc/SAVE_CN.md
在获取模型后,用户仅需要在服务器上执行如下命令即可部署推理在线服务。
python -m paddle_serving_server_gpu.serve --model fit_a_line/uci_housing_model --thread 10 --port 9393 --name uci
其中 paddle_serving_server_gpu.serve 是使用 GPU 部署在线服务的模块,如果使用 CPU 则是 paddle_serving_server.serve。其它参数则分别是模型所在位置、当前服务的并发数量、服务端口和 HTTP 服务的名称。
在部署成功后,用户就可以在自己的设备上使用如下 cURL 命令向服务器请求推理服务。
curl -H "Content-Type:application/json" -X POST -d '{"feed":[{"x": [0.0137, -0.1136, 0.2553, -0.0692, 0.0582, -0.0727, -0.1583, -0.0584, 0.6283, 0.4919, 0.1856, 0.0795, -0.0332]}], "fetch":["price"]}' http://X.X.X.X:9393/uci/prediction
其中 “X” 和其后的一串数字是波士顿房价预测这个模型用于推理的 13 个特征值,而 “price” 是咱们希望获取的推理结果。“X.X.X.X”是服务器的地址,而 “9393” 和“uci”分别和前面部署命令中 port 和 name 参数指定的值相对应。
以上过程可以说是完全 0 代码部署在线推理服务,当然这只是最简单的 Paddle Serving 的使用方式,其中服务端和客户端之间是使用的 HTTP 协议通信,我们可以把这种在线服务称之为 Web 服务。
如果用户希望使用性能更好的 RPC 通信协议,即部署 RPC 在线服务,或者需要部署的模型稍微复杂一些,需要数据预处理或后处理,那么就需要使用下面的进阶部署方案了。
说到这里,有的用户可能就会头疼了,不是为别的,就是因为刚刚提到的数据处理。要知道无论是图像还是自然语言的文本,这些数据的处理都需要一定的领域知识,可是咱们大部分的用户朋友们可不是图像学或语言学专业毕业的,做个数据处理不仅需要学习相关的基础知识,还要编写不少代码。这样的情况下,使用 Paddle Serving 还会很简单完成部署吗?答案是当然可以!不过咱们也实事求是,0 代码是不太可能的,不过低代码还是没问题的,请往下看!
进阶流程—低代码完成带数据处理的在线服务部署
在 CV 和 NLP 领域,原始的数据通常要经过复杂的预处理才能转换为模型的直接输入,预测结果也需要经过后处理变成更直观的图像或者文字,这就咱们常说的数据预处理和后处理。这些本不是深度学习开发的核心环节,却经常成为开发者们最头疼的步骤。
为了方便用户使用 Paddle Serving,飞桨的工程师们开发了内置预处理模块 paddle-serving-app。paddle-serving-app 模块集成了许多辅助功能,可以帮助用户更快地体验示例推理服务、编写和部署自己的推理服务、分析推理服务中的各阶段耗时、对服务进行调试等。paddle-serving-app 的安装方法也很简单仅需要一条命令即可。
pip install paddle_serving_app
paddle-serving-app 最主要的作用之一就是其内部添加了许多图像(CV)和文本(NLP)的预处理方法。
对于 CV 任务,大部分预处理方法的操作都很相似。因此在 paddle-serving-app 中,这些预处理操作都被封装成了独立的类,然后 paddle-serving-app 提供了 Sequential 类,Sequential 类可以将各个预处理操作的类串联起来,形成不同任务所需要的预处理方法。目前提供的预处理步骤包括:File2Image(从文件读取图像)、URL2Image(从链接中读取图像)、Normalize(归一化)、CenterCrop(裁剪)、Resize(尺寸变换)、RGB2BGR(格式转换)、Transpose(通道转换)等方法。此外对于图像检测、图像分割等任务,paddle-serving-app 还提供了 RCNNPostProcess、SegPostProcess 等后处理方法,可以将推理结果可视化。
对于 NLP 任务,不同类型的任务所对应的预处理方法会差异很大,定制化程度较深。因此对于不同的 NLP 任务分别实现了不同数据处理方法,分别是中文分词模型预处理 LACReader、中文语义模型预处理 ChineseBertReader 和中文情感分析模型预处理 SentaReader。
此外,paddle-serving-app 中内置了多种 NLP 和 CV 领域的示例模型的获取方法,用户可以通过执行如下命令即可下载模型文件压缩包,其中 model_name 为模型名称。
python -m paddle_serving_app.package --get_model ${model_name}
因此 Paddle Serving 配合 paddle-serving-app 有如猛虎添翼,可以帮助用户轻松完成更加复杂的在线服务部署场景。
下面我们将通过部署图像分割服务和中文情感分析服务两个示例,来为大家讲解如何使用 Paddle Serving 和 paddle-serving-app 模块实现低代码部署 RPC 服务和 Web 服务。
部署图像分割服务
图像分割通过给出图像中每个像素点的标签,将图像划分成若干带类别标签的区块的视觉任务,可以看作对每个像素进行分类。图像分割是图像处理的重要组成部分,也是难点之一。随着人工智能的发展,图像分割技术已经在交通控制、医疗影像和人脸识别等多个领域得到了广泛的应用。
本例将部署图像分割的 RPC 服务,RPC 服务与前面的 Web 服务相比,对于用户来说最大的差异是要编写客户端脚本,通过客户端脚本来使用推理服务。而对于服务端来说,同样只需要一条命令就可以启动服务。下面我们来介绍具体的实现过程。
1. 获取示例模型文件
使用 paddle-serving-app 下载图像分割模型示例文件。
python -m paddle_serving_app.package --get deeplabv3+cityscapes
tar xf deeplabv3+cityscapes.tar.gz
解压后将会生成服务端和客户端的部署文件 seg_server_conf 和 seg_client_conf。其中 seg_server_conf 是在服务端使用,而 seg_client_conf 需要转存到客户端使用。
2. 启动推理服务
使用如下命令启动图像分割在线服务,服务端口号为 9393。
python -m paddle_serving_server_gpu.serve --model seg_server_conf --port 9393 --gpu_ids 0
3. 启动客户端
本示例中,需要对图像做预处理和后处理,这是因为图像在输入到模型网络之前需要经过预处理将原始图像进行尺寸的转换,变成 numpy.array 格式的像素值矩阵。而模型的输出是一个矩阵,矩阵值可以标记不同的区域,但是并不直观。需要经过后处理来将推理结果可视化,即将矩阵转化为图片。
上述预处理和后处理操作,将会通过少量代码在客户端调用 paddle-serving-app 来实现。图像分割服务客户端代码(Seg_Client.py)如下:
from paddle_serving_client import Client
# 从app模块中获取图像预处理方法
from paddle_serving_app.reader import Sequential, File2Image, Resize, SegPostprocess
import sys
import cv2
# 创建客户端
client = Client()
# 加载客户端的配置文件
client.load_client_config("seg_client_conf/serving_client_conf.prototxt")
# 连接服务,X.X.X.X为服务端的地址
client.connect(["X.X.X.X:9393"])
# 图像预处理,从文件中读取图像,统一图像尺寸为512*512并做像素插值
preprocess = Sequential(
[File2Image(), Resize(
(512, 512), interpolation=cv2.INTER_LINEAR)])
# 分割任务的后处理算子,参数为训练时的分割类别数,本例为19类分割
postprocess = SegPostprocess(19)
# 在线预估
filename = "munster.png"
im = preprocess(filename)
fetch_map = client.predict(feed={"image": im}, fetch=["arg_max_0.tmp_0"])
fetch_map["filename"] = filename
# 图像后处理
postprocess(fetch_map)
用户可以在自己的电脑上执行下面的命令来调用 Seg_Client.py 脚本使用推理服务。
python Seg_Client.py
推理成功后会在当前目录生成一张图像分割结果图片。
原始图像:
后处理后的推理结果图像:
部署中文情感分析服务
情感分析任务是对于一条中文语句,来判断这条语句的情感属于积极还是消极,如下图所示。
本示例任务的整体流程如下图所示,原始的语句会进行多次预处理,并且待分析句子将会通过 LAC 模型进行切词处理,然后将切词的结果交给 Senta 模型做情感分析推理,总之,我们可以把使用 Senta 模型推理之前的部分都看做 Senta 模型输入数据的预处理。
本例将使用 Web 服务的形式进行部署。在部署 Web 服务的场景中,上述数据预处理操作都会在服务端通过编写脚本实现。具体操作步骤如下所示:
1. 获取示例模型文件
使用 paddle-serving-app 下载图像分割模型示例文件。
python -m paddle_serving_app.package --get_model senta_bilstm
python -m paddle_serving_app.package --get_model lac
tar -xzf senta_bilstm.tar.gz
tar -xzf lac.tar.gz
解压后将会生成 LAC 模型和 Senta 模型的服务端和客户端的部署文件 lac_model、lac_client、senta_bilstm_model 和 senta_bilstm_client。
2. 启动推理服务
先在 9300 端口上启动预处理使用的 LAC 模型的推理服务。
python -m paddle_serving_server.serve --model lac_model --port 9300
在 Senta 模型的推理服务中,会在预处理部分去访问本地的 9300 端口,获取 LAC 模型的推理结果再进一步处理成为 Senta 模型的输入数据。启动 Senta 服务的脚本(senta_web_service.py)如下所示:
from paddle_serving_server.web_service import WebService
from paddle_serving_client import Client
from paddle_serving_app.reader import LACReader, SentaReader
class SentaService(WebService):
#初始化LAC模型预测服务
def init_lac_client(self, lac_port, lac_client_config):
self.lac_reader = LACReader()
self.senta_reader = SentaReader()
# 创建LAC模型推理的客户端
self.lac_client = Client()
# 加载LAC模型的配置文件
self.lac_client.load_client_config(lac_client_config)
# 连接LAC服务
self.lac_client.connect(["X.X.X.X:{}".format(lac_port)])
#定义Senta模型推理服务的预处理,调用顺序:lac reader->LAC模型推理->推理结果后处理->senta reader
def preprocess(self, feed=[], fetch=[]):
feed_data = [{
"words": self.lac_reader.process(x["words"])
} for x in feed]
lac_result = self.lac_client.predict(
feed=feed_data, fetch=["crf_decode"])
feed_batch = []
result_lod = lac_result["crf_decode.lod"]
for i in range(len(feed)):
segs = self.lac_reader.parse_result(
feed[i]["words"],
lac_result["crf_decode"][result_lod[i]:result_lod[i + 1]])
feed_data = self.senta_reader.process(segs)
feed_batch.append({"words": feed_data})
return feed_batch, fetch
# Senta Service封装了启动Senta模型和对接Senta预处理的流程
#声明推理服务
senta_service = SentaService(name="senta")
#加载Senta模型的配置文件
senta_service.load_model_config("senta_bilstm_model")
#配置推理服务的工作目录和端口
senta_service.prepare_server(workdir="workdir", port=9393)
#初始化LAC分词推理服务的客户端
senta_service.init_lac_client(
lac_port=9300, lac_client_config="lac_model/serving_server_conf.prototxt")
#启动Senta模型推理服务的RPC服务部分,Senta模型使用RPC协议和LAC模型通信
senta_service.run_rpc_service()
#启动Senta模型推理服务的http服务部分
senta_service.run_web_service()
用户可以在服务端上执行下面的命令来调用 senta_web_service.py 脚本来启动 Senta 推理服务,推理服务的端口为 9393。
3. 通过客户端访问推理服务
通过 HTTP 请求来访问服务,其中 X.X.X.X 为服务端的地址。
curl -H "Content-Type:application/json" -X POST -d '{"feed":[{"words": "天气不错"}], "fetch":["class_probs"]}' http://X.X.X.X:9393/senta/prediction
获取到的返回结果如下所示,class_probs 中为样本的推理概率,分别为消极情绪的概率和积极情绪的概率。
{"result":{"class_probs":[[0.0690595954656601,0.9309403896331787]]}}
除了以上内容,Paddle Serving 还内置了更多类型、更多方向的推理服务示例等您来尝试。并且作为工业级的在线服务框架,Paddle Serving 还拥有 ABTest、模型热加载等实际业务场景中常用的功能,点击下面的链接可以了解更多框架相关的信息和用法。
https://github.com/PaddlePaddle/Serving
写在最后
综上所述,飞桨的服务化部署框架 Paddle Serving 可以为人工智能落地的最后一公里提供越来越专业、可靠、易用的服务。当前 Paddle Serving 支持部署 RPC 服务和 Web 服务两种类型且都支持通过一行命令启动服务的功能。如果推理服务中涉及数据处理,则用户可以通过 paddle-serving-app 模块编写少量代码,即可轻松搞定数据处理工作。
Paddle Serving 接下来会在后续的版本中继续降低用户的使用门槛,提高用户部署在线服务的效率,开放更多开箱即用的模型,敬请关注!
如果您加入官方 QQ 群,您将遇上大批志同道合的深度学习同学。官方 QQ 群:703252161。
如果您想详细了解更多飞桨的相关内容,请参阅以下文档。
官网地址:https://www.paddlepaddle.org.cn
飞桨 Paddle Serving 项目地址:
GitHub:https://github.com/PaddlePaddle/Serving
Gitee: https://gitee.com/paddlepaddle/Serving
飞桨开源框架项目地址:
GitHub: https://github.com/PaddlePaddle/Paddle
Gitee: https://gitee.com/paddlepaddle/Paddle