上云无忧 > 文档中心 > 第八章:精通深度学习的高级内容 - 工业部署:Paddle Inference和Paddle Serving
飞桨PaddlePaddle开源深度学习平台
第八章:精通深度学习的高级内容 - 工业部署:Paddle Inference和Paddle Serving

文档简介:
飞桨原生推理库Paddle Inference 在实际应用中,推理阶段会面临和训练时完全不一样的硬件环境,当然也对应着不一样的计算性能要求。我们训练得到的模型,需要能在具体生产环境中正确、高效地实现推理功能,完成上线部署。 上线部署可能会遇到各种问题,比如:
*此产品及展示信息均由百度智能云官方提供。免费试用 咨询热线:400-826-7010,为您提供专业的售前咨询,让您快速了解云产品,助您轻松上云! 微信咨询
  免费试用、价格特惠

飞桨原生推理库Paddle Inference

在实际应用中,推理阶段会面临和训练时完全不一样的硬件环境,当然也对应着不一样的计算性能要求。我们训练得到的模型,需要能在具体生产环境中正确、高效地实现推理功能,完成上线部署。 上线部署可能会遇到各种问题,比如:

  • 预测面临特殊硬件环境:上线部署的硬件环境和训练时不同。
  • 业务系统是多语言环境:业务系统使用C++或者Java实现,不是Python。
  • 模型性能(速度和大小)需优化:推理计算耗时太高, 可能造成服务不可用。模型的内存占用过高造成无法上线。

对工业级部署而言,要求的条件往往非常繁多而且苛刻,不是每个深度学习框架在实际生产部署上都能有良好的支持。飞桨提供了一系列的模型部署工具和方案,可以让用户的模型上线工作事半功倍。

Paddle Inference是什么

Paddle Inference是飞桨原生推理库,使用静态图或者动态图保存Inference模型,在C++后端调用模型,并部署到高性能的业务系统中。

飞桨框架的推理部署能力经过多个版本的升级迭代,形成了完善的推理库Paddle Inference。Paddle Inference功能特性丰富、性能优异,针对不同平台不同应用场景进行了深度的适配优化,做到高吞吐、低时延,保证了飞桨模型在服务器端即训即用,快速部署。

针对前面提到的几个模型部署问题, Paddle Inference 提供了对应的解决方案:

  • 主流软硬件环境兼容适配

    支持服务器端X86 CPU、NVIDIA GPU芯片,兼容Linux/MAC OS/Windows系统。

  • 多语言环境丰富接口可灵活调用

    支持C++, Python, C, Go和R语言API, 接口简单灵活,20行代码即可完成部署。可通过Python API,实现对性能要求不太高的场景快速支持;通过C++高性能接口,可与线上系统联编;通过基础的C API可扩展支持更多语言的生产环境。

  • 多种性能优化策略

  1. 内存/显存复用提升服务吞吐量:在推理初始化阶段,对模型中的OP输出Tensor 进行依赖分析,将两两互不依赖的Tensor在内存/显存空间上进行复用,进而增大计算并行量,提升服务吞吐量。
  2. 细粒度OP横向纵向融合减少计算量:在推理初始化阶段,按照已有的融合模式将模型中的多个OP融合成一个OP,减少了模型的计算量的同时,也减少了 Kernel Launch的次数,从而提升推理性能。目前Paddle Inference支持的融合模式多达几十个。
  3. 内置高性能的CPU/GPU Kernel:内置同Intel、NVIDIA共同打造的高性能kernel,保证了模型推理高性能的执行。
  4. 子图集成TensorRT加快GPU推理速度:Paddle Inference采用子图的形式集成TensorRT,针对GPU推理场景,TensorRT可对一些子图进行优化,包括OP的横向和纵向融合,过滤冗余的OP,并为OP自动选择最优的kernel,加快推理速度。 注释:TensorRT是英伟达针对GPU提供的高性能的深度学习推理优化器,可以为深度学习应用提供低延迟、高吞吐率的部署推理。
  5. 支持加载PaddleSlim量化压缩后的模型:PaddleSlim是飞桨深度学习模型压缩工具,Paddle Inference可联动PaddleSlim,支持加载量化、裁剪和蒸馏后的模型并部署,由此减小模型存储空间、减少计算占用内存、加快模型推理速度。

