3

foreach ループ内で h2o.gbm への複数の呼び出しを並行して行うのは簡単だと素朴に考えました。しかし、奇妙なエラーが発生しました。

Error in { : 
         task 3 failed - "java.lang.AssertionError: Can't unlock: Not locked!"

以下のコード

library(foreach)
library(doParallel)
library(doSNOW)

Xtr.hf = as.h2o(Xtr)
Xval.hf = as.h2o(Xval)

cl = makeCluster(6, type="SOCK")
registerDoSNOW(cl)
junk <- foreach(i=1:6, 
            .packages=c("h2o"), 
            .errorhandling = "stop",
            .verbose=TRUE) %dopar% 
{
   h2o.init(ip="localhost", nthreads=2, max_mem_size = "5G") 
   for ( j in 1:3 ) { 
     bm2 <- h2o.gbm(
     training_frame = Xtr.hf,  
     validation_frame = Xval.hf, 
     x=2:ncol(Xtr.hf),
     y=1,          
     distribution="gaussian",
     ntrees = 100,
     max_depth = 3,
     learn_rate = 0.1,
     nfolds = 1)
  }
  h2o.shutdown(prompt=FALSE)    
  return(iname)
}
stopCluster(cl)
4

1 に答える 1

3

注: これは R の並列 foreach の適切な使用法ではありませんが、最初に質問に答えてから、その理由を説明します。(ところで、この回答で「クラスター」を使用する場合、R「クラスター」ではなく、H2Oクラスター(ローカルマシン上にある場合でも)を指しています。)

すべてのモデルが作成される単一のH2O クラスターを持つことを意図していると仮定して、コードを書き直しました。

library(foreach)
library(doParallel)
library(doSNOW)
library(h2o)

h2o.init(ip="localhost", nthreads=-1, max_mem_size = "5G") 

Xtr.hf = as.h2o(Xtr)
Xval.hf = as.h2o(Xval)

cl = makeCluster(6, type="SOCK")
registerDoSNOW(cl)
junk <- foreach(i=1:6, 
            .packages=c("h2o"), 
            .errorhandling = "stop",
            .verbose=TRUE) %dopar% 
{
   for ( j in 1:3 ) { 
     bm2 <- h2o.gbm(
     training_frame = Xtr.hf,  
     validation_frame = Xval.hf, 
     x=2:ncol(Xtr.hf),
     y=1,          
     distribution="gaussian",
     ntrees = 100,
     max_depth = 3,
     learn_rate = 0.1,
     nfolds = 1)

   #TODO: do something with bm2 here?

  }
  return(iname)  #???
}
stopCluster(cl)

つまり、アウトライン形式で:

  • H2O を起動し、ロードXtrXvalます。
  • R クライアントで 6 つのスレッドを開始する
  • 各スレッドで 3 つの GBM モデルを (1 つずつ) 作成します。

h2o.shutdown()あなたがそれを意図していなかったと推測して、コマンドを削除しました(H2O クラスターをシャットダウンすると、作成したばかりのモデルが削除されます)。そして、モデルで何かをしたい場所を強調しました。nthreads=-1そして、2 つだけでなく、マシン上のすべてのスレッド (つまりin )を H2O に与えましたh2o.init()

H2O モデルを並行して作成することはできますが、最終的にリソースを奪い合うことになるため、一般的には悪い考えです。一度に 1 つずつ実行し、H2O 独自の並列コードに依存して計算をクラスター全体に分散することをお勧めします。(クラスターが単一のマシンである場合、これは非常に効率的です。)

R で並列ループを作成するのに苦労したという事実によって、H2O の動作方法を見逃していると思います。H2O は Java で記述されたサーバーであり、R は API 呼び出しを送信する単なる軽いクライアントです。 . GBM の計算は R では行われません。それらはすべて Java コードで行われます。

コードを解釈するもう 1 つの方法は、H2O の複数のインスタンス、つまり複数の H2O クラスターを実行することです。これは、一連のマシンがあり、H2O アルゴリズムがマルチノード クラスター全体でうまくスケーリングされないことがわかっている場合に適しています。単一のマシンでそれを行うことは、ほぼ間違いなく悪い考えです。しかし、議論のために、これはあなたがそれを行う方法です(テストされていません):

library(foreach)
library(doParallel)
library(doSNOW)

cl = makeCluster(6, type="SOCK")
registerDoSNOW(cl)
junk <- foreach(i=1:6, 
            .packages=c("h2o"), 
            .errorhandling = "stop",
            .verbose=TRUE) %dopar% 
{
   library(h2o)
   h2o.init(ip="localhost", port = 54321 + (i*2), nthreads=2, max_mem_size = "5G") 

    Xtr.hf = as.h2o(Xtr)
    Xval.hf = as.h2o(Xval)

   for ( j in 1:3 ) { 
     bm2 <- h2o.gbm(
     training_frame = Xtr.hf,  
     validation_frame = Xval.hf, 
     x=2:ncol(Xtr.hf),
     y=1,          
     distribution="gaussian",
     ntrees = 100,
     max_depth = 3,
     learn_rate = 0.1,
     nfolds = 1)

    #TODO: save bm2 here
  }
  h2o.shutdown(prompt=FALSE)    
  return(iname)  #???
}
stopCluster(cl)

概要は次のとおりです。

  • 6 つの R スレッドを作成する
  • 各スレッドで、localhost で実行されているが、そのクラスターに固有のポートで実行されている H2O クラスターを開始します。(これi*2は、各 H2O クラスターが実際に 2 つのポートを使用しているためです。)
  • データを H2O クラスターにアップロードします (つまり、これはクラスターごとに 1 回ずつ、6 回繰り返されます)。
  • 3 つの GBM モデルを 1 つずつ作成します。
  • それらのモデルで何かをする
  • 現在のスレッドのクラスターを強制終了します。

マシンに 12 以上のスレッドと 30 GB 以上のメモリがあり、データが比較的小さい場合、これは 1 つの H2O クラスターを使用して 12 GBM モデルを連続して作成するのとほぼ同じくらい効率的です。そうでない場合は、さらに悪化すると思います。(しかし、6 台のリモート マシンで 6 つの H2O クラスターを事前に開始している場合、これは便利なアプローチかもしれません。これを行う方法を知りたいと思っていたことを認めなければなりません。並列ライブラリを使用するまでは思いつきませんでした。あなたの質問を見ました!)

注: 現在のバージョン (3.10.0.6) の時点で、上記のコードが機能しないことはわかっています。これは、事実上ポートを無視していることを意味するバグがあるためです。h2o.init()(回避策: コマンドラインで 6 つの H2O クラスターすべてを事前に開始するか、環境変数でポートを設定します。)

于 2016-09-17T17:18:00.513 に答える