Подтвердить что ты не робот

Почему каретный поезд занимает столько памяти?

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

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

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

4b9b3361

Ответ 1

Проблема состоит из двух раз. i) train не просто подходит для модели с помощью glm(), она будет загружать эту модель, поэтому даже с настройками по умолчанию train() будет выполнять 25 выборок начальной загрузки, что в сочетании с проблемой ii) является (или) источником вашей проблемы, а ii) train() просто вызывает функцию glm() со значениями по умолчанию. И эти значения по умолчанию предназначены для хранения кадра модели (аргумент model = TRUE of ?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 в комментариях ниже.

Чтобы продолжить, изучите код более подробно или напишите Max Kuhn, сопровождающему карету, чтобы узнать о вариантах уменьшения объема памяти.

Ответ 2

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

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

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

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

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

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

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

Max

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

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