Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C-API for inference. #1062

Merged
merged 57 commits into from
Apr 21, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
fbb1b0e
Start Doing C-API for predict.
reyoung Jan 3, 2017
aa6e252
Doing C-API
reyoung Jan 4, 2017
3fcd81f
Stash
reyoung Jan 5, 2017
a873a40
Try to use standard way to import gflags.
reyoung Jan 5, 2017
106620e
Merge branch 'feature/use_std_cmake' into feature/c_api
reyoung Jan 5, 2017
fdb64ac
add unittest for prediction
reyoung Jan 5, 2017
a22c889
Merge branch 'develop' of github.com:baidu/Paddle into feature/c_api
reyoung Jan 10, 2017
657d204
Merge branch 'feature/add_third_party_for_gflags' into feature/c_api
reyoung Jan 10, 2017
873368f
Add style check to target
reyoung Jan 10, 2017
fe8d5ff
Add WITH_C_API option
reyoung Jan 10, 2017
d23bae7
Merge branch 'develop' of github.com:baidu/Paddle into feature/c_api
reyoung Jan 11, 2017
06b1a6a
Fix unittest
reyoung Jan 11, 2017
4fd6888
C-API for model inference.
reyoung Jan 11, 2017
005ac1f
Add warning message
reyoung Jan 11, 2017
3bc0d8b
Revert unchanged files
reyoung Jan 11, 2017
987a908
Fix a bug, should be ALL in custom_target
reyoung Jan 12, 2017
3b5bed6
Add dump binary config
reyoung Jan 12, 2017
0874a7e
Fix typo in API.h
reyoung Jan 12, 2017
6243853
Add comments.
reyoung Jan 12, 2017
6402214
Fix unittest
reyoung Jan 13, 2017
88c3862
Merge branch 'develop' of github.com:baidu/Paddle into feature/c_api
reyoung Jan 19, 2017
30a6f9b
Start doing shared c_api library
reyoung Jan 19, 2017
510ccfe
Make Paddle exports the symbols
reyoung Jan 19, 2017
4380e73
Merge branch 'develop' of github.com:baidu/Paddle into feature/c_api
reyoung Mar 6, 2017
8a1e32d
Fix compile error.
reyoung Mar 7, 2017
c32ade7
Add todo
reyoung Mar 7, 2017
97c6425
Add some more interfaces
reyoung Mar 7, 2017
3519c63
complete some functions of c-api.
Mar 9, 2017
8feb583
Merge branch 'feature/fix_ccache_not_in_path' into feature/c_api
reyoung Mar 9, 2017
d34322e
Merge branch 'develop' of github.com:baidu/Paddle into feature/c_api
reyoung Mar 9, 2017
5a9987a
Fix bugs in lizhao's code
reyoung Mar 9, 2017
7bb12fd
Refactor API follow comments.
reyoung Mar 10, 2017
5ac9c22
Install shared lib
reyoung Mar 10, 2017
08113b2
Merge branch 'develop' of github.com:baidu/Paddle into feature/c_api
reyoung Mar 20, 2017
b528828
Rename some API to C-Style
reyoung Mar 21, 2017
0afd5c3
Stash
reyoung Mar 21, 2017
c5eac0a
Rename API
reyoung Mar 24, 2017
58e5b87
Add license
reyoung Mar 24, 2017
d49c627
GNU Style API
reyoung Mar 24, 2017
9c1c19b
Merge branch 'develop' of github.com:baidu/Paddle into feature/c_api
reyoung Mar 24, 2017
470bbcf
Add example
reyoung Mar 24, 2017
34b3ee3
Add sequence exampleAdd sequence exampleAdd sequence exampleAdd sequence
reyoung Mar 26, 2017
852a94f
Add model_inference directory
reyoung Mar 26, 2017
0d73f4c
Add usage documentation of C-API.
reyoung Mar 26, 2017
6b78a11
Merge branch 'develop' of github.com:baidu/Paddle into feature/c_api
reyoung Mar 26, 2017
6623096
Add Implementation documentation.
reyoung Mar 26, 2017
505d207
Add toc
reyoung Mar 26, 2017
e7bc880
Revert unchanged file.
reyoung Mar 26, 2017
ddbb610
Find a bug about recommark.
reyoung Mar 27, 2017
18a3588
Merge branch 'develop' of github.com:baidu/Paddle into feature/c_api
reyoung Apr 14, 2017
87dfc12
Follow comments
reyoung Apr 14, 2017
bda2008
Add TODO for GPU unittest
reyoung Apr 14, 2017
28c4cee
Merge branch 'develop' of github.com:baidu/Paddle into feature/c_api
reyoung Apr 19, 2017
91927cc
Change name conventions.
reyoung Apr 20, 2017
d6a7648
Merge branch 'develop' of github.com:baidu/Paddle into feature/c_api
reyoung Apr 20, 2017
dfd79c8
Follow comments.
reyoung Apr 20, 2017
4e0f72e
Typo
reyoung Apr 21, 2017
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
2 changes: 1 addition & 1 deletion paddle/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ add_subdirectory(gserver)
add_subdirectory(pserver)
add_subdirectory(trainer)
add_subdirectory(scripts)

