2011-07-01 91 views
18

當我剛剛使用glm進行訓練時,一切正常,我甚至不會耗盡記憶。但是當我運行train(..., method='glm')時,我用完了內存。爲什麼插頁式火車佔用這麼多的記憶?

這是因爲train爲交叉驗證(或任何trControl過程)的每次迭代存儲大量數據?我正在尋找trainControl,我無法找到如何防止此...任何提示?我只關心績效總結,可能是預測的迴應。

(我知道這是不是涉及到從參數整定網格搜索的每次迭代中存儲的數據,因爲有一個爲GLM的無網格,我相信。)

+1

小心地爲別人嘗試一個小的可重複的例子嗎? –

回答

34

的問題是雙重的。 ⅰ)train並不僅僅適合經由glm()一個模型,它將引導該模型,因此,即使與所述默認值,train()將做25個bootstrap樣本,其中,加上問題ⅱ)(或一個)問題的來源和ii)train()只是簡單地調用glm()函數與它的默認值。這些默認值是存儲模型框架(參數model = TRUE?glm),其中包括模型框架樣式中的數據副本。由train()返回的對象已經存儲了$trainingData中的數據副本,並且$finalModel中的"glm"對象也具有實際數據的副本。

在這一點上,只需使用train()運行glm()將生產的完全展開model.frame的原始數據,這將都需要在內存中的重採樣過程舉辦25個人副本 - 這些是否同時持有或由於重新採樣發生在lapply()調用中,因此快速查看代碼不會立即清除。還將有25份原始數據。

重新採樣結束後,返回的對象將包含原始數據的2個副本和model.frame的完整副本。如果您的訓練數據相對於可用RAM來說很大,或者在model.frame中包含許多要擴展的因素,那麼您可以輕鬆使用大量的內存,只是攜帶數據副本。

如果您添加model = FALSE到您的火車通話,這可能會有所作爲。下面是使用在?glm所述clotting數據的一個小例子:

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在下面的註釋中所述。

爲了進一步深入研究代碼,或者發郵件給Max Kuhn,caret的維護人員,以瞭解有關減少內存佔用情況的選項。

+1

很好的答案(就像你的典型,加文)。只會添加glm對象的大小:'> m3 = glm(lot1〜log(u),data = clotting,family = Gamma) > object.size(m3) 47272 bytes' –

+0

@Dwin謝謝,點。我會將該輸出添加到答案中,當然還有歸屬地。 –

+0

謝謝,我請Max在這裏添加一個答案。 – Yang

27

Gavin的回答是現貨。我建立的功能易於使用,而不是速度或效率[1]

首先,使用公式接口可能是一個問題,當你有很多預測變量時。這是R核心可以解決的問題;公式方法需要保留一個非常大但稀疏的矩陣,並且R有包來有效地處理這個問題。例如,對於n = 3,000和p = 2,000,3樹隨機森林模型對象的大小是其1.5倍,使用公式界面(282s vs 12s)時執行時間要長23倍。

其次,您不必保留訓練數據(請參閱trainControl()中的returnData參數)。另外,由於R沒有任何真正的共享內存基礎結構,因此Gavin對於保留在內存中的數據的副本數量是正確的。基本上,每個重新採樣都會創建一個列表,並使用lapply()來處理列表,然後僅返回重新採樣的估計值。另一種方法是依次製作一份數據副本(用於當前重新採樣),執行所需的操作,然後重複其餘的迭代。存在I/O問題,無法進行任何並行處理。 [2]

如果你有一個大的數據集,我建議使用非公式接口(即使實際模型,如glm,最終使用公式)。此外,對於大型數據集,train()保存重新採樣索引供resamples()及其他功能使用。你也可以刪除這些。

Yang - 最好通過str(data)瞭解更多關於數據的信息,這樣我們就可以理解尺寸和其他方面(例如具有多個層次的因素等)。

我希望幫助,

最大

[1]我不應該,我們竭盡全力的時候,我們可以適應儘可能少的模型成爲可能。 「子模型」技巧用於許多模型,例如pls,gbm,rpart,earth和其他許多模型。此外,當一個模型公式和非公式接口(如lda()earth(),我們默認非公式界面。

[2]每一次的,而我得到的瘋狂衝動重啓train()功能。使用foreach可能會圍繞一些問題。

+0

歡迎來到SO @Max,謝謝你提供的信息。我很高興你寫了'train()'以方便使用;我最近一直在使用它來進行一些隨機梯度提升,並且自己寫了一些調整代碼,這是一個啓示,要切換到** caret **和'train()'! –

+0

我提供我自己的模型矩陣和響應向量(必須這樣才能使用'findCorrelation'),所以我不使用任何模型的公式接口。什麼是子模型技巧? – Yang

+1

你提到過哪些包來處理公式的內存使用問題? 「而R有一攬子解決方案來有效處理這個問題」 – Eduardo

1

我認爲以上的回答是有點過時。插入符號和caretEnsemble包現在包括trainControl附加參數「微調」。修剪最初設置爲false,但改變它如果您使用的是模型集合,您還應該指定這兩個參數值,如果您使用的是模型集合,那麼您應該將此參數與returnData = FALSE組合使用,貪婪/堆棧合奏trainControl中的ameter。

對於我的情況,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)) 
相關問題