Sök…


Anmärkningar

Parallellisering på fjärrmaskiner kräver att bibliotek laddas ner på varje maskin. Föredrar package::function() samtal. Flera paket har inbyggd inbyggd parallellisering, inklusive caret , pls och plyr .

Microsoft R Open (Revolution R) använder också flertrådade BLAS / LAPACK-bibliotek som i sin helhet parallellerar många vanliga funktioner.

Parallell behandling med förhandspaket

foreach paketet ger kraften i parallellbehandling till R. Men innan du vill använda multi core-CPU: er måste du tilldela ett multi core-kluster. doSNOW paketet är en möjlighet.

En enkel användning av förhandslingan är att beräkna summan av kvadratroten och kvadratet med alla siffror från 1 till 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
} 

Strukturen för utgången från foreach styrs av .combine argumentet. Standardutgångsstrukturen är en lista. I koden ovan används c för att returnera en vektor istället. Observera att en beräkningsfunktion (eller operatör) som "+" också kan användas för att utföra en beräkning och returnera ett ytterligare bearbetat objekt.

Det är viktigt att nämna att resultatet av varje foreach-loop är det sista samtalet. I detta exempel kommer k att läggas till resultatet.

Parameter detaljer
.kombinera kombinera funktion. Bestämmer hur slingans resultat ska kombineras. Möjliga värden är c , cbind , rbind , "+" , "*" ...
.i ordning om TRUE är resultatet beställt i enlighet med ordningen för iterationen vairable (här i ). Om FALSE beställs inte resultatet. Detta kan ha positiva effekter på beräkningstiden.
.packages för funktioner som tillhandahålls av något paket utom base , som t.ex. mass , randomForest eller annat, måste du förse dessa paket med c("mass", "randomForest")

Parallell behandling med parallellt paket

Baspaketet parallel tillåter parallell beräkning genom forking, socklar och generering av slumptal.

Upptäck antalet kärnor som finns på localhost:

parallel::detectCores(all.tests = FALSE, logical = TRUE)

Skapa ett kluster av kärnorna på localhost:

parallelCluster <- parallel::makeCluster(parallel::detectCores())

Först måste en funktion som är lämplig för parallellisering skapas. Tänk på mtcars . En regression på mpg skulle kunna förbättras genom att skapa en separat regressionsmodell för varje nivå av 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])
}

Skapa en funktion som kan gå igenom alla möjliga iterationer av zlevels . Detta är fortfarande i serie men är ett viktigt steg eftersom det bestämmer den exakta processen som kommer att parallelliseras.

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

Curry denna funktion:

worker <- function(zlevel) {
    fitmodel(zlevel,datax, datay, dataz)
  }

Parallell datoranvändning med parallel kan inte komma åt den globala miljön. Lyckligtvis skapar varje funktion en lokal miljö som parallel kan komma åt. Skapa en omslagsfunktion möjliggör parallellisering. Funktionen som ska tillämpas måste också placeras i miljön.

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

Skapa nu ett kluster och kör omslagsfunktionen.

parallelcluster <- parallel::makeCluster(parallel::detectCores())
models <- parallel::parLapply(parallelcluster,zlevels,
                              wrapper(datax, datay, dataz))

Stopp alltid klustret när du är klar.

parallel::stopCluster(parallelcluster)

Det parallel paketet innehåller hela apply() , förinställd med par .

Slumpmässig nummergenerering

Ett stort problem med parallellisering är att använda RNG som frön. Slumpmässiga siffror med antalet uppdateras av antalet operationer från antingen början av sessionen eller den senaste set.seed() . Eftersom parallella processer uppstår från samma funktion kan den använda samma frö, vilket kan orsaka identiska resultat! Samtal körs i serie på de olika kärnorna, utan ger någon fördel.

En uppsättning frön måste genereras och skickas till varje parallell process. Detta görs automatiskt i vissa paket ( parallel , snow osv.), Men måste adresseras uttryckligen i andra.

s <- seed
for (i in 1:numofcores) {
    s <- nextRNGStream(s)
    # send s to worker i as .Random.seed
}

Frön kan också ställas in för reproducerbarhet.

clusterSetRNGStream(cl = parallelcluster, iseed)

mcparallelDo

Paketet mcparallelDo möjliggör utvärdering av R-kod asynkront på Unix-lika (t.ex. Linux och MacOSX) operativsystem. Den underliggande filosofin för paketet är i linje med behoven för undersökande dataanalys snarare än kodning. Tänk på det future paketet för kodning av asynkroni.

Exempel

Skapa data

data(ToothGrowth)

Trigger mcparallelDo för att utföra analys på en gaffel

mcparallelDo({glm(len ~ supp * dose, data=ToothGrowth)},"interactionPredictorModel")

Gör andra saker, t.ex.

binaryPredictorModel <- glm(len ~ supp, data=ToothGrowth)
gaussianPredictorModel <- glm(len ~ dose, data=ToothGrowth)

Resultatet från mcparallelDo returnerar i ditt målmiljö, t.ex. .GlobalEnv, när det är komplett med ett meddelande (som standard)

summary(interactionPredictorModel)

Andra exempel

# 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)
}


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow