-
Notifications
You must be signed in to change notification settings - Fork 5.6k
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
C-API for inference. #1062
Changes from 1 commit
fbb1b0e
aa6e252
3fcd81f
a873a40
106620e
fdb64ac
a22c889
657d204
873368f
fe8d5ff
d23bae7
06b1a6a
4fd6888
005ac1f
3bc0d8b
987a908
3b5bed6
0874a7e
6243853
6402214
88c3862
30a6f9b
510ccfe
4380e73
8a1e32d
c32ade7
97c6425
3519c63
8feb583
d34322e
5a9987a
7bb12fd
5ac9c22
08113b2
b528828
0afd5c3
c5eac0a
58e5b87
d49c627
9c1c19b
470bbcf
34b3ee3
852a94f
0d73f4c
6b78a11
6623096
505d207
e7bc880
ddbb610
18a3588
87dfc12
bda2008
28c4cee
91927cc
d6a7648
dfd79c8
4e0f72e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
#include "PaddleCAPI.h" | ||
#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; | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 目前还不支持sparse与sequence数据 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 是的,这个预测目前只支持Dense输入输出的预测。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 先checkin这个版本吧。。 |
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() |
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; | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这里PDMatCreateNone似乎用不到,paddle本身的Matrix提供的接口是resizeOrCreate There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 如果矩阵是GPU上的,返回给用户一个指向row的指针,用户似乎无法直接读取数据吧 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 是无法直接读取的。这里只是获得raw pointer 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; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
#ifndef __PADDLE_PADDLE_CAPI_PADDLECAPI_H_INCLUDED__ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. #pragma once 我们的规范貌似是这个? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 是不是定义一个enum更好 typedef enum {
PD_NO_ERROR = 0,
PD_NULLPTR = 1
} PD_Code; There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
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); | ||
} | ||
} | ||
} |
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; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 考虑增加PDIVectorSet接口 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这个目前只有只读接口,为了预测的时候可以读取到预测的label。暂时不加上输入数据。 |
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 |
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) |
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)); | ||
} |
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)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
看到大家都把这个目录叫做 "c", 这个作为参考
There was a problem hiding this comment.
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
所以有一些项目的会把这部分放到c目录下。而对于Paddle,一来C/CPP区分界限不明显,二来但就这个C-API来说,本身也是C与C++的混合写法。所以很难独立成C目录。