Paddle Inference场景划分

Paddle Inference应用场景,按照API接口类型可以分C++, Python, C, Go和R。

Python适合直接应用,可通过Python API实现性能要求不太高的场景的快速支持;C++接口属于高性能接口,可与线上系统联编。C接口是基于C++,用于支持更多语言的生产环境。

不同接口的使用流程是一致的,仅语言写法上的不同以及个别操作细节存在差异。其中,比较常见的场景是C++和Python。

Paddle Inference C++ 接口的部署流程

模型部署首先要有部署的模型文件。在模型训练过程中或者模型训练结束后,可以通过save_inference_model 接口来导出标准化的模型文件。save_inference_model可以根据推理需要的输入和输出, 对训练模型进行剪枝, 去除和推理无关部分, 得到的模型相比训练时更加精简, 适合进一步优化和部署。注意,读者在之前章节接触到的paddle.save和paddle.load接口,更多是用于模型训练后测试预测效果,而追求高性能的上线系统,优先推荐Paddle inference产品提供的接口。

其中,静态图和动态图的保存模型API接口不同,如下案例所展示。

  • 静态图保存模型

paddle.static.save_inference_model(path_prefix="./sample_model", feed_vars=[image], fetch_vars=[out], executor=exe)

  • 动态图保存模型 Paddle 2.0做动态图模型保存的方式跟1.8版本存在很大差异, 请先确认使用框架为2.0以后版本。由于部署工具只支持静态图保存的模型格式,所以动态图的模型程序需要通过“动转静”功能将模型保存成静态图的格式。Paddle2.0支持透过to_static装饰器模式及to_static直接函数调用两种方式完成动态图转静态图的部署,以下分别详述:

    1. tostatic裝飾器模式:

动转静 paddle.jit.to_static 装饰器支持 input_spec 参数,用于指定被装饰函数每个 Tensor 类型输入参数的 shape 、 dtype 、 name 等签名信息。不必再显式地传入 Tensor 数据以触发网络层 shape 的推导。 Paddle 会解析 to_static 中指定的 input_spec 参数,构建网络的起始输入,进行后续的模型组网。同时,借助 input_spec 参数,可以自定义输入 Tensor 的 shape ,比如指定 shape 为 [None, 784] ,其中 None 表示变长的维度。

如下是一个简单的使用样例:

# 导入Paddle相关包 import paddle from paddle.jit import to_static from paddle.static import
 InputSpec from paddle.nn import Layer # 定义线性回归网络,继承自paddle.nn.Layer # 该网络仅
包含一层fc class SimpleNet(Layer): # 在__init__函数中仅初始化linear层 def 
__init__(self): super(SimpleNet, self).__init__()
        self.linear = paddle.nn.Linear(10, 3) # 在forward函数中定义该网络的具体前向计算;
@to_static装饰器用于依次指定参数x和y对应Tensor签名信息 # 下述案例是输入为10个特征,
输出为1维的数字  @to_static(input_spec=[InputSpec(shape=[None, 10], name='x'),
 InputSpec(shape=[1], name='y')]) def forward(self, x, y): out = self.linear(x)
        out = out + y return out

net = SimpleNet() # 保存预测格式模型 paddle.jit.save(net, './simple_net')

/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/layers/utils.py:
77: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'coll
ections.abc' is deprecated, and in 3.8 it will stop working
  return (isinstance(seq, collections.Sequence) and
W0506 15:07:20.690174   141 gpu_context.cc:244] Please NOTE: device: 0, GPU Compute Capabil
ity: 7.0, Driver API Version: 10.1, Runtime API Version: 10.1
W0506 15:07:20.695869   141 gpu_context.cc:272] device: 0, cuDNN Version: 7.6.

