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

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
上级 63861f32
# 使用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模型的预测性能。该模块依旧在持续开发中,目前支持的模型如下表所示:
## 内容
- [编译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子图运行原理)
## <a name="编译Paddle-TRT预测库">编译Paddle-TRT预测库</a>
**使用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
|分类模型|检测模型|分割模型|
|---|---|---|
|mobilenetv1|yolov3|ICNET|
|resnet50|SSD||
|vgg16|mask-rcnn||
|resnext|faster-rcnn||
|AlexNet|cascade-rcnn||
|Se-ResNext|retinanet||
|GoogLeNet|mobilenet-SSD||
|DPN|||
```
# 在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
```
在这篇文档中,我们将会对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() {};
```
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 中包含了预测库依赖的第三方库
## <a name="Paddle-TRT接口使用">Paddle-TRT接口使用</a>
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<float> out_data;
auto output_names = predictor->GetOutputNames();
auto output_t = predictor->GetOutputTensor(output_names[0]);
std::vector<int> output_shape = output_t->shape();
int out_num = std::accumulate(output_shape.begin(), output_shape.end(), 1, std::multiplies<int>());
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使用介绍](#Paddle-TRT使用介绍)
- [Paddle-TRT样例编译测试](#Paddle-TRT样例编译测试)
- [Paddle-TRT INT8使用](#Paddle-TRT_INT8使用)
- [Paddle-TRT子图运行原理](#Paddle-TRT子图运行原理)
- [Paddle-TRT性能测试](#Paddle-TRT性能测试)
## <a name="Paddle-TRT参数介绍">Paddle-TRT参数介绍</a>
## <a name="Paddle-TRT使用介绍">Paddle-TRT使用介绍</a>
在使用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子图方式来运行。以下我们将对此接口中的参数进行详细的介绍:
的方式来指定使用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。
- **`workspace_size`**,类型:int,默认值为1 << 20。指定TensorRT使用的工作空间大小,TensorRT会在该大小限制下筛选合适的kernel执行预测运算
- **`max_batch_size`**,类型:int,默认值1。需要提前设置最大的batch大小,运行时batch大小不得超过此限定值
- **`min_subgraph_size`**,类型:int,默认值3Paddle-TRT是以子图的形式运行,为了避免性能损失,当子图内部节点个数大于`min_subgraph_size`的时候,才会使用Paddle-TRT运行。
- **`precision`**,类型:`enum class Precision {kFloat32 = 0, kHalf, kInt8,};`, 默认值为`AnalysisConfig::Precision::kFloat32`。指定使用TRT的精度,支持FP32kFloat32),FP16kHalf),Int8kInt8)。若需要使用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的输入。
## <a name="Paddle-TRT样例编译测试">Paddle-TRT样例编译测试</a>
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.sh
└── run_impl.sh
```
- `mobilenet_test.cc` 为单线程的程序文件
- `thread_mobilenet_test.cc` 为多线程的程序文件
- `mobilenetv1` 为模型文件
- `mobilenet_test.cc` 为使用paddle-TRT预测的C++源文件
- `fluid_generate_calib_test.cc` 为使用TRT int8离线量化校准的C++源文件
- `fluid_int8_test.cc` 为使用TRT执行int8预测的C++源文件
- `mobilenetv1` 为模型文件夹
- `run.sh` 为预测运行脚本文件
在这里假设预测库的路径为 ``BASE_DIR/fluid_inference_install_dir/`` ,样例所在的目录为 ``SAMPLE_BASE_DIR/sample``
在这里假设样例所在的目录为 `SAMPLE_BASE_DIR/sample/paddle-TRT`
2. 编译样例
3. 配置编译与运行脚本
编译运行预测样例之前,需要根据运行环境配置编译与运行脚本`run.sh`。`run.sh`的选项与路径配置的部分如下:
```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
# 设置是否开启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
```
3. 编译多线程的样例
按照实际运行环境配置`run.sh`中的选项开关和所需lib路径。
4. 编译与运行样例
```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
```
## <a name="Paddle-TRT_INT8使用">Paddle-TRT INT8使用</a>
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样例
将`run.sh`文件中的`mobilenet_test`改为`fluid_generate_calib_test`,运行
```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
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
```
运行结束后,在 `SAMPLE_BASE_DIR/sample/build/mobilenetv1/_opt_cache` 模型目录下会多出一个名字为trt_calib_*的文件,即校准表。
将`run.sh`文件中的`fluid_generate_calib_test`改为`fluid_int8_test`,将模型路径改为`SAMPLE_BASE_DIR/sample/paddle-TRT/mobilenetv1_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
```shell
sh run.sh
```
即可执行int8预测样例。
## <a name="Paddle-TRT子图运行原理">Paddle-TRT子图运行原理</a>
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*/,
</p>
我们可以在原始模型网络中看到,绿色节点表示可以被TensorRT支持的节点,红色节点表示网络中的变量,黄色表示Paddle只能被Paddle原生实现执行的节点。那些在原始网络中的绿色节点被提取出来汇集成子图,并由一个TensorRT节点代替,成为转换网络中的`block-25` 节点。在网络运行过程中,如果遇到该节点,Paddle将调用TensorRT库来对其执行。
我们可以在原始模型网络中看到,绿色节点表示可以被TensorRT支持的节点,红色节点表示网络中的变量,黄色表示Paddle只能被Paddle原生实现执行的节点。那些在原始网络中的绿色节点被提取出来汇集成子图,并由一个TensorRT节点代替,成为转换后网络中的`block-25` 节点。在网络运行过程中,如果遇到该节点,Paddle将调用TensorRT库来对其执行。
## <a name="Paddle-TRT性能测试">Paddle-TRT性能测试</a>
### 测试环境
- 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|
......@@ -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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册