You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 19:42:31