注意:這不太好使用的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