7

我正在尝试通过 R 使用 H2O 来使用一个大型数据集(约 10GB)的子集构建多个模型。这些数据是一年的数据,我正在尝试构建 51 个模型(即在第 1 周进行训练,在第 2 周进行预测等),每周大约有 1.5-250 万行,包含 8 个变量。

我已经在循环中完成了这个,我知道这并不总是 R 中的最佳方式。我发现的另一个问题是 H2O 实体会累积先前的对象,所以我创建了一个函数来删除除主要数据之外的所有对象放。

h2o.clean <- function(clust = localH2O, verbose = TRUE, vte = c()){
  # Find all objects on server
  keysToKill <- h2o.ls(clust)$Key
  # Remove items to be excluded, if any
  keysToKill <- setdiff(keysToKill, vte)
  # Loop thru and remove items to be removed
  for(i in keysToKill){
    h2o.rm(object = clust, keys = i)

    if(verbose == TRUE){
      print(i);flush.console()

    }    
  }
  # Print remaining objects in cluster.
  h2o.ls(clust)
}

该脚本运行良好一段时间然后崩溃 - 通常抱怨内存不足并交换到磁盘。

这里有一些伪代码来描述这个过程

# load h2o library
library(h2o)
# create h2o entity
localH2O = h2o.init(nthreads = 4, max_mem_size = "6g")
# load data
dat1.hex = h2o.importFile(localH2O, inFile, key = "dat1.hex")

# Start loop
for(i in 1:51){
# create test/train hex objects
train1.hex <- dat1.hex[dat1.hex$week_num == i,]
test1.hex <- dat1.hex[dat1.hex$week_num == i + 1,]
# train gbm
dat1.gbm <- h2o.gbm(y = 'click_target2', x = xVars, data = train1.hex
                      , nfolds = 3
                      , importance = T
                      , distribution = 'bernoulli' 
                      , n.trees = 100
                      , interaction.depth = 10,
                      , shrinkage = 0.01
  )
# calculate out of sample performance
test2.hex <- cbind.H2OParsedData(test1.hex,h2o.predict(dat1.gbm, test1.hex))
colnames(test2.hex) <- names(head(test2.hex))
gbmAuc <- h2o.performance(test2.hex$X1, test2.hex$click_target2)@model$auc

# clean h2o entity
h2o.clean(clust = localH2O, verbose = F, vte = c('dat1.hex'))

} # end loop

我的问题是,如果有的话,在独立实体中管理数据和内存的正确方法是什么(这不是在 hadoop 或集群上运行 - 只是一个大型 EC2 实例(~ 64gb RAM + 12 CPU))过程?我是否应该在每次循环后杀死并重新创建 H2O 实体(这是原始过程,但每次从文件中读取数据每次迭代增加约 10 分钟)?每次循环后是否有适当的方法来垃圾收集或释放内存?

任何建议,将不胜感激。

4

4 回答 4

9

此答案适用于原始 H2O 项目(发布 2.xyz)。

在最初的 H2O 项目中,H2O R 包在 H2O 集群 DKV(分布式键/值存储)中创建了许多带有“Last.value”前缀的临时 H2O 对象。

这些在 Web UI 的 Store View 和 R 中调用 h2o.ls() 都是可见的。

我建议做的是:

  • 在每次循环迭代的底部,使用 h2o.assign() 对要保存到已知键名的任何内容进行深层复制
  • 使用 h2o.rm() 删除您不想保留的任何内容,尤其是“Last.value”临时文件
  • 在循环的某处在 R 中显式调用 gc()

这是一个为您删除 Last.value 临时对象的函数。传入 H2O 连接对象作为参数:

removeLastValues <- function(conn) {
    df <- h2o.ls(conn)
    keys_to_remove <- grep("^Last\\.value\\.", perl=TRUE, x=df$Key, value=TRUE)
    unique_keys_to_remove = unique(keys_to_remove)
    if (length(unique_keys_to_remove) > 0) {
        h2o.rm(conn, unique_keys_to_remove)
    }
}

这是 H2O github 存储库中使用此技术的 R 测试的链接,可以无限期运行而不会耗尽内存:

https://github.com/h2oai/h2o/blob/master/R/tests/testdir_misc/runit_looping_slice_quantile.R

于 2015-03-30T02:50:02.433 回答
4

2015 年 12 月 15 日的新建议:更新到最新的稳定版(Tibshirani 3.6.0.8 或更高版本)。我们完全重新设计了 R & H2O 处理内部临时变量的方式,并且内存管理更加顺畅。

下一步:R 死变量可以使 H2O 温度保持“活跃”......所以每次循环迭代都运行一个 R gc() 。一旦 R 的 GC 删除了死变量,H2O 将回收该内存。

在那之后,你的集群应该只保留特定命名的东西,比如加载的数据集和模型。这些您需要大致与创建它们一样快地删除它们,以避免在 K/V 存储中积累大量数据。

如果您有任何其他问题,请通过发布到 google 组 h2o 流告诉我们: https ://groups.google.com/forum/#!forum/h2ostream

悬崖

于 2015-12-16T18:07:17.340 回答
2

这个问题的最新答案是您可能应该只使用h2o.grid()函数而不是编写循环。

于 2017-08-01T16:04:35.067 回答
0

对于 H2O 新版本(当前为 3.24.0.3),他们建议使用以下建议:

my for loop {
 # perform loop

 rm(R object that isn’t needed anymore)
 rm(R object of h2o thing that isn’t needed anymore)

 # trigger removal of h2o back-end objects that got rm’d above, since the rm can be lazy.
 gc()
 # optional extra one to be paranoid.  this is usually very fast.
 gc()

 # optionally sanity check that you see only what you expect to see here, and not more.
 h2o.ls()

 # tell back-end cluster nodes to do three back-to-back JVM full GCs.
 h2o:::.h2o.garbageCollect()
 h2o:::.h2o.garbageCollect()
 h2o:::.h2o.garbageCollect()
}

这里的来源:http: //docs.h2o.ai/h2o/latest-stable/h2o-docs/faq/general-troubleshooting.html

于 2019-05-16T17:41:50.257 回答