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 #1271

Open
sdcb opened this issue Jun 4, 2024 · 3 comments
Open

希望提供C API #1271

sdcb opened this issue Jun 4, 2024 · 3 comments
Assignees

Comments

@sdcb
Copy link

sdcb commented Jun 4, 2024

问题描述
您好,感谢您们对Paddle2ONNX项目的贡献。我在使用Paddle2ONNX进行模型转换时遇到了移植问题。目前只有C++ API,对于我们团队来说,如果有C API的话,将会更容易将该项目移植到C#等其它编程语言中。能否考虑提供一个C API接口?我们相信这会为更多开发者带来便利,非常感谢!

更多信息 :

  • 用于部署的推理引擎: 无特殊要求
  • 为什么需要转换为ONNX格式:为了在多种平台和设备上进行推理
  • Paddle2ONNX版本: 最近更新的版本

报错截图

其他信息

@Zheng-Bicheng
Copy link
Collaborator

您好,我的理解上C API无非是对C++ API再做了一层封装,难度应该不大。您是否能提交一个PR来完成这个工作呢,我可以配合您来完成。(我也很想把该项目移植到C#等其它编程语言中,但是现在确实人手有限)

@Zheng-Bicheng Zheng-Bicheng self-assigned this Jun 5, 2024
@sdcb
Copy link
Author

sdcb commented Jun 5, 2024

这是一套可能的设计(可能大语言模型生成):

paddle2onnx_c_api.h:

#ifndef PADDLE2ONNX_C_API_H
#define PADDLE2ONNX_C_API_H

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

// 默认和C++ API一样的导出逻辑
#if defined(_WIN32)
#ifdef PADDLE2ONNX_C_LIB
#define PADDLE2ONNX_C_API __declspec(dllexport)
#else
#define PADDLE2ONNX_C_API __declspec(dllimport)
#endif
#else
#define PADDLE2ONNX_C_API __attribute__((visibility("default")))
#endif

// 数据结构定义
typedef struct {
    char op_name[100];
    char export_op_name[100];
} Paddle2ONNX_CustomOp;

typedef struct {
    char name[100];
    int64_t* shape;
    int32_t rank;
    int32_t dtype;
} Paddle2ONNX_ModelTensorInfo;

typedef struct {
    int64_t background_label;
    int64_t keep_top_k;
    float nms_eta;
    float nms_threshold;
    float score_threshold;
    int64_t nms_top_k;
    bool normalized;
} Paddle2ONNX_NMSParameters;

typedef struct {
    Paddle2ONNX_ModelTensorInfo inputs[100];
    Paddle2ONNX_ModelTensorInfo outputs[100];
    int num_inputs;
    int num_outputs;
} Paddle2ONNX_TensorInfoContainer;

// API函数声明
PADDLE2ONNX_C_API int Paddle2ONNX_IsExportable(
    const char* model, const char* params, int32_t opset_version,
    bool auto_upgrade_opset, bool verbose, bool enable_onnx_checker,
    bool enable_experimental_op, bool enable_optimize,
    Paddle2ONNX_CustomOp* ops, int op_count, const char* deploy_backend);

PADDLE2ONNX_C_API int Paddle2ONNX_Export(
    const char* model, const char* params, char** out, int* out_size,
    int32_t opset_version, bool auto_upgrade_opset, bool verbose,
    bool enable_onnx_checker, bool enable_experimental_op, bool enable_optimize,
    Paddle2ONNX_CustomOp* ops, int op_count, const char* deploy_backend,
    char** calibration_cache, int* calibration_size, const char* external_file,
    bool* save_external, bool export_fp16_model, char** disable_fp16_op_types,
    int disable_fp16_op_types_count);

PADDLE2ONNX_C_API int Paddle2ONNX_RemoveMultiClassNMS(
    const char* onnx_model, int model_size, char** out_model, int* out_model_size);

PADDLE2ONNX_C_API int Paddle2ONNX_ConvertFP32ToFP16(
    const char* onnx_model, int model_size, char** out_model, int* out_model_size);

#ifdef __cplusplus
}
#endif

#endif // PADDLE2ONNX_C_API_H

这是可能的paddle2onnx_c_api.c实现:

#include "paddle2onnx_c_api.h"
#include "paddle2onnx/converter.h"  // Assume this is the correct path to C++ header