在上述的样例中, to_static 装饰器中的 input_spec 为一个 InputSpec 对象组成的列表,用于依次指定参数 x 和 y 对应的 Tensor 签名信息。在实例化 SimpleNet 后,可以直接调用 paddle.jit.save 保存静态图模型,不需要执行任何其他的代码。

2. to_static函数调用模式: 若期望在动态图下训练模型,在训练完成后保存预测模型,并指定预测时需要的签名信息,则可以选择在保存模型时,直接调用 to_static 函数。使用样例如下:

# 定义线性回归网络,继承自paddle.nn.Layer # 该网络仅包含一层fc class SimpleNet(Layer): 
def __init__(self): super(SimpleNet, self).__init__()
        self.linear = paddle.nn.Linear(10, 3) # 在forward函数中定义该网络的具体前向计算 
def forward(self, x, y): out = self.linear(x)
        out = out + y return out

net = SimpleNet() # 训练过程 (伪代码) for epoch_id in range(10):
    train_step(net, train_reader) # 直接调用to_static函数,paddle会根据input_spec信息对
forward函数进行递归的动转静,得到完整的静态图模型 net = to_static(net, input_spec=[InputS
pec(shape=[None, 10], name='x'), InputSpec(shape=[1], name='y')])
 # 保存预测格式模型 paddle.jit.save(net, './simple_net')

如果不需要使用静态图的模式训练,第二种方式更加简单便捷,可以优先采用。


使用Paddle Inference进行推理部署的流程

在保存好模型之后,使用C++程序调用预测模型的步骤如下图所示。


  1. 配置推理选项。paddle_infer::Config是飞桨提供的配置管理器API。在使用Paddle Inference进行推理部署过程中,需要使用paddle_infer::Config详细地配置推理引擎参数,包括但不限于在何种设备(CPU/GPU)上部署、加载模型路径、开启/关闭计算图分析优化、使用MKLDNN/TensorRT进行部署的加速等。(注释:MKLDNN是Intel为了CPU推出的深度学习加速库,对标NVIDIA为GPU推出的深度学习加速库TensorRT)
  2. 创建paddle_infer::Predictor。paddle_infer::Predictor是飞桨提供的推理引擎API。根据设定好的推理配置paddle_infer::Config创建推理引擎paddle_infer::Config,也就是推理引擎的一个实例。创建期间会进行模型加载、分析和优化等工作。
  3. 准备输入数据。准备好待输入推理引擎的数据,首先获得模型中每个输入的名称以及指向该数据块(CPU或GPU上)的指针,再根据名称将对应的数据块拷贝进paddle_infer::Tensor。飞桨采用paddle_infer::Tensor作为输入/输出数据结构,可以减少额外的拷贝,提升推理性能。
  4. 调用Predictor->Run执行推理。
  5. 获取推理输出。与输入数据类似,根据输出名称将输出的数据(矩阵向量)由paddle_infer::Tensor拷贝至(CPU或GPU上)以进行后续的处理。
  6. 最后,获取输出并不意味着预测过程的结束,在一些特别的场景中,单纯的矩阵向量不能让使用者明白它有什么意义。进一步地,我们需要根据向量本身的意义,解析数据,获取实际的输出。举个例子,transformer 翻译模型,我们将字词变成向量输入到预测引擎中,而预测引擎反馈给我们的,仍然是矩阵向量。但是这些矩阵向量是有意义的,我们需要利用这些向量去找翻译结果所对应的句子,才能完成了使用 transformer 翻译的过程。 如上是使用的基本流程,如果需要实际使用Paddle Inference在自己的C++程序中完成模型预测,具体使用方法和示例可参考下述文档。

注:Paddle Inference的使用示例可以参考服务器端部署-原生推理库Paddle Inference。


  1. 启动服务

