注意:这种使用R的并行foreach可能性不大,但我会先回答你的问题,然后解释原因。(顺便说一下,在本答案中,当我使用“群集”一词时,我指的是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)
}
return(iname)
}
stopCluster(cl)
即以大纲形式:
- 启动 H2O,并将
Xtr
和 Xval
加载到其中
- 在您的 R 客户端中启动 6 个线程
- 在每个线程中依次创建 3 个 GBM 模型
我删除了 h2o.shutdown()
命令,猜测您不想这样做(当关闭 H2O 集群时,您刚刚创建的模型会被删除)。我还突出了您可能需要对模型进行处理的位置。我已经为 H2O 提供了您计算机上的所有线程(即 nthreads=-1
在 h2o.init()
中),而不仅仅是 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)
}
h2o.shutdown(prompt=FALSE)
return(iname)
}
stopCluster(cl)
现在大纲如下:
- 创建6个R线程
- 在每个线程中启动一个H2O集群,该集群在本地主机上运行,但端口是唯一的。(因为每个H2O集群实际上使用两个端口,“i * 2”)
- 将您的数据上传到H2O集群(即将重复6次,每个集群都执行一次)。
- 制作3个GBM模型,一个接一个地进行。
- 对这些模型做些什么
- 终止当前线程的集群。
如果你的机器有12+个线程和30+ GB内存,并且数据相对较小,那么这将与使用一个H2O集群并串行制作12个GBM模型一样有效。如果没有,我认为它会更糟。 (但是,如果您已经在6台远程计算机上预先启动了6个H2O集群,则可能会成为一种有用的方法-我必须承认,一直以来我一直在想如何做到这一点,并且在看到您的问题之前从未想过使用并行库!)
注意:截至当前版本(3.10.0.6),我知道上面的代码不起作用,因为在h2o.init()
中存在错误,有效地表示它忽略了端口。(解决方法:在命令行上预先启动所有6个H2O集群,或在环境变量中设置端口。)
h2o.init(ip="localhost", port = 54321 + (i*2),...)
。通过分配不同的端口,h2o为每个线程创建了一个单独的集群。 - horaceTas.h2o()
数据上传必须放在 for 循环内部。(我也把library(h2o)
放在 foreach 循环里,不过我不确定是否有必要。)(正如所指出的那样,该代码在修复端口错误之前都无法工作。) - Darren Cookh2o.init(...)
会创建一个集群,每个集群都附加到一个且仅一个线程上。我不能在同一个集群内运行多个线程。这就是它应该工作的方式吗? - horaceT