C API 教程
在本教程中,我们将安装 XGBoost 库,并配置我们的 C/C++ 应用程序的 CMakeLists.txt 文件,以便将 XGBoost 库与我们的应用程序链接。之后,我们将看到一些使用 C API 的有用提示,并提供代码片段作为示例,以使用 C API 中可用的各种函数来执行加载、训练模型和在测试数据集上进行预测等基本任务。有关 API 参考,请访问 XGBoost C 包
要求
安装 CMake - 请按照 CMake 安装文档 的说明进行操作。安装 Conda - 请按照 Conda 安装文档 的说明进行操作。
在 conda 环境中安装 XGBoost
在你的终端上运行以下命令。下面的命令将在你克隆的仓库中的XGBoost文件夹内安装XGBoost。
# clone the XGBoost repository & its submodules
git clone --recursive https://github.com/dmlc/xgboost
cd xgboost
mkdir build
cd build
# Activate the Conda environment, into which we'll install XGBoost
conda activate [env_name]
# Build the compiled version of XGBoost inside the build folder
cmake .. -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX
# install XGBoost in your conda environment (usually under [your home directory]/miniconda3)
make install
配置你的应用程序的CMakeList.txt文件以与XGBoost链接
这里,我们假设您的C++应用程序使用CMake进行构建。
在你的应用程序的 CMakeList.txt 中使用 find_package()
和 target_link_libraries()
来链接 XGBoost 库:
cmake_minimum_required(VERSION 3.18)
project(your_project_name LANGUAGES C CXX VERSION your_project_version)
find_package(xgboost REQUIRED)
add_executable(your_project_name /path/to/project_file.c)
target_link_libraries(your_project_name xgboost::xgboost)
为了确保 CMake 能够定位 XGBoost 库,在调用 CMake 时提供 -DCMAKE_PREFIX_PATH=$CONDA_PREFIX
参数。此选项指示 CMake 在 $CONDA_PREFIX
中定位 XGBoost 库,这是您的 Conda 环境所在的位置。
# Navigate to the build directory for your application
cd build
# Activate the Conda environment where we previously installed XGBoost
conda activate [env_name]
# Invoke CMake with CMAKE_PREFIX_PATH
cmake .. -DCMAKE_PREFIX_PATH=$CONDA_PREFIX
# Build your application
make
需要记住的有用提示
以下是使用C API时的一些有用提示:
错误处理:始终检查C API函数的返回值。
在C应用程序中:使用以下宏来保护所有对XGBoost的C API函数的调用。该宏会打印所有发生的错误/异常:
1#define safe_xgboost(call) { \
2 int err = (call); \
3 if (err != 0) { \
4 fprintf(stderr, "%s:%d: error in %s: %s\n", __FILE__, __LINE__, #call, XGBGetLastError()); \
5 exit(1); \
6 } \
7}
在你的应用程序中,将所有 C API 函数调用用以下宏包裹:
DMatrixHandle train;
safe_xgboost(XGDMatrixCreateFromFile("/path/to/training/dataset/", silent, &train));
在C++应用程序中:修改宏
safe_xgboost
以在发生错误时抛出异常。
1#define safe_xgboost(call) { \
2 int err = (call); \
3 if (err != 0) { \
4 throw std::runtime_error(std::string(__FILE__) + ":" + std::to_string(__LINE__) + \
5 ": error in " + #call + ":" + XGBGetLastError()); \
6 } \
7}
断言技术:它在 C/C++ 中都有效。如果表达式计算结果为 0(假),则表达式、源代码文件名和行号将被发送到标准错误,然后调用 abort() 函数。它可用于测试代码中你做出的假设。
DMatrixHandle dmat;
assert( XGDMatrixCreateFromFile("training_data.libsvm", 0, &dmat) == 0);
始终记得通过 BoosterHandle 和 DMatrixHandle 适当地释放分配的空间:
1#include <assert.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <xgboost/c_api.h>
5
6int main(int argc, char** argv) {
7 int silent = 0;
8
9 BoosterHandle booster;
10
11 // do something with booster
12
13 //free the memory
14 XGBoosterFree(booster);
15
16 DMatrixHandle DMatrixHandle_param;
17
18 // do something with DMatrixHandle_param
19
20 // free the memory
21 XGDMatrixFree(DMatrixHandle_param);
22
23 return 0;
24}
对于树模型,在训练和评分/预测过程中使用一致的数据格式非常重要,否则会导致错误的输出。例如,如果我们的训练数据是
dense matrix
格式,那么您的预测数据集也应该是dense matrix
格式;如果在libsvm
格式中进行训练,那么预测的数据集也应该是libsvm
格式。在booster handle对象中设置参数值时,始终使用字符串。参数值可以是任何数据类型(例如int、char、float、double等),但它们应始终编码为字符串。
BoosterHandle booster;
XGBoosterSetParam(booster, "parameter_name", "0.1");
使用C API函数的示例代码
如果数据集以文件形式存在,可以使用
XGDMatrixCreateFromFile()
将其加载到DMatrix
对象中。
DMatrixHandle data; // handle to DMatrix
// Load the data from file & store it in data variable of DMatrixHandle datatype
safe_xgboost(XGDMatrixCreateFromFile("/path/to/file/filename", silent, &data));
你也可以使用
XGDMatrixCreateFromMat()
从二维矩阵创建一个DMatrix
对象。
1// 1D matrix
2const int data1[] = { 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
3
4// 2D matrix
5const int ROWS = 5, COLS = 3;
6const int data2[ROWS][COLS] = { {1, 2, 3}, {2, 4, 6}, {3, -1, 9}, {4, 8, -1}, {2, 5, 1}, {0, 1, 5} };
7DMatrixHandle dmatrix1, dmatrix2;
8// Pass the matrix, no of rows & columns contained in the matrix variable
9// here '0' represents the missing value in the matrix dataset
10// dmatrix variable will contain the created DMatrix using it
11safe_xgboost(XGDMatrixCreateFromMat(data1, 1, 50, 0, &dmatrix));
12// here -1 represents the missing value in the matrix dataset
13safe_xgboost(XGDMatrixCreateFromMat(data2, ROWS, COLS, -1, &dmatrix2));
使用
XGBoosterCreate()
创建一个用于训练和测试数据集的 Booster 对象
1BoosterHandle booster;
2const int eval_dmats_size;
3// We assume that training and test data have been loaded into 'train' and 'test'
4DMatrixHandle eval_dmats[eval_dmats_size] = {train, test};
5safe_xgboost(XGBoosterCreate(eval_dmats, eval_dmats_size, &booster));
对于每个
DMatrix
对象,使用XGDMatrixSetFloatInfo()
设置标签。之后,您可以使用XGDMatrixGetFloatInfo()
访问标签。
1const int ROWS=5, COLS=3;
2const int data[ROWS][COLS] = { {1, 2, 3}, {2, 4, 6}, {3, -1, 9}, {4, 8, -1}, {2, 5, 1}, {0, 1, 5} };
3DMatrixHandle dmatrix;
4
5safe_xgboost(XGDMatrixCreateFromMat(data, ROWS, COLS, -1, &dmatrix));
6
7// variable to store labels for the dataset created from above matrix
8float labels[ROWS];
9
10for (int i = 0; i < ROWS; i++) {
11 labels[i] = i;
12}
13
14// Loading the labels
15safe_xgboost(XGDMatrixSetFloatInfo(dmatrix, "label", labels, ROWS));
16
17// reading the labels and store the length of the result
18bst_ulong result_len;
19
20// labels result
21const float *result;
22
23safe_xgboost(XGDMatrixGetFloatInfo(dmatrix, "label", &result_len, &result));
24
25for(unsigned int i = 0; i < result_len; i++) {
26 printf("label[%i] = %f\n", i, result[i]);
27}
根据需求使用
XGBoosterSetParam()
设置Booster
对象的参数。查看完整的参数列表 这里 。
1BoosterHandle booster;
2safe_xgboost(XGBoosterSetParam(booster, "booster", "gblinear"));
3// default max_depth =6
4safe_xgboost(XGBoosterSetParam(booster, "max_depth", "3"));
5// default eta = 0.3
6safe_xgboost(XGBoosterSetParam(booster, "eta", "0.1"));
分别使用
XGBoosterUpdateOneIter()
和XGBoosterEvalOneIter()
来训练和评估模型。
1int num_of_iterations = 20;
2const char* eval_names[eval_dmats_size] = {"train", "test"};
3const char* eval_result = NULL;
4
5for (int i = 0; i < num_of_iterations; ++i) {
6 // Update the model performance for each iteration
7 safe_xgboost(XGBoosterUpdateOneIter(booster, i, train));
8
9 // Give the statistics for the learner for training & testing dataset in terms of error after each iteration
10 safe_xgboost(XGBoosterEvalOneIter(booster, i, eval_dmats, eval_names, eval_dmats_size, &eval_result));
11 printf("%s\n", eval_result);
12}
备注
对于自定义损失函数,请使用 XGBoosterBoostOneIter()
并手动指定梯度和二阶梯度。
使用
XGBoosterPredictFromDMatrix()
预测测试集的结果
1char const config[] =
2 "{\"training\": false, \"type\": 0, "
3 "\"iteration_begin\": 0, \"iteration_end\": 0, \"strict_shape\": false}";
4/* Shape of output prediction */
5uint64_t const* out_shape;
6/* Dimension of output prediction */
7uint64_t out_dim;
8/* Pointer to a thread local contiguous array, assigned in prediction function. */
9float const* out_result = NULL;
10safe_xgboost(
11 XGBoosterPredictFromDMatrix(booster, dmatrix, config, &out_shape, &out_dim, &out_result));
12
13for (unsigned int i = 0; i < output_length; i++){
14 printf("prediction[%i] = %f \n", i, output_result[i]);
15}
使用
XGBoosterGetNumFeature()
获取数据集中特征的数量。
1bst_ulong num_of_features = 0;
2
3// Assuming booster variable of type BoosterHandle is already declared
4// and dataset is loaded and trained on booster
5// storing the results in num_of_features variable
6safe_xgboost(XGBoosterGetNumFeature(booster, &num_of_features));
7
8// Printing number of features by type conversion of num_of_features variable from bst_ulong to unsigned long
9printf("num_feature: %lu\n", (unsigned long)(num_of_features));
使用
XGBoosterSaveModel()
保存模型
BoosterHandle booster;
const char *model_path = "/path/of/model.json";
safe_xgboost(XGBoosterSaveModel(booster, model_path));
使用
XGBoosterLoadModel()
加载模型
1BoosterHandle booster;
2const char *model_path = "/path/of/model.json";
3
4// create booster handle first
5safe_xgboost(XGBoosterCreate(NULL, 0, &booster));
6
7// set the model parameters here
8
9// load model
10safe_xgboost(XGBoosterLoadModel(booster, model_path));
11
12// predict the model here
使用
XGDMatrixFree()
和XGBoosterFree()
释放代码中使用的所有内部结构。这一步对于防止内存泄漏非常重要。
safe_xgboost(XGDMatrixFree(dmatrix));
safe_xgboost(XGBoosterFree(booster));