我正试图通过R使用H2O,使用一个大型ish数据集(~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
我的问题是,对于这种类型的进程,在独立实体中管理数据和内存的正确方法是什么(如果有的话)?我应该在每次循环后杀死并重新创建H2O实体吗(这是原始过程,但每次从文件中读取数据会增加每次迭代约10分钟)?在每个循环之后,是否有适当的方法来垃圾收集或释放内存?
如有任何建议,我们将不胜感激。
这个答案适用于原始H2O项目(2.x.y.z版本)。
在最初的H2O项目中,H2O R包在H2O簇DKV(分布式密钥/值存储)中创建了许多带有"Last.Value"前缀的临时H2O对象。
在Web UI的商店视图中以及通过从R.调用h2o.ls()都可以看到这些
我建议做的是:
- 在每个循环迭代的底部,使用h2o.assign()对要保存到已知密钥名称的任何内容进行深度复制
- 使用h2o.rm()删除任何不想保留的内容,特别是"Last.value"temps
- 在循环中的某个位置显式调用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年12月15日起的新建议:更新至最新稳定版本(Tibshirani 3.6.0.8或更高版本)。我们完全重新设计了R&H2O处理内部温度变量,内存管理更加顺畅。
下一篇:H2O温度可以通过R个死变量保持"活着"。。。所以每次循环迭代都运行一个Rgc()。一旦R的GC移除了死变量,H2O将回收该内存。
之后,集群应该只保留特定命名的东西,比如加载的数据集和模型。为了避免在K/V存储中积累大量数据,您需要以大致相同的速度删除这些数据。
如果您有任何问题,请通过发布到谷歌群组h2o流来告诉我们:https://groups.google.com/forum/#!论坛/h2ostream
Cliff
这个问题的最新答案是,您可能只应该使用h2o.grid()
函数,而不是编写循环。
对于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