与 foreach 并行预测 nnet 输出时 R 内存爆炸

Posted

技术标签:

【中文标题】与 foreach 并行预测 nnet 输出时 R 内存爆炸【英文标题】:R memory blowup when predicting nnet output in parallel with foreach 【发布时间】:2018-03-02 23:30:24 【问题描述】:

我有一个(大型)神经网络正在由 R 中的 nnet 包训练。我希望能够模拟来自这个神经网络的预测,并使用我使用过的类似 foreach 的东西以并行方式进行之前成功(全部在 Windows 机器上)。

我的代码本质上是这样的

library(nnet)

data = data.frame(out=c(0, 0.1, 0.4, 0.6),
              in1=c(1, 2, 3, 4),
              in2=c(10, 4, 2, 6))

net = nnet(out ~ in1 + in2, data=data, size=5)

library(doParallel)
registerDoParallel(cores=detectCores()-2)

results = foreach(test=1:10, .combine=rbind, .packages=c("nnet")) %dopar% 
  result = predict(net, newdata = data.frame(in1=test, in2=5))
  return(result)

除了一个更大的神经网络被拟合和预测;大约 300MB。

上面的代码在使用传统的 for 循环或使用 %do% 时运行良好,但在使用 %dopar% 时,所有正在使用的内核都会加载到内存中 - 每个内核大约 700MB。如果我运行它足够长的时间,一切最终都会爆炸。

查找了类似的问题,我仍然不知道是什么原因造成的。省略“预测”部分可以让一切顺利进行。

如何让每个核心查找不变的“网络”而不是将其加载到内存中?还是不可能?

【问题讨论】:

【参考方案1】:

当您启动新的并行工作器时,您实际上是在创建一个新环境,这意味着您在该新环境中执行的任何操作都需要访问相关的变量/函数。

例如,您必须指定.packages=c("nnet"),因为您需要在每个新工作人员(环境)中使用nnet 包,这就是您从全局环境“克隆”或“导出”到每个工作人员环境的方式。

因为您需要经过训练的神经网络来进行预测,所以您还需要将其导出给每个工作人员,而且我看不出有办法解决您遇到的内存爆炸问题。如果您仍然对并行化感兴趣但内存不足,我唯一的建议是查看doMPI

【讨论】:

【参考方案2】:

如何让每个核心查找不变的“网络”而不是将其加载到内存中?还是不可能?

CPak 的回复解释了发生了什么;您正在单独的 R 会话中有效地运行主脚本的多个副本(=workers)。由于您使用的是 Windows,因此调用

registerDoParallel(cores = n)

扩展到:

cl <- parallel::makeCluster(n, type = "PSOCK")
registerDoParallel(cl)

哪些设置n 独立背景 R 工作人员拥有自己的独立内存地址空间。

现在,如果您使用的是类 Unix 系统,则它对应于使用 n forked R workers,参见。 parallel::mclapply()。 Windows 上的 R 不支持分叉进程。使用分叉处理,您将有效地得到您所要求的,因为分叉的子进程将共享主进程已经分配的对象(只要这些对象没有被修改),例如net.

【讨论】:

以上是关于与 foreach 并行预测 nnet 输出时 R 内存爆炸的主要内容,如果未能解决你的问题,请参考以下文章

R神经网络相关的R包

在 R foreach() 下并行运行时无法识别动态库依赖项

如果我从 randomforest、gbm、svm、nnet 生成预测以获得更准确的预测,如何组合结果(预测)?

R中的并行foreach共享内存

使用 foreach 进行并行处理时出错:“找不到函数“%dopar%””

使用 R doParallel 或 foreach 从 mysql 并行获取数据