我不明白为什么我的随机林网格搜索挂起。我尝试了许多关于Stackoverflow的建议,但都不起作用。首先,这是我的代码:
library(data.table)
library(h2o)
library(dplyr)
# Initialise H2O
localH2O = h2o.init(nthreads = -1, min_mem_size = "9240M", max_mem_size = "11336M")
h2o.removeAll()
# Specify some dirs, inputs etc. (not shown)
laufnummer <- 10
set.seed(laufnummer)
maxmodels <- 500
# Convert to h2o
h2o_input <- as.h2o(input)
# Split: 80% = train; 0 = valid; rest = 20% = test
splits <- h2o.splitFrame(h2o_input, c(0.80,0))
train <- h2o.assign(splits[[1]], "train") # 80%
test <- h2o.assign(splits[[3]], "test") # 10%
设置参数:
# Select range of ntrees
min_ntrees <- 10
max_ntrees <- 2500
stepsize_ntrees <- 20
ntrees_opts <- seq(min_ntrees,max_ntrees, stepsize_ntrees)
# Select range of tries
min_mtries <- 1
max_mtries <- 12
stepsize_mtries <- 1
mtries_opts <- seq(min_mtries,max_mtries, stepsize_mtries)
# Cross-validation number of folds
nfolds <- 5
hyper_params_dl = list(ntrees = ntrees_opts,
mtries = mtries_opts)
search_criteria_dl = list(
strategy = "RandomDiscrete",
max_models = maxmodels)
最后,随机网格搜索(这是它挂起的地方,几乎总是在25%)
rf_grid <- h2o.grid(seed = laufnummer,
algorithm = "randomForest",
grid_id = "dlgrid",
x = predictors,
y = response,
training_frame = train,
nfolds = nfolds,
keep_cross_validation_predictions = TRUE,
model_id = "rf_grid",
hyper_params = hyper_params_dl,
search_criteria = search_criteria_dl
)
以下是我已经尝试过的:
- 没有在init中设置nthreads:没有效果
- 将nthreads设置为4:无效
- 设置较低的内存(我有16 GB):没有效果
- 在网格搜索中添加了并行度=0:没有效果
- 没有使用h2o.removeAll():没有效果
- 始终使用h2o。结束时关闭(提示=FALSE):无效
- 使用了不同版本的JDK、R和h2o。(现在所有人都使用最新版本)
问题是网格搜索进度停止在25%左右,有时甚至更低。
有帮助的是将代码切换到GBM而不是RF,但它有时也会挂在那里(我需要RF!)。同样有帮助的是将模型数量从5000个减少到500个,但仅适用于NN和GBM,而不适用于RF。
经过几周的努力,我将非常感谢任何帮助!!非常感谢。
更新:感谢您的建议,以下是我的尝试:1.导入已使用h2o.importfile()拆分的文件:无效这并不奇怪,因为它是一个很小的数据集,加载需要几秒钟。2.将nthreads设置为1:无效3.不要使用xgboost:我不知道我使用了它。4.不要使用RF:不可能,因为我试图比较机器学习算法。5.h2o.init(jvm_custom_args=c("-XX:+PrintGCDetails","-XX::PrintGCTimeStamps"):不起作用,因为添加此参数后,h2o不会启动。6.额外购买了8GB的RAM,并将max_mem_size分别设置为18和22GB:effect=停止在65%和80%左右,而不是25%。有趣的是进度条越来越慢,直到它完全停止。然后发生了类似于硬重置的事情,因为我使用了不同的键盘布局(Win10),并且设置为默认。。。注:500 GBM或NN在相同的数据集下运行良好。7.将型号数量减少到300个:没有效果。
因此,我的结论是,这肯定是内存问题,但我无法真正监控它。任务管理器中的RAM不是100%,而是分配的max_mem_size。任何能帮助我进一步找出问题的帮助都将不胜感激——谢谢大家!!
挂起的原因很可能是内存不足。您要么需要使用更少的内存,要么在具有更多内存的系统上运行作业。
这里有很多因素在起作用,除非您知道底层资源的使用情况,否则如何调试它们并不一定很明显。
以下三个部分提供了关于如何监控内存使用情况、如何减少内存使用情况以及如何获得更多内存的系统的建议。
以下是一些内存监控建议:
-
监控您的物理内存使用情况。在Mac或Linux上使用类似
top
的程序即可完成此操作。一个重要的数字是RSS(常驻集大小),它表示主机上实际使用的物理内存量。 -
监控任何交换。请确保您的系统没有交换到磁盘。当您试图(一次)使用的虚拟内存多于主机上的物理内存时,就会发生交换。在linux上,
vmstat
命令非常适合显示交换。 -
使用-XX:+PrintGCDetails-XX:+PringGCTimeStamps打开java GC日志记录,您将获得更多的日志输出,它将向您显示java本身是否因内存不足而陷入困境。这很有可能。以下是如何在从R:内部启动H2O-3时传递
jvm_custom_args
标志的示例
h2o.init(jvm_custom_args = c("-XX:+PrintGCDetails", "-XX:+PrintGCTimeStamps"))
您将看到一条消息显示:
H2O is not running yet, starting it now...
Note: In case of errors look at the following log files:
/var/folders/vv/pkzvhy8x5hsfbsjg75_6q4ch0000gn/T//RtmpUsdTRQ/h2o_tomk_started_from_r.out
/var/folders/vv/pkzvhy8x5hsfbsjg75_6q4ch0000gn/T//RtmpUsdTRQ/h2o_tomk_started_from_r.err
上面的.out文件现在将包含GC日志输出,如下所示:
...
02-02 08:30:29.785 127.0.0.1:54321 21814 main INFO: Open H2O Flow in your web browser: http://127.0.0.1:54321
02-02 08:30:29.785 127.0.0.1:54321 21814 main INFO:
02-02 08:30:29.886 127.0.0.1:54321 21814 #84503-22 INFO: GET /, parms: {}
02-02 08:30:29.946 127.0.0.1:54321 21814 #84503-20 INFO: GET /, parms: {}
02-02 08:30:29.959 127.0.0.1:54321 21814 #84503-21 INFO: GET /, parms: {}
02-02 08:30:29.980 127.0.0.1:54321 21814 #84503-22 INFO: GET /3/Capabilities/API, parms: {}
02-02 08:30:29.981 127.0.0.1:54321 21814 #84503-22 INFO: Locking cloud to new members, because water.api.schemas3.CapabilitiesV3
02-02 08:30:30.005 127.0.0.1:54321 21814 #84503-25 INFO: GET /3/InitID, parms: {}
14.334: [GC (Allocation Failure) [PSYoungGen: 94891K->3020K(153088K)] 109101K->56300K(299008K), 0.0193290 secs] [Times: user=0.22 sys=0.01, real=0.02 secs]
14.371: [GC (Allocation Failure) [PSYoungGen: 120914K->3084K(153088K)] 174194K->173560K(338432K), 0.0256458 secs] [Times: user=0.29 sys=0.04, real=0.03 secs]
14.396: [Full GC (Ergonomics) [PSYoungGen: 3084K->0K(153088K)] [ParOldGen: 170475K->163650K(435200K)] 173560K->163650K(588288K), [Metaspace: 22282K->22282K(1069056K)], 0.0484233 secs] [Times: user=0.47 sys=0.00, real=0.05 secs]
14.452: [GC (Allocation Failure) [PSYoungGen: 118503K->160K(281088K)] 282153K->280997K(716288K), 0.0273738 secs] [Times: user=0.30 sys=0.05, real=0.02 secs]
14.479: [Full GC (Ergonomics) [PSYoungGen: 160K->0K(281088K)] [ParOldGen: 280837K->280838K(609792K)] 280997K->280838K(890880K), [Metaspace: 22282K->22282K(1069056K)], 0.0160751 secs] [Times: user=0.09 sys=0.00, real=0.02 secs]
14.516: [GC (Allocation Failure) [PSYoungGen: 235456K->160K(281088K)] 516294K->515373K(890880K), 0.0320757 secs] [Times: user=0.30 sys=0.10, real=0.03 secs]
14.548: [Full GC (Ergonomics) [PSYoungGen: 160K->0K(281088K)] [ParOldGen: 515213K->515213K(969216K)] 515373K->515213K(1250304K), [Metaspace: 22282K->22282K(1069056K)], 0.0171208 secs] [Times: user=0.09 sys=0.00, real=0.02 secs]
"分配失败"的消息看起来很可怕,但实际上是完全正常的。当您看到背靠背的完整GC周期需要花费大量"实际秒"时,就需要担心了。
以下是使用较少内存的一些建议:
将数据拆分一次并保存到磁盘,然后在两个独立的as.H2O或H2O.importFile步骤中在新的H2O-3集群中读回。
在您的示例中,您正在执行splitFrame。这会在内存中复制您的数据。
首选h2o.importFile而不是as.h2o.
我不知道这对你的情况有多大影响,但h2o.importFile是为大数据设计和测试的,而as.h2o不是。
使用更少的数据。
您没有说明数据的形状,但如果automl或网格搜索适用于GBM,而不适用于DRF,那么这肯定意味着内存不足。这两种算法在计算方面几乎完全相同,但DRF模型往往更大,因为DRF具有更高的树深度,这意味着它需要更多的内存来存储模型。
使用nthreads选项可以减少并发工作线程的数量。
运行的活动并发线程越多,需要的内存就越多,因为每个线程都需要一些工作内存。例如,您可以尝试将nthreads设置为CPU核心数的一半。
不要使用xgboost。
Xgboost在使用内存方面很特别,因为它在java堆之外生成了数据的第二个副本。这意味着,当您使用xgboost时,您不希望将整个主机的内存分配给java max_mem_size(或Xmx),否则可能会遇到问题(尤其是交换)。
不要使用DRF。
DRF树更深,因此生成的模型更大。或者,构建(并在内存中保留)更少的DRF模型、更浅的DRF模式或具有更少树的模式。
获得更多内存的最佳快速建议是在云中运行。您不一定需要多节点设置。如果能够充分解决问题,那么使用单个大型节点更容易。在你的情况下,很可能会。考虑到您上面所说的(即您现在有16 GB,如果不使用DRF,它就会结束),我将首先使用EC2中的m5.4xlarge
实例,该实例有64 GB的RAM,成本低于1美元/小时,并将其最大_mem_size设置为48G。