web-dev-qa-db-fra.com

Comment imprimer en utilisant% dopar%

J'ai une boucle foreach qui utilise %dopar% avec doSNOW comme back-end. Comment puis-je demander à la boucle d'imprimer quelque chose à chaque itération?

Mon code ci-dessous est ce que j'utilise actuellement, mais il n'imprime rien.

foreach(ntree=rep(25,2),.combine=combine,.packages='randomForest',
    .inorder=FALSE) %dopar% {
        print("RANDOM FOREST")
        randomForest(classForm,data=data,na.action=na.action,do.trace=do.trace,ntree=ntree,mtry=mtry)
    }   
62
someoneHuman

Il existe un certain nombre de bonnes solutions publiées ici, mais je trouve qu'il est plus facile de se connecter à un socket et d'utiliser un processus distinct pour générer les appels de journal dans une console.

J'utilise la fonction suivante:

log.socket <- make.socket(port=4000)

Log <- function(text, ...) {
  msg <- sprintf(paste0(as.character(Sys.time()), ": ", text, "\n"), ...)
  cat(msg)
  write.socket(log.socket, msg)
}

Vous pouvez ensuite placer des instructions de journal dans le code, telles que:

Log("Processing block %d of %d", i, n.blocks)

La sortie du journal peut être visualisée en temps réel à l'aide de n'importe quel outil d'écoute de socket simple. Par exemple, en utilisant netcat sous Linux:

nc -l 4000

L'instruction de journal ci-dessus s'afficherait dans le terminal netcat comme suit:

2014-06-25 12:30:45: Processing block 2 of 13

Cette méthode a l'avantage de fonctionner à distance et fournit une sortie aussi détaillée que vous souhaitez vous connecter.

p.s. Pour ceux sous Windows, voir port netcat de Jon Craton .

p.p.s Je suppose que le write.socket La fonction R n'est probablement pas adaptée aux threads, mais à moins que vous ne vous connectiez à haute fréquence, il est peu probable que vous rencontriez un problème. Quelque chose à savoir cependant.

25
hendalst

La sortie produite par les travailleurs de la neige est jetée par défaut, mais vous pouvez utiliser l'option "outfile" de makeCluster pour changer cela. La définition de outfile dans la chaîne vide ("") empêchera la neige de rediriger la sortie, ce qui entraîne souvent l'affichage de la sortie de vos messages d'impression sur le terminal du processus maître.

Créez et enregistrez simplement votre cluster avec quelque chose comme:

library(doSNOW)
cl <- makeCluster(4, outfile="")
registerDoSNOW(cl)

Votre boucle foreach n'a pas du tout besoin de changer.

Cela fonctionne pour moi avec les clusters SOCK et les clusters MPI utilisant Rmpi ​​construit avec Open MPI. Sous Windows, vous ne verrez aucune sortie si vous utilisez Rgui. Si vous utilisez Rterm.exe à la place, vous le ferez.

Notez qu'en plus de votre propre sortie, vous verrez des messages produits par snow qui peuvent également être utiles.


Pour utiliser une barre de progression, doSNOW version 1.0.14 a une option progress. Voici un exemple complet:

library(doSNOW)
library(tcltk)
library(randomForest)
cl <- makeSOCKcluster(3)
registerDoSNOW(cl)

ntasks <- 100
pb <- tkProgressBar(max=ntasks)
progress <- function(n) setTkProgressBar(pb, n)
opts <- list(progress=progress)

x <- matrix(runif(500), 100)
y <- gl(2, 50)

rf <- foreach(ntree=rep(25, ntasks), .combine=combine,
        .multicombine=TRUE, .packages='randomForest',
        .options.snow=opts) %dopar% {
  randomForest(x, y, ntree=ntree)
}

L'option progress est assez générale, vous pouvez donc simplement imprimer un message en utilisant une fonction telle que:

progress <- function(n) cat(sprintf("task %d is complete\n", n))

