c++中的Xgboost负载模型(python ->c++预测分数不匹配)

xgboost load model in c++ (python -> c++ prediction scores mismatch)

本文关键字:c++ 不匹配 Xgboost 中的 负载 模型 python      更新时间:2023-10-16

我正在联系所有的c++天才。

我已经在python中训练(并成功测试)了xgboost模型,如下所示:

dtrain 
=xgb.DMatrix(np.asmatrix(X_train),label=np.asarray(y_train,dtype=np.int), feature_names=feat_names)
optimal_model = xgb.train(plst, dtrain)
dtest = xgb.DMatrix(np.asmatrix(X_test),feature_names=feat_names)
optimal_model.save_model('sigdet.model')

我已经关注了一篇关于XgBoost的文章(见链接),它解释了在c++中加载和应用预测的正确方法:

// Load Model
g_learner = std::make_unique<Learner>(Learner::Create({}));
        std::unique_ptr<dmlc::Stream> fi(
            dmlc::Stream::Create(filename, "r"));
        g_learner->Load(fi.get());
// Predict
    DMatrixHandle h_test;
        XGDMatrixCreateFromMat((float *)features, 1, numFeatures , -999.9f, &h_test);
        xgboost::bst_ulong out_len;

        std::vector<float> preds;
        g_learner->Predict((DMatrix*)h_test,true, &preds); 

我的问题(1):我需要创建一个DMatrix*,但是我只有一个DMatrixHandle。我如何正确地创建一个DMatrix与我的数据?

我的问题(2):当我尝试以下预测方法时:

DMatrixHandle h_test;
XGDMatrixCreateFromMat((float *)features, 1, numFeatures , -999.9f, &h_test);
xgboost::bst_ulong out_len;

int res = XGBoosterPredict(g_modelHandle, h_test, 1, 0, &out_len, (const float**)&scores);

我得到的分数与加载完全相同的模型并使用它进行预测(在python中)完全不同。

谁能帮助我在c++和python之间实现一致的结果,谁就可能上天堂。顺便说一句,我需要在c++中为实时应用程序应用预测,否则我会使用不同的语言。

要获取DMatrix,您可以这样做:

g_learner->Predict(static_cast<std::shared_ptr<xgboost::DMatrix>*>(h_test)->get(), true, &pred);
对于问题(2),我没有答案。这其实和我遇到的问题一样。我在python中有一个XGBRegression,我在c++中使用相同的功能获得了不同的结果。

所以你用来序列化你的模型的方法:

    optimal_model.save_model('sigdet.model')

此方法剥离模型的所有特征名称(参见https://github.com/dmlc/xgboost/issues/3089)。

当您将模型加载到c++中进行预测时,不一定要维护列特征的顺序。您可以通过调用.dump_model()方法验证这一点。

此外,在Python和c++模型对象上调用.dump_model()将产生相同的决策树,但Python将具有所有特性名称,而c++可能具有f0, f1, f2, ....您可以比较这两种方法以获得实际的列排序,然后您的预测将跨语言匹配(不完全匹配,b/c四舍五入)。

我不知道列是如何排序的,但它似乎是一个稳定的过程,即使你在滑动数据窗口上重新训练相同的模型,也能保持排序。我不是百分之百有信心,也希望你能说清楚。

这个问题存在于许多Python训练的,其他语言预测的XGBoost模型中。我在Java中遇到过这个问题,似乎没有办法在XGBoost的不同绑定之间持久保存特性列的顺序。

下面是一个例子,但是程序的预测是相同的:

const int cols=3,rows=100;
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<50;i++)
    train_labels[i] = 0;
for (int i=50;i<rows;i++)
    train_labels[i] = 1;

// 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, "objective", "binary:logistic");
XGBoosterSetParam(h_booster, "eval_metric", "error");
XGBoosterSetParam(h_booster, "silent", "0");
XGBoosterSetParam(h_booster, "max_depth", "9");
XGBoosterSetParam(h_booster, "eta", "0.1");
XGBoosterSetParam(h_booster, "min_child_weight", "3");
XGBoosterSetParam(h_booster, "gamma", "0.6");
XGBoosterSetParam(h_booster, "colsample_bytree", "1");
XGBoosterSetParam(h_booster, "subsample", "1");
XGBoosterSetParam(h_booster, "reg_alpha", "10");
// perform 200 learning iterations
for (int iter=0; iter<10; iter++)
    XGBoosterUpdateOneIter(h_booster, iter, h_train[0]);
// predict
const int sample_rows = 100;
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);

在问题(2)中,使用python训练模型,使用c++进行预测。特征向量为float*数组。

DMatrixHandle h_test;
XGDMatrixCreateFromMat((float *)features, 1, numFeatures , -999.9f, &h_test);
xgboost::bst_ulong out_len;
int res = XGBoosterPredict(g_modelHandle, h_test, 1, 0, &out_len, (const 
float**)&scores);

所以你的模型需要使用密集矩阵格式(numpy数组)进行训练。以下是官方文档中的python代码片段。

data = np.random.rand(5, 10)  # 5 entities, each contains 10 features
label = np.random.randint(2, size=5)  # binary target
dtrain = xgb.DMatrix(data, label=label)