#ifdef __cplusplus
extern "C" {
#endif

// Helper function to convert C CustomOps array to C++ vector
static std::vector<paddle2onnx::CustomOp> ConvertCtoCppCustomOps(Paddle2ONNX_CustomOp* ops, int op_count) {
    std::vector<paddle2onnx::CustomOp> cpp_ops(op_count);
    for (int i = 0; i < op_count; i++) {
        strcpy(cpp_ops[i].op_name, ops[i].op_name);
        strcpy(cpp_ops[i].export_op_name, ops[i].export_op_name);
    }
    return cpp_ops;
}

PADDLE2ONNX_C_API int Paddle2ONNX_IsExportable(
    const char* model,
    const char* params,
    int32_t opset_version,
    bool auto_upgrade_opset,
    bool verbose,
    bool enable_onnx_checker,
    bool enable_experimental_op,
    bool enable_optimize,
    Paddle2ONNX_CustomOp* ops,
    int op_count,
    const char* deploy_backend) {
    try {
        std::vector<paddle2onnx::CustomOp> cpp_ops = ConvertCtoCppCustomOps(ops, op_count);
        bool result = paddle2onnx::IsExportable(model, params, opset_version,
                                                auto_upgrade_opset, verbose,
                                                enable_onnx_checker, enable_experimental_op,
                                                enable_optimize, cpp_ops.data(), op_count,
                                                deploy_backend);
        return result ? 0 : 1;
    } catch (...) {
        return -1;
    }
}

PADDLE2ONNX_C_API int Paddle2ONNX_Export(
    const char* model,
    const char* params,
    char** out, int* out_size,
    int32_t opset_version,
    bool auto_upgrade_opset,
    bool verbose,
    bool enable_onnx_checker,
    bool enable_experimental_op,
    bool enable_optimize,
    Paddle2ONNX_CustomOp* ops,
    int op_count,
    const char* deploy_backend,
    char** calibration_cache,
    int* calibration_size,
    const char* external_file,
    bool* save_external,
    bool export_fp16_model,
    char** disable_fp16_op_types,
    int disable_fp16_op_types_count) {
    try {
        std::vector<paddle2onnx::CustomOp> cpp_ops = ConvertCtoCppCustomOps(ops, op_count);
        std::string output;
        std::vector<std::string> disabled_ops(disable_fp16_op_types, disable_fp16_op_types + disable_fp16_op_types_count);
        bool result = paddle2onnx::Export(model, params, &output, opset_version,
                                          auto_upgrade_opset, verbose, enable_onnx_checker,
                                          enable_experimental_op, enable_optimize,
                                          cpp_ops.data(), op_count, deploy_backend,
                                          nullptr, 0, external_file, save_external, export_fp16_model,
                                          disabled_ops.data(), disable_fp16_op_types_count);
        if (result) {
            *out_size = output.size();
            *out = new char[*out_size];
            std::memcpy(*out, output.c_str(), *out_size);
        }
        return result ? 0 : 1;
    } catch (...) {
        return -1;
    }
}

PADDLE2ONNX_C_API int Paddle2ONNX_RemoveMultiClassNMS(
    const char* onnx_model,
    int model_size,
    char** out_model,
    int* out_model_size) {
    try {
        std::string output;
        bool result = paddle2onnx::RemoveMultiClassNMS(onnx_model, model_size, &output);
        if (result) {
            *out_model_size = output.size();
            *out_model = new char[*out_model_size];
            std::memcpy(*out_model, output.c_str(), *out_model_size);
        }
        return result ? 0 : 1;
    } catch (...) {
        return -1;
    }
}

PADDLE2ONNX_C_API int Paddle2ONNX_ConvertFP32ToFP16(
    const char* onnx_model,
    int model_size,
    char** out_model,
    int* out_model_size) {
    try {
        std::string output;
        bool result = paddle2onnx::ConvertFP32ToFP16(onnx_model, model_size, &output);
        if (result) {
            *out_model_size = output.size();
            *out_model = new char[*out_model_size];
            std::memcpy(*out_model, output.c_str(), *out_model_size);
        }
        return result ? 0 : 1;
    } catch (...) {
        return -1;
    }
}

#ifdef __cplusplus
}
#endif

请供参考,由于我不太懂cmake的原理,因此希望上面这些代码对您有帮助。

@jzhang533
Copy link
Collaborator

我简单翻了一下代码。

CMake 里有个编译选项: WITH_STATIC,打开它编译后,配合 header 文件:https://github.com/PaddlePaddle/Paddle2ONNX/blob/develop/paddle2onnx/converter.h 。应该已经算是一个 C API 了。

只是好像没什么文档,我也没有实际跑过。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants