我天真地以为在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)
答案 0 :(得分:3)
注意:这不太可能很好地使用R的并行foreach,但我会首先回答你的问题,然后解释原因。 (顺便说一句,当我在这个答案中使用“cluster”时,我指的是一个H2O集群(即使只是在本地机器上),而不是R“集群”。)
我已经重新编写了你的代码,假设有一个单个 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)
即。大纲形式:
Xtr
和Xval
加载到其中我删除了h2o.shutdown()
命令,猜测你并不打算这样做(当你关闭H2O集群时,你刚刚制作的模型被删除)。我已经强调了你可能希望在你的模型上做些什么。我已经为你的机器上的所有线程(即nthreads=-1
中的h2o.init()
)提供了H2O,而不仅仅是2。
你可以并行制作H2O模型,但这通常是一个坏主意,因为它们最终会争夺资源。最好一次做一个,并依靠H2O自己的并行代码在集群上传播计算。 (当群集是单个机器时,这往往非常有效。)
事实上你已经遇到了在R中进行并行循环的麻烦,让我觉得你错过了H2O的工作方式:它是一个用Java编写的服务器,而R只是一个轻量级的客户端发送它的API调用。 GBM计算不在R中完成;它们都是用Java代码完成的。
解释代码的另一种方法是运行多个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)
现在的大纲是:
i*2
是因为每个H2O群集实际上使用了两个端口。)如果您的计算机上有12个以上的线程,以及30多GB的内存,和数据相对较小,这将大致与使用一个H2O群集和生成12 GBM模型一样高效连载。如果没有,我相信情况会更糟。 (但是,如果您在6台远程计算机上预先启动了6个H2O集群,这可能是一种有用的方法 - 我必须承认我一直想知道如何执行此操作,并且直到使用并行库才发生在我身上我看到了你的问题!)
注意:从当前版本(3.10.0.6)开始,我知道上述代码无效,因为h2o.init()
中的a bug有效意味着它忽略了港口。 (解决方法:在命令行上预启动所有6个H2O群集,或在环境变量中设置端口。)