飞桨框架ROCm版预测示例

使用海光CPU/DCU进行预测与使用Intel CPU/Nvidia GPU预测相同,支持飞桨原生推理库(Paddle Inference),适用于高性能服务器端、云端推理。当前Paddle ROCm版本完全兼容Paddle CUDA版本的 C++/Python API,直接使用原有的GPU预测命令和参数即可。

C++预测部署

注意:更多C++预测API使用说明请参考 Paddle Inference - C++ API

第一步:源码编译C++预测库

当前 Paddle ROCm版只支持通过源码编译的方式提供C++预测库。编译环境准备请参考 飞桨框架ROCm版安装说明:通过源码编译安装

  1. # 下载源码,切换到 release/2.1 分支
  2. git clone -b release/2.1 https://github.com/PaddlePaddle/Paddle.git
  3. cd Paddle
  4. # 创建编译目录
  5. mkdir build && cd build
  6. # 执行cmake,注意这里需打开预测优化选项 ON_INFER
  7. cmake .. -DPY_VERSION=3.7 -DWITH_ROCM=ON -DWITH_TESTING=OFF -DON_INFER=ON
  8. -DWITH_MKL=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
  9. # 使用以下命令来编译
  10. make -j$(nproc)

编译完成之后,build 目录下的 paddle_inference_install_dir 即为 C++ 预测库,目录结构如下:

  1. build/paddle_inference_install_dir
  2. ├── CMakeCache.txt
  3. ├── paddle
  4. ├── include C++ 预测库头文件目录
  5. ├── crypto
  6. ├── experimental
  7. ├── internal
  8. ├── paddle_analysis_config.h
  9. ├── paddle_api.h
  10. ├── paddle_infer_declare.h
  11. ├── paddle_inference_api.h C++ 预测库头文件
  12. ├── paddle_mkldnn_quantizer_config.h
  13. ├── paddle_pass_builder.h
  14. └── paddle_tensor.h
  15. └── lib
  16. ├── libpaddle_inference.a C++ 静态预测库文件
  17. └── libpaddle_inference.so C++ 动态态预测库文件
  18. ├── third_party
  19. ├── install 第三方链接库和头文件
  20. ├── cryptopp
  21. ├── gflags
  22. ├── glog
  23. ├── mkldnn
  24. ├── mklml
  25. ├── protobuf
  26. └── xxhash
  27. └── threadpool
  28. └── ThreadPool.h
  29. └── version.txt

其中 version.txt 文件中记录了该预测库的版本信息,包括Git Commit ID、使用OpenBlas或MKL数学库、ROCm/MIOPEN版本号,如:

  1. GIT COMMIT ID: e75412099f97a49701324788b468d80391293ea9
  2. WITH_MKL: ON
  3. WITH_MKLDNN: ON
  4. WITH_GPU: OFF
  5. WITH_ROCM: ON
  6. HIP version: 4.0.20496-4f163c68
  7. MIOpen version: v2.11
  8. CXX compiler version: 7.3.1

第二步:准备预测部署模型

下载 ResNet50 模型后解压,得到 Paddle 预测格式的模型,位于文件夹 ResNet50 下。如需查看模型结构,可将 inference.pdmodel 文件通过模型可视化工具 Netron 打开。

  1. wget https://paddle-inference-dist.bj.bcebos.com/Paddle-Inference-Demo/resnet50.tgz
  2. tar zxf resnet50.tgz
  3. # 获得模型目录即文件如下
  4. resnet50/
  5. ├── inference.pdmodel
  6. ├── inference.pdiparams.info
  7. └── inference.pdiparams

第三步:获取预测示例代码并编译运行

预先要求

本章节 C++ 预测示例代码位于 Paddle-Inference-Demo/c++/resnet50

请先将示例代码下载到本地,再将第一步中编译得到的 paddle_inference_install_dir 重命名为 paddle_inference 文件夹,移动到示例代码的 Paddle-Inference-Demo/c++/lib 目录下。使用到的文件如下所示:

  1. -rw-r--r-- 1 root root 3479 Jun 2 03:14 README.md README 说明
  2. -rw-r--r-- 1 root root 3051 Jun 2 03:14 resnet50_test.cc 预测 C++ 源码程序
  3. drwxr-xr-x 2 root root 4096 Mar 5 07:43 resnet50 第二步中下载并解压的预测部署模型文件夹
  4. -rw-r--r-- 1 root root 387 Jun 2 03:14 run.sh 运行脚本
  5. -rwxr-xr-x 1 root root 1077 Jun 2 03:14 compile.sh 编译脚本
  6. -rw-r--r-- 1 root root 9032 Jun 2 07:26 ../lib/CMakeLists.txt CMAKE 文件
  7. drwxr-xr-x 1 root root 9032 Jun 2 07:26 ../lib/paddle_inference 第一步编译的到的 Paddle Infernece C++ 预测库文件夹

编译运行预测样例之前,需要根据运行环境配置编译脚本 compile.sh

  1. # 根据预编译库中的 version.txt 信息判断是否将以下标记打开
  2. WITH_MKL=ON
  3. WITH_GPU=OFF # 注意这里需要关掉 WITH_GPU
  4. USE_TENSORRT=OFF
  5. WITH_ROCM=ON # 注意这里需要打开 WITH_ROCM
  6. ROCM_LIB=/opt/rocm/lib

