/ / doMC no loop R e foreach não funciona - windows, r, foreach, processamento paralelo, domc

doMC no loop R e foreach não funciona - windows, r, foreach, processamento paralelo, domc

Eu estou tentando obter o pacote foreach para processamento paralelo no trabalho R e estou tendo alguns problemas:

O pacote do doMC que é necessário para fazer foreachtrabalho não existe no CRAN para Windows. Alguns blogs sugerem que o doSNOW deve fazer o mesmo trabalho. No entanto, quando eu executo o comando foreach com doSNOW, %dopar% parece não funcionar mais rápido do que %do%. Na verdade, é muito mais lento. Meu CPU é um Intel i7 860 @ 2.80GHz com 8 GB de RAM. Abaixo está o meu código:

##Run example in 1 core
require(foreach)
require(doSNOW)
x= iris[which(iris[,5] != "setosa"),c(1,5)]
trials = 10000
system.time({
r= foreach(icount(trials), .combine=cbind) %do% {
ind=sample(100,100,replace=TRUE)
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
coefficients(results1)
}
})[3]
#  elapsed
#  37.28

# Same example in 2 cores
registerDoSNOW(makeCluster(2,type="SOCK"))
getDoParWorkers()
trials = 10000
system.time({
r= foreach(icount(trials), .combine=cbind) %dopar% {
ind=sample(100,100,replace=TRUE)
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
coefficients(results1)
}
})[3]
# elapsed
#  108.14

Eu re-instalado todos os pacotes necessários, mas ainda os mesmos problemas. Aqui está a saída:

sessionInfo()

#R version 2.15.1 (2012-06-22)
#Platform: i386-pc-mingw32/i386 (32-bit)

#locale:
#[1] LC_COLLATE=English_United States.1252
#[2] LC_CTYPE=English_United States.1252
#[3] LC_MONETARY=English_United States.1252
#[4] LC_NUMERIC=C
#[5] LC_TIME=English_United States.1252

#attached base packages:
#[1] parallel  stats     graphics  grDevices datasets  utils     methods
#[8] base

#other attached packages:
#[1] doParallel_1.0.1 codetools_0.2-8  doSNOW_1.0.6     snow_0.3-10
#[5] iterators_1.0.6  foreach_1.4.0    rcom_2.2-5       rscproxy_2.0-5

#loaded via a namespace (and not attached):
#[1] compiler_2.15.1 tools_2.15.1

Respostas:

4 para resposta № 1

Você está melhor no Windows para usar doParallel():

require(foreach)
require(doParallel)
cl <- makeCluster(6) #use 6 cores, ie for an 8-core machine
registerDoParallel(cl)

Em seguida, execute o seu foreach() %dopar% {}

EDIT: OP mencionado ainda vendo o problema, incluindo o meu código exato. Executado em uma VM Windows7 de 4 núcleos, R 2.15.1 de 32 bits, permitindo apenas doParallel para usar 3 dos meus núcleos:

require(foreach)
require(doParallel)
cl <- makeCluster(3)
registerDoParallel(cl)

x= iris[which(iris[,5] != "setosa"),c(1,5)]

trials = 1000
system.time(
foreach(icount(trials), .combine=cbind) %do%
{
ind=sample(100,100,replace=TRUE)
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
coefficients(results1)
})[3]

system.time(
foreach(icount(trials), .combine=cbind) %dopar%
{
ind=sample(100,100,replace=TRUE)
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
coefficients(results1)
})[3]

No meu caso, estou recebendo 17,6 segundos para %do% e 14,8 seg. %dopar%. Observando as tarefas executadas, parece que muito do tempo de execução é o cbind, que é um problema comum em paralelo. Em minhas próprias simulações, fiz um trabalho personalizado para salvar meus resultados detalhados como parte da tarefa paralela em vez de devolvê-los por meio de foreach, para remover essa parte da sobrecarga. YMMV.


3 para resposta № 2

Eu sei que esta é uma pergunta antiga, mas eu vimatravés dele enquanto procura por outra coisa e pensei em adicionar minha solução. Acho mais eficaz dividir o número geral de tentativas em grupos separados de tentativas (o número de grupos sendo igual ao número de núcleos de processador), em vez de tentando paralelizar todos os testes de uma só vez e lidar com todas as despesas gerais. Aqui está uma comparação usando o exemplo do OP:

require(doParallel)

x <- iris[which(iris[,5] != "setosa"),c(1,5)]
trials <- 10000

# example using a single core
t1 <- system.time({
r1 <- foreach(icount(trials), .combine=cbind) %do% {
ind <- sample(100,100,replace= TRUE)
results1 <- glm(x[ind,2]~x[ind,1],family=binomial(logit))
coefficients(results1)
}
})[3]

# example using 4 cores and parallelizing each model trial
nCores <- 4
cl <- makeCluster(nCores)
registerDoParallel(cl)

t2 <- system.time({
r2 <- foreach(icount(trials), .combine=cbind) %dopar% {
ind <- sample(100,100,replace= TRUE)
results1 <- glm(x[ind,2]~x[ind,1],family=binomial(logit))
coefficients(results1)
}
})[3]

# example using 4 cores and parallelizing a group of trial runs
trialsPerCore <- as.integer(ceiling(trials / nCores)) # number of trials
# do to on each core
# function to do a single model run
model <- function(x) {
ind <- sample(100,100,replace= TRUE)
results1 <- glm(x[ind,2]~x[ind,1],family=binomial(logit))
coefficients(results1)
}
# function producing a group of model runs
modelRun <- function(trials, x) {
replicate(trials, model(x))
}
# call the model run for each core
t3 <- system.time(
r3 <- foreach(icount(nCores), .combine= cbind) %dopar% modelRun(trialsPerCore, x)
)[3]

stopCluster(cl)

Tempos de execução em um quad-core i7 de 3.4 GHz executando o Ubuntu 12.04:

> t1
elapsed
34.5
> t2
elapsed
26.5
> t3
elapsed
8.295

2 para resposta № 3

Isso não é atípico para esse tipo de paralelismo e pode depender do sistema operacional. Eu tive resultado semelhante a você, mas quando fiz uma mudança boba no código

require(foreach)
require(doSNOW)

x= iris[which(iris[,5] != "setosa"),c(1,5)]

trials = 1000
system.time(
foreach(icount(trials), .combine=cbind) %do%
{
ind=sample(100,100,replace=TRUE)
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
coefficients(results1)
})[3]


registerDoSNOW(  makeCluster(2,type="SOCK"))
getDoParWorkers()
trials = 1000
system.time(
foreach(icount(trials), .combine=cbind) %dopar%
{
ind=sample(100,100,replace=TRUE)
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
results1 = glm(x[ind,2]~x[ind,1],family=binomial(logit))
coefficients(results1)
})[3]

para simular o trabalho pesado no foreach, eu tenho umponto de equilíbrio para ambos. Este é o preço do overhead. Eu recentemente tive um caso semelhante e lidou com ele diretamente com o MPI, que tem muito menos sobrecarga, mas é muito mais complexo de usar (Dirk discordará, eu assumo). (Mude isso para "muito menos elegante".