C++ 预测 API介绍

为了更简单方便地预测部署,PaddlePaddle 提供了一套高层 C++ API 预测接口。

下面是详细介绍。

内容

使用AnalysisPredictor进行高性能预测

Paddle Fluid采用 AnalysisPredictor 进行预测。AnalysisPredictor 是一个高性能预测引擎,该引擎通过对计算图的分析,完成对计算图的一系列的优化(如OP的融合、内存/显存的优化、 MKLDNN,TensorRT 等底层加速库的支持等),能够大大提升预测性能。

为了展示完整的预测流程,下面是一个使用 AnalysisPredictor 进行预测的完整示例,其中涉及到的具体概念和配置会在后续部分展开详细介绍。

AnalysisPredictor 预测示例

  1. #include "paddle_inference_api.h"
  2.  
  3. namespace paddle {
  4. void CreateConfig(AnalysisConfig* config, const std::string& model_dirname) {
  5. // 模型从磁盘进行加载
  6. config->SetModel(model_dirname + "/model",
  7. model_dirname + "/params");
  8. // config->SetModel(model_dirname);
  9. // 如果模型从内存中加载,可以使用SetModelBuffer接口
  10. // config->SetModelBuffer(prog_buffer, prog_size, params_buffer, params_size);
  11. config->EnableUseGpu(100 /*设定GPU初始显存池为MB*/, 0 /*设定GPU ID为0*/); //开启GPU预测
  12.  
  13. /* for cpu
  14. config->DisableGpu();
  15. config->EnableMKLDNN(); // 开启MKLDNN加速
  16. config->SetCpuMathLibraryNumThreads(10);
  17. */
  18.  
  19. // 使用ZeroCopyTensor,此处必须设置为false
  20. config->SwitchUseFeedFetchOps(false);
  21. // 若输入为多个,此处必须设置为true
  22. config->SwitchSpecifyInputNames(true);
  23. config->SwitchIrDebug(true); // 可视化调试选项,若开启,则会在每个图优化过程后生成dot文件
  24. // config->SwitchIrOptim(false); // 默认为true。如果设置为false,关闭所有优化
  25. // config->EnableMemoryOptim(); // 开启内存/显存复用
  26. }
  27.  
  28. void RunAnalysis(int batch_size, std::string model_dirname) {
  29. // 1. 创建AnalysisConfig
  30. AnalysisConfig config;
  31. CreateConfig(&config, model_dirname);
  32.  
  33. // 2. 根据config 创建predictor,并准备输入数据,此处以全0数据为例
  34. auto predictor = CreatePaddlePredictor(config);
  35. int channels = 3;
  36. int height = 224;
  37. int width = 224;
  38. float input[batch_size * channels * height * width] = {0};
  39.  
  40. // 3. 创建输入
  41. // 使用了ZeroCopy接口,可以避免预测中多余的CPU copy,提升预测性能
  42. auto input_names = predictor->GetInputNames();
  43. auto input_t = predictor->GetInputTensor(input_names[0]);
  44. input_t->Reshape({batch_size, channels, height, width});
  45. input_t->copy_from_cpu(input);
  46.  
  47. // 4. 运行预测引擎
  48. CHECK(predictor->ZeroCopyRun());
  49.  
  50. // 5. 获取输出
  51. std::vector<float> out_data;
  52. auto output_names = predictor->GetOutputNames();
  53. auto output_t = predictor->GetOutputTensor(output_names[0]);
  54. std::vector<int> output_shape = output_t->shape();
  55. int out_num = std::accumulate(output_shape.begin(), output_shape.end(), 1, std::multiplies<int>());
  56.  
  57. out_data.resize(out_num);
  58. output_t->copy_to_cpu(out_data.data());
  59. }
  60. } // namespace paddle
  61.  
  62. int main() {
  63. // 模型下载地址 http://paddle-inference-dist.cdn.bcebos.com/tensorrt_test/mobilenet.tar.gz
  64. paddle::RunAnalysis(1, "./mobilenet");
  65. return 0;
  66. }

使用AnalysisConfig管理预测配置

AnalysisConfig管理AnalysisPredictor的预测配置,提供了模型路径设置、预测引擎运行设备选择以及多种优化预测流程的选项。配置方法如下:

通用优化配置

  1. config->SwitchIrOptim(true); // 开启计算图分析优化,包括OP融合等
  2. config->EnableMemoryOptim(); // 开启内存/显存复用

Note: 使用ZeroCopyTensor必须设置:

  1. config->SwitchUseFeedFetchOps(false); // 关闭feed和fetch OP使用,使用ZeroCopy接口必须设置此项

设置模型和参数路径

从磁盘加载模型时,根据模型和参数文件存储方式不同,设置AnalysisConfig加载模型和参数的路径有两种形式:

  • 非combined形式:模型文件夹model_dir下存在一个模型文件和多个参数文件时,传入模型文件夹路径,模型文件名默认为__model__
  1. config->SetModel("./model_dir");
  • combined形式:模型文件夹model_dir下只有一个模型文件model和一个参数文件params时,传入模型文件和参数文件路径。
  1. config->SetModel("./model_dir/model", "./model_dir/params");