启动服务有如下两种模式,读者可根据场景选择。

  •  HTTP模式:web service,支持平台广,服务器端方便加入前后处理(服务逻辑不仅是模型预测,比如加入用户权限的校验、数据的预处理、根据模型预测结果做进一步计算等内容),但速度慢
  •  RPC模式:速度快,但不方便加服务逻辑,支持的平台数量略少。

模式1:使用HTTP服务

Paddle Serving提供了一个名为paddle_serving_server.serve的内置python模块,可以使用单行命令启动RPC服务或HTTP服务。如果我们指定参数–name uci,则意味着我们将拥有一个HTTP服务,其URL为 $IP:$PORT/uci/prediction。

这个启动服务命令的主要参数有四个:

  • model:用的模型文件。
  • thread:最大并发数。
  • port:服务端口。
  • name:服务的访问名称。

# 此段代码在AI Studio上运行无法停止,需要手动中止再运行下面的部分 # 可以在本地上后台运行 !
python -m paddle_serving_server.serve --model uci_housing_model --thread 10 --port 9292 --name uci

/opt/conda/envs/python35-paddle120-env/lib/python3.7/runpy.py:125: RuntimeWarning: 
'paddle_serving_server.serve' found in sys.modules after import of package 'paddle_s
erving_server', but prior to execution of 'paddle_serving_server.serve';
 this may result in unpredictable behaviour
  warn(RuntimeWarning(msg))
This API will be deprecated later. Please do not use it
This API will be deprecated later. Please do not use it
web service address:
http://172.29.162.26:9292/uci/prediction
 * Serving Flask app "serve" (lazy loading)
 * Environment: production  WARNING: This is a development server. Do not use it in a
 production deployment. Use a production WSGI server instead.
 * Debug mode: off
Frist time run, downloading PaddleServing components ...
--2022-05-06 15:10:21--  https://paddle-serving.bj.bcebos.com/test-dev/bin/serving-cpu-avx-openblas-0.6.0.tar.gz
Resolving paddle-serving.bj.bcebos.com (paddle-serving.bj.bcebos.com)..
. 182.61.200.229, 182.61.200.195, 2409:8c04:1001:1002:0:ff:b001:368a
Connecting to paddle-serving.bj.bcebos.com (paddle-serving.bj.bcebos.com)|182.61.200.229|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 90291581 (86M) [application/octet-stream]
Saving to: ‘serving-cpu-avx-openblas-0.6.0.tar.gz’

serving-cpu-avx-ope 100%[===================>]  86.11M  31.5MB/s    in 2.7s    

2022-05-06 15:10:24 (31.5 MB/s) - ‘serving-cpu-avx-openblas-0.6.0.tar.gz’ saved [90291581/90291581]

Decompressing files ..
Going to Run Comand
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle_serving_serve
r/serving-cpu-avx-openblas-0.6.0/serving -enable_model_toolkit -inferservice_path workdi
r -inferservice_file infer_service.prototxt -max_concurrency 0 -num_threads 10 -port 12000
 -precision fp32 -use_calib False -reload_interval_s 10 -resource_path workdir -resource_
