在 C++ 中使用 XGBOOST

Using XGBOOST in c++

如何在 C++ 中使用 XGBOOST https://github.com/dmlc/xgboost/ 库?我创建了 Python 和 Java API,但是我找不到 API for c++

没有我知道的例子。有一个包含 C/C++ api 包的 c_api.h 文件,您必须找到使用它的方法。我刚刚这样做了。我花了几个小时阅读代码并尝试了一些东西。但最终我设法创建了一个 xgboost 的工作 C++ 示例。

我最终使用了 C API,请看下面的示例:

// create the train data
int cols=3,rows=5;
float train[rows][cols];
for (int i=0;i<rows;i++)
    for (int j=0;j<cols;j++)
        train[i][j] = (i+1) * (j+1);

float train_labels[rows];
for (int i=0;i<rows;i++)
    train_labels[i] = 1+i*i*i;


// convert to DMatrix
DMatrixHandle h_train[1];
XGDMatrixCreateFromMat((float *) train, rows, cols, -1, &h_train[0]);

// load the labels
XGDMatrixSetFloatInfo(h_train[0], "label", train_labels, rows);

// read back the labels, just a sanity check
bst_ulong bst_result;
const float *out_floats;
XGDMatrixGetFloatInfo(h_train[0], "label" , &bst_result, &out_floats);
for (unsigned int i=0;i<bst_result;i++)
    std::cout << "label[" << i << "]=" << out_floats[i] << std::endl;

// create the booster and load some parameters
BoosterHandle h_booster;
XGBoosterCreate(h_train, 1, &h_booster);
XGBoosterSetParam(h_booster, "booster", "gbtree");
XGBoosterSetParam(h_booster, "objective", "reg:linear");
XGBoosterSetParam(h_booster, "max_depth", "5");
XGBoosterSetParam(h_booster, "eta", "0.1");
XGBoosterSetParam(h_booster, "min_child_weight", "1");
XGBoosterSetParam(h_booster, "subsample", "0.5");
XGBoosterSetParam(h_booster, "colsample_bytree", "1");
XGBoosterSetParam(h_booster, "num_parallel_tree", "1");

// perform 200 learning iterations
for (int iter=0; iter<200; iter++)
    XGBoosterUpdateOneIter(h_booster, iter, h_train[0]);

// predict
const int sample_rows = 5;
float test[sample_rows][cols];
for (int i=0;i<sample_rows;i++)
    for (int j=0;j<cols;j++)
        test[i][j] = (i+1) * (j+1);
DMatrixHandle h_test;
XGDMatrixCreateFromMat((float *) test, sample_rows, cols, -1, &h_test);
bst_ulong out_len;
const float *f;
XGBoosterPredict(h_booster, h_test, 0,0,&out_len,&f);

for (unsigned int i=0;i<out_len;i++)
    std::cout << "prediction[" << i << "]=" << f[i] << std::endl;


// free xgboost internal structures
XGDMatrixFree(h_train[0]);
XGDMatrixFree(h_test);
XGBoosterFree(h_booster);

为了解决这个问题,我们从 C++ 源代码运行 xgboost 程序。

使用 XGBoost C API。

  BoosterHandle booster;
  const char *model_path = "/path/of/model";

  // create booster handle first
  XGBoosterCreate(NULL, 0, &booster);

  // by default, the seed will be set 0
  XGBoosterSetParam(booster, "seed", "0");

  // load model
  XGBoosterLoadModel(booster, model_path);

  const int feat_size = 100;
  const int num_row = 1;
  float feat[num_row][feat_size];

  // create some fake data for predicting
  for (int i = 0; i < num_row; ++i) {
    for(int j = 0; j < feat_size; ++j) {
      feat[i][j] = (i + 1) * (j + 1)
    }
  }

  // convert 2d array to DMatrix
  DMatrixHandle dtest;
  XGDMatrixCreateFromMat(reinterpret_cast<float*>(feat),
                         num_row, feat_size, NAN, &dtest);

  // predict
  bst_ulong out_len;
  const float *f;
  XGBoosterPredict(booster, dtest, 0, 0, &out_len, &f);
  assert(out_len == num_row);
  std::cout << f[0] << std::endl;

  // free memory
  XGDMatrixFree(dtest);
  XGBoosterFree(booster);

请注意,当您要加载现有模型时(如上面的代码所示),您必须确保训练中的数据格式与预测中的相同。所以,如果你用 XGBoosterPredict 预测,它接受一个密集矩阵作为参数,你必须在训练中使用密集矩阵。

使用 libsvm 格式进行训练并使用密集矩阵进行预测可能会导致错误的预测,如 XGBoost FAQ 所说:

“Sparse” elements are treated as if they were “missing” by the tree booster, and as zeros by the linear booster. For tree models, it is important to use consistent data formats during training and scoring.

你需要的是:https://github.com/EmbolismSoil/xgboostpp

#include "xgboostpp.h"
#include <algorithm>
#include <iostream>

int main(int argc, const char* argv[])
{
    auto nsamples = 2;
    auto xgb = XGBoostPP(argv[1], 3); //特征列有4列, label有3个, iris例子中分别为三种类型的花,回归任何的话,这里nlabel=1即可

    //result = array([[9.9658281e-01, 2.4966884e-03, 9.2058454e-04],
    //       [9.9608469e-01, 2.4954407e-03, 1.4198524e-03]], dtype=float32)
    XGBoostPP::Matrix features(2, 4);
    features <<
        5.1, 3.5, 1.4, 0.2,
        4.9, 3.0, 1.4, 0.2;

    XGBoostPP::Matrix y;
    auto ret = xgb.predict(features, y);
    if (ret != 0){
        std::cout << "predict error" << std::endl;
    }

    std::cout << "intput : \n" << features << std::endl << "output: \n" << y << std::endl;
}

如果 Python 中的训练没问题,而您只需要 运行 C++ 中的预测,那么有一个很好的工具可以从经过训练的模型中生成静态 if/else-code:

https://github.com/popcorn/xgb2cpp

在花了一天时间尝试在 C++ 中加载和使用 xgboost 模型但没有成功后,我最终使用了它。 xgb2cpp 生成的代码可以立即运行,并且还有一个很好的好处,那就是它没有任何依赖性。