Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 116 additions & 37 deletions doc/fluid/advanced_usage/deploy/inference/native_infer.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,20 @@ PaddleTensor 定义了预测最基本的输入输出的数据格式,常用字

## 利用Config 创建不同引擎

高层 API 底层有多种优化实现,我们称之为 engine;不同 engine 的切换通过传递不同的 Config 实现重载
高层 API 底层有多种优化实现,我们称之为 engine;不同 engine 的切换通过传递不同的 Config 实现重载

- `NativeConfig` 原生 engine,由 paddle 原生的 forward operator
组成,可以天然支持所有paddle 训练出的模型,
`Config` 有两种,`NativeConfig` 较简单和稳定,`AnalysisConfig` 功能更新,性能更好

- `AnalysisConfig` TensorRT mixed engine 用于 GPU
- `NativeConfig` 原生 engine,由 paddle 原生的 forward operator
组成,可以天然支持所有paddle 训练出的模型,
- `AnalysisConfig`
- 支持计算图的分析和优化
- 支持最新的各类 op fuse,性能一般比 `NativeConfig` 要好
- 支持 TensorRT mixed engine 用于 GPU
加速,用子图的方式支持了 [TensorRT] ,支持所有paddle
模型,并自动切割部分计算子图到 TensorRT 上加速(WIP),具体的使用方式可以参考[这里](http://paddlepaddle.org/documentation/docs/zh/1.1/user_guides/howto/inference/paddle_tensorrt_infer.html)。

模型,并自动切割部分计算子图到 TensorRT 上加速,具体的使用方式可以参考[这里](http://paddlepaddle.org/documentation/docs/zh/1.1/user_guides/howto/inference/paddle_tensorrt_infer.html)

## 预测部署过程
## 基于 NativeConfig 的预测部署过程

总体上分为以下步骤

Expand Down Expand Up @@ -70,68 +73,144 @@ CHECK(predictor->Run(slots, &outputs));
## 高阶使用

### 输入输出的内存管理

`PaddleTensor` 的 `data` 字段是一个 `PaddleBuf`,用于管理一段内存用于数据的拷贝。

`PaddleBuf` 在内存管理方面有两种模式:

1. 自动分配和管理内存
```c++
int some_size = 1024;
PaddleTensor tensor;
tensor.data.Resize(some_size);
```

```c++
int some_size = 1024;
PaddleTensor tensor;
tensor.data.Resize(some_size);
```

2. 外部内存传入
```c++
int some_size = 1024;
// 用户外部分配内存并保证 PaddleTensor 使用过程中,内存一直可用
void* memory = new char[some_size];

tensor.data.Reset(memory, some_size);
// ...

// 用户最后需要自行删除内存以避免内存泄漏

delete[] memory;
```

```c++
int some_size = 1024;
// 用户外部分配内存并保证 PaddleTensor 使用过程中,内存一直可用
void* memory = new char[some_size];

tensor.data.Reset(memory, some_size);
// ...

// 用户最后需要自行删除内存以避免内存泄漏

delete[] memory;
```

两种模式中,第一种比较方便;第二种则可以严格控制内存的管理,便于与 `tcmalloc` 等库的集成。

### 基于 contrib::AnalysisConfig 提升性能
*AnalyisConfig 目前正在预发布阶段,用 `namespace contrib` 进行了保护,后续可能会有调整*
### 基于 AnalysisConfig 提升性能

`AnalysisConfig` 是目前我们重点优化的版本。

类似 `NativeConfig` , `AnalysisConfig` 可以创建一个经过一系列优化的高性能预测引擎。 其中包含了计算图的分析和优化,以及对一些重要 Op 的融合改写等,**对使用了 While, LSTM, GRU 等模型性能有大幅提升**
类似 `NativeConfig` , `AnalysisConfig` 可以创建一个经过一系列优化的高性能预测引擎。 其中包含了计算图的分析和优化,以及对一些重要 Op 的融合改写等,比如对使用了 While, LSTM, GRU 等模型性能有大幅提升 。

`AnalysisConfig` 的使用方法也和 `NativeConfig` 类似,但 *目前仅支持 CPU,正在增加对GPU 的支持*
`AnalysisConfig` 的使用方法也和 `NativeConfig` 类似

```c++
AnalysisConfig config;
config.SetModel(dirname); // 设定模型的目录
config.EnableUseGpu(100, 0 /*gpu id*/); // 使用GPU, CPU下使用config.DisableGpu();
config.SwitchSpecifyInputNames(true); // 需要指定输入的 name
config.SwitchIrOptim(); // 打开优化开关,运行时会执行一系列的优化
AnalysisConfig config(dirname); // dirname 是模型的路径
// 对于不同的模型存储格式,也可以用 AnalysisConfig config(model_file, params_file)
config.EnableUseGpu(100/*初始显存池大小(MB)*/, 0 /*gpu id*/); // 使用GPU, CPU下使用config.DisableGpu();
config.SwitchIrOptim(); // 打开优化开关,运行时会执行一系列的计算图优化
```

这里需要注意的是,输入的 PaddleTensor 需要指定,比如之前的例子需要修改为

```c++
auto predictor =
paddle::CreatePaddlePredictor<paddle::contrib::AnalysisConfig>(config); // 注意这里需要 AnalysisConfig
auto predictor = paddle::CreatePaddlePredictor(config); // 注意这里需要 AnalysisConfig
// 创建输入 tensor
int64_t data[4] = {1, 2, 3, 4};
paddle::PaddleTensor tensor;
tensor.shape = std::vector<int>({4, 1});
tensor.data.Reset(data, sizeof(data));
tensor.dtype = paddle::PaddleDType::INT64;
tensor.name = "input0"; // 注意这里的 name 需要设定
```

后续的执行过程与 `NativeConfig` 完全一致。

### 多线程预测的建议

#### 数据并行的服务

这种场景下,每个服务线程执行同一种模型,支持 CPU 和 GPU。

Paddle 并没有相关的接口支持,但用户可以简单组合得出,下面演示最简单的实现,用户最好参考具体应用场景做调整

```c++
auto main_predictor = paddle::CreatePaddlePredictor(config);

const int num_threads = 10; // 假设有 10 个服务线程
std::vector<std::thread> threads;
std::vector<decl_type(main_predictor)> predictors;

// 最好初始化时把所有predictor都创建好
predictors.emplace_back(std::move(main_predictor));
for (int i = 1; i < num_threads; i++) {
predictors.emplace_back(main_predictor->Clone());
}
// 创建线程并执行
for (int i = 0; i < num_threads; i++) {
threads.emplace_back([i, &]{
auto& predictor = predictors[i];
// 执行
CHECK(predictor->Run(...));
});
}

// 结尾
for (auto& t : threads) {
if (t.joinable()) t.join();
}

// 结束
```

#### 模型并行的服务

这种场景,使用多个线程/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)


2 changes: 1 addition & 1 deletion external/Paddle
Submodule Paddle updated 55 files
+2 −1 cmake/flags.cmake
+4 −4 paddle/fluid/API.spec
+8 −7 paddle/fluid/framework/details/CMakeLists.txt
+2 −2 paddle/fluid/framework/details/build_strategy.cc
+18 −17 paddle/fluid/framework/details/inplace_op_pass.cc
+8 −7 paddle/fluid/framework/details/inplace_op_pass.h
+364 −28 paddle/fluid/framework/details/memory_optimize_helper.cc
+84 −35 paddle/fluid/framework/details/memory_optimize_helper.h
+454 −9 paddle/fluid/framework/details/memory_optimize_helper_test.cc
+78 −347 paddle/fluid/framework/details/memory_optimize_pass.cc
+7 −50 paddle/fluid/framework/details/memory_optimize_pass.h
+0 −417 paddle/fluid/framework/details/memory_optimize_pass_test.cc
+1 −0 paddle/fluid/framework/details/sequential_execution_pass.cc
+0 −2 paddle/fluid/framework/details/sequential_execution_pass.h
+1 −1 paddle/fluid/framework/inplace_op_inference.h
+17 −16 paddle/fluid/framework/inplace_op_inference_test.cc
+7 −3 paddle/fluid/framework/ir/identity_scale_op_clean_pass.cc
+1 −0 paddle/fluid/framework/ir/infer_clean_graph_pass.cc
+2 −9 paddle/fluid/framework/parallel_executor.cc
+0 −71 paddle/fluid/inference/analysis/ir_passes/subgraph_detector.cc
+1 −26 paddle/fluid/inference/analysis/ir_passes/subgraph_detector.h
+47 −15 paddle/fluid/inference/api/paddle_api.h
+46 −0 paddle/fluid/inference/api/paddle_pass_builder.cc
+2 −45 paddle/fluid/inference/api/paddle_pass_builder.h
+5 −5 paddle/fluid/operators/controlflow/compare_op.cc
+6 −7 paddle/fluid/operators/detection/density_prior_box_op.h
+30 −39 paddle/fluid/operators/detection/prior_box_op.h
+19 −1 paddle/fluid/operators/elementwise/elementwise_op.h
+4 −0 paddle/fluid/operators/lstm_op.h
+5 −0 paddle/fluid/operators/lstmp_op.h
+1 −1 paddle/fluid/operators/random_crop_op.h
+93 −16 paddle/fluid/pybind/pybind.cc
+436 −233 paddle/scripts/fast_install.sh
+1 −0 python/paddle/__init__.py
+13 −0 python/paddle/distributed/__init__.py
+22 −16 python/paddle/distributed/launch.py
+0 −1 python/paddle/fluid/__init__.py
+4 −1 python/paddle/fluid/compiler.py
+2 −2 python/paddle/fluid/contrib/int8_inference/README.md
+5 −1 python/paddle/fluid/contrib/tests/CMakeLists.txt
+0 −4 python/paddle/fluid/contrib/tests/test_calibration.py
+2 −1 python/paddle/fluid/framework.py
+8 −12 python/paddle/fluid/layers/control_flow.py
+4 −1 python/paddle/fluid/layers/io.py
+6 −2 python/paddle/fluid/layers/layer_function_generator.py
+2 −1 python/paddle/fluid/layers/nn.py
+2 −2 python/paddle/fluid/layers/ops.py
+3 −3 python/paddle/fluid/optimizer.py
+4 −1 python/paddle/fluid/parallel_executor.py
+9 −0 python/paddle/fluid/tests/unittests/CMakeLists.txt
+1 −1 python/paddle/fluid/tests/unittests/parallel_executor_test_base.py
+4 −0 python/paddle/fluid/tests/unittests/test_fuse_elewise_add_act_pass.py
+48 −0 python/paddle/fluid/tests/unittests/test_ir_memory_optimize_transformer.py
+1 −0 python/setup.py.in
+1 −6 tools/manylinux1/build_scripts/build.sh