r - 为什么 save 和 saveRDS 在 dopar 中的行为不同?

标签 r foreach machine-learning parallel-processing r-caret

(这是我第一次尝试创建可重现的示例问题 - 请随时评论以更好的方式来描述或说明问题!)

主要问题声明

我正在使用 foreach 并行训练约 25,000 个模型的%dopar%caretList (来自 caretEnsemble 包)。由于 R 崩溃和内存问题,我需要将每个预测保存为单独的对象,因此我的工作流程如下所示 - 请参阅下面的可重现示例。

cl <- makePSOCKcluster(4)
clusterEvalQ(cl, library(foreach))
registerDoParallel(cl)

multiple.forecasts <- foreach(x=1:1,.combine='rbind',.packages=c('zoo','earth','caret',"glmnet","caretEnsemble")) %dopar% {
  tryCatch({
    results <- caretList(mpg ~ cyl,data=mtcars,trControl=fitControl,methodList=c("glmnet","lm","earth"),continue_on_fail = TRUE)
    for (i in 1:length(results)) {
      results[[i]]$trainingData <- c() ## should be trimming out trainingData
    }
    save(results,file="foreach_results.Rdata") ## export each caretList as its own object
    1
  },
  error = function(e) {
    write.csv(e$message,file="foreach_failure.txt") ## monitor failures as needed
    0
  }
  )
}

(IRL 此项目不涉及 mtcars 数据 - foreach 循环的每次迭代都会迭代列表中的数据帧之一,并为每个数据帧保存一个新的预测对象。)

当此对象保存在 foreach 中时循环中,由于压缩,对象大小在 Windows 中约为 136 KB。

但是,当创建并保存此对象时,使用 foreach ,像这样:

results <- caretList(mpg ~ cyl,data=mtcars,trControl=fitControl,methodList=c("glmnet","lm","earth"),continue_on_fail = TRUE)
for (i in 1:length(results)) {
    results[[i]]$trainingData <- c()
}
save(results,file="no_foreach_results.Rdata")

该对象大致相同,在 Windows 中大约为 156KB。那么 Windows 中保存的对象大小会增加什么?

在实际工作流程中,较小的非foreach对象平均约为 4 MB,较大的 foreach对象平均为 10 MB,因此当我保存大约 25,000 个这些文件时,这会产生真正的存储问题。

  • 为什么在 foreach 循环中保存的对象大小如此之大,我能对此采取什么措施吗?

注释

  • 我的假设是 save foreach内保存整个环境:而不只是保存对象,即使使用 saveRDS 命令这样做也是如此(见下文),导出到每个工作人员的环境都有一些隐式保存。
  • Trim似乎不适用于 caretList :trim trainControl选项似乎没有修剪它应该做的事情,因为我必须手动添加命令来修剪 trainingData .
  • 我当前的解决方法是设置 save压缩为xz :我需要 foreach 循环来利用多核,因此我需要更大的对象。然而,这会使工作流程减慢约 3-4 倍,这就是我寻找解决方案的原因。
  • 需要 PSOCK 集群来解决 caret 中的问题。并行化:参见答案here .
  • SaveRDS对问题没有帮助:我已经使用 saveRDS 进行了测试而不是save ,但对象大小的差异无处不在。
  • 删除 tryCatch无济于事:即使没有tryCatchforeach循环中,对象大小的差异无处不在。

技术细节

可重现的示例:

library(caret)
library(caretEnsemble)

## train a caretList without foreach loop
fitControl <- trainControl(## 10-fold CV
  method = "repeatedcv",
  number = 10,
  ## repeated ten times
  repeats = 10,
  trim=TRUE)

results <- caretList(mpg ~ cyl,data=mtcars,trControl=fitControl,methodList=c("glmnet","lm","earth"),continue_on_fail = TRUE)
for (i in 1:length(results)) {
    results[[i]]$trainingData <- c()
}
object.size(results) ##returns about 546536 bytes
save(results,file="no_foreach_results.Rdata") ##in Windows, this object is about 136 KB

## train a caretList with foreach loop
library(doParallel)

cl <- makePSOCKcluster(4)
clusterEvalQ(cl, library(foreach))
registerDoParallel(cl)

multiple.forecasts <- foreach(x=1:1,.combine='rbind',.packages=c('zoo','earth','caret',"glmnet","caretEnsemble")) %dopar% {
  tryCatch({
    results <- caretList(mpg ~ cyl,data=mtcars,trControl=fitControl,methodList=c("glmnet","lm","earth"),continue_on_fail = TRUE)
    for (i in 1:length(results)) {
      results[[i]]$trainingData <- c()
    }
    save(results,file="foreach_results.Rdata") ## in Windows, this object is about 160 KB
    ## loading this file back in and running object.size gives about 546504 bytes, approximately the same
    1
  },
  error = function(e) {
    write.csv(e$message,file="foreach_failure.txt")
    0
  }
  )
}

sessionInfo() 输出:

R version 3.2.2 (2015-08-14)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows Server 2012 x64 (build 9200)

locale:
[1] LC_COLLATE=English_United States.1252  LC_CTYPE=English_United States.1252   
[3] LC_MONETARY=English_United States.1252 LC_NUMERIC=C                          
[5] LC_TIME=English_United States.1252    

attached base packages:
[1] parallel  stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] doParallel_1.0.10   iterators_1.0.8     earth_4.4.4         plotmo_3.1.4        TeachingDemos_2.10 
 [6] plotrix_3.6-2       glmnet_2.0-5        foreach_1.4.3       Matrix_1.2-4        caretEnsemble_2.0.0
[11] caret_6.0-64        ggplot2_2.1.0       RevoUtilsMath_8.0.1 RevoUtils_8.0.1     RevoMods_8.0.1     
[16] RevoScaleR_8.0.1    lattice_0.20-33     rpart_4.1-10       

loaded via a namespace (and not attached):
 [1] Rcpp_0.12.4        compiler_3.2.2     nloptr_1.0.4       plyr_1.8.3         tools_3.2.2       
 [6] lme4_1.1-11        digest_0.6.9       nlme_3.1-126       gtable_0.2.0       mgcv_1.8-12       
[11] SparseM_1.7        gridExtra_2.2.1    stringr_1.0.0      MatrixModels_0.4-1 stats4_3.2.2      
[16] grid_3.2.2         nnet_7.3-12        data.table_1.9.6   pbapply_1.2-1      minqa_1.2.4       
[21] reshape2_1.4.1     car_2.1-2          magrittr_1.5       scales_0.4.0       codetools_0.2-14  
[26] MASS_7.3-45        splines_3.2.2      pbkrtest_0.4-6     colorspace_1.2-6   quantreg_5.21     
[31] stringi_1.0-1      munsell_0.4.3      chron_2.3-47  

最佳答案

我也不知道为什么,但我想出的解决方法就是运行

rm(训练数据)

从环境中删除任何重型存储 - 例如训练数据集 - 并阻止其保存到磁盘。

(很高兴不仅仅是我一个人对此感到疯狂。)

关于r - 为什么 save 和 saveRDS 在 dopar 中的行为不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38837319/

相关文章:

php - 使 foreach 循环中的 $id 唯一

javascript - 如何使用 jquery 和 codeigniter 从 foreach 循环获取当前值

python - 准确度测量值 val_acc 可信吗?

python - 在python中调用Libsvm模型

r - 将分隔的字符串拆分为 R 数据框中的不同列

r - 是否可以使用Rstudio在不使用Pandoc的情况下直接将.Rmd转换为LaTeX?

r - 连接来自向量的相邻字符串

c# 使用子字符串和正则表达式编辑大字符串

r - 如果向量长度不同,如何单独粘贴到列表中

machine-learning - 为什么不同的批量大小在 Keras 中给出不同的精度?