La fonction peut accepter 0, 1 ou 2 arguments. Le premier argument fourni est le nombre total de tâches terminées et le second est le numéro de tâche de la tâche qui vient de se terminer.

L'exemple le plus simple imprime simplement un . lorsqu'une tâche se termine:

progress <- function() cat('.')

Cet exemple affiche les deux arguments et peut être utilisé pour démontrer que les tâches ne sont pas toujours terminées dans l'ordre:

progress <- function(nfin, tag) {
  cat(sprintf('tasks completed: %d; tag: %d\n', nfin, tag))
}
55
Steve Weston

Une façon dont j'ai gardé une trace de la progression sur les nœuds pendant de longues opérations est de créer une barre de progression en utilisant tkProgressBar à partir du package tcltk. Ce n'est pas tout à fait ce que vous avez demandé, mais cela devrait vous permettre de voir quelque chose des nœuds. Au moins, cela se produit lorsque le cluster est un cluster de socket exécuté sur l'hôte local (qui est une machine Windows). Le problème potentiel est que la barre de progression reste et encombre votre moniteur ou qu'elle obtient closed et que les informations imprimées ont disparu. Pour moi, ce n'était pas un problème, car je voulais juste savoir quel était le statut actuel.

library(parallel)
library(doSNOW)
cl<-makeCluster(detectCores(),type="SOCK")
registerDoSNOW(cl)

En utilisant votre code,

foreach(ntree=rep(25,2),.combine=combine,.packages=c('randomForest','tcltk'),
    .inorder=FALSE) %dopar% {
        mypb <- tkProgressBar(title = "R progress bar", label = "",
          min = 0, max = 1, initial = 0, width = 300)
        setTkProgressBar(mypb, 1, title = "RANDOM FOREST", label = NULL)
    ans <- randomForest(classForm,data=data,na.action=na.action,do.trace=do.trace,ntree=ntree,mtry=mtry)
    close(mypb)
    ans
    }

Voici un exemple d'utilisation plus générale:

jSeq <- seq_len(30)

foreach(i = seq_len(2), .packages = c('tcltk', 'foreach')) %dopar% {
    mypb <- tkProgressBar(title = "R progress bar", label = "",
        min = 0, max = max(jSeq), initial = 0, width = 300)
    foreach(j = jSeq) %do% {
        Sys.sleep(.1)
        setTkProgressBar(mypb, j, title = "RANDOM FOREST", label = NULL)
    }
    NULL
}
12
BenBarnes

J'avais aussi le même problème. J'étais en train de régler les paramètres de la forêt aléatoire en utilisant le package foreach et je voulais imprimer une ligne "Résultats" après chaque itération, mais je ne pouvais pas comprendre sans passer par l'affichage d'une barre de progression et autres.

Voici ce que j'ai fait, dans ma fonction, j'ai ajouté cette ligne

write.table(result, file=paste("RF_ntree_",ntree,"_dims_",dims,".txt", sep=""),
  sep="\t", row.names=F)

Ainsi, après chaque itération, les résultats sont écrits dans un fichier texte avec des noms tels que RF_ntree_250_dims_100.txt.

Donc, si je veux suivre la progression, je rafraîchis simplement le dossier dans lequel les fichiers texte sont écrits.

PS: les résultats s'accumulent également dans une trame de données.

11
user1509107

cat("blah-blah-blah\n", file=stdout()) a tendance à fonctionner pour moi (linux/emacs/ess). Je suppose que cela fonctionne également pour certaines autres plates-formes.

2
Ott Toomet

Une alternative consiste à utiliser la journalisation des fichiers (par exemple, le package log4r) et à imprimer séparément la sortie à l'écran (par exemple, par 'tail -f').

Cela fonctionne bien si vous envisagez de créer des journaux de toute façon, et vous pouvez utiliser les packages existants avec toutes les cloches et sifflets associés.

0
Ott Toomet