From ad262e4a583485072d3239c52546901678dc3eb5 Mon Sep 17 00:00:00 2001
From: Pei Yang
Date: Mon, 30 Sep 2019 12:28:51 +0800
Subject: [PATCH] Reorganized and refined tutorial doc for paddle-TensorRT.
(#1445)
* refine trt doc, test=develop, test=document_preview
* add note for adding virtual destructor for nvinfer.h, add step 1 to get infer lib with trt, test=develop, test=document_preview
---
.../deploy/inference/paddle_tensorrt_infer.md | 342 ++++++++----------
.../deploy/inference/python_infer_cn.md | 3 +-
2 files changed, 159 insertions(+), 186 deletions(-)
diff --git a/doc/fluid/advanced_usage/deploy/inference/paddle_tensorrt_infer.md b/doc/fluid/advanced_usage/deploy/inference/paddle_tensorrt_infer.md
index e05e0f3ef..da244f879 100644
--- a/doc/fluid/advanced_usage/deploy/inference/paddle_tensorrt_infer.md
+++ b/doc/fluid/advanced_usage/deploy/inference/paddle_tensorrt_infer.md
@@ -1,229 +1,151 @@
# 使用Paddle-TensorRT库预测
-NVIDIA TensorRT 是一个高性能的深度学习预测库,可为深度学习推理应用程序提供低延迟和高吞吐量。PaddlePaddle 采用了子图的形式对TensorRT进行了集成,即我们可以使用该模块来提升Paddle模型的预测性能。该模块依旧在持续开发中,目前已支持的模型有:AlexNet, MobileNetV1, ResNet50, VGG19, ResNext, Se-ReNext, GoogLeNet, DPN, ICNET, Deeplabv3, MobileNet-SSD等。在这篇文档中,我们将会对Paddle-TensorRT库的获取、使用和原理进行介绍。
+NVIDIA TensorRT 是一个高性能的深度学习预测库,可为深度学习推理应用程序提供低延迟和高吞吐量。PaddlePaddle 采用子图的形式对TensorRT进行了集成,即我们可以使用该模块来提升Paddle模型的预测性能。该模块依旧在持续开发中,目前支持的模型如下表所示:
+
+|分类模型|检测模型|分割模型|
+|---|---|---|
+|mobilenetv1|yolov3|ICNET|
+|resnet50|SSD||
+|vgg16|mask-rcnn||
+|resnext|faster-rcnn||
+|AlexNet|cascade-rcnn||
+|Se-ResNext|retinanet||
+|GoogLeNet|mobilenet-SSD||
+|DPN|||
+
+在这篇文档中,我们将会对Paddle-TensorRT库的获取、使用和原理进行介绍。
+
+**Note:**
+
+1. 从源码编译时,TensorRT预测库目前仅支持使用GPU编译,且需要设置编译选项TENSORRT_ROOT为TensorRT所在的路径。
+2. Windows支持需要TensorRT 版本5.0以上。
+3. Paddle-TRT目前仅支持固定输入shape。
+4. 若使用用户自行安装的TensorRT,需要手动在`NvInfer.h`文件中为`class IPluginFactory`和`class IGpuAllocator`分别添加虚析构函数:
+ ```c++
+ virtual ~IPluginFactory() {};
+ virtual ~IGpuAllocator() {};
+ ```
## 内容
-- [编译Paddle-TRT预测库](#编译Paddle-TRT预测库)
-- [Paddle-TRT接口使用](#Paddle-TRT接口使用)
-- [Paddle-TRT参数介绍](#Paddle-TRT参数介绍)
+- [Paddle-TRT使用介绍](#Paddle-TRT使用介绍)
- [Paddle-TRT样例编译测试](#Paddle-TRT样例编译测试)
- [Paddle-TRT INT8使用](#Paddle-TRT_INT8使用)
- [Paddle-TRT子图运行原理](#Paddle-TRT子图运行原理)
+- [Paddle-TRT性能测试](#Paddle-TRT性能测试)
+## Paddle-TRT使用介绍
-## 编译Paddle-TRT预测库
-
-**使用Docker编译预测库**
-
-TensorRT预测库目前仅支持使用GPU编译。
-
-1. 下载Paddle
-
- ```
- git clone https://github.com/PaddlePaddle/Paddle.git
- ```
-
-2. 获取docker镜像
-
- ```
- nvidia-docker run --name paddle_trt -v $PWD/Paddle:/Paddle -it hub.baidubce.com/paddlepaddle/paddle:latest-dev /bin/bash
- ```
-
-3. 编译Paddle TensorRT
-
- ```
- # 在docker容器中执行以下操作
- cd /Paddle
- mkdir build
- cd build
- # TENSORRT_ROOT为TRT的路径,默认为 /usr,根据自己需求进行改动
- # MKLDNN 可以根据自己的需求自行打开
- cmake .. \
- -DWITH_FLUID_ONLY=ON \
- -DWITH_MKL=ON \
- -DWITH_MKLDNN=OFF \
- -DCMAKE_BUILD_TYPE=Release \
- -DWITH_PYTHON=OFF \
- -DTENSORRT_ROOT=/usr \
- -DON_INFER=ON
-
- # 编译
- make -j
- # 生成预测库
- make inference_lib_dist -j
- ```
-
- 编译后的库的目录如下:
-
- ```
- fluid_inference_install_dir
- ├── paddle
- │
- ├── CMakeCache.txt
- ├── version.txt
- ├── third_party
- ├── boost
- ├── install
- └── engine3
- ```
-
- `fluid_inference_install_dir`下, paddle目录包含了预测库的头文件和预测库的lib, version.txt 中包含了lib的版本和配置信息,third_party 中包含了预测库依赖的第三方库
-
-## Paddle-TRT接口使用
-
-Paddle-TRT预测使用总体上分为以下步骤:
-1. 创建合适的配置AnalysisConfig.
-2. 根据配置创建 `PaddlePredictor`.
-3. 创建输入tensor.
-4. 获取输出tensor,输出结果.
-
-以下的代码展示了完整的过程:
-
-```c++
-#include "paddle_inference_api.h"
-
-namespace paddle {
-using paddle::AnalysisConfig;
-
-void RunTensorRT(int batch_size, std::string model_dirname) {
- // 1. 创建AnalysisConfig
- AnalysisConfig config(model_dirname);
- // config->SetModel(model_dirname + "/model",
- // model_dirname + "/params");
- config->EnableUseGpu(10, 0 /*gpu_id*/);
- // 我们在这里使用了 ZeroCopyTensor, 因此需要将此设置成false
- config->SwitchUseFeedFetchOps(false);
- config->EnableTensorRtEngine(1 << 20 /*work_space_size*/, batch_size /*max_batch_size*/, AnalysisConfig::Precision::kFloat32, false /*use_static*/);
-
- // 2. 根据config 创建predictor
- auto predictor = CreatePaddlePredictor(config);
- // 3. 创建输入 tensor
- int channels = 3;
- int height = 224;
- int width = 224;
-
- float *input = new float[input_num];
- memset(input, 0, input_num * sizeof(float));
-
- 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. 运行
- predictor->ZeroCopyRun()
-
- // 5. 获取输出
- std::vector out_data;
- auto output_names = predictor->GetOutputNames();
- auto output_t = predictor->GetOutputTensor(output_names[0]);
- std::vector output_shape = output_t->shape();
- int out_num = std::accumulate(output_shape.begin(), output_shape.end(), 1, std::multiplies());
-
- out_data.resize(out_num);
- output_t->copy_to_cpu(out_data.data());
- }
-} // namespace paddle
-
-int main() {
- // 模型下载地址 http://paddle-inference-dist.cdn.bcebos.com/tensorrt_test/mobilenet.tar.gz
- paddle::RunTensorRT(1, "./mobilenet");
- return 0;
-}
-```
-
-## Paddle-TRT参数介绍
-
-在使用AnalysisPredictor时,我们通过配置
+在使用AnalysisPredictor时,我们通过配置AnalysisConfig中的接口
```c++
config->EnableTensorRtEngine(1 << 20 /* workspace_size*/,
- batch_size /*max_batch_size*/,
- 3 /*min_subgraph_size*/,
- AnalysisConfig::Precision::kFloat32 /*precision*/,
- false /*use_static*/,
+ batch_size /* max_batch_size*/,
+ 3 /* min_subgraph_size*/,
+ AnalysisConfig::Precision::kFloat32 /* precision*/,
+ false /* use_static*/,
false /* use_calib_mode*/);
```
-的方式来指定使用Paddle-TRT子图方式来运行。以下我们将对此接口中的参数进行详细的介绍:
-
-- **`workspace_size`**,类型:int,默认值为`1 << 20`。
-- **`max_batch_size`**,类型:int,默认值1。需要提前设置最大的batch的大小,运行时batch数目不得超过此大小。
-- **`min_subgraph_size`**,类型:int,默认值3。Paddle-TRT是以子图的形式运行,为了避免性能损失,当子图内部节点个数大于`min_subgraph_size`的时候,才会使用Paddle-TRT运行。
-- **`precision`**,类型:`enum class Precision {kFloat32 = 0, kInt8,};`, 默认值为`AnalysisConfig::Precision::kFloat32`。如果需要使用Paddle-TRT calib int8的时候,需要指定precision为 `AnalysisConfig::Precision::kInt8`, 且`use_calib_mode` 为true
-- **`use_static`**,类型:bool, 默认值为false。如果指定为true,在初次运行程序的时候会将TRT的优化信息进行序列化,下次运行的时候直接加载优化的序列化信息而不需要重新生成。
-- **`use_calib_mode`**,类型:bool, 默认值为false。如果需要运行Paddle-TRT calib int8的时候,需要将此设置为true。
+的方式来指定使用Paddle-TRT子图方式来运行。
+该接口中的参数的详细介绍如下:
+
+- **`workspace_size`**,类型:int,默认值为1 << 20。指定TensorRT使用的工作空间大小,TensorRT会在该大小限制下筛选合适的kernel执行预测运算。
+- **`max_batch_size`**,类型:int,默认值为1。需要提前设置最大的batch大小,运行时batch大小不得超过此限定值。
+- **`min_subgraph_size`**,类型:int,默认值为3。Paddle-TRT是以子图的形式运行,为了避免性能损失,当子图内部节点个数大于`min_subgraph_size`的时候,才会使用Paddle-TRT运行。
+- **`precision`**,类型:`enum class Precision {kFloat32 = 0, kHalf, kInt8,};`, 默认值为`AnalysisConfig::Precision::kFloat32`。指定使用TRT的精度,支持FP32(kFloat32),FP16(kHalf),Int8(kInt8)。若需要使用Paddle-TRT int8离线量化校准,需设定`precision`为 `AnalysisConfig::Precision::kInt8`, 且设置`use_calib_mode` 为true。
+- **`use_static`**,类型:bool, 默认值为false。如果指定为true,在初次运行程序的时候会将TRT的优化信息进行序列化到磁盘上,下次运行时直接加载优化的序列化信息而不需要重新生成。
+- **`use_calib_mode`**,类型:bool, 默认值为false。若要运行Paddle-TRT int8离线量化校准,需要将此选项设置为true。
**Note:** Paddle-TRT目前只支持固定shape的输入,不支持变化shape的输入。
## Paddle-TRT样例编译测试
-1. 下载样例
- ```
- https://paddle-inference-dist.cdn.bcebos.com/tensorrt_test/paddle_trt_samples_v1.5.tar.gz
- ```
+1. 下载或编译带有 TensorRT 的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/paddle-TRT`目录下。
- 解压后的目录如下:
+ `paddle-TRT` 文件夹目录结构如下:
```
- sample
+ paddle-TRT
├── CMakeLists.txt
├── mobilenet_test.cc
- ├── thread_mobilenet_test.cc
+ ├── fluid_generate_calib_test.cc
+ ├── fluid_int8_test.cc
├── mobilenetv1
│ ├── model
│ └── params
- └── run_impl.sh
+ ├── run.sh
+ └── run_impl.sh
```
+
+ - `mobilenet_test.cc` 为使用paddle-TRT预测的C++源文件
+ - `fluid_generate_calib_test.cc` 为使用TRT int8离线量化校准的C++源文件
+ - `fluid_int8_test.cc` 为使用TRT执行int8预测的C++源文件
+ - `mobilenetv1` 为模型文件夹
+ - `run.sh` 为预测运行脚本文件
- - `mobilenet_test.cc` 为单线程的程序文件
- - `thread_mobilenet_test.cc` 为多线程的程序文件
- - `mobilenetv1` 为模型文件
-
- 在这里假设预测库的路径为 ``BASE_DIR/fluid_inference_install_dir/`` ,样例所在的目录为 ``SAMPLE_BASE_DIR/sample``
+ 在这里假设样例所在的目录为 `SAMPLE_BASE_DIR/sample/paddle-TRT`
-2. 编译样例
+3. 配置编译与运行脚本
+
+ 编译运行预测样例之前,需要根据运行环境配置编译与运行脚本`run.sh`。`run.sh`的选项与路径配置的部分如下:
+
+ ```shell
+ # 设置是否开启MKL、GPU、TensorRT,如果要使用TensorRT,必须打开GPU
+ WITH_MKL=ON
+ WITH_GPU=ON
+ USE_TENSORRT=ON
+
+ # 按照运行环境设置预测库路径、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
- cd SAMPLE_BASE_DIR/sample
- # sh run_impl.sh {预测库的地址} {测试脚本的名字} {模型目录}
- sh run_impl.sh BASE_DIR/fluid_inference_install_dir/ mobilenet_test SAMPLE_BASE_DIR/sample/mobilenetv1
- ```
-
-3. 编译多线程的样例
-
- ```shell
- cd SAMPLE_BASE_DIR/sample
- # sh run_impl.sh {预测库的地址} {测试脚本的名字} {模型目录}
- sh run_impl.sh BASE_DIR/fluid_inference_install_dir/ thread_mobilenet_test SAMPLE_BASE_DIR/sample/mobilenetv1
+ sh run.sh
```
+
## Paddle-TRT INT8使用
1. Paddle-TRT INT8 简介
- 神经网络的参数在一定程度上是冗余的,在很多任务上,我们可以在保证模型精度的前提下,将Float32的模型转换成Int8的模型。目前,Paddle-TRT支持离线将预训练好的Float32模型转换成Int8的模型,具体的流程如下:1)**生成校准表**(Calibration table);我们准备500张左右的真实输入数据,并将数据输入到模型中去,Paddle-TRT会统计模型中每个op输入和输出值的范围信息,并将记录到校准表中,这些信息有效的减少了模型转换时的信息损失。2)生成校准表后,再次运行模型,**Paddle-TRT会自动加载校准表**,并进行INT8模式下的预测。
+ 神经网络的参数在一定程度上是冗余的,在很多任务上,我们可以在保证模型精度的前提下,将Float32的模型转换成Int8的模型。目前,Paddle-TRT支持离线将预训练好的Float32模型转换成Int8的模型,具体的流程如下:
+
+ 1) **生成校准表**(Calibration table):我们准备500张左右的真实输入数据,并将数据输入到模型中去,Paddle-TRT会统计模型中每个op输入和输出值的范围信息,并将其记录到校准表中,这些信息有效减少了模型转换时的信息损失。
+
+ 2) 生成校准表后,再次运行模型,**Paddle-TRT会自动加载校准表**,并进行INT8模式下的预测。
2. 编译测试INT8样例
-
- ```shell
- cd SAMPLE_BASE_DIR/sample
- # sh run_impl.sh {预测库的地址} {测试脚本的名字} {模型目录}
- # 我们随机生成了500个输入来模拟这一过程,建议大家用真实样例进行实验。
- sh run_impl.sh BASE_DIR/fluid_inference_install_dir/ fluid_generate_calib_test SAMPLE_BASE_DIR/sample/mobilenetv1
-
- ```
-
- 运行结束后,在 `SAMPLE_BASE_DIR/sample/build/mobilenetv1/_opt_cache` 模型目录下会多出一个名字为trt_calib_*的文件,即校准表。
-
- ``` shell
- # 执行INT8预测
- # 将带校准表的模型文件拷贝到特定地址
- cp -rf SAMPLE_BASE_DIR/sample/build/mobilenetv1 SAMPLE_BASE_DIR/sample/mobilenetv1_calib
- sh run_impl.sh BASE_DIR/fluid_inference_install_dir/ fluid_int8_test SAMPLE_BASE_DIR/sample/mobilenetv1_calib
- ```
+ 将`run.sh`文件中的`mobilenet_test`改为`fluid_generate_calib_test`,运行
+
+ ```shell
+ sh run.sh
+ ```
+
+ 即可执行生成校准表样例,在该样例中,我们随机生成了500个输入来模拟这一过程,在实际业务中,建议大家使用真实样例。运行结束后,在 `SAMPLE_BASE_DIR/sample/paddle-TRT/build/mobilenetv1/_opt_cache` 模型目录下会多出一个名字为trt_calib_*的文件,即校准表。
+
+ 生成校准表后,将带校准表的模型文件拷贝到特定地址
+
+ ```shell
+ cp -rf SAMPLE_BASE_DIR/sample/paddle-TRT/build/mobilenetv1/ SAMPLE_BASE_DIR/sample/paddle-TRT/mobilenetv1_calib
+ ```
+
+ 将`run.sh`文件中的`fluid_generate_calib_test`改为`fluid_int8_test`,将模型路径改为`SAMPLE_BASE_DIR/sample/paddle-TRT/mobilenetv1_calib`,运行
+
+ ```shell
+ sh run.sh
+ ```
+
+ 即可执行int8预测样例。
## Paddle-TRT子图运行原理
- PaddlePaddle采用子图的形式对TensorRT进行集成,当模型加载后,神经网络可以表示为由变量和运算节点组成的计算图。Paddle TensorRT实现的功能是能够对整个图进行扫描,发现图中可以使用TensorRT优化的子图,并使用TensorRT节点替换它们。在模型的推断期间,如果遇到TensorRT节点,Paddle会调用TensoRT库对该节点进行优化,其他的节点调用Paddle的原生实现。TensorRT在推断期间能够进行Op的横向和纵向融合,过滤掉冗余的Op,并对特定平台下的特定的Op选择合适的kenel等进行优化,能够加快模型的预测速度。
+ PaddlePaddle采用子图的形式对TensorRT进行集成,当模型加载后,神经网络可以表示为由变量和运算节点组成的计算图。Paddle TensorRT实现的功能是对整个图进行扫描,发现图中可以使用TensorRT优化的子图,并使用TensorRT节点替换它们。在模型的推断期间,如果遇到TensorRT节点,Paddle会调用TensorRT库对该节点进行优化,其他的节点调用Paddle的原生实现。TensorRT在推断期间能够进行Op的横向和纵向融合,过滤掉冗余的Op,并对特定平台下的特定的Op选择合适的kernel等进行优化,能够加快模型的预测速度。
下图使用一个简单的模型展示了这个过程:
@@ -238,4 +160,54 @@ config->EnableTensorRtEngine(1 << 20 /* workspace_size*/,
- 我们可以在原始模型网络中看到,绿色节点表示可以被TensorRT支持的节点,红色节点表示网络中的变量,黄色表示Paddle只能被Paddle原生实现执行的节点。那些在原始网络中的绿色节点被提取出来汇集成子图,并由一个TensorRT节点代替,成为转换网络中的`block-25` 节点。在网络运行过程中,如果遇到该节点,Paddle将调用TensorRT库来对其执行。
+ 我们可以在原始模型网络中看到,绿色节点表示可以被TensorRT支持的节点,红色节点表示网络中的变量,黄色表示Paddle只能被Paddle原生实现执行的节点。那些在原始网络中的绿色节点被提取出来汇集成子图,并由一个TensorRT节点代替,成为转换后网络中的`block-25` 节点。在网络运行过程中,如果遇到该节点,Paddle将调用TensorRT库来对其执行。
+
+## Paddle-TRT性能测试
+
+### 测试环境
+- CPU:Intel(R) Xeon(R) Gold 5117 CPU @ 2.00GHz GPU:Tesla P4
+- TensorRT4.0, CUDA8.0, CUDNNV7
+- 测试模型 ResNet50,MobileNet,ResNet101, Inception V3.
+
+### 测试对象
+**PaddlePaddle, Pytorch, Tensorflow**
+
+- 在测试中,PaddlePaddle使用子图优化的方式集成了TensorRT, 模型[地址](https://github.com/PaddlePaddle/models/tree/develop/PaddleCV/image_classification/models)。
+- Pytorch使用了原生的实现, 模型[地址1](https://github.com/pytorch/vision/tree/master/torchvision/models)、[地址2](https://github.com/marvis/pytorch-mobilenet)。
+- 对TensorFlow测试包括了对TF的原生的测试,和对TF—TRT的测试,**对TF—TRT的测试并没有达到预期的效果,后期会对其进行补充**, 模型[地址](https://github.com/tensorflow/models)。
+
+
+#### ResNet50
+
+|batch_size|PaddlePaddle(ms)|Pytorch(ms)|TensorFlow(ms)|
+|---|---|---|---|
+|1|4.64117 |16.3|10.878|
+|5|6.90622| 22.9 |20.62|
+|10|7.9758 |40.6|34.36|
+
+#### MobileNet
+
+|batch_size|PaddlePaddle(ms)|Pytorch(ms)|TensorFlow(ms)|
+|---|---|---|---|
+|1| 1.7541 | 7.8 |2.72|
+|5| 3.04666 | 7.8 |3.19|
+|10|4.19478 | 14.47 |4.25|
+
+#### ResNet101
+
+|batch_size|PaddlePaddle(ms)|Pytorch(ms)|TensorFlow(ms)|
+|---|---|---|---|
+|1|8.95767| 22.48 |18.78|
+|5|12.9811 | 33.88 |34.84|
+|10|14.1463| 61.97 |57.94|
+
+
+#### Inception v3
+
+|batch_size|PaddlePaddle(ms)|Pytorch(ms)|TensorFlow(ms)|
+|---|---|---|---|
+|1|15.1613 | 24.2 |19.1|
+|5|18.5373 | 34.8 |27.2|
+|10|19.2781| 54.8 |36.7|
+
+
diff --git a/doc/fluid/advanced_usage/deploy/inference/python_infer_cn.md b/doc/fluid/advanced_usage/deploy/inference/python_infer_cn.md
index 23b0d0e2d..507e8178e 100644
--- a/doc/fluid/advanced_usage/deploy/inference/python_infer_cn.md
+++ b/doc/fluid/advanced_usage/deploy/inference/python_infer_cn.md
@@ -135,7 +135,8 @@ results = predictor.run([x_t, y_t])
* `enable_tensorrt_engine(workspace_size: int = 1 << 20,
max_batch_size: int,
min_subgraph_size: int,
- precision: AnalysisConfig.precision, use_static: bool,
+ precision: AnalysisConfig.precision,
+ use_static: bool,
use_calib_mode: bool) -> None`
* `enable_mkldnn() -> None`
* PaddlePredictor
--
GitLab