file resource.prototxt -workflow_path workdir -workflow_file workflow.prototxt -bthread_
concurrency 10 -max_body_size 67108864 
I0100 00:00:00.000000   371 op_repository.h:68] RAW: Succ regist op: GeneralCopyOp
I0100 00:00:00.000000   371 op_repository.h:68] RAW: Succ regist op: GeneralDistKVInferOp
I0100 00:00:00.000000   371 op_repository.h:68] RAW: Succ regist op: GeneralDistKVQuantInferOp
I0100 00:00:00.000000   371 op_repository.h:68] RAW: Succ regist op: GeneralInferOp
I0100 00:00:00.000000   371 op_repository.h:68] RAW: Succ regist op: GeneralReaderOp
I0100 00:00:00.000000   371 op_repository.h:68] RAW: Succ regist op: GeneralResponseOp
I0100 00:00:00.000000   371 op_repository.h:68] RAW: Succ regist op: GeneralTextReaderOp
I0100 00:00:00.000000   371 op_repository.h:68] RAW: Succ regist op: GeneralTextResponseOp
I0100 00:00:00.000000   371 service_manager.h:79] RAW: Service[LoadGeneralModelService] insert successfully!
I0100 00:00:00.000000   371 load_general_model_service.pb.h:333] RAW: Success regist 
service[LoadGeneralModelService][PN5baidu14paddle_serving9predictor26load
_general_model_service27LoadGeneralModelServiceImplE]
I0100 00:00:00.000000   371 service_manager.h:79] RAW: Service[GeneralModelService] insert successfully!
I0100 00:00:00.000000   371 general_model_service.pb.h:1507] RAW: Success regist 
service[GeneralModelService][PN5baidu14paddle_serving9predictor13general_model23GeneralModelServiceImplE]
I0100 00:00:00.000000   371 factory.h:155] RAW: Succ insert one factory, tag: PAD
DLE_INFER, base type N5baidu14paddle_serving9predictor11InferEngineE
W0100 00:00:00.000000   371 paddle_engine.cpp:29] RAW: Succ regist factory: ::
baidu::paddle_serving::predictor::FluidInferEngine->::baidu::paddle_serving::predictor:
:InferEngine, tag: PADDLE_INFER in macro! --- Running analysis [ir_graph_build_pass] 
--- Running analysis [ir_graph_clean_pass] --- Running analysis [ir_analysis_pass] 
--- Running analysis [ir_params_sync_among_devices_pass] --- Running
 analysis [adjust_cudnn_workspace_size_pass] --- Running analysis [inference_o
p_replace_pass] --- Running analysis [memory_optimize_pass] ---
 Running analysis [ir_graph_to_program_pass] ^C

其他命令的参数介绍如下表所示。

Argument Type Default Description
thread int 4 Concurrency of current service
port int 9292 Exposed port of current service to users
name str "" Service name, can be used to generate HTTP request url
model str "" Path of paddle model directory to be served
mem_optim bool False Enable memory optimization
ir_optim bool False Enable analysis and optimization of calculation graph
use_mkl (Only for cpu version) bool False Run inference with MKL

可通过如下网址 $IP:$PORT/uci/prediction 直接访问预测服务,通过feed和fetch变量设定模型输入和输出。我们可使用 curl 命令来发送HTTP POST请求给刚刚启动的服务。 当然,用户也可以调用Python库来发送HTTP POST请求,请参考Python库Request。

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://127.0.0.1:9292/uci/prediction 

模式2:使用RPC服务

用户还可以使用paddle_serving_server.serve启动RPC服务。 尽管用户需要基于Paddle Serving的python客户端API进行一些开发,但是RPC服务通常比HTTP服务更快。当该命令没有指定–name时,使用的就是RPC服务。

# 在终端中运行这段代码 !python -m paddle_serving_server.serve --model uci_housing_model --thread 10 --port 9292 

使用RPC服务则需要在访问预测服务的客户端写程序,同时客户端需事先安装paddle Serving client。 但客户端程序极为简单,仅用如下十行代码即可完成。

