web-dev-qa-db-ja.com

%dopar%を使用しているときに印刷するにはどうすればよいですか

バックエンドとしてforeach%dopar%を使用するdoSNOWループがあります。反復ごとにループを出力させるにはどうすればよいですか?

以下のコードは現在使用しているものですが、何も印刷していません。

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

ここには多くの優れたソリューションが投稿されていますが、ソケットにログを記録し、別のプロセスを使用してログ呼び出しをコンソールに出力するのが最も簡単だと思います。

次の機能を使用します。

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

その後、次のようなログステートメントをコードに配置できます。

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

ログ出力は、単純なソケットリスニングツールを使用してリアルタイムで表示できます。たとえば、Linuxでnetcatを使用する場合:

nc -l 4000

上記のログステートメントは、netcat端末に次のように表示されます。

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

この方法には、リモートで作業するという利点があり、ログに記録するのと同じくらい詳細な出力を提供します。

追伸. Windowsの場合は、 Jon Cratonのnetcatポート を参照してください。

p.p.s write.socket R関数はおそらくスレッドセーフではありませんが、高頻度でログを記録している場合を除き、問題が発生する可能性はほとんどありません。ただし、注意する必要があります。

25
hendalst

スノーワーカーによって生成された出力はデフォルトで破棄されますが、makeClusterの「outfile」オプションを使用してそれを変更できます。 outfileを空の文字列( "")に設定すると、snowが出力をリダイレクトするのを防ぎ、多くの場合、印刷プロセスからの出力がマスタープロセスのターミナルに表示されるようになります。

次のようなクラスターを作成して登録するだけです。

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

Foreachループを変更する必要はまったくありません。

これは、SOCKクラスターとOpen = MPIでビルドされたRmpiを使用したMPIクラスターの両方で機能します。Windowsでは、Rguiを使用している場合、出力は表示されません。代わりに、します。

独自の出力に加えて、雪によって生成されたメッセージも表示されることに注意してください。


プログレスバーを使用するために、doSNOWバージョン1.0.14にはprogressオプションがあります。完全な例を次に示します。

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

progressオプションはかなり一般的なため、次のような関数を使用してメッセージを簡単に出力できます。

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

この関数は、0、1、または2つの引数を取ることができます。最初に指定された引数は完了したタスクの合計数であり、2番目は完了したタスクのタスク番号です。

最も単純な例では、単に.タスクが完了したとき:

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

この例は両方の引数を表示し、タスクが常に順序どおりに完了しないことを示すために使用できます。

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

長時間の操作中にノードの進行状況を追跡する方法は、tkProgressBarパッケージのtcltkを使用して進行状況バーを作成することです。それはあなたが求めたものではありませんが、ノードから何かを見ることができるはずです。少なくとも、クラスターがローカルホスト(Windowsマシン)で実行されているソケットクラスターである場合はそうです。潜在的な問題は、プログレスバーが残ってモニターが乱雑になるか、closedが表示され、印刷された情報がなくなることです。しかし、私にとっては、それは問題ではありませんでした。現在のステータスが何であるかを知りたいだけだったからです。

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

コードを使用して、

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
    }

これがより一般的な使用例です:

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

私も同じ問題を抱えていました。 foreachパッケージを使用してランダムフォレストのパラメーターを調整し、各反復後に「結果」行を出力したかったのですが、プログレスバーなどを表示せずに把握できませんでした。

私がやったことは、私の機能で、この行を追加しました

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

したがって、各反復の後、結果はRF_ntree_250_dims_100.txtなどの名前のテキストファイルに書き込まれます。

したがって、進行状況を追跡したい場合は、テキストファイルが書き込まれているフォルダーを更新するだけです。

PS:結果はデー​​タフレームにも蓄積されています。

11
user1509107

cat("blah-blah-blah\n", file=stdout())は私(linux/emacs/ess)で動作する傾向があります。他のプラットフォームでも機能すると思います。

2
Ott Toomet

別の方法は、ファイルロギング(log4rパッケージなど)を使用して、画面に出力を個別に印刷することです(「tail -f」など)。

とにかくログを作成することを検討している場合、これはうまく機能します。また、既存のパッケージを関連するすべての付加機能とともに使用できます。

0
Ott Toomet