目录
1.简介
1.1与模型直接推理的比较
1.2流程图
1.3高性能
1.4多功能集成
2.预测部署示例--python
2.1模型获取
2.1.1paddlepaddle框架
2.1.2Tensorflow、Pytorch、Caffe
2.2paddle-inference的使用
2.3完整可运行代码
1.简介
Paddle Inference 是飞桨的原生推理库, 作用于服务器端和云端,提供高性能的推理能力。
由于能力直接基于飞桨的训练算子,因此Paddle Inference 可以通用支持飞桨训练出的所有模型。
Paddle Inference 功能特性丰富,性能优异,针对不同平台不同的应用场景进行了深度的适配优化,做到高吞吐、低时延,保证了飞桨模型在服务器端即训即用,快速部署。
1.1与模型直接推理的比较
训练好的模型直接转为eval评估模式也可以进行推理,那么为什么还要使用inference库呢。
相比于模型的推理模式,inference可使用MKLDNN、CUDNN、TensorRT进行预测加速,同时支持用 X2Paddle 工具从第三方框架(TensorFlow、Pytorh 、 Caffe 等)产出的模型,可联动PaddleSlim,支持加载量化、裁剪和蒸馏后的模型部署。
eval模式的模型适用于训练好的模型直接进行预测,paddle inference适用于对推理性能、通用性有要求的用户,针对不同平台不同的应用场景进行了深度的适配优化,保证模型在服务器端即训即用,快速部署。
1.2流程图
1.3高性能
-
内存/显存复用提升服务吞吐量
- 在推理初始化阶段,对模型中的OP输出Tensor 进行依赖分析,将两两互不依赖的Tensor在内存/显存空间上进行复用,进而增大计算并行量,提升服务吞吐量。
-
细粒度OP横向纵向融合减少计算量
- 在推理初始化阶段,按照已有的融合模式将模型中的多个OP融合成一个OP,减少了模型的计算量的同时,也减少了 Kernel Launch的次数,从而能提升推理性能。目前Paddle Inference支持的融合模式多达几十个。
-
内置高性能的CPU/GPU Kernel
- 内置同Intel、Nvidia共同打造的高性能kernel,保证了模型推理高性能的执行。
1.4多功能集成
-
集成TensorRT加快GPU推理速度
- Paddle Inference采用子图的形式集成TensorRT,针对GPU推理场景,TensorRT可对一些子图进行优化,包括OP的横向和纵向融合,过滤冗余的OP,并为OP自动选择最优的kernel,加快推理速度。
-
集成oneDNN CPU推理加速引擎
- 一行代码开始oneDNN加速,快捷高效。
-
支持PaddleSlim量化压缩模型的部署
- PaddleSlim是飞桨深度学习模型压缩工具,Paddle Inference可联动PaddleSlim,支持加载量化、裁剪和蒸馏后的模型并部署,由此减小模型存储空间、减少计算占用内存、加快模型推理速度。其中在模型量化方面,Paddle Inference在X86 CPU上做了深度优化,常见分类模型的单线程性能可提升近3倍,ERNIE模型的单线程性能可提升2.68倍。
-
支持X2Paddle转换得到的模型
- 除支持飞桨训练的模型外,也支持用 X2Paddle 工具从第三方框架(比如 TensorFlow、Pytorch 或者 Caffe 等)产出的模型。
2.预测部署示例--python
2.1模型获取
2.1.1paddlepaddle框架
paddlepaddle既支持动态图也支持静态图的开发,训练好的动态图模型可通过两部保存为静态图,静态图用于推理部署性能更优。
第一步:加载模型和参数,使用paddle.load()
model_state_dict = paddle.load('lenet.pdparams')
opt_state_dict = paddle.load('lenet.pdopt')
model.set_state_dict(model_state_dict)
optim.set_state_dict(opt_state_dict)
第二步:转为静态图后保存,调用paddle.jit.to_static转换,
paddle.jit.save保存
net = to_static(model, input_spec=[InputSpec(shape=[None, 1, 28, 28], name='x')])
paddle.jit.save(net, 'inference_model/lenet')
2.1.2Tensorflow、Pytorch、Caffe
用 X2Paddle 工具从第三方框架(TensorFlow、Pytorh 、 Caffe 等)产出的模型转为paddlepaddle inference支持的模型。
2.2paddle-inference的使用
简单使用的几个步骤:
加载预测模型并进行预测配置
首先,我们加载预测模型,并配置预测时的一些选项,根据配置创建预测引擎:
config = Config("inference_model/lenet/lenet.pdmodel", "inference_model/lenet/lenet.pdiparams") # 通过模型和参数文件路径加载
config.disable_gpu() # 使用cpu预测
predictor = create_predictor(config) # 根据预测配置创建预测引擎predictor
设置输入
我们先通过获取输入Tensor的名称,再根据名称获取到输入Tensor的句柄。
# 获取输入变量名称
input_names = predictor.get_input_names()
input_handle = predictor.get_input_handle(input_names[0])
下面我们准备输入数据,并将其拷贝至待预测的设备上。这里我们使用了随机数据,在实际使用中可以将其换为需要预测的真实图片。
### 设置输入
fake_input = np.random.randn(1, 1, 28, 28).astype("float32")
input_handle.reshape([1, 1, 28, 28])
input_handle.copy_from_cpu(fake_input)
运行预测
predictor.run()
获取输出
# 获取输出变量名称
output_names = predictor.get_output_names()
output_handle = predictor.get_output_handle(output_names[0])
output_data = output_handle.copy_to_cpu()
2.3完整可运行代码
准备模型:ResNet50,可从下面的链接下载,该模型是paddle静态图模型,可直接使用
wget https://paddle-inference-dist.bj.bcebos.com/Paddle-Inference-Demo/resnet50.tgz
tar zxf resnet50.tgz# 获得模型目录即文件如下
resnet50/
├── inference.pdmodel
├── inference.pdiparams.info
└── inference.pdiparams
将以下代码保存为 python_demo.py
文件:
可以看到,这就是上述inference使用方式介绍的代码加上argparse解析库封装后得到的程序
import argparse
import numpy as np# 引用 paddle inference 预测库
import paddle.inference as paddle_inferdef main():args = parse_args()# 创建 configconfig = paddle_infer.Config(args.model_file, args.params_file)# 根据 config 创建 predictorpredictor = paddle_infer.create_predictor(config)# 获取输入的名称input_names = predictor.get_input_names()input_handle = predictor.get_input_handle(input_names[0])# 设置输入fake_input = np.random.randn(args.batch_size, 3, 318, 318).astype("float32")input_handle.reshape([args.batch_size, 3, 318, 318])input_handle.copy_from_cpu(fake_input)# 运行predictorpredictor.run()# 获取输出output_names = predictor.get_output_names()output_handle = predictor.get_output_handle(output_names[0])output_data = output_handle.copy_to_cpu() # numpy.ndarray类型print("Output data size is {}".format(output_data.size))print("Output data shape is {}".format(output_data.shape))def parse_args():parser = argparse.ArgumentParser()parser.add_argument("--model_file", type=str, help="model filename")parser.add_argument("--params_file", type=str, help="parameter filename")parser.add_argument("--batch_size", type=int, default=1, help="batch size")return parser.parse_args()if __name__ == "__main__":main()
执行程序:
# 参数输入为本章节第2步中下载的 ResNet50 模型
python python_demo.py --model_file ./resnet50/inference.pdmodel --params_file ./resnet50/inference.pdiparams --batch_size 2
结果