Eu estava fazendo experiências com a construção incremental do conjunto XGBoost em uma etapa. Quando o Booster é criado pela função xgboost.train ( biblioteca python ), tudo parece funcionar bem.
No entanto, quando eu crio o booster e o atualizo usando Booster.update assim:
`` `python
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)
A última linha causa falha de segmentação. Anexei o relatório de falha para python 2.7.13
Gostaria de esclarecer qual é a minha expectativa de fazer atualizações incrementais do objeto Booster vazio retornado por
booster_ = xgboost.Booster({'objective': 'reg:linear', 'max_depth': 1})
De acordo com o algoritmo de aumento de gradiente geral, eu esperava que depois de atualizar em uma amostra (X, y) na DMatrix dtrain
com
booster_.update(dtrain, 1)
o impulsionador vazio se tornaria f_0(x)
- a previsão constante, ou f_1(x)
- previsão após uma etapa de aumento de gradiente, conforme mostrado abaixo (de Hastie, Tibshirani, Friedman; página
Consegui rastrear o problema até um vetor RegTree::FVec.data
vazio no exemplo de reprodução fornecido. O rastreamento (manual) da segunda chamada para booster_.update
é o seguinte:
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);
falha aqui:
inclua / xgboost / tree_model.h: # L528
..., feat.fvalue(split_index), feat.is_missing(split_index), ...
parece que feat.data.size() == 0
. Não sei por que, após a primeira chamada para .update()
esse vetor ainda está vazio, mas não está vazio após a chamada alternativa para .train()
.
Eu descobri qual era a raiz do problema. Acontece que a criação de um booster vazio chamando
booster_ = xgboost.Booster({'objective': 'reg:linear'})
inicializa apenas parcialmente o Booster GBTree. Em particular, o parâmetro crucial num_feature
é definido por padrão como 0 e não é atualizado para um número adequado de recursos por uma chamada .update()
subsequente.
No entanto, passar um valor explícito para num_feature
resolve a falha de segmentação:
booster_ = xgboost.Booster({'objective': 'reg:linear', 'num_feature': dtrain.num_col()})
Acho que xgboost.Booster()
deve emitir um aviso se cache=()
estiver vazio, ou
'num_feature'
não está explicitamente definido no argumento params
.
Comentários muito úteis
Eu descobri qual era a raiz do problema. Acontece que a criação de um booster vazio chamando
inicializa apenas parcialmente o Booster GBTree. Em particular, o parâmetro crucial
num_feature
é definido por padrão como 0 e não é atualizado para um número adequado de recursos por uma chamada
.update()
subsequente.No entanto, passar um valor explícito para
num_feature
resolve a falha de segmentação:Acho que
xgboost.Booster()
deve emitir um aviso secache=()
estiver vazio, ou'num_feature'
não está explicitamente definido no argumentoparams
.