2014-01-23 2 views
4

Я знаком с foreach, %dopar% и тому подобное. Я также знаком с parallel вариант для cv.glmnet. Но как вы создали вложенную parallelistion, как показано ниже?Вложенные параллельные функции R (

library(glmnet) 
library(foreach) 
library(parallel) 
library(doSNOW) 
Npar <- 1000 
Nobs <- 200 
Xdat <- matrix(rnorm(Nobs * Npar), ncol = Npar) 
Xclass <- rep(1:2, each = Nobs/2) 
Ydat <- rnorm(Nobs) 

Parallel кросс-проверки:

cl <- makeCluster(8, type = "SOCK") 
registerDoSNOW(cl) 
system.time(mods <- foreach(x = 1:2, .packages = "glmnet") %dopar% { 
    idx <- Xclass == x 
    cv.glmnet(Xdat[idx,], Ydat[idx], nfolds = 4, parallel = TRUE) 
}) 
stopCluster(cl) 

не параллельно перекрестной проверки:

cl <- makeCluster(8, type = "SOCK") 
registerDoSNOW(cl) 
system.time(mods <- foreach(x = 1:2, .packages = "glmnet") %dopar% { 
    idx <- Xclass == x 
    cv.glmnet(Xdat[idx,], Ydat[idx], nfolds = 4, parallel = FALSE) 
}) 
stopCluster(cl) 

Для двух системных времен я получаю очень незначительную разницу.

Возможен ли параллелизм? Или мне нужно явно использовать вложенный оператор?

Боковой вопрос: если в объекте кластера доступно 8 ядер, а цикл foreach содержит две задачи, каждой задаче будет задано 1 ядро ​​(а остальные 6 ядер остаются без дела) или каждой задаче будут даны четыре ядра (используя все 8 ядер в целом)? Каким образом можно запросить, сколько ядер используется в данный момент времени?

+3

'foreach' отправляет каждую задачу в одно ядро. Следовательно, для 'cv.glmnet' доступно только одно ядро. Если вам нужна вложенная распараллеливание, вам нужно сделать это на уровне 'foreach': http://cran.r-project.org/web/packages/foreach/vignettes/nested.pdf – Roland

+0

Итак - уточнить - мне нужно будет выполнить процедуру перекрестной проверки вручную? Если так, то я подозревал. – dynamo

ответ

3

В примере с параллельной параллельной проверкой сама cv.glmnet не будет работать параллельно, потому что в рабочей среде кластера нет встроенного параллельного бэкэнда. Внешний цикл foreach будет работать параллельно, но не цикл foreach в функции cv.glmnet.

Чтобы использовать doSNOW для наружных и внутренних контуров Foreach, можно инициализировать снег кластера рабочих с помощью clusterCall:

cl <- makeCluster(2, type = "SOCK") 
clusterCall(cl, function() { 
    library(doSNOW) 
    registerDoSNOW(makeCluster(2, type = "SOCK")) 
    NULL 
}) 
registerDoSNOW(cl) 

Это регистрирует doSNOW как для мастера и рабочих, так что каждый вызов cv.glmnet будет выполняться в кластере из двух рабочих групп, если указан parallel=TRUE.

Трюк с вложенным параллелизмом заключается в том, чтобы избежать создания слишком большого количества процессов и переназначения процессора (или процессоров), поэтому вам нужно быть осторожным при регистрации параллельных бэкэндов. Мой пример имеет смысл для процессора с четырьмя ядрами, хотя в общей сложности создано шесть рабочих, поскольку «внешние» рабочие не делают много, пока выполняются внутренние петли foreach. Обычно при запуске на кластере использовать doSNOW для запуска одного рабочего на узел, а затем использовать doMC для запуска одного рабочего на ядро ​​на каждом из этих узлов.

Обратите внимание, что ваш пример не использует много времени для вычисления, поэтому не стоит использовать два уровня параллелизма. Я бы использовал гораздо большую проблему, чтобы определить преимущества различных подходов.

Смежные вопросы