Des modèles parallèles entièrement reproductibles utilisant le caret

quand j'exécute 2 forêts au hasard à caret, j'obtiens exactement les mêmes résultats si je mets une graine au hasard:

library(caret)
library(doParallel)

set.seed(42)
myControl <- trainControl(method='cv', index=createFolds(iris$Species))

set.seed(42)
model1 <- train(Species~., iris, method='rf', trControl=myControl)

set.seed(42)
model2 <- train(Species~., iris, method='rf', trControl=myControl)

> all.equal(predict(model1, type='prob'), predict(model2, type='prob'))
[1] TRUE

cependant, si j'enregistre un back-end parallèle pour accélérer la modélisation, j'obtiens un résultat différent chaque fois que j'exécute le model:

cl <- makeCluster(detectCores())
registerDoParallel(cl)

set.seed(42)
myControl <- trainControl(method='cv', index=createFolds(iris$Species))

set.seed(42)
model1 <- train(Species~., iris, method='rf', trControl=myControl)

set.seed(42)
model2 <- train(Species~., iris, method='rf', trControl=myControl)

stopCluster(cl)

> all.equal(predict(model1, type='prob'), predict(model2, type='prob'))
[1] "Component 2: Mean relative difference: 0.01813729"
[2] "Component 3: Mean relative difference: 0.02271638"

Est-il un moyen de corriger ce problème? Il a été suggéré d'utiliser le doRNG, mais train utilise des boucles imbriquées, qui ne sont actuellement pas supportées:

library(doRNG)
cl <- makeCluster(detectCores())
registerDoParallel(cl)
registerDoRNG()

set.seed(42)
myControl <- trainControl(method='cv', index=createFolds(iris$Species))

set.seed(42)
> model1 <- train(Species~., iris, method='rf', trControl=myControl)
Error in list(e1 = list(args = seq(along = resampleIndex)(), argnames = "iter",  : 
  nested/conditional foreach loops are not supported yet.
See the package's vignette for a work around.

mise à jour: Je pensais que c' le problème pourrait être résolu en utilisant doSNOW et clusterSetupRNG, mais je n'ai pas pu y arriver.

set.seed(42)
library(caret)
library(doSNOW)
cl <- makeCluster(8, type = "SOCK")
registerDoSNOW(cl)

myControl <- trainControl(method='cv', index=createFolds(iris$Species))

clusterSetupRNG(cl, seed=rep(12345,6))
a <- clusterCall(cl, runif, 10000)
model1 <- train(Species~., iris, method='rf', trControl=myControl)

clusterSetupRNG(cl, seed=rep(12345,6))
b <- clusterCall(cl, runif, 10000)
model2 <- train(Species~., iris, method='rf', trControl=myControl)

all.equal(a, b)
[1] TRUE
all.equal(predict(model1, type='prob'), predict(model2, type='prob'))
[1] "Component 2: Mean relative difference: 0.01890339"
[2] "Component 3: Mean relative difference: 0.01656751"

stopCluster(cl)

Qu'est-ce que foreach a de spécial, et pourquoi n'utilise-t-il pas les graines que j'ai initiées sur le cluster? les objets a et b sont identiques, alors pourquoi pas model1 et <!--10?

38
demandé sur Richie Cotton 2012-11-15 22:01:17

2 réponses

une façon simple d'exécuter un modèle entièrement reproductible en mode parallèle en utilisant le caret paquet est en utilisant l'argument seeds lors de l'appel de la commande train. Ici la question ci-dessus est résolue, consultez la page d'aide trainControl pour plus d'informations.

library(doParallel); library(caret)

#create a list of seed, here change the seed for each resampling
set.seed(123)

#length is = (n_repeats*nresampling)+1
seeds <- vector(mode = "list", length = 11)

#(3 is the number of tuning parameter, mtry for rf, here equal to ncol(iris)-2)
for(i in 1:10) seeds[[i]]<- sample.int(n=1000, 3)

#for the last model
seeds[[11]]<-sample.int(1000, 1)

 #control list
 myControl <- trainControl(method='cv', seeds=seeds, index=createFolds(iris$Species))

 #run model in parallel
 cl <- makeCluster(detectCores())
 registerDoParallel(cl)
 model1 <- train(Species~., iris, method='rf', trControl=myControl)

 model2 <- train(Species~., iris, method='rf', trControl=myControl)
 stopCluster(cl)

 #compare
 all.equal(predict(model1, type='prob'), predict(model2, type='prob'))
[1] TRUE
42
répondu BBrill 2016-12-01 01:51:56

so caret utilise le paquet foreach pour paralléliser. Il est probablement un moyen de définir la graine à chaque itération, mais nous aurions besoin de plus d'options de configuration train.

alternativement, vous pouvez créer une fonction de modélisation personnalisée qui imite la fonction interne pour les forêts aléatoires et définir la graine vous-même.

Max

7
répondu topepo 2015-06-09 00:58:28