配置CPU预测

  1. config->DisableGpu(); // 禁用GPU
  2. config->EnableMKLDNN(); // 开启MKLDNN,可加速CPU预测
  3. config->SetCpuMathLibraryNumThreads(10); // 设置CPU Math库线程数,CPU核心数支持情况下可加速预测

配置GPU预测

  1. config->EnableUseGpu(100, 0); // 初始化100M显存,使用GPU ID为0
  2. config->GpuDeviceId(); // 返回正在使用的GPU ID
  3. // 开启TensorRT预测,可提升GPU预测性能,需要使用带TensorRT的预测库
  4. config->EnableTensorRtEngine(1 << 20 /*workspace_size*/,
  5. batch_size /*max_batch_size*/,
  6. 3 /*min_subgraph_size*/,
  7. AnalysisConfig::Precision::kFloat32 /*precision*/,
  8. false /*use_static*/,
  9. false /*use_calib_mode*/);

使用ZeroCopyTensor管理输入/输出

ZeroCopyTensor是AnalysisPredictor的输入/输出数据结构。ZeroCopyTensor的使用可以避免预测时候准备输入以及获取输出时多余的数据copy,提高预测性能。

Note: 使用ZeroCopyTensor,务必在创建config时设置config->SwitchUseFeedFetchOps(false);

  1. // 通过创建的AnalysisPredictor获取输入和输出的tensor
  2. auto input_names = predictor->GetInputNames();
  3. auto input_t = predictor->GetInputTensor(input_names[0]);
  4. auto output_names = predictor->GetOutputNames();
  5. auto output_t = predictor->GetOutputTensor(output_names[0]);
  6.  
  7. // 对tensor进行reshape
  8. input_t->Reshape({batch_size, channels, height, width});
  9.  
  10. // 通过copy_from_cpu接口,将cpu数据输入;通过copy_to_cpu接口,将输出数据copy到cpu
  11. input_t->copy_from_cpu<float>(input_data /*数据指针*/);
  12. output_t->copy_to_cpu(out_data /*数据指针*/);
  13.  
  14. // 设置LOD
  15. std::vector<std::vector<size_t>> lod_data = {{0}, {0}};
  16. input_t->SetLoD(lod_data);
  17.  
  18. // 获取Tensor数据指针
  19. float *input_d = input_t->mutable_data<float>(PaddlePlace::kGPU); // CPU下使用PaddlePlace::kCPU
  20. int output_size;
  21. float *output_d = output_t->data<float>(PaddlePlace::kGPU, &output_size);

C++预测样例编译测试

inference 文件夹目录结构如下:

  1. inference
  2. ├── CMakeLists.txt
  3. ├── mobilenet_test.cc
  4. ├── thread_mobilenet_test.cc
  5. ├── mobilenetv1
  6. ├── model
  7. └── params
  8. ├── run.sh
  9. └── run_impl.sh
  • mobilenet_test.cc 为单线程预测的C++源文件
  • thread_mobilenet_test.cc 为多线程预测的C++源文件
  • mobilenetv1 为模型文件夹
  • run.sh 为预测运行脚本文件
    • 配置编译与运行脚本

编译运行预测样例之前,需要根据运行环境配置编译与运行脚本run.shrun.sh的选项与路径配置的部分如下:

  1. # 设置是否开启MKL、GPU、TensorRT,如果要使用TensorRT,必须打开GPU
  2. WITH_MKL=ON
  3. WITH_GPU=OFF
  4. USE_TENSORRT=OFF
  5.  
  6. # 按照运行环境设置预测库路径、CUDA库路径、CUDNN库路径、TensorRT路径、模型路径
  7. LIB_DIR=YOUR_LIB_DIR
  8. CUDA_LIB_DIR=YOUR_CUDA_LIB_DIR
  9. CUDNN_LIB_DIR=YOUR_CUDNN_LIB_DIR
  10. TENSORRT_ROOT_DIR=YOUR_TENSORRT_ROOT_DIR
  11. MODEL_DIR=YOUR_MODEL_DIR

按照实际运行环境配置run.sh中的选项开关和所需lib路径。

  • 编译与运行样例
  1. sh run.sh

性能调优

CPU下预测

  • 在CPU型号允许的情况下,尽量使用带AVX和MKL的版本。
  • 可以尝试使用Intel的 MKLDNN 加速。
  • 在CPU可用核心数足够时,可以将设置config->SetCpuMathLibraryNumThreads(num);中的num值调高一些。

GPU下预测

  • 可以尝试打开 TensorRT 子图加速引擎, 通过计算图分析,Paddle可以自动将计算图中部分子图融合,并调用NVIDIA的 TensorRT 来进行加速,详细内容可以参考 使用Paddle-TensorRT库预测

多线程预测

Paddle Fluid支持通过在不同线程运行多个AnalysisPredictor的方式来优化预测性能,支持CPU和GPU环境。

使用多线程预测的样例详见C++预测样例编译测试中下载的预测样例中的 thread_mobilenet_test.cc文件。可以将run.shmobilenet_test替换成thread_mobilenet_test再执行

  1. sh run.sh

即可运行多线程预测样例。