未验证 提交 63861f32 编写于 作者: P Pei Yang 提交者: GitHub

refine native infer doc and index, test=develop, test=document_preview (#1431)

上级 3df76b0f
......@@ -2,7 +2,15 @@
服务器端部署
############
PaddlePaddle Fluid 提供了 C++ API 来支持模型的部署上线
推理(Inference)指的是在设备上运行训练好的模型,依据输入数据来进行预测。Paddle Fluid提供了预测库及其C++和Python的API来支持模型的部署上线。
使用Paddle Fluid预测主要包含以下几个步骤:
1. 加载由Paddle Fluid训练的模型和参数文件;
2. 准备输入数据。即将待预测的数据(如图片)转换成Paddle Fluid模型接受的格式,并将其设定为预测引擎的输入;
3. 运行预测引擎,获得模型的输出;
4. 根据业务需求解析输出结果,获得需要的信息。
以上步骤使用的API会在后续部分进行详细介绍。
.. toctree::
:titlesonly:
......
# C++ 预测 API介绍
为了更简单方便的预测部署,PaddlePaddle 提供了一套高层 API 预测接口。
预测库包含:
- 头文件主要包括:
- `paddle_analysis_config.h `
- `paddle_api.h `
- `paddle_inference_api.h`
- 库文件:
- `libpaddle_fluid.so`
- `libpaddle_fluid.a`
为了更简单方便地预测部署,PaddlePaddle 提供了一套高层 C++ API 预测接口。
下面是详细介绍。
## 内容
- [NativePredictor使用](#NativePredictor使用)
- [AnalysisPredictor使用](#AnalysisPredictor使用)
- [输入输出的管理](#输入输出的管理)
- [多线程预测](#多线程预测)
- [性能建议](#性能建议)
## <a name="NativePredictor使用">NativePredictor使用</a>
- [使用AnalysisPredictor进行高性能预测](#使用AnalysisPredictor进行高性能预测)
- [使用AnalysisConfig管理预测配置](#使用AnalysisConfig管理预测配置)
- [使用ZeroCopyTensor管理输入/输出](#使用ZeroCopyTensor管理输入/输出)
- [C++预测样例编译测试](#C++预测样例编译测试)
- [性能调优](#性能调优)
`NativePredictor`为原生预测引擎,底层由 PaddlePaddle 原生的 forward operator
组成,可以天然**支持所有Paddle 训练出的模型**
#### NativePredictor 使用样例
```c++
#include "paddle_inference_api.h"
namespace paddle {
// 配置NativeConfig
void CreateConfig(NativeConfig *config, const std::string& model_dirname) {
config->use_gpu=true;
config->device=0;
config->fraction_of_gpu_memory=0.1;
/* for cpu
config->use_gpu=false;
config->SetCpuMathLibraryNumThreads(1);
*/
// 设置模型的参数路径
config->prog_file = model_dirname + "model";
config->param_file = model_dirname + "params";
// 当模型输入是多个的时候,这个配置是必要的。
config->specify_input_name = true;
}
void RunNative(int batch_size, const std::string& model_dirname) {
// 1. 创建NativeConfig
NativeConfig config;
CreateConfig(&config, model_dirname);
// 2. 根据config 创建predictor
auto predictor = CreatePaddlePredictor(config);
int channels = 3;
int height = 224;
int width = 224;
float *data = new float[batch_size * channels * height * width];
// 3. 创建输入 tensor
PaddleTensor tensor;
tensor.name = "image";
tensor.shape = std::vector<int>({batch_size, channels, height, width});
tensor.data = PaddleBuf(static_cast<void *>(data),
sizeof(float) * (batch_size * channels * height * width));
tensor.dtype = PaddleDType::FLOAT32;
std::vector<PaddleTensor> paddle_tensor_feeds(1, tensor);
// 4. 创建输出 tensor
std::vector<PaddleTensor> outputs;
// 5. 预测
predictor->Run(paddle_tensor_feeds, &outputs, batch_size);
const size_t num_elements = outputs.front().data.length() / sizeof(float);
auto *data_out = static_cast<float *>(outputs.front().data.data());
}
} // namespace paddle
int main() {
// 模型下载地址 http://paddle-inference-dist.cdn.bcebos.com/tensorrt_test/mobilenet.tar.gz
paddle::RunNative(1, "./mobilenet");
return 0;
}
```
## <a name="使用AnalysisPredictor进行高性能预测"> 使用AnalysisPredictor进行高性能预测</a>
Paddle Fluid采用 AnalysisPredictor 进行预测。AnalysisPredictor 是一个高性能预测引擎,该引擎通过对计算图的分析,完成对计算图的一系列的优化(如OP的融合、内存/显存的优化、 MKLDNN,TensorRT 等底层加速库的支持等),能够大大提升预测性能。
## <a name="AnalysisPredictor使用"> AnalysisPredictor使用</a>
AnalysisConfig 创建了一个高性能预测引擎。该引擎通过对计算图的分析,完成对计算图的一系列的优化(Op 的融合, MKLDNN,TRT等底层加速库的支持 etc),大大提升预测引擎的性能。
为了展示完整的预测流程,下面是一个使用 AnalysisPredictor 进行预测的完整示例,其中涉及到的具体概念和配置会在后续部分展开详细介绍。
#### AnalysisPredictor 使用样
#### AnalysisPredictor 预测示
```c++
#include "paddle_inference_api.h"
......@@ -101,25 +29,25 @@ namespace paddle {
void CreateConfig(AnalysisConfig* config, const std::string& model_dirname) {
// 模型从磁盘进行加载
config->SetModel(model_dirname + "/model",
model_dirname + "/params");
model_dirname + "/params");
// config->SetModel(model_dirname);
// 如果模型从内存中加载,可以使用SetModelBuffer接口
// config->SetModelBuffer(prog_buffer, prog_size, params_buffer, params_size);
config->EnableUseGpu(10 /*the initial size of the GPU memory pool in MB*/, 0 /*gpu_id*/);
config->EnableUseGpu(100 /*设定GPU初始显存池为MB*/, 0 /*设定GPU ID为0*/); //开启GPU预测
/* for cpu
config->DisableGpu();
config->EnableMKLDNN(); // 可选
config->EnableMKLDNN(); // 开启MKLDNN加速
config->SetCpuMathLibraryNumThreads(10);
*/
// 当使用ZeroCopyTensor的时候,此处一定要设置为false。
// 使用ZeroCopyTensor,此处必须设置为false
config->SwitchUseFeedFetchOps(false);
// 当多输入的时候,此处一定要设置为true
// 若输入为多个,此处必须设置为true
config->SwitchSpecifyInputNames(true);
config->SwitchIrDebug(true); // 开关打开,会在每个图优化过程后生成dot文件,方便可视化。
// config->SwitchIrOptim(false); // 默认为true。如果设置为false,关闭所有优化,执行过程同 NativePredictor
// config->EnableMemoryOptim(); // 开启内存/显存复用
config->SwitchIrDebug(true); // 可视化调试选项,若开启,则会在每个图优化过程后生成dot文件
// config->SwitchIrOptim(false); // 默认为true。如果设置为false,关闭所有优化
// config->EnableMemoryOptim(); // 开启内存/显存复用
}
void RunAnalysis(int batch_size, std::string model_dirname) {
......@@ -127,7 +55,7 @@ void RunAnalysis(int batch_size, std::string model_dirname) {
AnalysisConfig config;
CreateConfig(&config, model_dirname);
// 2. 根据config 创建predictor
// 2. 根据config 创建predictor,并准备输入数据,此处以全0数据为例
auto predictor = CreatePaddlePredictor(config);
int channels = 3;
int height = 224;
......@@ -135,14 +63,13 @@ void RunAnalysis(int batch_size, std::string model_dirname) {
float input[batch_size * channels * height * width] = {0};
// 3. 创建输入
// 同NativePredictor样例一样,此处可以使用PaddleTensor来创建输入
// 以下的代码中使用了ZeroCopy的接口,同使用PaddleTensor不同的是:此接口可以避免预测中多余的cpu copy,提升预测性能。
auto input_names = predictor->GetInputNames();
// 使用了ZeroCopy接口,可以避免预测中多余的CPU copy,提升预测性能
auto input_names = predictor->GetInputNames();
auto input_t = predictor->GetInputTensor(input_names[0]);
input_t->Reshape({batch_size, channels, height, width});
input_t->copy_from_cpu(input);
// 4. 运行
// 4. 运行预测引擎
CHECK(predictor->ZeroCopyRun());
// 5. 获取输出
......@@ -166,24 +93,61 @@ int main() {
```
## <a name="输入输出的管理"> 输入输出的管理</a>
### PaddleTensor 的使用
PaddleTensor可用于NativePredictor和AnalysisPredictor,在 NativePredictor样例中展示了PaddleTensor的使用方式。
PaddleTensor 定义了预测最基本的输入输出的数据格式,常用字段如下:
## <a name="使用AnalysisConfig管理预测配置"> 使用AnalysisConfig管理预测配置</a>
AnalysisConfig管理AnalysisPredictor的预测配置,提供了模型路径设置、预测引擎运行设备选择以及多种优化预测流程的选项。配置方法如下:
#### 设置模型和参数路径
从磁盘加载模型时,根据模型和参数文件存储方式不同,设置AnalysisConfig加载模型和参数的路径有两种形式:
- `name`,类型:string,用于指定输入数据对应的模型中variable的名字
- `shape`,类型:`vector<int>`, 表示一个Tensor的shape
- `data`,类型:`PaddleBuf`, 数据以连续内存的方式存储在`PaddleBuf`中,`PaddleBuf`可以接收外面的数据或者独立`malloc`内存,详细可以参考头文件中相关定义。
- `dtype`,类型:`PaddleType`, 有`PaddleDtype::FLOAT32`, `PaddleDtype::INT64`, `PaddleDtype::INT32`三种, 表示 Tensor 的数据类型。
- `lod`,类型:`vector<vector<size_t>>`,在处理变长输入的时候,需要对 `PaddleTensor`设置LoD信息。可以参考[LoD-Tensor使用说明](../../../user_guides/howto/basic_concept/lod_tensor.html)
* conbined形式:模型文件夹`model_dir`下存在一个模型文件和多个参数文件时,传入模型文件夹路径,模型文件名默认为`__model__`
``` c++
config->SetModel("./model_dir");
```
* 非combined形式:模型文件夹`model_dir`下只有一个模型文件`model`和一个参数文件`params`时,传入模型文件和参数文件路径。
``` c++
config->SetModel("./model_dir/model", "./model_dir/params");
```
### ZeroCopyTensor的使用
ZeroCopyTensor的使用可避免预测时候准备输入以及获取输出时多余的数据copy,提高预测性能。**只可用于AnalysisPredictor**
#### 通用优化配置
``` c++
config->SwitchIrOptim(true); // 开启计算图分析优化,包括OP融合等
config->EnableMemoryOptim(); // 开启内存/显存复用
```
**Note:** 使用ZeroCopyTensor必须设置:
``` c++
config->SwitchUseFeedFetchOps(false); // 关闭feed和fetch OP使用,使用ZeroCopy接口必须设置此项
```
**Note:**使用ZeroCopyTensor,务必在创建config时设置`config->SwitchUseFeedFetchOps(false)`
#### 配置CPU预测
``` c++
config->DisableGpu(); // 禁用GPU
config->EnableMKLDNN(); // 开启MKLDNN,可加速CPU预测
config->SetCpuMathLibraryNumThreads(10); // 设置CPU Math库线程数,CPU核心数支持情况下可加速预测
```
#### 配置GPU预测
``` c++
config->EnableUseGpu(100, 0); // 初始化100M显存,使用GPU ID为0
config->GpuDeviceId(); // 返回正在使用的GPU ID
// 开启TensorRT预测,可提升GPU预测性能,需要使用带TensorRT的预测库
config->EnableTensorRtEngine(1 << 20 /*workspace_size*/,
batch_size /*max_batch_size*/,
3 /*min_subgraph_size*/,
AnalysisConfig::Precision::kFloat32 /*precision*/,
false /*use_static*/,
false /*use_calib_mode*/);
```
## <a name="使用ZeroCopyTensor管理输入/输出"> 使用ZeroCopyTensor管理输入/输出</a>
ZeroCopyTensor是AnalysisPredictor的输入/输出数据结构。ZeroCopyTensor的使用可以避免预测时候准备输入以及获取输出时多余的数据copy,提高预测性能。
**Note:** 使用ZeroCopyTensor,务必在创建config时设置`config->SwitchUseFeedFetchOps(false);`
```c++
// 通过创建的AnalysisPredictor获取输入和输出的tensor
auto input_names = predictor->GetInputNames();
auto input_t = predictor->GetInputTensor(input_names[0]);
......@@ -201,54 +165,77 @@ output_t->copy_to_cpu(out_data /*数据指针*/);
std::vector<std::vector<size_t>> lod_data = {{0}, {0}};
input_t->SetLoD(lod_data);
// 获取tensor数据指针
// 获取Tensor数据指针
float *input_d = input_t->mutable_data<float>(PaddlePlace::kGPU); // CPU下使用PaddlePlace::kCPU
int output_size;
float *output_d = output_t->data<float>(PaddlePlace::kGPU, &output_size);
```
## <a name="多线程预测"> 多线程预测</a>
多线程场景下,每个服务线程执行同一种模型,支持 CPU 和 GPU。
## <a name="C++预测样例编译测试"> C++预测样例编译测试</a>
1. 下载或编译paddle预测库,参考[安装与编译C++预测库](./build_and_install_lib_cn.html)
2. 下载[预测样例](https://paddle-inference-dist.bj.bcebos.com/tensorrt_test/paddle_inference_sample_v1.6.tar.gz)并解压,进入`sample/inference`目录下。
`inference` 文件夹目录结构如下:
```shell
inference
├── CMakeLists.txt
├── mobilenet_test.cc
├── thread_mobilenet_test.cc
├── mobilenetv1
│ ├── model
│ └── params
├── run.sh
└── run_impl.sh
```
- `mobilenet_test.cc` 为单线程预测的C++源文件
- `thread_mobilenet_test.cc` 为多线程预测的C++源文件
- `mobilenetv1` 为模型文件夹
- `run.sh` 为预测运行脚本文件
3. 配置编译与运行脚本
编译运行预测样例之前,需要根据运行环境配置编译与运行脚本`run.sh``run.sh`的选项与路径配置的部分如下:
```shell
# 设置是否开启MKL、GPU、TensorRT,如果要使用TensorRT,必须打开GPU
WITH_MKL=ON
WITH_GPU=OFF
USE_TENSORRT=OFF
# 按照运行环境设置预测库路径、CUDA库路径、CUDNN库路径、模型路径
LIB_DIR=YOUR_LIB_DIR
CUDA_LIB_DIR=YOUR_CUDA_LIB_DIR
CUDNN_LIB_DIR=YOUR_CUDNN_LIB_DIR
MODEL_DIR=YOUR_MODEL_DIR
```
按照实际运行环境配置`run.sh`中的选项开关和所需lib路径。
4. 编译与运行样例
```shell
sh run.sh
```
## <a name="性能调优"> 性能调优</a>
### CPU下预测
1. 在CPU型号允许的情况下,尽量使用带AVX和MKL的版本。
2. 可以尝试使用Intel的 MKLDNN 加速。
3. 在CPU可用核心数足够时,可以将设置`config->SetCpuMathLibraryNumThreads(num);`中的num值调高一些。
### GPU下预测
1. 可以尝试打开 TensorRT 子图加速引擎, 通过计算图分析,Paddle可以自动将计算图中部分子图融合,并调用NVIDIA的 TensorRT 来进行加速,详细内容可以参考 [使用Paddle-TensorRT库预测](./paddle_tensorrt_infer.html)
### 多线程预测
Paddle Fluid支持通过在不同线程运行多个AnalysisPredictor的方式来优化预测性能,支持CPU和GPU环境。
使用多线程预测的样例详见[C++预测样例编译测试](#C++预测样例编译测试)中下载的[预测样例](https://paddle-inference-dist.cdn.bcebos.com/tensorrt_test/paddle_trt_samples_v1.6.tar.gz)中的
`thread_mobilenet_test.cc`文件。可以将`run.sh``mobilenet_test`替换成`thread_mobilenet_test`再执行
下面演示最简单的实现,用户需要根据具体应用场景做相应的调整
```c++
auto main_predictor = paddle::CreatePaddlePredictor(config);
const int num_threads = 10; // 假设有 10 个服务线程
std::vector<std::thread> threads;
std::vector<decl_type(main_predictor)> predictors;
// 将克隆的 predictor 放入 vector 供线程使用
for (int i = 0; i < num_threads; i++) {
predictors.emplace_back(main_predictor->Clone());
}
// 创建线程并执行
for (int i = 0; i < num_threads; i++) {
threads.emplace_back([i, &]{
auto& predictor = predictors[i];
// 执行
CHECK(predictor->Run(...));
});
}
// 线程join
for (auto& t : threads) {
if (t.joinable()) t.join();
}
// 结束
```
sh run.sh
```
## <a name="性能建议"> 性能建议</a>
1. 在CPU型号允许的情况下,尽量使用带AVX和MKL的版本
2. CPU或GPU预测,可以尝试把`NativeConfig`改成`AnalysisConfig`来进行优化
3. 尽量使用`ZeroCopyTensor`避免过多的内存copy
4. CPU下可以尝试使用Intel的`MKLDNN`加速
5. GPU 下可以尝试打开`TensorRT`子图加速引擎, 通过计算图分析,Paddle可以自动将计算图中部分子图切割,并调用NVidia的 `TensorRT` 来进行加速。
详细内容可以参考 [Paddle-TRT 子图引擎](./paddle_tensorrt_infer.html)
即可运行多线程预测样例。
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册