J'expérimentais la construction d'ensembles XGBoost incrémentiels en une étape. Lorsque le Booster est créé par la fonction xgboost.train ( bibliothèque python ), tout semble fonctionner correctement.
Cependant, lorsque je crée le booster et le met à jour en utilisant Booster.update comme ceci :
```python
booster_ = xgboost.Booster({'objective': 'reg:linear'})
booster_.update(dtrain, 1)
the python process fails with a segmentation fault.
## Environment info
Operating System:
* **python 3.6** Mac OS X 10.10.5 (Darwin 14.5.0), Ubuntu 14.04.5 LTS (GNU/Linux 3.19.0-25-generic x86_64);
* **python 2.7** Mac OS X 10.10.6 (Darwin 15.6.0);
Compiler:
* **python 3.6** used `pip install xgboost`;
* **python 2.7** gcc (6.3.0 --without-multilib);
`xgboost` version used:
* **python 3.6** version 0.6 from pip;
* **python 2.7.13** git HEAD 4a63f4ab43480adaaf13bde2485d5bfedd952520;
## Steps to reproduce
```python
import xgboost
dtrain = xgboost.DMatrix(data=[[-1.0], [0.0], [1.0]], label=[0.0, -1.0, 1.0])
booster_ = xgboost.Booster({'objective': 'reg:linear', 'max_depth': 1})
booster_.update(dtrain, 1)
booster_.update(dtrain, 1)
La dernière ligne provoque un défaut de segmentation. Je joins le rapport de crash pour python 2.7.13
Je voudrais clarifier ce que j'attends des mises à jour incrémentielles de l'objet Booster vide renvoyé par
booster_ = xgboost.Booster({'objective': 'reg:linear', 'max_depth': 1})
Selon l'algorithme général d'amplification du gradient, je m'attendais à ce qu'après la mise à jour d'un échantillon (X, y) dans DMatrix dtrain
avec
booster_.update(dtrain, 1)
le booster vide deviendrait soit f_0(x)
-- la prédiction constante, soit f_1(x)
-- prédiction après une étape d'amplification du gradient, comme indiqué ci-dessous (de Hastie, Tibshirani, Friedman; 2013 10e ed page 361).
J'ai réussi à retracer le problème jusqu'à un vecteur vide RegTree::FVec.data
dans l'exemple de reproduction fourni. La trace (manuelle) du deuxième appel à booster_.update
est la suivante :
this->UpdateOneIter(...);
this->PredictRaw(train, &preds_);
gbm_->Predict(data, out_preds, ntree_limit=0);
PredLoopInternal<GBTree>(p_fmat, out_preds, 0, ntree_limit, true);
PredValue(inst, gid, info.GetRoot(ridx), &feats, tree_begin, tree_end);
int tid = trees[i]->GetLeafIndex(*p_feats, root_index);
échoue ici :
include/xgboost/tree_model.h:#L528
..., feat.fvalue(split_index), feat.is_missing(split_index), ...
il semble que feat.data.size() == 0
. Je ne sais pas pourquoi après le premier appel à .update()
ce vecteur est toujours vide, mais non vide après l'appel alternatif à .train()
.
J'ai découvert quelle était la racine du problème. Il s'avère que créer un booster vide en appelant
booster_ = xgboost.Booster({'objective': 'reg:linear'})
n'initialise que partiellement le booster GBTree. En particulier, le paramètre crucial num_feature
est défini par défaut sur 0 et n'est pas mis à jour avec un nombre approprié de fonctionnalités par un appel .update()
ultérieur.
Cependant, passer une valeur explicite pour num_feature
résout l'erreur de segmentation :
booster_ = xgboost.Booster({'objective': 'reg:linear', 'num_feature': dtrain.num_col()})
Je pense que xgboost.Booster()
devrait émettre un avertissement si cache=()
est vide, ou
'num_feature'
n'est pas explicitement défini dans l'argument params
.
Commentaire le plus utile
J'ai découvert quelle était la racine du problème. Il s'avère que créer un booster vide en appelant
n'initialise que partiellement le booster GBTree. En particulier, le paramètre crucial
num_feature
est défini par défaut sur 0 et n'est pas mis à jour avec un nombre approprié de fonctionnalités par un appel
.update()
ultérieur.Cependant, passer une valeur explicite pour
num_feature
résout l'erreur de segmentation :Je pense que
xgboost.Booster()
devrait émettre un avertissement sicache=()
est vide, ou'num_feature'
n'est pas explicitement défini dans l'argumentparams
.