Estaba experimentando con la construcción de conjuntos XGBoost incremental de un paso. Cuando el Booster es creado por la función xgboost.train ( biblioteca de Python ), todo parece funcionar bien.
Sin embargo, cuando creo el refuerzo y lo actualizo usando Booster.update así:
`` pitón
booster_ = xgboost.Booster ({'objetivo': '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 última línea provoca una falla de segmentación. Adjunto el informe de fallos para python 2.7.13
Me gustaría aclarar cuál es mi expectativa de hacer actualizaciones incrementales del objeto Booster vacío devuelto por
booster_ = xgboost.Booster({'objective': 'reg:linear', 'max_depth': 1})
De acuerdo con el algoritmo de aumento de gradiente general, esperaba que después de actualizar una muestra (X, y) en DMatrix dtrain
con
booster_.update(dtrain, 1)
el refuerzo vacío se convertiría en f_0(x)
- la predicción constante, o f_1(x)
- predicción después de un paso de aumento de gradiente, como se muestra a continuación (de Hastie, Tibshirani, Friedman; página de la
Logré rastrear el problema hasta un vector RegTree::FVec.data
vacío en el ejemplo de reproducción proporcionado. La traza (manual) de la segunda llamada a booster_.update
es la siguiente:
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);
falla aquí:
incluir / xgboost / tree_model.h: # L528
..., feat.fvalue(split_index), feat.is_missing(split_index), ...
parece que feat.data.size() == 0
. No sé por qué después de la primera llamada a .update()
este vector todavía está vacío, pero no está vacío después de la llamada alternativa a .train()
.
Descubrí cuál era la raíz del problema. Resulta que crear un amplificador vacío llamando
booster_ = xgboost.Booster({'objective': 'reg:linear'})
solo inicializa parcialmente el amplificador GBTree. En particular, el parámetro crucial num_feature
se establece de forma predeterminada en 0 y no se actualiza a un número adecuado de funciones mediante una llamada .update()
posterior.
Sin embargo, pasar un valor explícito para num_feature
resuelve el error de segmentación:
booster_ = xgboost.Booster({'objective': 'reg:linear', 'num_feature': dtrain.num_col()})
Creo que xgboost.Booster()
debería emitir una advertencia si cache=()
está vacío, o
'num_feature'
no se establece explícitamente en el argumento params
.
Comentario más útil
Descubrí cuál era la raíz del problema. Resulta que crear un amplificador vacío llamando
solo inicializa parcialmente el amplificador GBTree. En particular, el parámetro crucial
num_feature
se establece de forma predeterminada en 0 y no se actualiza a un número adecuado de funciones mediante una llamada
.update()
posterior.Sin embargo, pasar un valor explícito para
num_feature
resuelve el error de segmentación:Creo que
xgboost.Booster()
debería emitir una advertencia sicache=()
está vacío, o'num_feature'
no se establece explícitamente en el argumentoparams
.