Почему каретный поезд занимает столько памяти? - PullRequest
20 голосов
/ 01 июля 2011

Когда я тренируюсь только с использованием glm, все работает, и я даже близко не подхожу к истощению памяти. Но когда я запускаю train(..., method='glm'), мне не хватает памяти.

Это потому, что train хранит много данных для каждой итерации перекрестной проверки (или какой-либо другой процедуры trControl)? Я смотрю на trainControl и не могу найти, как предотвратить это ... какие-то намеки? Я забочусь только о сводке производительности и, возможно, о предполагаемых ответах.

(я знаю, что это не связано с хранением данных из каждой итерации поиска по сетке настройки параметров, потому что, я думаю, нет сетки для glm.)

Ответы [ 3 ]

37 голосов
/ 01 июля 2011

Проблема в два раза. i) train не просто соответствует модели через glm(), она будет загружать эту модель, поэтому даже при значениях по умолчанию train() сделает 25 загрузочных выборок который вместе с проблемой ii) является (или a ) источником вашей проблемы, а ii) train() просто вызывает функцию glm() с его по умолчанию. И эти значения по умолчанию - хранить фрейм модели (аргумент model = TRUE из ?glm), который включает в себя копию данных в стиле фрейма модели. Объект, возвращаемый train(), уже хранит копию данных в $trainingData, а объект "glm" в $finalModel также имеет копию фактических данных.

На этом этапе при простом запуске glm() с использованием train() будет получено 25 копий полностью развернутых model.frame и исходных данных, которые необходимо будет хранить в памяти во время процесс повторной выборки - неважно, проводятся ли они одновременно или последовательно, не сразу понятно из быстрого просмотра кода, поскольку повторная выборка происходит при вызове lapply(). Также будет 25 копий необработанных данных.

После завершения повторной выборки возвращаемый объект будет содержать 2 копии необработанных данных и полную копию model.frame. Если ваши тренировочные данные велики по сравнению с доступной оперативной памятью или содержат много факторов, которые необходимо расширить в 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 , по электронной почте, чтобы узнать о возможностях уменьшить объем используемой памяти.

31 голосов
/ 02 июля 2011

Ответ Гэвина точен.Я построил функцию для простоты использования, а не для скорости или эффективности. [1]

Во-первых, использование интерфейса формул может быть проблемой, когда у вас много предикторов.Это то, что R Core может исправить;подход на основе формул требует сохранения очень большой, но разреженной матрицы terms(), и у R есть пакеты для эффективного решения этой проблемы.Например, при n = 3 000 и p = 2 000 объект модели случайного леса с тремя деревьями был в 1,5 раза больше и занимал в 23 раза больше времени при использовании интерфейса формулы (282 с против 12 с).

Во-вторых, вам не нужно хранить обучающие данные (см. Аргумент returnData в trainControl()).

Кроме того, поскольку R не имеет реальной инфраструктуры разделяемой памяти, Гэвинправильно о количестве копий данных, которые хранятся в памяти.Как правило, список создается для каждой повторной выборки, а lapply() используется для обработки списка, а затем возвращаются только пересчитанные оценки.Альтернативой может быть последовательное создание одной копии данных (для текущей повторной выборки), выполнение необходимых операций, а затем повторение для оставшихся итераций.Проблема заключается в вводе-выводе и невозможности выполнения какой-либо параллельной обработки.[2]

Если у вас большой набор данных, я предлагаю использовать не-формулу интерфейса (хотя в реальной модели, такой как glm, в конечном итоге используется формула).Кроме того, для больших наборов данных train() сохраняет индексы передискретизации для использования resamples() и другими функциями.Вы могли бы, вероятно, удалить их тоже.

Ян - было бы хорошо узнать больше о данных через str(data), чтобы мы могли понять измерения и другие аспекты (например, факторы с множеством уровней и т. Д.).

Я надеюсь, чтопомогает,

Макс

[1] Я не должен идти на все, чтобы соответствовать как можно меньшему количеству моделей, когда это возможно.Трюк «подмодель» используется для многих моделей, таких как pls, gbm, rpart, earth и многих других.Кроме того, когда модель имеет формулу и не-формулы интерфейсов (например, lda() или earth(), мы по умолчанию используем не-формулы интерфейса.

[2] Время от времени я получаю безумныйнастоятельно рекомендуется перезагрузить функцию train(). Использование foreach может обойти некоторые из этих проблем.

2 голосов
/ 05 марта 2018

Я думаю, что приведенные выше ответы немного устарели.Пакеты caret и caretEnsemble теперь включают в параметр trainControl 'trim' дополнительный параметр.Изначально для Trim установлено значение FALSE, но его значение TRUE значительно уменьшит размер модели.Вы должны использовать это в сочетании с returnData = FALSE для наименьшего возможного размера модели.Если вы используете ансамбль модели, вы также должны указать эти два параметра в ансамбле жадного / стека trainControl.

В моем случае модель объемом 1,6 ГБ сократилась до ~ 500 МБ с обоими параметрами в управлении ансамблем и дополнительно сократилась до ~ 300 МБ, также используя параметры в жадном управлении ансамблем.

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))
...