运行 run.sh 脚本进行编译和运行,即可获取最后的预测结果:

  1. bash run.sh
  2. # 成功执行之后,得到的预测输出结果如下:
  3. ... ...
  4. I0602 04:12:03.708333 52627 analysis_predictor.cc:595] ======= optimize end =======
  5. I0602 04:12:03.709321 52627 naive_executor.cc:98] --- skip [feed], feed -> inputs
  6. I0602 04:12:03.710139 52627 naive_executor.cc:98] --- skip [save_infer_model/scale_0.tmp_1], fetch -> fetch
  7. I0602 04:12:03.711813 52627 device_context.cc:624] oneDNN v2.2.1
  8. WARNING: Logging before InitGoogleLogging() is written to STDERR
  9. I0602 04:12:04.106405 52627 resnet50_test.cc:73] run avg time is 394.801 ms
  10. I0602 04:12:04.106503 52627 resnet50_test.cc:88] 0 : 0
  11. I0602 04:12:04.106525 52627 resnet50_test.cc:88] 100 : 2.04163e-37
  12. I0602 04:12:04.106552 52627 resnet50_test.cc:88] 200 : 2.1238e-33
  13. I0602 04:12:04.106573 52627 resnet50_test.cc:88] 300 : 0
  14. I0602 04:12:04.106591 52627 resnet50_test.cc:88] 400 : 1.6849e-35
  15. I0602 04:12:04.106603 52627 resnet50_test.cc:88] 500 : 0
  16. I0602 04:12:04.106618 52627 resnet50_test.cc:88] 600 : 1.05767e-19
  17. I0602 04:12:04.106643 52627 resnet50_test.cc:88] 700 : 2.04094e-23
  18. I0602 04:12:04.106670 52627 resnet50_test.cc:88] 800 : 3.85254e-25
  19. I0602 04:12:04.106683 52627 resnet50_test.cc:88] 900 : 1.52391e-30

Python预测部署示例

注意:更多Python预测API使用说明请参考 Paddle Inference - Python API

第一步:安装 Python 预测库

Paddle ROCm 版的 Python 预测库请参考 飞桨框架ROCm版安装说明 进行安装或编译。

第二步:准备预测部署模型

下载 ResNet50 模型后解压,得到 Paddle 预测格式的模型,位于文件夹 ResNet50 下。如需查看模型结构,可将 inference.pdmodel 文件通过模型可视化工具 Netron 打开。

  1. wget https://paddle-inference-dist.bj.bcebos.com/Paddle-Inference-Demo/resnet50.tgz
  2. tar zxf resnet50.tgz
  3. # 获得模型目录即文件如下
  4. resnet50/
  5. ├── inference.pdmodel
  6. ├── inference.pdiparams.info
  7. └── inference.pdiparams

第三步:准备预测部署程序

将以下代码保存为 python_demo.py 文件:

  1. import argparse
  2. import numpy as np
  3. # 引用 paddle inference 预测库
  4. import paddle.inference as paddle_infer
  5. def main():
  6. args = parse_args()
  7. # 创建 config
  8. config = paddle_infer.Config(args.model_file, args.params_file)
  9. # 根据 config 创建 predictor
  10. predictor = paddle_infer.create_predictor(config)
  11. # 获取输入的名称
  12. input_names = predictor.get_input_names()
  13. input_handle = predictor.get_input_handle(input_names[0])
  14. # 设置输入
  15. fake_input = np.random.randn(args.batch_size, 3, 318, 318).astype("float32")
  16. input_handle.reshape([args.batch_size, 3, 318, 318])
  17. input_handle.copy_from_cpu(fake_input)
  18. # 运行predictor
  19. predictor.run()
  20. # 获取输出
  21. output_names = predictor.get_output_names()
  22. output_handle = predictor.get_output_handle(output_names[0])
  23. output_data = output_handle.copy_to_cpu() # numpy.ndarray类型
  24. print("Output data size is {}".format(output_data.size))
  25. print("Output data shape is {}".format(output_data.shape))
  26. def parse_args():
  27. parser = argparse.ArgumentParser()
  28. parser.add_argument("--model_file", type=str, help="model filename")
  29. parser.add_argument("--params_file", type=str, help="parameter filename")
  30. parser.add_argument("--batch_size", type=int, default=1, help="batch size")
  31. return parser.parse_args()
  32. if __name__ == "__main__":
  33. main()

第四步:执行预测程序

  1. # 参数输入为本章节第2步中下载的 ResNet50 模型
  2. python python_demo.py --model_file ./resnet50/inference.pdmodel
  3. --params_file ./resnet50/inference.pdiparams
  4. --batch_size 2
  5. # 成功执行之后,得到的预测输出结果如下:
  6. ... ...
  7. I0602 04:14:13.455812 52741 analysis_predictor.cc:595] ======= optimize end =======
  8. I0602 04:14:13.456934 52741 naive_executor.cc:98] --- skip [feed], feed -> inputs
  9. I0602 04:14:13.458562 52741 naive_executor.cc:98] --- skip [save_infer_model/scale_0.tmp_1], fetch -> fetch
  10. Output data size is 2000
  11. Output data shape is (2, 1000)