注意:这不太好使用的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)
#TODO: do something with bm2 here?
}
return(iname) #???
}
stopCluster(cl)
即以大纲形式:
- 开始H2O和负载
Xtr
和Xval
进去
- 开始6个线程在你的[R客户
- 在每个线程使3个GBM模型(一个后对方)
我放弃了h2o.shutdown()
命令,猜测你不打算这样做(当你关闭H2O集群时,你刚删除的模型就会被删除)。我已经强调了你可能想用你的模型做些什么。我也已经给H2O你的机器的所有线程上(即在h2o.init()
的nthreads=-1
),而不仅仅是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)
现在的概况是:
- 创建6个R螺纹
- 在每个线程,启动H2O集群运行在本地主机上,但是在该集群特有的端口上运行。 (
i*2
是因为每个H2O簇实际上都使用两个端口。)
- 将您的数据上传到H2O簇(即,这将重复6次,每个簇一次)。
- 制作3个GBM模型,一个接一个。
- 对这些模型做些什么
- 杀死当前线程的集群。
如果你有你的机器上12+线程,30 + GB内存,和数据相对较少,这将是大约为使用一个H2O集群和串行使得12款GBM高效。如果不是,我相信会更糟。 (但是,如果你已经在6台远程机器上预先启动了6个H2O簇,这可能是一个有用的方法 - 我必须承认我一直在想如何做到这一点,并且直到使用并行库才发生,直到我我看到你的问题)
!注:为当前版本(3.10.0.6),我知道上面的代码将无法正常工作,因为在h2o.init()
a bug这实际上意味着它被忽略的端口。 (解决方法:在命令行上预先启动所有6个H2O簇,或将端口设置为环境变量。)
感谢您的解释。所以你的代码和我的唯一区别是'h2o.init(ip =“localhost”,port = 54321 +(i * 2),...)'。通过分配不同的端口,h2o为每个线程创建一个单独的群集。 – horaceT
@horaceT另外'as.h2o()'数据上传必须在for循环中进行。 (我也把'library(h2o)'放到了foreach循环中,不过我不确定这是否是必需的。)(正如注意到代码不会工作,直到端口错误被修复,无论如何。) –
我有没有测试它,但我只是想了解这个概念。调用'h2o.init(...)'创建一个集群,每个集群连接到一个且只有一个线程。我不能在同一集群内运行多个线程。这是它应该如何工作? – horaceT