2016-09-16 1 views
3

Я наивно думал, что прямо вперед сделать несколько вызовов h2o.gbm параллельно внутри цикла foreach. Но получилась странная ошибка.запустить алгоритмы h2o внутри цикла foreach?

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) 

ответ

3

ПРИМЕЧАНИЯ: Это маловероятно, хорошее использование параллельного Еогеаспа АиРа, но я отвечу на ваш вопрос, а затем объяснить, почему. (BTW, когда я использую «кластер» в этом ответе, я имею в виду кластер 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 в него
  • Start 6 потоков в вашем R клиента
  • В каждой нити делают 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) 

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

Теперь контур является:

  • Создать-R темы
  • В каждом потоке, начать H2O кластер, который работает на localhost, но на порт, уникальный для этого кластера. (i*2 - это потому, что каждый кластер H2O фактически использует два порта.)
  • Загрузите свои данные в кластер H2O (т. Е. Это будет повторяться 6 раз, один раз для каждого кластера).
  • Сделайте 3 модели GBM, один за другим.
  • Сделайте что-нибудь с этими моделями
  • Убить кластер для текущей темы.

Если у вас есть 12+ нитей на вашей машине, и 30+ ГБ памяти, и данные относительно мал, то это будет примерно так эффективно, как с помощью одного кластера H2O и делает 12 моделей GBM в последовательный. Если нет, я считаю, что это будет хуже. (Но если у вас есть 6 кластеров H2O на 6 удаленных машинах, это может быть полезным подходом - я должен признать, что мне было интересно, как это сделать, и использование параллельной библиотеки для него никогда не приходило в голову до тех пор, пока Я видел ваш вопрос)

Примечание: в текущей версии (3.10.0.6), я знаю, приведенный выше код не будет работать, так как есть в h2o.init()a bug, что фактически означает, что игнорирование порта. (Временные решения: либо предварительно запустить все 6 кластеров H2O в командной строке, либо установить порт в переменной окружения.)

+0

Спасибо за объяснение. Таким образом, единственное различие между вашими кодами и моими: 'h2o.init (ip =" localhost ", port = 54321 + (i * 2), ...)'. Назначая другой порт, h2o создает отдельный кластер для каждого потока. – horaceT

+0

@horaceT Кроме того, загрузка данных 'as.h2o()' должна проходить внутри цикла for. (Я также поместил библиотеку (h2o) 'внутри цикла foreach, хотя я не уверен, что это было необходимо.) (Как уже отмечалось, код не будет работать до тех пор, пока ошибка порта не будет исправлена.) –

+0

У меня есть не проверял, но я просто хочу понять концепцию. Вызов 'h2o.init (...)' создает кластер, и каждый кластер привязывается к одному и только одному потоку. Я не могу иметь несколько потоков, работающих внутри одного и того же кластера. Так оно и должно работать? – horaceT

Смежные вопросы