|
|
|
@ -4,8 +4,8 @@
|
|
|
|
|
|
|
|
|
|
### 使用流程
|
|
|
|
|
|
|
|
|
|
使用 C-API 分为:准备工作和预测程序开发两部分。
|
|
|
|
|
- 准备
|
|
|
|
|
使用 C-API 分为:准备预测模型和预测程序开发两部分。
|
|
|
|
|
- 准备预测模型
|
|
|
|
|
1. 将神经网络模型结构进行序列化。
|
|
|
|
|
- 调用C-API预测时,需要提供序列化之后的网络结构和训练好的模型参数文件。
|
|
|
|
|
1. 将PaddlePaddle训练出的模型参数文件(多个)合并成一个文件。
|
|
|
|
@ -14,18 +14,17 @@
|
|
|
|
|
- **注意**:以上两种方式只需选择其一即可。
|
|
|
|
|
- 调用 PaddlePaddle C-API 开发预测序
|
|
|
|
|
1. 初始化PaddlePaddle运行环境。
|
|
|
|
|
1. 创建神经网络的输入,组织输入数据。
|
|
|
|
|
1. 加载模型。
|
|
|
|
|
1. 创建神经网络的输入,组织输入数据。
|
|
|
|
|
1. 进行前向计算,获得计算结果。
|
|
|
|
|
1. 清理。
|
|
|
|
|
|
|
|
|
|
本文档以手写数字识别任务为例,介绍如何使用 C-API 进行预测,完整代码请查看[此目录](https://github.com/PaddlePaddle/Paddle/tree/develop/paddle/capi/examples/model_inference/dense)。
|
|
|
|
|
|
|
|
|
|
这里我们以手写数字识别任务为例,介绍如何使用 C-API 进行预测,完整代码请查看[此目录](https://github.com/PaddlePaddle/Paddle/tree/develop/paddle/capi/examples/model_inference/dense)。
|
|
|
|
|
|
|
|
|
|
运行目录下的 `python mnist_v2.py` 可以使用 PaddlePaddle 内置的 [MNIST 数据集](http://yann.lecun.com/exdb/mnist/)进行训练。脚本中的模型定义了一个简单的含有[两个隐层的全连接网络](https://github.com/PaddlePaddle/book/blob/develop/02.recognize_digits/README.cn.md#softmax回归softmax-regression),网络接受一幅图片作为输入,将图片分类到 0 ~ 9 类别标签之一。训练好的模型默认保存在当前运行目录下的`models`目录中。下面,我们将调用 C-API 加载训练好的模型进行预测。
|
|
|
|
|
### 准备预测模型
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 外部准备
|
|
|
|
|
通过在终端执行`python mnist_v2.py`
|
|
|
|
|
运行[目录](https://github.com/PaddlePaddle/Paddle/tree/develop/paddle/capi/examples/model_inference/dense)下的 `mnist_v2.py` s可以使用 PaddlePaddle 内置的 [MNIST 数据集](http://yann.lecun.com/exdb/mnist/)进行训练。脚本中的模型定义了一个简单的含有[两个隐层的全连接网络](https://github.com/PaddlePaddle/book/blob/develop/02.recognize_digits/README.cn.md#softmax回归softmax-regression),网络接受一幅图片作为输入,将图片分类到 0 ~ 9 类别标签之一。训练好的模型默认保存在当前运行目录下的`models`目录中。下面,我们将调用 C-API 加载训练好的模型进行预测。
|
|
|
|
|
|
|
|
|
|
1. 序列化神经网络模型配置
|
|
|
|
|
|
|
|
|
@ -52,8 +51,7 @@
|
|
|
|
|
代码示例如下:
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
from paddle.utils.merge_model import merge_v2_model
|
|
|
|
|
|
|
|
|
|
from paddle.utils.merge_model import merge_v2_modelss
|
|
|
|
|
from mnist_v2 import network
|
|
|
|
|
|
|
|
|
|
net = network(is_infer=True)
|
|
|
|
@ -70,54 +68,65 @@
|
|
|
|
|
|
|
|
|
|
### 编写预测代码
|
|
|
|
|
|
|
|
|
|
#### step 1. 初始化及加载模型
|
|
|
|
|
#### step 1. 初始化PaddlePaddle运行环境
|
|
|
|
|
使用C-API第一步需首先调用[`paddle_init`](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/capi/main.h#L27) 初始化PaddlePaddle运行环境。接口接受两个参数:参数的个数和参数。
|
|
|
|
|
|
|
|
|
|
1. 初始化PaddlePaddle运行环境。
|
|
|
|
|
```c
|
|
|
|
|
// Initalize the PaddlePaddle runtime environment.
|
|
|
|
|
char* argv[] = {"--use_gpu=False"};
|
|
|
|
|
CHECK(paddle_init(1, (char**)argv));
|
|
|
|
|
```
|
|
|
|
|
下面的代码片段在初始化PaddlePaddle运行环境时指定不使用GPU:
|
|
|
|
|
|
|
|
|
|
1. 加载训练好的模型。
|
|
|
|
|
```c
|
|
|
|
|
// Initalize the PaddlePaddle runtime environment.
|
|
|
|
|
char* argv[] = {"--use_gpu=False"};
|
|
|
|
|
CHECK(paddle_init(1, (char**)argv));
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
这里需要介绍C-API使用中的一个重要概念:Gradient Machine。概念上,在 PaddlePaddle 内部,一个GradientMachine类的对象管理着一组计算层(PaddlePaddle Layers)来完成前向和反向计算,并处理与之相关的所有细节。特别的,在调用C-API预测时只需进行前向计算。这篇文档的之后部分我们会使用`gradient machine`来特指调用PaddlePaddle C-API创建的GradientMachine类的对象。
|
|
|
|
|
下面的代码片段在初始化PaddlePaddle运行环境时指定了两个参数:不使用GPU和[使用MKLDNN](https://github.com/PaddlePaddle/Paddle/blob/develop/doc/design/mkl/mkldnn.md):
|
|
|
|
|
|
|
|
|
|
每一个 `gradient machine` 都会管理维护一份训练好的模型,模型可以通过以下两种方式获取:
|
|
|
|
|
1. 从磁盘加载;这时`gradient machine`会独立拥有一份训练好的模型;
|
|
|
|
|
1. 共享自其它`gradient machine`的模型;这种情况多出现在使用多线程预测时;
|
|
|
|
|
```c
|
|
|
|
|
char* argv[] = {"--use_gpu=False", "--use_mkldnn=True"};
|
|
|
|
|
CHECK(paddle_init(2, (char**)argv));
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
下面的代码片段创建 `gradient machine`,并从指定路径加载训练好的模型。
|
|
|
|
|
#### step2. 加载模型
|
|
|
|
|
|
|
|
|
|
```c
|
|
|
|
|
// Read the binary configuration file generated by `convert_protobin.sh`
|
|
|
|
|
long size;
|
|
|
|
|
void* buf = read_config(CONFIG_BIN, &size);
|
|
|
|
|
这里介绍C-API使用中的一个重要概念:Gradient Machine。概念上,在 PaddlePaddle 内部一个GradientMachine类的对象管理着一组计算层(PaddlePaddle Layers)来完成前向和反向计算,并处理与之相关的所有细节。在调用C-API预测时,只需进行前向计算而无需调用反向计算。这篇文档的之后部分我们会使用`gradient machine`来特指调用PaddlePaddle C-API创建的GradientMachine类的对象。
|
|
|
|
|
|
|
|
|
|
// Create the gradient machine for inference.
|
|
|
|
|
paddle_gradient_machine machine;
|
|
|
|
|
CHECK(paddle_gradient_machine_create_for_inference(&machine, buf, (int)size));
|
|
|
|
|
每一个 `gradient machine` 都会管理维护一份训练好的模型,下面是两种最常用的模型加载方式:
|
|
|
|
|
|
|
|
|
|
// Load the trained model. Modify the parameter MODEL_PATH to set the correct
|
|
|
|
|
// path of the trained model.
|
|
|
|
|
CHECK(paddle_gradient_machine_load_parameter_from_disk(machine, MODEL_PATH));
|
|
|
|
|
```
|
|
|
|
|
1. 从磁盘加载:这时`gradient machine`会独立拥有一份训练好的模型;
|
|
|
|
|
1. 共享自其它`gradient machine`的模型:这种情况多出现在使用多线程预测时,通过多个线程共享同一个模型来减少内存开销。可参考[此示例](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/capi/examples/model_inference/multi_thread/main.c)。
|
|
|
|
|
|
|
|
|
|
下面的代码片段创建 `gradient machine`,并从指定路径加载训练好的模型。
|
|
|
|
|
|
|
|
|
|
```c
|
|
|
|
|
// Read the binary configuration file generated by `convert_protobin.sh`
|
|
|
|
|
long size;
|
|
|
|
|
void* buf = read_config(CONFIG_BIN, &size);
|
|
|
|
|
|
|
|
|
|
// Create the gradient machine for inference.
|
|
|
|
|
paddle_gradient_machine machine;
|
|
|
|
|
CHECK(paddle_gradient_machine_create_for_inference(&machine, buf, (int)size));
|
|
|
|
|
|
|
|
|
|
// Load the trained model. Modify the parameter MODEL_PATH to set the correct
|
|
|
|
|
// path of the trained model.
|
|
|
|
|
CHECK(paddle_gradient_machine_load_parameter_from_disk(machine, MODEL_PATH));
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
##### 注意事项
|
|
|
|
|
1. 以上代码片段使用“仅序列化神经网络结构”的方式加载模型,需要同时指定模型参数存储的路径。
|
|
|
|
|
- 使用PaddlePaddle V2 API训练,模型中所有可学习参数会被存为一个压缩文件,需要手动进行解压,将它们放在同一目录中,C-API不会直接加载 V2 API 存储的压缩文件。
|
|
|
|
|
1. 如果使用`merge model`方式将神经网络结构和训练好的参数序列化到一个文件,请参考此[示例](https://github.com/PaddlePaddle/Mobile/blob/develop/Demo/linux/paddle_image_recognizer.cpp#L59)。
|
|
|
|
|
1. 加载模型有多种方式,也可以在程序运行过程中再加载另外一个模型。
|
|
|
|
|
|
|
|
|
|
#### step 2. 创建神经网络输入,组织输入数据
|
|
|
|
|
|
|
|
|
|
基本使用概念:
|
|
|
|
|
- 在PaddlePaddle内部,神经网络中一个计算层的输入/输出被组织为一个 `Argument` 结构体,如果神经网络有多个输入或者多个输入,每一个输入/输入都会对应有自己的`Argument`。
|
|
|
|
|
- 在PaddlePaddle内部,神经网络中一个计算层的输入输出被组织为一个 `Argument` 结构体,如果神经网络有多个输入或者多个输出,每一个输入/输出都会对应有自己的`Argument`。
|
|
|
|
|
- `Argument` 并不真正“存储”数据,而是将输入/输出数据有机地组织在一起。
|
|
|
|
|
- 在`Argument`内部由:1. `Matrix`(二维矩阵,存储浮点类型输入/输出);2. `IVector`(一维数组,**仅用于存储整型值**,多用于自然语言处理任务)来实际存储数据。
|
|
|
|
|
|
|
|
|
|
*注:本文档使用的示例任务手写数字识别不涉及一维整型数组作为输入,因此,本文档仅讨论二维稠密矩阵作为输入的情形。更多输入数据格式请参考输入/输出数据一节的内容。*
|
|
|
|
|
|
|
|
|
|
这篇文档的之后部分会使用`argument`来**特指** PaddlePaddle C-API中神经网的一个输入/输出,使用`paddle_matrix`**特指**`argument`中用于存储数据的`Matrix`类的对象。
|
|
|
|
|
这篇文档的之后部分会使用`argument`来**特指** PaddlePaddle C-API中神经网络的一个输入/输出,使用`paddle_matrix`**特指**`argument`中用于存储数据的`Matrix`类的对象。
|
|
|
|
|
|
|
|
|
|
于是,在组织神经网络输入,获取输出时,需要思考完成以下工作:
|
|
|
|
|
1. 为每一个输入/输出创建`argument`;
|