add_subdirectory(capi)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in
${CMAKE_CURRENT_SOURCE_DIR}/setup.py)

Expand Down
49 changes: 49 additions & 0 deletions paddle/capi/Arguments.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include "PaddleCAPI.h"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

看到大家都把这个目录叫做 "c", 这个作为参考

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/dmlc/mxnet/tree/master/src/c_api

一般项目目录第一层是编码语言,就比如Paddle

-- paddle
 |- python
 |- proto

所以有一些项目的会把这部分放到c目录下。而对于Paddle,一来C/CPP区分界限不明显,二来但就这个C-API来说,本身也是C与C++的混合写法。所以很难独立成C目录。

#include "PaddleCAPIPrivate.h"

#define cast(v) paddle::capi::cast<paddle::capi::CArguments>(v)

extern "C" {
int PDArgsCreateNone(PD_Arguments* args) {
auto ptr = new paddle::capi::CArguments();
*args = ptr;
return PD_NO_ERROR;
}

int PDArgsDestroy(PD_Arguments args) {
if (args == nullptr) return PD_NULLPTR;
delete cast(args);
return PD_NO_ERROR;
}

int PDArgsGetSize(PD_Arguments args, uint64_t* size) {
if (args == nullptr || size == nullptr) return PD_NULLPTR;
*size = cast(args)->args.size();
return PD_NO_ERROR;
}

int PDArgsResize(PD_Arguments args, uint64_t size) {
if (args == nullptr) return PD_NULLPTR;
cast(args)->args.resize(size);
return PD_NO_ERROR;
}

int PDArgsSetValue(PD_Arguments args, uint64_t ID, PD_Matrix mat) {
if (args == nullptr || mat == nullptr) return PD_NULLPTR;
auto m = paddle::capi::cast<paddle::capi::CMatrix>(mat);
if (m->mat == nullptr) return PD_NULLPTR;
auto a = cast(args);
if (ID >= a->args.size()) return PD_OUT_OF_RANGE;
a->args[ID].value = m->mat;
return PD_NO_ERROR;
}

int PDArgsGetValue(PD_Arguments args, uint64_t ID, PD_Matrix mat) {
if (args == nullptr || mat == nullptr) return PD_NULLPTR;
auto m = paddle::capi::cast<paddle::capi::CMatrix>(mat);
auto a = cast(args);
if (ID >= a->args.size()) return PD_OUT_OF_RANGE;
m->mat = a->args[ID].value;
return PD_NO_ERROR;
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

目前还不支持sparse与sequence数据

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是的,这个预测目前只支持Dense输入输出的预测。

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arguments希望添加一个设置frameWidthframeHeight的接口,以支持使用变长图像数据的模型。
另外,如果使用maxid_layer作为输出,最终labels存在ids里面,对应的概率存在in里面,要不要增加一个获取in的接口,还是改paddle的core代码?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

先checkin这个版本吧。。

47 changes: 47 additions & 0 deletions paddle/capi/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
if (WITH_DOUBLE)
set(PADDLE_FLOAT_TYPE double)
else ()
set(PADDLE_FLOAT_TYPE float)
endif()

configure_file(config.h.in config.h @ONLY)

set(CAPI_HEADER
PaddleCAPI.h)
set(CAPI_PRIVATE_HEADER
PaddleCAPIPrivate.h)
file(GLOB CAPI_SOURCES *.cpp)

add_library(paddle_capi SHARED ${CAPI_SOURCES})

target_include_directories(paddle_capi PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
add_dependencies(paddle_capi gen_proto_cpp)

target_link_libraries(paddle_capi
paddle_gserver
paddle_function
paddle_pserver
paddle_trainer_lib
paddle_network
paddle_math
paddle_utils
paddle_parameter
paddle_proto
paddle_cuda
${PROTOBUF_LIBRARY}
${LIBGLOG_LIBRARY}
${GFLAGS_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
${CBLAS_LIBS}
${ZLIB_LIBRARIES}
${INTERAL_LIBS}
${CMAKE_DL_LIBS})


set(PADDLE_CAPI_INC_PATH
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR})

if (WITH_TESTING)
add_subdirectory(tests)
endif()
61 changes: 61 additions & 0 deletions paddle/capi/Matrix.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#include "PaddleCAPI.h"
#include "PaddleCAPIPrivate.h"
#include "hl_cuda.h"

#define cast(v) paddle::capi::cast<paddle::capi::CMatrix>(v)
extern "C" {
int PDMatCreate(PD_Matrix* mat, uint64_t height, uint64_t width, bool useGpu) {
auto ptr = new paddle::capi::CMatrix();
ptr->mat = paddle::Matrix::create(height, width, false, useGpu);
*mat = ptr;
return PD_NO_ERROR;
}

int PDMatCreateNone(PD_Matrix* mat) {
auto ptr = new paddle::capi::CMatrix();
*mat = ptr;
return PD_NO_ERROR;
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里PDMatCreateNone似乎用不到,paddle本身的Matrix提供的接口是resizeOrCreate

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里还是用得上的,因为从Arguments中把Matrix拿出来,需要用一个Matrix变量接这个Matrix。初始化的时候可以设置成None。参考这里

int PDMatDestroy(PD_Matrix mat) {
if (mat == nullptr) return PD_NULLPTR;
auto ptr = cast(mat);
delete ptr;
return PD_NO_ERROR;
}

int PDMatCopyToRow(PD_Matrix mat, uint64_t rowID, pd_real* rowArray) {
if (mat == nullptr) return PD_NULLPTR;
auto ptr = cast(mat);
if (ptr->mat == nullptr) return PD_NULLPTR;
if (rowID >= ptr->mat->getHeight()) return PD_OUT_OF_RANGE;
paddle::real* buf = ptr->mat->getRowBuf(rowID);
size_t width = ptr->mat->getWidth();
#ifndef PADDLE_ONLY_CPU
hl_memcpy(buf, rowArray, sizeof(paddle::real) * width);
#else
std::copy(rowArray, rowArray + width, buf);
#endif
return PD_NO_ERROR;
}

int PDMatGetRow(PD_Matrix mat, uint64_t rowID, pd_real** rawRowBuffer) {
if (mat == nullptr) return PD_NULLPTR;
auto ptr = cast(mat);
if (ptr->mat == nullptr) return PD_NULLPTR;
if (rowID >= ptr->mat->getHeight()) return PD_OUT_OF_RANGE;
*rawRowBuffer = ptr->mat->getRowBuf(rowID);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

如果矩阵是GPU上的,返回给用户一个指向row的指针,用户似乎无法直接读取数据吧

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是无法直接读取的。这里只是获得raw pointer
所以GPU的应该给一个回调之类的。

int PDMatAccessRow(PD_Matrix mat, uint64_t rowID, void(*callback)(pd_real* row));

return PD_NO_ERROR;
}

int PDMatGetShape(PD_Matrix mat, uint64_t* height, uint64_t* width) {
if (mat == nullptr) return PD_NULLPTR;
if (height != nullptr) {
*height = cast(mat)->mat->getHeight();
}
if (width != nullptr) {
*width = cast(mat)->mat->getWidth();
}
return PD_NO_ERROR;
}
}
54 changes: 54 additions & 0 deletions paddle/capi/PaddleCAPI.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#ifndef __PADDLE_PADDLE_CAPI_PADDLECAPI_H_INCLUDED__
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#pragma once 我们的规范貌似是这个?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个因为是会被用户使用的库,所以 还是用 #if 作为guard把。

#define __PADDLE_PADDLE_CAPI_PADDLECAPI_H_INCLUDED__
#include <stdbool.h>
#include <stdint.h>
#include "config.h"
#ifdef __cplusplus
extern "C" {
#endif

#define PD_NO_ERROR 0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是不是定义一个enum更好

typedef enum {
  PD_NO_ERROR = 0,
  PD_NULLPTR = 1
} PD_Code;

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是。

#define PD_NULLPTR 1
#define PD_OUT_OF_RANGE 2
#define PD_UNDEFINED_ERROR -1

typedef void* PD_Vector;

int PDVecCreate(PD_Vector* vec, uint64_t size, bool useGpu);

int PDVecDestroy(PD_Vector vec);

int PDVecIsSparse(PD_Vector vec, bool* isSparse);

typedef void* PD_Matrix;

int PDMatCreate(PD_Matrix* mat, uint64_t height, uint64_t width, bool useGpu);

int PDMatDestroy(PD_Matrix mat);

int PDMatCopyToRow(PD_Matrix mat, uint64_t rowID, pd_real* rowArray);

int PDMatGetRow(PD_Matrix mat, uint64_t rowID, pd_real** rawRowBuffer);

int PDMatCreateNone(PD_Matrix* mat);

int PDMatGetShape(PD_Matrix mat, uint64_t* height, uint64_t* width);

typedef void* PD_Arguments;

int PDArgsCreateNone(PD_Arguments* args);

int PDArgsDestroy(PD_Arguments args);

int PDArgsGetSize(PD_Arguments args, uint64_t* size);

int PDArgsResize(PD_Arguments args, uint64_t size);

int PDArgsSetValue(PD_Arguments args, uint64_t ID, PD_Matrix mat);

int PDArgsGetValue(PD_Arguments args, uint64_t ID, PD_Matrix mat);

#ifdef __cplusplus
}
#endif
#endif
27 changes: 27 additions & 0 deletions paddle/capi/PaddleCAPIPrivate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include "PaddleCAPI.h"
#include "paddle/math/Matrix.h"
#include "paddle/math/Vector.h"
#include "paddle/parameter/Argument.h"
#pragma once

namespace paddle {
namespace capi {

struct CVector {
VectorPtr vec;
};

struct CMatrix {
MatrixPtr mat;
};

struct CArguments {
std::vector<paddle::Argument> args;
};

template <typename T>
inline T* cast(void* ptr) {
return reinterpret_cast<T*>(ptr);
}
}
}
26 changes: 26 additions & 0 deletions paddle/capi/Vector.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include "PaddleCAPI.h"
#include "PaddleCAPIPrivate.h"

#define cast(v) paddle::capi::cast<paddle::capi::CVector>(v)
extern "C" {
int PDVecCreate(PD_Vector* vec, uint64_t size, bool useGpu) {
auto ptr = new paddle::capi::CVector();
ptr->vec = paddle::Vector::create(size, useGpu);
*vec = ptr;
return PD_NO_ERROR;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

同上述的Matrix

int PDVecDestroy(PD_Vector vec) {
auto v = cast(vec);
v->vec.reset();
delete v;
return PD_NO_ERROR;
}

int PDVecIsSparse(PD_Vector vec, bool* isSparse) {
if (isSparse == nullptr || vec == nullptr) {
return PD_NULLPTR;
}
*isSparse = cast(vec)->vec->isSparse();
return PD_NO_ERROR;
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

考虑增加PDIVectorSet接口

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个目前只有只读接口,为了预测的时候可以读取到预测的label。暂时不加上输入数据。

6 changes: 6 additions & 0 deletions paddle/capi/config.h.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef __PADDLE_PADDLE_CAPI_CONFIG_H_INCLUDED__
#define __PADDLE_PADDLE_CAPI_CONFIG_H_INCLUDED__

typedef @PADDLE_FLOAT_TYPE@ pd_real;

#endif
15 changes: 15 additions & 0 deletions paddle/capi/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
function(add_capi_unittest TARGET_NAME)
add_executable(
${TARGET_NAME}
${ARGN})
target_link_libraries(
${TARGET_NAME}
paddle_capi
paddle_test_main
${GTEST_LIBRARIES})
target_include_directories(${TARGET_NAME} PUBLIC ${PADDLE_CAPI_INC_PATH})
add_test(NAME ${TARGET_NAME} COMMAND ${TARGET_NAME})
endfunction()

add_capi_unittest(capi_test_mats test_Vector.cpp
test_Matrix.cpp test_Arguments.cpp)
54 changes: 54 additions & 0 deletions paddle/capi/tests/test_Arguments.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#include "PaddleCAPI.h"
#include "gtest/gtest.h"
#include "paddle/utils/ThreadLocal.h"

static std::vector<pd_real> randomBuffer(size_t bufSize) {
auto& eng = paddle::ThreadLocalRandomEngine::get();
std::uniform_real_distribution<pd_real> dist(-1.0, 1.0);
std::vector<pd_real> retv;
retv.reserve(bufSize);
for (size_t i = 0; i < bufSize; ++i) {
retv.push_back(dist(eng));
}
return retv;
}

TEST(CAPIArguments, create) {
PD_Arguments args;
ASSERT_EQ(PD_NO_ERROR, PDArgsCreateNone(&args));
uint64_t size;
ASSERT_EQ(PD_NO_ERROR, PDArgsGetSize(args, &size));
ASSERT_EQ(0UL, size);
ASSERT_EQ(PD_NO_ERROR, PDArgsDestroy(args));
}

TEST(CAPIArguments, value) {
PD_Arguments args;
ASSERT_EQ(PD_NO_ERROR, PDArgsCreateNone(&args));
ASSERT_EQ(PD_NO_ERROR, PDArgsResize(args, 1));

PD_Matrix mat;
ASSERT_EQ(PD_NO_ERROR, PDMatCreate(&mat, 128, 64, false));
for (size_t i = 0; i < 128; ++i) {
std::vector<pd_real> sampleBuf = randomBuffer(64);
PDMatCopyToRow(mat, i, sampleBuf.data());
}
ASSERT_EQ(PD_NO_ERROR, PDArgsSetValue(args, 0, mat));

PD_Matrix val;
ASSERT_EQ(PD_NO_ERROR, PDMatCreateNone(&val));

ASSERT_EQ(PD_NO_ERROR, PDArgsGetValue(args, 0, val));

for (size_t i = 0; i < 128; ++i) {
pd_real* row1;
pd_real* row2;

ASSERT_EQ(PD_NO_ERROR, PDMatGetRow(mat, i, &row1));
ASSERT_EQ(PD_NO_ERROR, PDMatGetRow(val, i, &row2));
ASSERT_EQ(row1, row2);
}
ASSERT_EQ(PD_NO_ERROR, PDMatDestroy(val));
ASSERT_EQ(PD_NO_ERROR, PDMatDestroy(mat));
ASSERT_EQ(PD_NO_ERROR, PDArgsDestroy(args));
}
33 changes: 33 additions & 0 deletions paddle/capi/tests/test_Matrix.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include "PaddleCAPI.h"
#include "gtest/gtest.h"

TEST(CAPIMatrix, create) {
PD_Matrix mat;
ASSERT_EQ(PD_NO_ERROR, PDMatCreate(&mat, 128, 32, false));
std::vector<pd_real> sampleRow;
sampleRow.resize(32);
for (size_t i = 0; i < sampleRow.size(); ++i) {
sampleRow[i] = 1.0 / (i + 1.0);
}
ASSERT_EQ(PD_NO_ERROR, PDMatCopyToRow(mat, 0, sampleRow.data()));
ASSERT_EQ(PD_OUT_OF_RANGE, PDMatCopyToRow(mat, 128, sampleRow.data()));

pd_real* arrayPtr;

ASSERT_EQ(PD_NO_ERROR, PDMatGetRow(mat, 0, &arrayPtr));
for (size_t i = 0; i < sampleRow.size(); ++i) {
ASSERT_NEAR(sampleRow[i], arrayPtr[i], 1e-5);
}

uint64_t height, width;
ASSERT_EQ(PD_NO_ERROR, PDMatGetShape(mat, &height, &width));
ASSERT_EQ(128, height);
ASSERT_EQ(32, width);
ASSERT_EQ(PD_NO_ERROR, PDMatDestroy(mat));
}

TEST(CAPIMatrix, createNone) {
PD_Matrix mat;
ASSERT_EQ(PD_NO_ERROR, PDMatCreateNone(&mat));
ASSERT_EQ(PD_NO_ERROR, PDMatDestroy(mat));
}
Loading