未验证 提交 45f142c0 编写于 作者: Z Zhaolong Xing 提交者: GitHub

refine inference api (#888)

* refine inference api

test=develop

* fix typo

* fix typo

* fix comments
上级 4c9c3d75
# C++ 预测 API介绍 # C++ 预测 API介绍
为了更简单方便的预测部署,Fluid 提供了一套高层 API 用来隐藏底层不同的优化实现 为了更简单方便的预测部署,PaddlePaddle 提供了一套高层 API 预测接口
预测库包含: 预测库包含:
- 头文件 `paddle_inference_api.h` 定义了所有的接口 - 头文件主要包括:
- 库文件`libpaddle_fluid.so``libpaddle_fluid.a` - `paddle_analysis_config.h `
- `paddle_api.h `
- `paddle_inference_api.h`
- 库文件:
- `libpaddle_fluid.so`
- `libpaddle_fluid.a`
下面是详细介绍 下面是详细介绍
## PaddleTensor
PaddleTensor 定义了预测最基本的输入输出的数据格式,常用字段: ## 内容
- [NativePredictor使用](#NativePredictor使用)
- [AnalysisPredictor使用](#AnalysisPredictor使用)
- [输入输出的管理](#输入输出的管理)
- [多线程预测](#多线程预测)
- [性能建议](#性能建议)
- `name` 用于指定输入数据对应的 模型中variable 的名字 ## <a name="NativePredictor使用">NativePredictor使用</a>
- `shape` 表示一个 Tensor 的 shape
- `data` 数据以连续内存的方式存储在`PaddleBuf` 中,`PaddleBuf` 可以接收外面的数据或者独立`malloc`内存,详细可以参考头文件中相关定义。
- `dtype` 表示 Tensor 的数据类型
## 利用Config 创建不同引擎 `NativePredictor`为原生预测引擎,底层由 PaddlePaddle 原生的 forward operator
组成,可以天然**支持所有Paddle 训练出的模型**
高层 API 底层有多种优化实现,我们称之为 engine;不同 engine 的切换通过传递不同的 Config 实现重载。
`Config` 有两种,`NativeConfig` 较简单和稳定,`AnalysisConfig` 功能更新,性能更好
- `NativeConfig` 原生 engine,由 paddle 原生的 forward operator
组成,可以天然支持所有paddle 训练出的模型
- `AnalysisConfig` #### NativePredictor 使用样例
- 支持计算图的分析和优化 ```c++
- 支持最新的各类 op fuse,性能一般比 `NativeConfig` 要好
- 支持 TensorRT mixed engine 用于 GPU
加速,用子图的方式支持了 [TensorRT] ,支持所有paddle
模型,并自动切割部分计算子图到 TensorRT 上加速,具体的使用方式可以参考[这里](http://paddlepaddle.org/documentation/docs/zh/1.1/user_guides/howto/inference/paddle_tensorrt_infer.html)
## 基于 NativeConfig 的预测部署过程
总体上分为以下步骤
1. 用合适的配置创建 `PaddlePredictor`
2. 创建输入用的 `PaddleTensor`,传入到 `PaddlePredictor`
3. 获取输出的 `PaddleTensor` ,将结果取出
下面完整演示一个简单的模型,部分细节代码隐去
```c++
#include "paddle_inference_api.h" #include "paddle_inference_api.h"
// 创建一个 config,并修改相关设置 namespace paddle {
paddle::NativeConfig config; // 配置NativeConfig
config.model_dir = "xxx"; void CreateConfig(NativeConfig *config, const std::string& model_dirname) {
config.use_gpu = false; config->use_gpu=true;
// 创建一个原生的 PaddlePredictor config->device=0;
auto predictor = config->fraction_of_gpu_memory=0.1;
paddle::CreatePaddlePredictor<paddle::NativeConfig>(config);
// 创建输入 tensor /* for cpu
int64_t data[4] = {1, 2, 3, 4}; config->use_gpu=false;
paddle::PaddleTensor tensor; config->SetCpuMathLibraryNumThreads(1);
tensor.shape = std::vector<int>({4, 1}); */
tensor.data.Reset(data, sizeof(data));
tensor.dtype = paddle::PaddleDType::INT64; // 设置模型的参数路径
// 创建输出 tensor,输出 tensor 的内存可以复用 config->prog_file = model_dirname + "model";
std::vector<paddle::PaddleTensor> outputs; config->param_file = model_dirname + "params";
// 执行预测 // 当模型输入是多个的时候,这个配置是必要的。
CHECK(predictor->Run(slots, &outputs)); config->specify_input_name = true;
// 获取 outputs ... }
```
编译时,联编 `libpaddle_fluid.a/.so` 便可。
## 高阶使用
### 输入输出的内存管理
`PaddleTensor``data` 字段是一个 `PaddleBuf`,用于管理一段内存用于数据的拷贝。 void RunNative(int batch_size, const std::string& model_dirname) {
// 1. 创建NativeConfig
NativeConfig config;
CreateConfig(&config);
// 2. 根据config 创建predictor
auto predictor = CreatePaddlePredictor(config);
int channels = 3;
int height = 224;
int width = 224;
float data[batch_size * channels * height * width] = {0};
// 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 = static_cast<float *>(outputs.front().data.data());
}
} // namespace paddle
`PaddleBuf` 在内存管理方面有两种模式: int main() {
// 模型下载地址 http://paddle-inference-dist.cdn.bcebos.com/tensorrt_test/mobilenet.tar.gz
paddle::RunNative(1, "./mobilenet");
return 0;
}
```
1. 自动分配和管理内存 ## <a name="AnalysisPredictor使用"> AnalysisPredictor使用</a>
AnalysisConfig 创建了一个高性能预测引擎。该引擎通过对计算图的分析,完成对计算图的一系列的优化(Op 的融合, MKLDNN,TRT等底层加速库的支持 etc),大大提升预测引擎的性能。
```c++ #### AnalysisPredictor 使用样例
int some_size = 1024;
PaddleTensor tensor;
tensor.data.Resize(some_size);
```
2. 外部内存传入 ```c++
void CreateConfig(AnalysisConfig* config, const std::string& model_dirname) {
// 模型从磁盘进行加载
config->SetModel(model_dirname + "/model",
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*/);
/* for cpu
config->DisableGpu();
config->EnableMKLDNN(); // 可选
config->SetCpuMathLibraryNumThreads(10);
*/
// 当使用ZeroCopyTensor的时候,此处一定要设置为false。
config->SwitchUseFeedFetchOps(false);
// 当多输入的时候,此处一定要设置为true
config->SwitchSpecifyInputNames(true);
config->SwitchIrDebug(true); // 开关打开,会在每个图优化过程后生成dot文件,方便可视化。
// config->SwitchIrOptim(false); // 默认为true。如果设置为false,关闭所有优化,执行过程同 NativePredictor
// config->EnableMemoryOptim(); // 开启内存/显存复用
}
```c++ void RunAnalysis(int batch_size, std::string model_dirname) {
int some_size = 1024; // 1. 创建AnalysisConfig
// 用户外部分配内存并保证 PaddleTensor 使用过程中,内存一直可用 AnalysisConfig config;
void* memory = new char[some_size]; CreateConfig(&config);
tensor.data.Reset(memory, some_size); // 2. 根据config 创建predictor
// ... auto predictor = CreatePaddlePredictor(config);
int channels = 3;
// 用户最后需要自行删除内存以避免内存泄漏 int height = 224;
int width = 224;
float input[batch_size * channels * height * width] = {0};
// 3. 创建输入
// 同NativePredictor样例一样,此处可以使用PaddleTensor来创建输入
// 以下的代码中使用了ZeroCopy的接口,同使用PaddleTensor不同的是:此接口可以避免预测中多余的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. 运行
CHECK(predictor->ZeroCopyRun());
delete[] memory; // 5. 获取输出
``` std::vector<float> out_data;
auto output_names = predictor->GetOutputNames();
两种模式中,第一种比较方便;第二种则可以严格控制内存的管理,便于与 `tcmalloc` 等库的集成。 auto output_t = predictor->GetOutputTensor(output_names[0]);
std::vector<int> output_shape = output_t->shape();
### 基于 AnalysisConfig 提升性能 int out_num = std::accumulate(output_shape.begin(), output_shape.end(), 1, std::multiplies<int>());
`AnalysisConfig` 是目前我们重点优化的版本。 out_data.resize(out_num);
output_t->copy_to_cpu(out_data.data());
}
} // namespace paddle
类似 `NativeConfig``AnalysisConfig` 可以创建一个经过一系列优化的高性能预测引擎。 其中包含了计算图的分析和优化,以及对一些重要 Op 的融合改写等,比如对使用了 While, LSTM, GRU 等模型性能有大幅提升 。 int main() {
// 模型下载地址 http://paddle-inference-dist.cdn.bcebos.com/tensorrt_test/mobilenet.tar.gz
paddle::RunAnalysis(1, "./mobilenet");
return 0;
}
`AnalysisConfig` 的使用方法也和 `NativeConfig` 类似
```c++
AnalysisConfig config(dirname); // dirname 是模型的路径
// 对于不同的模型存储格式,也可以用 AnalysisConfig config(model_file, params_file)
config.EnableUseGpu(100/*初始显存池大小(MB)*/, 0 /*gpu id*/); // 使用GPU, CPU下使用config.DisableGpu();
config.SwitchIrOptim(); // 打开优化开关,运行时会执行一系列的计算图优化
``` ```
这里需要注意的是,输入的 PaddleTensor 需要指定,比如之前的例子需要修改为 ## <a name="输入输出的管理"> 输入输出的管理</a>
### PaddleTensor 的使用
PaddleTensor可用于NativePredictor和AnalysisPredictor,在 NativePredictor样例中展示了PaddleTensor的使用方式。
PaddleTensor 定义了预测最基本的输入输出的数据格式,常用字段如下:
```c++ - `name`,类型:string,用于指定输入数据对应的模型中variable的名字
auto predictor = paddle::CreatePaddlePredictor(config); // 注意这里需要 AnalysisConfig - `shape`,类型:`vector<int>`, 表示一个Tensor的shape
// 创建输入 tensor - `data`,类型:`PaddleBuf`, 数据以连续内存的方式存储在`PaddleBuf`中,`PaddleBuf`可以接收外面的数据或者独立`malloc`内存,详细可以参考头文件中相关定义。
int64_t data[4] = {1, 2, 3, 4}; - `dtype`,类型:`PaddleType`, 有`PaddleDtype::FLOAT32`, `PaddleDtype::INT64`, `PaddleDtype::INT32`三种, 表示 Tensor 的数据类型。
paddle::PaddleTensor tensor; - `lod`,类型:`vector<vector<size_t>>`,在处理变长输入的时候,需要对 `PaddleTensor`设置LoD信息。可以参考[LoD-Tensor使用说明](../../../user_guides/howto/basic_concept/lod_tensor.html)
tensor.shape = std::vector<int>({4, 1});
tensor.data.Reset(data, sizeof(data));
tensor.dtype = paddle::PaddleDType::INT64;
```
后续的执行过程与 `NativeConfig` 完全一致。
### 变长序列输入 ### ZeroCopyTensor的使用
在处理变长输入的时候,需要对 `PaddleTensor` 设置LoD信息 ZeroCopyTensor的使用可避免预测时候准备输入以及获取输出时多余的数据copy,提高预测性能。**只可用于AnalysisPredictor**
``` c++ **Note:**使用ZeroCopyTensor,务必在创建config时设置`config->SwitchUseFeedFetchOps(false)`
# 假设序列长度依次为 [3, 2, 4, 1, 2, 3]
tensor.lod = {{0,
/*0 + 3=*/3,
/*3 + 2=*/5,
/*5 + 4=*/9,
/*9 + 1=*/10,
/*10 + 2=*/12,
/*12 + 3=*/15}};
```
更详细的例子可以参考[LoD-Tensor使用说明](../../../user_guides/howto/basic_concept/lod_tensor.html) ```
// 通过创建的AnalysisPredictor获取输入和输出的tensor
auto input_names = predictor->GetInputNames();
auto input_t = predictor->GetInputTensor(input_names[0]);
auto output_names = predictor->GetOutputNames();
auto output_t = predictor->GetOutputTensor(output_names[0]);
// 对tensor进行reshape
input_t->Reshape({batch_size, channels, height, width});
// 通过copy_from_cpu接口,将cpu数据输入;通过copy_to_cpu接口,将输出数据copy到cpu
input_t->copy_from_cpu<float>(input_data /*数据指针*/);
output_t->copy_to_cpu(out_data /*数据指针*/);
// 设置LOD
std::vector<std::vector<size_t>> lod_data = {{0}, {0}};
input_t->SetLoD(lod_data);
// 获取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。 多线程场景下,每个服务线程执行同一种模型,支持 CPU 和 GPU。
Paddle 并没有相关的接口支持,但用户可以简单组合得出,下面演示最简单的实现,用户最好参考具体应用场景做调整 下面演示最简单的实现,用户需要根据具体应用场景做相应的调整
```c++ ```c++
auto main_predictor = paddle::CreatePaddlePredictor(config); auto main_predictor = paddle::CreatePaddlePredictor(config);
...@@ -164,11 +218,12 @@ const int num_threads = 10; // 假设有 10 个服务线程 ...@@ -164,11 +218,12 @@ const int num_threads = 10; // 假设有 10 个服务线程
std::vector<std::thread> threads; std::vector<std::thread> threads;
std::vector<decl_type(main_predictor)> predictors; std::vector<decl_type(main_predictor)> predictors;
// 最好初始化时把所有predictor都创建好 // 线程外创建所有的predictor
predictors.emplace_back(std::move(main_predictor)); predictors.emplace_back(std::move(main_predictor));
for (int i = 1; i < num_threads; i++) { for (int i = 1; i < num_threads; i++) {
predictors.emplace_back(main_predictor->Clone()); predictors.emplace_back(main_predictor->Clone());
} }
// 创建线程并执行 // 创建线程并执行
for (int i = 0; i < num_threads; i++) { for (int i = 0; i < num_threads; i++) {
threads.emplace_back([i, &]{ threads.emplace_back([i, &]{
...@@ -178,7 +233,7 @@ for (int i = 0; i < num_threads; i++) { ...@@ -178,7 +233,7 @@ for (int i = 0; i < num_threads; i++) {
}); });
} }
// 结尾 // 线程join
for (auto& t : threads) { for (auto& t : threads) {
if (t.joinable()) t.join(); if (t.joinable()) t.join();
} }
...@@ -186,48 +241,12 @@ for (auto& t : threads) { ...@@ -186,48 +241,12 @@ for (auto& t : threads) {
// 结束 // 结束
``` ```
#### 模型并行的服务
这种场景,使用多个线程/CPU核加速单个模型的预测,**目前只支持 CPU下使用 MKL/MKLDNN 的情况**
使用 `AnalysisConfig` 的对应接口来设置底层科学计算库使用线程的数目,具体参考 [SetCpuMathLibraryNumThreads](https://github.com/PaddlePaddle/Paddle/blob/release/1.3/paddle/fluid/inference/api/paddle_analysis_config.h#L159)
```c++
config.SetCpuMathLibraryNumThreads(8); // 一个模型使用 8 个线程加速预测
// 查询状态,可以使用如下接口
config.cpu_math_library_num_threads(); // return an int
```
### 性能建议
1. 在 CPU型号允许的情况下,尽量使用带 AVX 和 MKL 的版本
2. 复用输入和输出的 `PaddleTensor` 以避免频繁分配内存拉低性能
3. CPU或GPU预测,可以尝试把 `NativeConfig` 改成成 `AnalysisConfig` 来进行优化
#### CPU下可以尝试使用 Intel 的 `MKLDNN` 加速
MKLDNN 对 `CNN` 类的模型预测有不错的加速效果,可以尝试对比与 `MKLML` 的性能。
使用方法:
```c++
// AnalysisConfig config(...);
config.EnableMKLDNN();
// 查看 mkldnn 是否已经打开,可以用如下代码
config.mkldnn_enabled(); // return a bool
```
#### GPU 下可以尝试打开 `TensorRT` 子图加速引擎
通过计算图分析,Paddle 可以自动将计算图中部分子图切割,并调用 NVidia 的 `TensorRT` 来进行加速。
详细内容可以参考 [TensorRT 子图引擎](./paddle_tensorrt_infer.html)
## 详细代码参考
`AnalysisConfig` 完整接口可以参考 [这里](https://github.com/PaddlePaddle/Paddle/blob/release/1.3/paddle/fluid/inference/api/paddle_analysis_config.h#L35)
[inference demos](https://github.com/PaddlePaddle/Paddle/tree/develop/paddle/fluid/inference/api/demo_ci)
## <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)
# 使用Paddle-TensorRT库预测 # 使用Paddle-TensorRT库预测
NVIDIA TensorRT 是一个高性能的深度学习预测库,可为深度学习推理应用程序提供低延迟和高吞吐量。PaddlePaddle 采用了子图的形式对TensorRT进行了集成,即我们可以使用该模块来提升Paddle模型的预测性能。该模块依旧在持续开发中,目前已支持的模型有:AlexNet, MobileNet, ResNet50, VGG19, ResNext, Se-ReNext, GoogleNet, DPN, ICNET, Deeplabv3, MobileNet-SSD等。在这篇文档中,我们将会对Paddle-TensorRT库的获取、使用和原理进行介绍。 NVIDIA TensorRT 是一个高性能的深度学习预测库,可为深度学习推理应用程序提供低延迟和高吞吐量。PaddlePaddle 采用了子图的形式对TensorRT进行了集成,即我们可以使用该模块来提升Paddle模型的预测性能。该模块依旧在持续开发中,目前已支持的模型有:AlexNet, MobileNetV1, ResNet50, VGG19, ResNext, Se-ReNext, GoogLeNet, DPN, ICNET, Deeplabv3, MobileNet-SSD等。在这篇文档中,我们将会对Paddle-TensorRT库的获取、使用和原理进行介绍。
## 内容 ## 内容
- [编译Paddle-TRT预测库](#编译Paddle-TRT预测库) - [编译Paddle-TRT预测库](#编译Paddle-TRT预测库)
- [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 INT8使用](#Paddle-TRT_INT8使用)
- [Paddle-TRT子图运行原理](#Paddle-TRT子图运行原理) - [Paddle-TRT子图运行原理](#Paddle-TRT子图运行原理)
...@@ -36,10 +37,10 @@ TensorRT预测库目前仅支持使用GPU编译。 ...@@ -36,10 +37,10 @@ TensorRT预测库目前仅支持使用GPU编译。
mkdir build mkdir build
cd build cd build
# TENSORRT_ROOT为TRT的路径,默认为 /usr,根据自己需求进行改动 # TENSORRT_ROOT为TRT的路径,默认为 /usr,根据自己需求进行改动
# MKL 可以根据自己的需求自行打开 # MKLDNN 可以根据自己的需求自行打开
cmake .. \ cmake .. \
-DWITH_FLUID_ONLY=ON \ -DWITH_FLUID_ONLY=ON \
-DWITH_MKL=OFF \ -DWITH_MKL=ON \
-DWITH_MKLDNN=OFF \ -DWITH_MKLDNN=OFF \
-DCMAKE_BUILD_TYPE=Release \ -DCMAKE_BUILD_TYPE=Release \
-DWITH_PYTHON=OFF \ -DWITH_PYTHON=OFF \
...@@ -70,13 +71,11 @@ TensorRT预测库目前仅支持使用GPU编译。 ...@@ -70,13 +71,11 @@ TensorRT预测库目前仅支持使用GPU编译。
## <a name="Paddle-TRT接口使用">Paddle-TRT接口使用</a> ## <a name="Paddle-TRT接口使用">Paddle-TRT接口使用</a>
[`paddle_inference_api.h`]('https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/fluid/inference/api/paddle_inference_api.h') 定义了使用TensorRT的所有接口。 Paddle-TRT预测使用总体上分为以下步骤:
总体上分为以下步骤:
1. 创建合适的配置AnalysisConfig. 1. 创建合适的配置AnalysisConfig.
2. 根据配创建 `PaddlePredictor`. 2. 根据配创建 `PaddlePredictor`.
3. 创建输入tensor. 3. 创建输入tensor.
4. 获取输出tensor,输出结果. 4. 获取输出tensor,输出结果.
以下的代码展示了完整的过程: 以下的代码展示了完整的过程:
...@@ -87,39 +86,43 @@ namespace paddle { ...@@ -87,39 +86,43 @@ namespace paddle {
using paddle::AnalysisConfig; using paddle::AnalysisConfig;
void RunTensorRT(int batch_size, std::string model_dirname) { void RunTensorRT(int batch_size, std::string model_dirname) {
// 1. 创建MixedRTConfig // 1. 创建AnalysisConfig
AnalysisConfig config(model_dirname); AnalysisConfig config(model_dirname);
// config->SetModel(model_dirname + "/model", // config->SetModel(model_dirname + "/model",
// model_dirname + "/params"); // model_dirname + "/params");
config->EnableUseGpu(10, 0 /*gpu_id*/);
config->EnableUseGpu(100, 0 /*gpu_id*/); // 我们在这里使用了 ZeroCopyTensor, 因此需要将此设置成false
config->EnableTensorRtEngine(1 << 20 /*work_space_size*/, batch_size /*max_batch_size*/); config->SwitchUseFeedFetchOps(false);
config->EnableTensorRtEngine(1 << 20 /*work_space_size*/, batch_size /*max_batch_size*/, AnalysisConfig::Precision::kFloat32, false /*use_static*/);
// 2. 根据config 创建predictor // 2. 根据config 创建predictor
auto predictor = CreatePaddlePredictor(config); auto predictor = CreatePaddlePredictor(config);
// 3. 创建输入 tensor // 3. 创建输入 tensor
int channels = 3;
int height = 224; int height = 224;
int width = 224; int width = 224;
float data[batch_size * 3 * height * width] = {0};
float *input = new float[input_num];
PaddleTensor tensor; memset(input, 0, input_num * sizeof(float));
tensor.shape = std::vector<int>({batch_size, 3, height, width});
tensor.data = PaddleBuf(static_cast<void *>(data), auto input_names = predictor->GetInputNames();
sizeof(float) * (batch_size * 3 * height * width)); auto input_t = predictor->GetInputTensor(input_names[0]);
tensor.dtype = PaddleDType::FLOAT32; input_t->Reshape({batch_size, channels, height, width});
std::vector<PaddleTensor> paddle_tensor_feeds(1, tensor); input_t->copy_from_cpu(input);
// 4. 创建输出 tensor // 4. 运行
std::vector<PaddleTensor> outputs; predictor->ZeroCopyRun()
// 5. 预测
predictor->Run(paddle_tensor_feeds, &outputs, batch_size); // 5. 获取输出
std::vector<float> out_data;
const size_t num_elements = outputs.front().data.length() / sizeof(float); auto output_names = predictor->GetOutputNames();
auto *data = static_cast<float *>(outputs.front().data.data()); auto output_t = predictor->GetOutputTensor(output_names[0]);
for (size_t i = 0; i < num_elements; i++) { std::vector<int> output_shape = output_t->shape();
std::cout << "output: " << data[i] << std::endl; 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 } // namespace paddle
int main() { int main() {
...@@ -129,11 +132,34 @@ int main() { ...@@ -129,11 +132,34 @@ int main() {
} }
``` ```
## <a name="Paddle-TRT参数介绍">Paddle-TRT参数介绍</a>
在使用AnalysisPredictor时,我们通过配置
```c++
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*/);
```
的方式来指定使用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。
**Note:** Paddle-TRT目前只支持固定shape的输入,不支持变化shape的输入。
## <a name="Paddle-TRT样例编译测试">Paddle-TRT样例编译测试</a> ## <a name="Paddle-TRT样例编译测试">Paddle-TRT样例编译测试</a>
1. 下载样例 1. 下载样例
``` ```
wget http://paddle-inference-dist.cdn.bcebos.com/tensorrt_test/paddle_trt_samples.tar.gz https://paddle-inference-dist.cdn.bcebos.com/tensorrt_test/paddle_trt_samples_v1.5.tar.gz
``` ```
解压后的目录如下: 解压后的目录如下:
...@@ -185,8 +211,9 @@ int main() { ...@@ -185,8 +211,9 @@ int main() {
sh run_impl.sh BASE_DIR/fluid_inference_install_dir/ fluid_generate_calib_test SAMPLE_BASE_DIR/sample/mobilenetv1 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` 模型目录下会多出一个名字为trt_calib_*的文件,即校准表。
运行结束后,在 `SAMPLE_BASE_DIR/sample/build/mobilenetv1/_opt_cache` 模型目录下会多出一个名字为trt_calib_*的文件,即校准表。
``` shell ``` shell
# 执行INT8预测 # 执行INT8预测
# 将带校准表的模型文件拷贝到特定地址 # 将带校准表的模型文件拷贝到特定地址
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册