R Language
Параллельная обработка
Поиск…
замечания
Для параллелизации на удаленных компьютерах библиотеки необходимо загружать на каждую машину. Предпочитают вызов package::function()
. Несколько пакетов имеют встроенную распараллеливание, включая caret
, pls
и plyr
.
Microsoft R Open (Revolution R) также использует многопоточные библиотеки BLAS / LAPACK, которые по своей сути распараллеливают многие общие функции.
Параллельная обработка с помощью пакета foreach
Пакет foreach
обеспечивает параллельную обработку R. Но прежде чем вы захотите использовать многоядерные процессоры, вам необходимо назначить многоядерный кластер. Пакет doSNOW
- одна из возможностей.
Простым использованием цикла foreach является вычисление суммы квадратного корня и квадрата всех чисел от 1 до 100000.
library(foreach)
library(doSNOW)
cl <- makeCluster(5, type = "SOCK")
registerDoSNOW(cl)
f <- foreach(i = 1:100000, .combine = c, .inorder = F) %dopar% {
k <- i ** 2 + sqrt(i)
k
}
Структура вывода foreach
контролируется аргументом .combine
. Структура вывода по умолчанию - это список. В приведенном выше коде c
вместо этого используется c
. Обратите внимание, что функция вычисления (или оператор), такая как "+"
также может использоваться для выполнения вычисления и возврата еще одного обработанного объекта.
Важно отметить, что результатом каждого цикла foreach является последний вызов. Таким образом, в этом примере k
будет добавлен k
.
параметр | подробности |
---|---|
.combine | Комбинация Функция. Определяет, как комбинируются результаты цикла. Возможные значения: c , cbind , rbind , "+" , "*" ... |
.с целью | если TRUE результат упорядочивается в соответствии с порядком итерации vairable (здесь i ). Если FALSE результат не упорядочен. Это может иметь положительные эффекты на время вычислений. |
.packages | для функций, которые предоставляются любой упаковкой, кроме base , например, mass , randomForest или же вы должны предоставить эти пакеты с помощью c("mass", "randomForest") |
Параллельная обработка с параллельным пакетом
parallel
базовый пакет позволяет осуществлять параллельное вычисление с помощью разветвления, сокетов и генерации случайных чисел.
Определите количество ядер, присутствующих на локальном хосте:
parallel::detectCores(all.tests = FALSE, logical = TRUE)
Создайте кластер ядер на локальном хосте:
parallelCluster <- parallel::makeCluster(parallel::detectCores())
Во-первых, необходимо создать функцию, подходящую для распараллеливания. Рассмотрим набор данных mtcars
. Регрессия на mpg
может быть улучшена путем создания отдельной модели регрессии для каждого уровня cyl
.
data <- mtcars
yfactor <- 'cyl'
zlevels <- sort(unique(data[[yfactor]]))
datay <- data[,1]
dataz <- data[,2]
datax <- data[,3:11]
fitmodel <- function(zlevel, datax, datay, dataz) {
glm.fit(x = datax[dataz == zlevel,], y = datay[dataz == zlevel])
}
Создайте функцию, которая может проходить через все возможные итерации zlevels
. Это все еще в серийном режиме, но является важным шагом, поскольку он определяет точный процесс, который будет распараллелен.
fitmodel <- function(zlevel, datax, datay, dataz) {
glm.fit(x = datax[dataz == zlevel,], y = datay[dataz == zlevel])
}
for (zlevel in zlevels) {
print("*****")
print(zlevel)
print(fitmodel(zlevel, datax, datay, dataz))
}
Выполните эту функцию:
worker <- function(zlevel) {
fitmodel(zlevel,datax, datay, dataz)
}
Параллельные вычисления с использованием parallel
не могут получить доступ к глобальной среде. К счастью, каждая функция создает локальное окружение parallel
может получить доступ. Создание функции обертки позволяет распараллеливать. Функция, которая должна применяться, также должна быть помещена в окружающую среду.
wrapper <- function(datax, datay, dataz) {
# force evaluation of all paramters not supplied by parallelization apply
force(datax)
force(datay)
force(dataz)
# these variables are now in an enviroment accessible by parallel function
# function to be applied also in the environment
fitmodel <- function(zlevel, datax, datay, dataz) {
glm.fit(x = datax[dataz == zlevel,], y = datay[dataz == zlevel])
}
# calling in this environment iterating over single parameter zlevel
worker <- function(zlevel) {
fitmodel(zlevel,datax, datay, dataz)
}
return(worker)
}
Теперь создайте кластер и запустите функцию обертки.
parallelcluster <- parallel::makeCluster(parallel::detectCores())
models <- parallel::parLapply(parallelcluster,zlevels,
wrapper(datax, datay, dataz))
Всегда завершайте кластер, когда закончите.
parallel::stopCluster(parallelcluster)
parallel
пакет включает в себя весь семейство apply()
префиксом par
.
Генерация случайных чисел
Основной проблемой с распараллеливанием является использование RNG в качестве семян. Случайные числа по числу повторяются числом операций либо с начала сеанса, либо с самого последнего set.seed()
. Поскольку параллельные процессы возникают из одной и той же функции, он может использовать одно и то же семя, что может привести к одинаковым результатам! Вызовы будут выполняться в последовательном порядке на разных ядрах, не давая преимущества.
Набор семян должен быть сгенерирован и отправлен каждому параллельному процессу. Это делается автоматически в некоторых пакетах ( parallel
, snow
и т. Д.), Но они должны быть явно адресованы другим.
s <- seed
for (i in 1:numofcores) {
s <- nextRNGStream(s)
# send s to worker i as .Random.seed
}
Семена также могут быть установлены для воспроизводимости.
clusterSetRNGStream(cl = parallelcluster, iseed)
mcparallelDo
Пакет mcparallelDo
позволяет асинхронно оценивать R-код на Unix-подобных (например, Linux и MacOSX) операционных системах. Основополагающая философия пакета согласовывается с потребностями анализа разведочных данных, а не с кодированием. Для кодирования асинхронности рассмотрим future
пакет.
пример
Создание данных
data(ToothGrowth)
Триггер mcparallelДля выполнения анализа на развилке
mcparallelDo({glm(len ~ supp * dose, data=ToothGrowth)},"interactionPredictorModel")
Делайте другие вещи, например
binaryPredictorModel <- glm(len ~ supp, data=ToothGrowth)
gaussianPredictorModel <- glm(len ~ dose, data=ToothGrowth)
Результат mcparallelDo возвращается в вашу целевую среду, например .GlobalEnv, когда она заполнена сообщением (по умолчанию)
summary(interactionPredictorModel)
Другие примеры
# Example of not returning a value until we return to the top level
for (i in 1:10) {
if (i == 1) {
mcparallelDo({2+2}, targetValue = "output")
}
if (exists("output")) print(i)
}
# Example of getting a value without returning to the top level
for (i in 1:10) {
if (i == 1) {
mcparallelDo({2+2}, targetValue = "output")
}
mcparallelDoCheck()
if (exists("output")) print(i)
}