Lorsque j'exécute 2 forêts aléatoires dans caret, j'obtiens exactement les mêmes résultats si je définis une graine aléatoire:
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 modèle:
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"
Existe-t-il un moyen de résoudre ce problème? Une suggestion a été d'utiliser le package doRNG , mais train
utilise des boucles imbriquées, qui ne sont actuellement pas prises en charge:
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 ce problème pouvait être résolu en utilisant doSNOW
et clusterSetupRNG
, mais je n'y arrivais pas vraiment.
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)
Quelle est la particularité de foreach, 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 model2
?
Une façon simple d'exécuter un modèle entièrement reproductible en mode parallèle à l'aide du package caret
consiste à utiliser l'argument semences lors de l'appel du contrôle de train. Ici, la question ci-dessus est résolue, consultez la page d'aide de 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
Caret utilise donc le package foreach pour se paralléliser. Il existe très probablement un moyen de définir la valeur de départ à chaque itération, mais nous aurions besoin de configurer plus d'options dans train
.
Vous pouvez également créer une fonction de modélisation personnalisée qui imite celle interne pour les forêts aléatoires et définir la graine vous-même.
Max