Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
FluidDoc
提交
45f142c0
F
FluidDoc
项目概览
PaddlePaddle
/
FluidDoc
通知
5
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
23
列表
看板
标记
里程碑
合并请求
111
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
F
FluidDoc
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
23
Issue
23
列表
看板
标记
里程碑
合并请求
111
合并请求
111
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
未验证
提交
45f142c0
编写于
6月 21, 2019
作者:
Z
Zhaolong Xing
提交者:
GitHub
6月 21, 2019
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
refine inference api (#888)
* refine inference api test=develop * fix typo * fix typo * fix comments
上级
4c9c3d75
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
252 addition
and
206 deletion
+252
-206
doc/fluid/advanced_usage/deploy/inference/native_infer.md
doc/fluid/advanced_usage/deploy/inference/native_infer.md
+188
-169
doc/fluid/advanced_usage/deploy/inference/paddle_tensorrt_infer.md
.../advanced_usage/deploy/inference/paddle_tensorrt_infer.md
+64
-37
未找到文件。
doc/fluid/advanced_usage/deploy/inference/native_infer.md
浏览文件 @
45f142c0
# 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
)
doc/fluid/advanced_usage/deploy/inference/paddle_tensorrt_infer.md
浏览文件 @
45f142c0
# 使用Paddle-TensorRT库预测
# 使用Paddle-TensorRT库预测
NVIDIA TensorRT 是一个高性能的深度学习预测库,可为深度学习推理应用程序提供低延迟和高吞吐量。PaddlePaddle 采用了子图的形式对TensorRT进行了集成,即我们可以使用该模块来提升Paddle模型的预测性能。该模块依旧在持续开发中,目前已支持的模型有:AlexNet, MobileNet
, ResNet50, VGG19, ResNext, Se-ReNext, Googl
eNet, DPN, ICNET, Deeplabv3, MobileNet-SSD等。在这篇文档中,我们将会对Paddle-TensorRT库的获取、使用和原理进行介绍。
NVIDIA TensorRT 是一个高性能的深度学习预测库,可为深度学习推理应用程序提供低延迟和高吞吐量。PaddlePaddle 采用了子图的形式对TensorRT进行了集成,即我们可以使用该模块来提升Paddle模型的预测性能。该模块依旧在持续开发中,目前已支持的模型有:AlexNet, MobileNet
V1, ResNet50, VGG19, ResNext, Se-ReNext, GoogL
eNet, 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 可以根据自己的需求自行打开
# MKL
DNN
可以根据自己的需求自行打开
cmake .. \
cmake .. \
-DWITH_FLUID_ONLY=ON \
-DWITH_FLUID_ONLY=ON \
-DWITH_MKL=O
FF
\
-DWITH_MKL=O
N
\
-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. 创建
MixedRT
Config
// 1. 创建
Analysis
Config
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.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录