|
| 1 | +# C-API 模型推断实现文档 |
| 2 | + |
| 3 | +本文档描述Paddle C-API的实现细节。Paddle C-API是多语言API的基础部分。Paddle需要暴露的API很多。先实现模型推断的API,通过模型推断API的实现作为一个样例,来进行讨论。至于为什么需要C-API,请参考[这里](./00.why_plain_c.md)。 |
| 4 | + |
| 5 | +## 暴露接口原则 |
| 6 | + |
| 7 | +1. 所有的接口均为C接口。即使用`extern "C"` |
| 8 | +2. 除构造某种类型的函数(`paddle_matrix_create`等),其他函数均返回`paddle_error`。且调用时不能抛出异常或出现运行时错误。 |
| 9 | +3. 所有类型名为`paddle_类型名`,所有与类型相关的函数,函数名为`paddle_类型名_函数名` |
| 10 | +4. 如果某一个Paddle Core概念(GradientMachine/Matrix)需要被暴露到其他语言,那么 |
| 11 | + * 为了暴露的接口尽量简单。只暴露概念的接口,而不暴露概念的实现。即暴露`GradientMachine`或者`Matrix`但不暴露`RecurrentGradientMachine`和`CpuSparseMatrix`。 |
| 12 | + * 暴露这个概念必要函数。`必要`是指,即完成某一个任务的最少函数。 |
| 13 | +5. 不在`capi`接口层做过多封装。 |
| 14 | + * 如果某一个Paddle概念必须要暴露,但是又过于琐碎。不在`capi`这一层进行封装,而是直接修改Paddle Core。让Paddle核心中,这一概念不再琐碎。 |
| 15 | + |
| 16 | + |
| 17 | +## 目录结构 |
| 18 | + |
| 19 | +```text |
| 20 | +Paddle |
| 21 | + `-- paddle |
| 22 | + `-- capi |
| 23 | + `-- examples # The example project for C-API. |
| 24 | + `-- tests # unittests for C-API |
| 25 | + `-- capi.h # C-API header file. |
| 26 | + `-- capi_private.h # The shared header file between implementation sources. |
| 27 | + `-- matrix.{h, cpp} |
| 28 | + `-- gradient_machine.{h, cpp} |
| 29 | + `-- ... |
| 30 | +``` |
| 31 | + |
| 32 | + |
| 33 | +Paddle的C-API目录结构如上图表所示。这个目录中除了`capi_private.h`之外的所有头文件,均会被安装到include/paddle路径下。C-API生成的二进制文件会被安装到`lib`目录下。即,安装后的目录结构为 |
| 34 | + |
| 35 | +```text |
| 36 | +`-- include |
| 37 | + `-- paddle |
| 38 | + `-- capi.h |
| 39 | + `-- matrix.h |
| 40 | + `-- gradient_machine.h |
| 41 | + `-- ... |
| 42 | +`-- lib |
| 43 | + `-- libpaddle_capi_shared.{so, dylib} # In mac, dynamic libary's file name extention is `dylib` |
| 44 | + `-- libpaddle_capi_whole.a # static library for all symbols of Paddle. |
| 45 | +``` |
| 46 | + |
| 47 | +## 实现方式 |
| 48 | + |
| 49 | +下面分别介绍某一类文件的实现方式。 |
| 50 | + |
| 51 | +### capi.h |
| 52 | + |
| 53 | +`capi.h`是用户使用C-API时所唯一需要引入的头文件。在`capi.h`中,引入了类型的头文件,`matrix.h`, `gradient_machine.h`。在引入其他类型的头文件时,使用相对路径的引用方式。即`#include "matrix.h"` |
| 54 | + |
| 55 | +### 具体某种类型的头文件 |
| 56 | + |
| 57 | +具体某种类型的头文件,即例如`matrix.h`,`gradient_machine.h`等。在这些头文件中,包含了某种类型的类型定义和暴露的全部函数。 |
| 58 | + |
| 59 | +这个头文件不假设其他文件的引用顺序,即使用户直接引用某种类型的头文件,也不应该报错(虽然不鼓励这样)。如果某一个类型需要引用另一个类型,例如`gradient_machine`需要引用`matrix`,则直接引入另一种类型的头文件,即`#include "matrix.h"`。 |
| 60 | + |
| 61 | +### capi_private.h |
| 62 | + |
| 63 | +`capi_prviate.h`是各个实现中共享的头文件,他主要包含了实际暴露的类型结构。在用户使用C-API时,Paddle的类型全部退化成`void *`,即`typedef paddle_matrix void*`。但,对于每种C-API暴露的类型,均是在`capi_private.h`中实现的结构体。 |
| 64 | + |
| 65 | +```cpp |
| 66 | +struct CMatrix { |
| 67 | + int type = MatrixType; |
| 68 | + std::shared_ptr<paddle::Matrix> mat; |
| 69 | +}; |
| 70 | +``` |
| 71 | +
|
| 72 | +通常,这个结构体包含两个项目。 |
| 73 | +
|
| 74 | +* `type`是一个类型的标志。对于每种类型,type字段均不尽相同。这样,即使C-API接受的类型全是`void *`,我们也可以确定每一个参数的类型。 |
| 75 | +
|
| 76 | + ```cpp |
| 77 | + void some_c_api_function(void* some_instance) { |
| 78 | + int* type = (int *) some_instance; |
| 79 | + switch (*type) { |
| 80 | + case MatrixType: |
| 81 | + CMatrix* mat = (CMatrix *) some_instance; |
| 82 | + ... |
| 83 | + ... |
| 84 | + } |
| 85 | + } |
| 86 | + ``` |
| 87 | +* 这个结构体中的另一个项目是,Paddle Core中这一类型接口的智能指针(shared_ptr)。 |
| 88 | + * 使用智能指针的原因是: 用户可以安全的释放某个C-API的实例,而不必在意Paddle Core是否还在使用这个实例。 |
| 89 | + * 例如,用户通过C-API获得了神经网络的参数实例。当用户使用完这个参数后,直接删除这个参数即可。即便Paddle Core中的模型还在使用这个参数,这个参数也不会一并删除。 |
| 90 | + |
| 91 | +### 具体某种类型的实现文件 |
| 92 | + |
| 93 | +具体某种类型的实现文件,即`matrix.cpp`, `gradient_machine.cpp`等文件。在这些文件中,使用C++ 11实现了C-API的接口,并且使用`extern "C"`导出这些接口。在实现过程中,对输入参数的安全性进行了必要的判断,并将C-API接口的参数转发给`Paddle Core`。 |
| 94 | + |
| 95 | +### libpaddle\_capi_shared.{so, dylib} |
| 96 | + |
| 97 | +`libpaddle_capi_shared`是C-API导出的动态库。这个动态库的连接参数与Paddle的其他二进制(例如`paddle_traienr`)类似。用户可以直接使用这个动态库来引入Paddle C-API。具体使用方法为`-lpaddle_capi_shared`。 |
| 98 | + |
| 99 | +### libpaddle\_capi_whole.a |
| 100 | + |
| 101 | +`libpaddle_capi_whole`是C-API导出的静态库。这个静态库包含了Paddle的全部符号。他是将`libpaddle_gserver.a`, `libpaddle_math.a`, `libpaddle_capi.a`等全部静态库中的目标文件全部打包后产生的文件。具体使用方法为`--whole-archive -lpaddle_capi_whole --no-whole-archive`。 |
| 102 | + |
| 103 | + |
| 104 | +### examples |
| 105 | + |
| 106 | +在样例中,使用`C99`开发了模型预测的样例代码。具体请参考[example/README.md](../../../paddle/capi/examples/README.md)。 |
0 commit comments