R Language
Parallelle verwerking
Zoeken…
Opmerkingen
Parallellisatie op externe machines vereist dat bibliotheken op elke machine worden gedownload. Voorkeur package::function()
aanroepen. Verschillende pakketten hebben ingebouwde standaardisatie, inclusief caret
, pls
en plyr
.
Microsoft R Open (Revolution R) maakt ook gebruik van multi-threaded BLAS / LAPACK-bibliotheken die intrinsiek veel algemene functies parallel lopen.
Parallelle verwerking met foreach-pakket
Het foreach
pakket brengt de kracht van parallelle verwerking naar R. Maar voordat u multi-core CPU's wilt gebruiken, moet u een multi-core cluster toewijzen. Het doSNOW
pakket is een mogelijkheid.
Een eenvoudig gebruik van de foreach-lus is het berekenen van de som van de vierkantswortel en het kwadraat van alle getallen van 1 tot 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
}
De structuur van de output van foreach
wordt bepaald door het .combine
argument. De standaarduitvoerstructuur is een lijst. In de bovenstaande code wordt c
gebruikt om in plaats daarvan een vector te retourneren. Merk op dat een berekeningsfunctie (of operator) zoals "+"
ook kan worden gebruikt om een berekening uit te voeren en een verder verwerkt object te retourneren.
Het is belangrijk om te vermelden dat het resultaat van elke foreach-lus het laatste gesprek is. In dit voorbeeld wordt dus k
aan het resultaat toegevoegd.
Parameter | Details |
---|---|
.combineren | functie combineren. Bepaalt hoe de resultaten van de lus worden gecombineerd. Mogelijke waarden zijn c , cbind , rbind , "+" , "*" ... |
.in volgorde | als het TRUE het resultaat geordend volgens de volgorde van de iteratie waarheidsgetrouw (hier i ). Als FALSE het resultaat niet besteld. Dit kan positieve gevolgen hebben voor de rekentijd. |
.pakketjes | voor functies die worden geleverd door elk pakket behalve base , zoals bijvoorbeeld mass , randomForest of anders, moet u deze pakketten voorzien van c("mass", "randomForest") |
Parallelle verwerking met parallel pakket
Het basispakket parallel
maakt parallelle berekening mogelijk via vorken, stopcontacten en het genereren van willekeurige getallen.
Detecteer het aantal aanwezige cores op de localhost:
parallel::detectCores(all.tests = FALSE, logical = TRUE)
Maak een cluster van de cores op de localhost:
parallelCluster <- parallel::makeCluster(parallel::detectCores())
Eerst moet een functie worden gecreëerd die geschikt is voor parallellisatie. Overweeg de mtcars
gegevensset. Een regressie op mpg
kan worden verbeterd door een afzonderlijk regressiemodel te maken voor elk niveau van 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])
}
Maak een functie die alle mogelijke iteraties van zlevels
. Dit is nog steeds in serie, maar is een belangrijke stap omdat het het exacte proces bepaalt dat parallel zal worden uitgevoerd.
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 deze functie:
worker <- function(zlevel) {
fitmodel(zlevel,datax, datay, dataz)
}
Parallel computing met behulp van parallel
heeft geen toegang tot de wereldwijde omgeving. Gelukkig creëert elke functie een lokale omgeving die parallel
toegankelijk is. Het creëren van een wrapper-functie maakt parallellisatie mogelijk. De functie die moet worden toegepast, moet ook in de omgeving worden geplaatst.
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)
}
Maak nu een cluster en voer de wrapperfunctie uit.
parallelcluster <- parallel::makeCluster(parallel::detectCores())
models <- parallel::parLapply(parallelcluster,zlevels,
wrapper(datax, datay, dataz))
Stop het cluster altijd wanneer u klaar bent.
parallel::stopCluster(parallelcluster)
Het parallel
pakket omvat de hele familie apply()
, voorafgegaan door par
.
Willekeurige nummergeneratie
Een groot probleem met parallellisatie is het gebruik van RNG als zaden. Willekeurige getallen door het nummer worden herhaald door het aantal bewerkingen vanaf het begin van de sessie of de meest recente set.seed()
. Omdat parallelle processen voortkomen uit dezelfde functie, kan het dezelfde seed gebruiken, wat mogelijk identieke resultaten veroorzaakt! Oproepen worden serieel op de verschillende kernen uitgevoerd, bieden geen voordeel.
Een set zaden moet worden gegenereerd en naar elk parallel proces worden verzonden. Dit wordt automatisch gedaan in sommige pakketten ( parallel
, snow
, enz.), Maar moet in andere pakketten expliciet worden aangepakt.
s <- seed
for (i in 1:numofcores) {
s <- nextRNGStream(s)
# send s to worker i as .Random.seed
}
Zaden kunnen ook worden ingesteld voor reproduceerbaarheid.
clusterSetRNGStream(cl = parallelcluster, iseed)
mcparallelDo
Het mcparallelDo
pakket zorgt voor de asynchrone evaluatie van R-code op Unix-achtige besturingssystemen (bijvoorbeeld Linux en MacOSX). De onderliggende filosofie van het pakket is afgestemd op de behoeften van verkennende gegevensanalyse in plaats van codering. Overweeg het future
pakket voor het coderen van asynchronie.
Voorbeeld
Maak gegevens
data(ToothGrowth)
Mcparallel activeren Doen om analyses op een vork uit te voeren
mcparallelDo({glm(len ~ supp * dose, data=ToothGrowth)},"interactionPredictorModel")
Doe andere dingen, bijv
binaryPredictorModel <- glm(len ~ supp, data=ToothGrowth)
gaussianPredictorModel <- glm(len ~ dose, data=ToothGrowth)
Het resultaat van mcparallelDo keert terug in uw targetEnvironment, bijvoorbeeld. GlobalEnv, wanneer deze compleet is met een bericht (standaard)
summary(interactionPredictorModel)
Andere voorbeelden
# 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)
}