当我只使用 训练时glm
,一切正常,我什至没有接近耗尽内存。但是当我运行时train(..., method='glm')
,我的内存不足。
这是因为train
为交叉验证的每次迭代(或任何 trControl 过程)存储了大量数据吗?我正在查看,trainControl
但找不到如何防止这种情况...任何提示?我只关心绩效总结,也许还有预测的反应。
(我知道这与存储参数调整网格搜索的每次迭代中的数据无关,因为我相信 glm 没有网格。)
问题有两个方面。i) train
不仅通过拟合模型glm()
,它还将引导该模型,因此即使使用默认值,train()
也会执行 25 个引导样本,再加上问题 ii) 是问题的(或一个)来源,并且ii) train()
只需使用其默认值调用该glm()
函数。这些默认值是存储模型框架(的参数),其中包括模型框架样式的数据副本。中返回的对象已经存储了数据的副本,并且中的对象也有实际数据的副本。model = TRUE
?glm
train()
$trainingData
"glm"
$finalModel
此时,简单地运行glm()
usingtrain()
将生成 25 个完全扩展数据model.frame
和原始数据的副本,这些副本在重采样过程中都需要保存在内存中——这些是同时保存还是连续保存,快速查看并不清楚在代码中,因为重采样发生在lapply()
调用中。还将有 25 个原始数据副本。
重采样完成后,返回的对象将包含原始数据的 2 个副本和model.frame
. 如果您的训练数据相对于可用 RAM 很大或包含许多要model.frame
在 .
如果您添加model = FALSE
到您的火车呼叫中,那可能会有所作为。clotting
这是一个使用数据的小例子?glm
:
clotting <- data.frame(u = c(5,10,15,20,30,40,60,80,100),
lot1 = c(118,58,42,35,27,25,21,19,18),
lot2 = c(69,35,26,21,18,16,13,12,12))
require(caret)
然后
> m1 <- train(lot1 ~ log(u), data=clotting, family = Gamma, method = "glm",
+ model = TRUE)
Fitting: parameter=none
Aggregating results
Fitting model on full training set
> m2 <- train(lot1 ~ log(u), data=clotting, family = Gamma, method = "glm",
+ model = FALSE)
Fitting: parameter=none
Aggregating results
Fitting model on full training set
> object.size(m1)
121832 bytes
> object.size(m2)
116456 bytes
> ## ordinary glm() call:
> m3 <- glm(lot1 ~ log(u), data=clotting, family = Gamma)
> object.size(m3)
47272 bytes
> m4 <- glm(lot1 ~ log(u), data=clotting, family = Gamma, model = FALSE)
> object.size(m4)
42152 bytes
所以返回的对象会有大小差异,训练期间的内存使用会更低。降低多少取决于内部是否在重采样过程中train()
保留内存中的所有副本。model.frame
返回的对象train()
也明显大于返回的对象glm()
- 正如@DWin 在下面的评论中提到的那样。
为了更进一步,要么更仔细地研究代码,要么给caret的维护者 Max Kuhn 发送电子邮件,询问减少内存占用的选项。
加文的回答很到位。我构建函数是为了易于使用,而不是为了速度或效率 [1]
首先,当您有很多预测变量时,使用公式界面可能会成为问题。这是 R Core 可以解决的问题;公式方法需要保留一个非常大但稀疏的terms()
矩阵,并且 R 具有有效处理该问题的包。例如,在 n = 3, 000 和 p = 2, 000 的情况下,使用公式接口(282s 与 12s)时,3-tree 随机森林模型对象的大小是 1.5 倍,执行时间要长 23 倍。
其次,您不必保留训练数据(请参阅returnData
参考资料中的论点trainControl()
)。
此外,由于 R 没有任何真正的共享内存基础设施,Gavin 关于保留在内存中的数据副本的数量是正确的。基本上,每个重采样都会创建一个列表,lapply()
用于处理该列表,然后仅返回重采样的估计值。另一种方法是按顺序制作数据的一个副本(对于当前的重新采样),执行所需的操作,然后重复剩余的迭代。问题在于 I/O 和无法进行任何并行处理。[2]
如果你有一个大数据集,我建议使用非公式接口(即使实际模型,如 glm,最终使用公式)。此外,对于大型数据集,train()
保存重采样索引以供resamples()
其他函数使用。你也可以删除这些。
杨 - 了解更多关于数据的信息会很好,str(data)
这样我们就可以了解维度和其他方面(例如,具有多层次的因素等)。
我希望这会有所帮助,
最大限度
[1] 我不应该竭尽全力尽可能少地拟合模型。“子模型”技巧用于许多模型,例如 pls、gbm、rpart、earth 和许多其他模型。此外,当模型具有公式和非公式接口时(例如lda()
或earth()
,我们默认为非公式接口。
[2] 每隔一段时间我就会有一种重新启动train()
功能的疯狂冲动。使用foreach
可能会解决其中一些问题。
我认为上面的答案有点过时了。caret 和 caretEnsemble 包现在在 trainControl 'trim' 中包含一个附加参数。Trim 最初设置为 FALSE,但将其更改为 TRUE 将显着减小模型大小。对于可能的最小模型尺寸,您应该将它与 returnData=FALSE 结合使用。如果您使用的是模型集成,您还应该在贪婪/堆栈集成 trainControl 中指定这两个参数。
就我而言,一个 1.6gb 的模型在集成控制中的两个参数都缩小到 ~500mb,并且还使用贪婪集成控制中的参数进一步缩小到 ~300mb。
Ensemble_control_A9 <- trainControl(trim=TRUE, method = "repeatedcv", number = 3, repeats = 2, verboseIter = TRUE, returnData = FALSE, returnResamp = "all", classProbs = TRUE, summaryFunction = twoClassSummary, savePredictions = TRUE, allowParallel = TRUE, sampling = "up")
Ensemble_greedy_A5 <- caretEnsemble(Ensemble_list_A5, metric="ROC", trControl=trainControl(number=2, trim=TRUE, returnData = FALSE, summaryFunction=twoClassSummary, classProbs=TRUE))