# A user can visit rpc service through paddle_serving_client API # client.py文件中代码如下,
此段程序不要在notebook里运行,仅作为展示 from paddle_serving_client import Client
client = Client()
client.load_client_config("uci_housing_client/serving_client_conf.prototxt")
client.connect(["127.0.0.1:9292"])
data = [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_map = client.predict(feed={"x": data}, fetch=["price"])
print(fetch_map)

另开一个终端,输入命令

python client.py

客户端程序通过配置文件serving_client_conf.prototxt 设定更多高级功能。 在声明了一个client实例后,client通过connect([“IP:PORT”])连接服务器,并使用predict获取预测结果。 在这里,client.predict函数具有两个参数。 feed是带有模型输入变量别名和值的python dict。fetch要从服务器返回的预测变量赋值。 在该示例中,在训练过程中保存可服务模型时,被赋值的tensor名为"x"和"price"。

往届优秀学员作品展示

CascadeRCNN和YOLOv3_Enhance的布匹瑕疵检测模型训练部署

  1. 项目背景

产品质量不稳定的问题一直困扰着我国许多传统制造业企业,而传统的质量管理手段实际执行时需要大量的人力资源、管理资源投入进行保障,并且,只是降低问题发生的概率,并不能够完全杜绝质量问题发生。 随着人工智能和计算机视觉等技术突飞猛进,诞生了工业质检的应用场景,如果能够将这些技术应用于各行各业,尤其是半导体、纺织、快速消费品等质量要求严格或劳动强度大的行业,将创造巨大的商业价值。

  1. 项目内容

本文聚焦于纺织行业的布匹疵点智能检测场景,使用PaddleDetection中CascadeRCNN和YOLOv3的增强模型进行训练、预测,大幅提升预测速度,并提供了多种模型部署方式,使模型具备在工业场景的落地能力,以期为各种工业质检场景提供解决方案示例。

  1. 实现方案

使用PaddleDetection结合Cascade RCNN,使用更大的训练与评估尺度(1000x1500),最终在单卡V100上速度为20FPS,COCO mAP达47.8%。并将模型导出,接到C++服务器端预测库或Serving服务。

  1. 实现结果

  1. 项目点评

基于PaddleClas中SSLD蒸馏方案训练得到的ResNet50_vd预训练模型,结合PaddleDetection中的丰富算子,面向服务器端实用的目标检测方案PSS-DET,使CascadeRCNN增强模型在预测速度上逼近YOLOv3增强模型,效果非常显著。并在Serving上进行工业部署,完成度十分高,实际意义很大。

  1. 项目链接 https://aistudio.baidu.com/aistudio/projectdetail/532715



相似文档
  • 飞桨轻量化推理引擎Paddle Lite: 飞桨具有完善的从训练到部署的一系列框架或工具,当读者完成模型的编写和训练后,如果希望将训练好的模型放到手机端或嵌入式端(如摄像头)等去运行,可以使用飞桨轻量化推理引擎Paddle Lite。
  • 飞桨场景应用开发套件-PaddleX: PaddleX是飞桨场景应用开发套件,它集成飞桨智能视觉领域图像分类、目标检测、语义分割、实例分割任务能力,将深度学习开发全流程从数据准备、模型训练与优化到多端部署端到端打通,并提供统一任务API接口及图形化开发界面Demo。开发者无需分别安装不同套件,以低代码的形式即可快速完成飞桨全流程开发。
  • 人工智能在中国的发展和落地概况: 根据艾瑞的分析报告,人工智能在未来十年迎来落地应用的黄金期,会全面赋能实体经济,行业的经济规模年增长率达40%+。在过去中国经济高速发展的四十年,人们形成了统一的认知:对于个人发展,选择大于能力。一个人选择跳上一辆高速行驶的火车,比个人奔跑快要重要。人工智能在各行业落地相关的产业就是未来十年的高速列车,所以恭喜学习本教程的诸位读者。在可预见的未来,大家会成为各行业应用人工智能技术的弄潮儿。
  • Hi 大家好, 我是百度AI Studio小助手. 大家在学习《百度架构师手把手带你零基础入门深度学习》课程的过程中将会经常使用到AI Studio中的Notebook项目,所以今天给大家介绍一些Notebook项目基本操作.
  • Python数据结构、 Python面向对象、 Python JSON、 Python 异常处理、 常见Linux命令。 Python数据结构: 数字、字符串、列表、元组、字典。
官方微信
联系客服
400-826-7010
7x24小时客服热线
分享
  • QQ好友
  • QQ空间
  • 微信
  • 微博
返回顶部