0

If below code path is repeated in the same process more than once, XGDMatrixCreateFromMat fails with -1 during second visit. For reference, I followed Using XGBOOST in c++.

But, If I remove the use of dtrain (XGBoosterCreate and the successive calls) in the booster, calling multiple times XGDMatrixCreateFromMat succeeds in the same process, but of course the point of creating the DMatrix is to be able to use with the booster for prediction. Please note that the below code path works when called multiple times from different processes.


DMatrixHandle dtrain[1];

XGDMatrixCreateFromMat(reinterpret_cast<float*>(copied_inputs), 
 data_size, input_dim, -1, &dtrain[0]);
XGDMatrixSetFloatInfo(dtrain[0], "label", copied_labels, data_size);

XGDMatrixCreateFromMat(reinterpret_cast<float*>(copied_test_inputs), 
 test_data_size, input_dim, -1, &dtest);
XGDMatrixSetFloatInfo(dtest, "label", copied_test_labels, test_data_size);

XGBoosterCreate(&dtrain[0], 1, &h_booster_);
for (auto param : hyper_params_) {
    XGBoosterSetParam(h_booster_, param.first.c_str(), param.second.c_str());
}
for (int iter = 0; iter < num_boost_round_; ++iter) {
    XGBoosterUpdateOneIter(h_booster_, iter, dtrain);
    const char* eval_out;
    XGBoosterEvalOneIter(h_booster_, iter, &dtest, &evnames, 1, &eval_out);
}

std::cout << "Deleting dtrain: " << XGDMatrixFree(dtrain) << std::endl;
std::cout << "Deleting dtest: " << XGDMatrixFree(dtest) << std::endl;

std::cout << "XGBoosterFree: " << XGBoosterFree(h_booster_) << std::endl;

How do I create new DMatrix and use it in booster multiple times in the same process.

Rahman
  • 21
  • 4

1 Answers1

1

I found out the actual error, by adding the following line.

if (XGDMatrixCreateFromMat(copied_inputs, data_size, input_dim, -1, &dmat) != 0) {
  std::string error_s(XGBGetLastError());
  std::cout << error_s << std::endl;
}

The error was There are NAN in the matrix, however, you did not set missing=NAN. This hinted me that there was a problem the way I created the float* input. Although, it runs without a problem first time, but the result probably was wrong. I was constructing a copied_inputs like below

float** copied_inputs = new float*[input_size];
float* copied_labels = new float[input_size];
for(size_t i = 0; i < input_size; ++i) {
  for(size_t j = 0; j < input_dim; ++j) {
    copied_inputs[i] = new float[input_dim];
    copied_inputs[i][j] = static_cast<float>(inputs[i][j]);
  }
  copied_labels[i] = static_cast<float>(outputs[i]);
}

The above construction of copied_inputs is clearly wrong as the way it is accessed in the XGDMatrixCreateFromMat is:

  for (xgboost::bst_ulong i = 0; i < nrow; ++i, data += ncol) {
    xgboost::bst_ulong matj = 0;
    for (xgboost::bst_ulong j = 0; j < ncol; ++j) {
      if (common::CheckNAN(data[j])) {
      } else {
        if (nan_missing || data[j] != missing) {
          data_vec[offset_vec[i] + matj] = Entry(j, data[j]);
          ++matj;
        }
      }
    }
  }

So, I changed my copied_inputs construction to:

  float* copied_inputs = new float[data_size * input_dim];
  float* copied_labels = new float[data_size];
  float* temp_copied_inputs = copied_inputs;
  for(size_t i = 0; i < data_size; ++i, temp_copied_inputs += input_dim) {
    for(size_t j = 0; j < input_dim; ++j) {
      temp_copied_inputs[j] = static_cast<float>(inputs[i][j]);
    }
    copied_labels[i] = static_cast<float>(outputs[i]);
  }

And that solved the problem of multiple runs.

Rahman
  • 21
  • 4