使用XGBoost与tidymodels时出现‘Invalid number of trees’错误的解决方法
解决XGBoost调参时「Invalid number of trees」错误
问题场景
使用R 4.2.2 + tidymodels在M1 Mac上针对131条观测、预处理后39个变量的患者数据集构建XGBoost分类模型,已完成交叉验证、数据处理recipe、超参数调参设置及网格构建,但运行tune_grid时反复出现「Invalid number of trees」错误。
相关代码
交叉验证对象
xgb_v_fold <- vfold_cv(data = prone_session_1, v = 5, repeats = 5, strata = mortality_28)
数据处理recipe
xgb_recipe <- recipe(prone_session_1, formula = mortality_28 ~ .) %>% step_rm(patient_id, bmi, weight_kg, fi_o2_supine, pa_o2_supine) %>% step_dummy(all_factor_predictors(), -mortality_28) %>% step_impute_bag(all_predictors()) %>% step_zv()
原模型调参设置
xgb_mod <- boost_tree(mode = 'classification', engine = 'xgboost', mtry = tune(), trees = tune(), min_n = tune(), tree_depth = tune(), learn_rate = tune(), loss_reduction = tune(), sample_size = tune(), stop_iter = tune() )
原调参网格
xgb_param_fin <- extract_parameter_set_dials(xgb_mod) %>% finalize(juice(xgb_recipe)) xgb_grid <- grid_regular(mtry(range = c(1, 39)), trees(), min_n(), tree_depth(range = c(1, 5)), learn_rate(), loss_reduction(), sample_size(range = c(1, 1)), stop_iter(), levels = 10 )
原Workflow运行代码
xgb_results <- workflow() %>% add_model(xgb_mod) %>% add_recipe(xgb_recipe) %>% tune_grid(resamples = xgb_v_fold, grid = xgb_grid)
错误信息
→ NA | error: ℹ In index: 2. Caused by error in `predict.xgb.Booster()`: ! [07:19:55] src/gbm/gbtree.cc:549: Check failed: tree_end <= model_.trees.size() (223 vs. 7) : Invalid number of trees. Stack trace: [bt] (0) 1 xgboost.so 0x000000013a10bd3c dmlc::LogMessageFatal::~LogMessageFatal() + 124 [bt] (1) 2 xgboost.so 0x000000013a16f3b0 xgboost::gbm::GBTree::PredictBatch(xgboost::DMatrix*, xgboost::PredictionCacheEntry*, bool, unsigned int, unsigned int) + 496 [bt] (2) 3 xgboost.so 0x000000013a271434 xgboost::LearnerImpl::PredictRaw(xgboost::DMatrix*, xgboost::PredictionCacheEntry*, bool, unsigned int, unsigned int) const + 116 [bt] (3) 4 xgboost.so 0x000000013a261fb4 xgboost::LearnerImpl::Predict(std::__1::shared_ptr<xgboost::DMatrix>, bool, xgboost::HostDeviceVector<float>*, unsigned int, unsigned int, bool, bool, bool, bool, bool) + 628 [bt] (4) 5 xgboost.so 0x000000013a2ca9e0 XGBoosterPredictFromDMatrix + 800 [b →
错误原因
核心问题是同时对trees(总树数量)和stop_iter(早停迭代次数)进行调参导致冲突:
stop_iter是早停机制的参数,当验证集性能不再提升时,XGBoost会提前停止训练,实际生成的树数量会远小于trees设置的数值。- 但预测时,tidymodels仍会尝试用
trees参数指定的数量去调用模型中的树,导致访问不存在的树节点,触发「Invalid number of trees」错误。
此外,数据集样本量仅131条,却使用5重复5折交叉验证,再加上grid_regular(levels=10)会生成海量调参组合(10^7级),不仅计算效率极低,也容易引发内存或训练逻辑的异常。另外sample_size(range = c(1,1))是固定值,无需放入调参网格。
解决步骤
方案1:移除早停参数,仅调总树数量
如果不需要早停机制,直接从模型定义中移除stop_iter = tune(),只对trees进行调参:
修改后的模型定义
xgb_mod <- boost_tree(mode = 'classification', engine = 'xgboost', mtry = tune(), trees = tune(), min_n = tune(), tree_depth = tune(), learn_rate = tune(), loss_reduction = tune(), sample_size = 1 # 固定值,无需调参 )
修改后的调参网格
xgb_grid <- grid_regular(mtry(range = c(1, 39)), trees(range = c(100, 500)), # 给trees设置合理范围 min_n(), tree_depth(range = c(1, 5)), learn_rate(), loss_reduction(), levels = 5 # 降低levels减少调参组合,适配小样本 )
方案2:启用早停,固定总树数量,仅调早停迭代次数
如果想用早停防止过拟合,需固定trees为一个较大值(确保早停能触发),只对stop_iter调参,同时需要在workflow中添加早停对应的验证集设置:
修改后的模型定义
xgb_mod <- boost_tree(mode = 'classification', engine = 'xgboost', mtry = tune(), trees = 1000, # 固定足够大的总树数 min_n = tune(), tree_depth = tune(), learn_rate = tune(), loss_reduction = tune(), sample_size = 1, stop_iter = tune() # 仅调早停迭代次数 ) %>% set_engine("xgboost", eval_metric = "logloss") # 指定早停用的评估指标
修改后的调参网格
xgb_grid <- grid_regular(mtry(range = c(1, 39)), min_n(), tree_depth(range = c(1, 5)), learn_rate(), loss_reduction(), stop_iter(range = c(5, 50)), # 早停迭代次数范围 levels = 5 )
运行Workflow时添加控制参数
xgb_results <- workflow() %>% add_model(xgb_mod) %>% add_recipe(xgb_recipe) %>% tune_grid(resamples = xgb_v_fold, grid = xgb_grid, control = control_grid(save_pred = TRUE, verbose = TRUE)) # 确保早停逻辑正常运行
额外优化建议
- 针对131条小样本,建议使用普通5折交叉验证(去掉
repeats=5),减少计算负担。 - 调参网格的
levels设置为3-5即可,避免生成过多无效组合。
内容的提问来源于stack exchange,提问作者for_the_love_of_cod
相关产品推荐
相关产品推荐

