使用stacks库堆叠Light GBM与随机森林时Booster不存在错误排查
关于stacks库堆叠LightGBM与随机森林时预测阶段Booster丢失的问题
我用stacks库做LightGBM和随机森林的模型堆叠,完成工作流配置、添加候选模型构建my_stack,执行blend_predictions()和fit_members()得到stack_mod后,调用predict()时触发以下错误:
Error in `purrr::map()`: ℹ In index: 1. ℹ With name: lightGBM_models_1_047. Caused by error in `predictor$predict()`: ! Attempting to use a Booster which no longer exists. This can happen if you have called Booster$finalize() or if this Booster was saved with saveRDS(). To avoid this error in the future, use saveRDS.lgb.Booster() or Booster$save_model() to save lightgbm Boosters.
我知道这个错误通常和LightGBM模型保存后复用有关,但搞不懂为什么前期stack相关步骤(包括识别并移除重复预测结果)都能正常执行,偏偏到预测时Booster就消失了?
原因分析
核心问题出在LightGBM Booster对象的特性和stacks库的内部处理逻辑上:
- LightGBM的Booster是C++对象的R包装器,不像纯R对象那样能被常规的R序列化/引用机制妥善保留。
blend_predictions()阶段只需要成员模型在当前会话中输出一次预测结果,用来生成堆叠所需的特征矩阵,这个过程不需要Booster对象长期存活;fit_members()只是完成成员模型的拟合,但stacks库默认可能没有为LightGBM的Booster做特殊的持久化处理。- 当你完成前面的步骤后,R的垃圾回收机制可能会清理掉没有被显式引用的底层C++ Booster对象,等到调用
predict()时,R包装器还在,但对应的C++对象已经不存在,就会触发这个错误。
解决办法
修改LightGBM模型的保存策略
在定义LightGBM模型时,显式避免Booster被自动finalize,或者改用官方推荐的保存方式:- 如果用parsnip接口,初始化模型时添加参数
save_model = TRUE,或者在拟合后手动用Booster$save_model()保存模型,再在预测前重新加载。 - 直接用lightgbm原生接口的话,调用
lgb.train()时设置save_name参数保存模型,后续用lgb.load()加载。
- 如果用parsnip接口,初始化模型时添加参数
显式保留Booster引用
在构建stack前,手动把LightGBM模型的Booster对象赋值给一个全局环境的变量,避免被垃圾回收:# 假设你的LightGBM工作流拟合后得到model_lgb booster_obj <- extract_fit_parsnip(model_lgb)$booster # 把booster_obj存入全局环境,防止被回收 assign("booster_obj", booster_obj, envir = .GlobalEnv)升级相关库版本
stacks和lightgbm的旧版本可能存在对象持久化的兼容bug,升级到最新版的stacks和lightgbm库,大概率能解决这类底层对象管理的问题。
内容的提问来源于stack exchange,提问作者MMiceli
相关产品推荐
相关产品推荐

