与foreach并行预测nnet输出时的R内存爆炸
R memory blowup when predicting nnet output in parallel with foreach
我有一个(大型)神经网络正在由 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 .如果我 运行 时间足够长,一切最终都会爆炸。
查找了类似的问题,我仍然不知道是什么原因造成的。省略 'predict' 部分可以使一切 运行 顺利进行。
如何让每个核心查找不变的 'net' 而不是将其加载到内存中?还是不可能?
当您启动新的并行工作器时,实际上是在创建一个新环境,这意味着您在该新环境中执行的任何操作都需要访问相关的 variables/functions。
例如,您必须指定 .packages=c("nnet")
,因为您需要在每个新工作人员(环境)中使用 nnet
包,这就是您 "clone" 或 "export" 从全局环境到每个worker环境
因为您需要训练有素的神经网络来进行预测,所以您还需要将其导出给每个工作人员,而且我看不出有什么办法可以解决您正在经历的内存爆炸问题。如果您仍然对并行化感兴趣但 运行 内存不足,我唯一的建议是查看 doMPI
.
How can I have each core lookup the unchanging 'net' rather than having it loaded into memory? Or is it not possible?
CPak 的回复解释了发生了什么;在单独的 R 会话中,您实际上是 运行 主脚本的多个副本 (=workers)。因为你在 Windows,正在呼叫
registerDoParallel(cores = n)
扩展为:
cl <- parallel::makeCluster(n, type = "PSOCK")
registerDoParallel(cl)
which what what sets n
独立的背景 R workers 有自己独立的内存地址空间。
现在,如果你使用的是类 Unix 系统,它会对应于使用 n
forked R worker,cf。 parallel::mclapply()
。 Windows 上的 R 不支持分叉进程。使用分叉处理,您将有效地得到您所要求的,因为分叉子进程将共享主进程已经分配的对象(只要这些对象未被修改),例如net
.
我有一个(大型)神经网络正在由 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 .如果我 运行 时间足够长,一切最终都会爆炸。
查找了类似的问题,我仍然不知道是什么原因造成的。省略 'predict' 部分可以使一切 运行 顺利进行。
如何让每个核心查找不变的 'net' 而不是将其加载到内存中?还是不可能?
当您启动新的并行工作器时,实际上是在创建一个新环境,这意味着您在该新环境中执行的任何操作都需要访问相关的 variables/functions。
例如,您必须指定 .packages=c("nnet")
,因为您需要在每个新工作人员(环境)中使用 nnet
包,这就是您 "clone" 或 "export" 从全局环境到每个worker环境
因为您需要训练有素的神经网络来进行预测,所以您还需要将其导出给每个工作人员,而且我看不出有什么办法可以解决您正在经历的内存爆炸问题。如果您仍然对并行化感兴趣但 运行 内存不足,我唯一的建议是查看 doMPI
.
How can I have each core lookup the unchanging 'net' rather than having it loaded into memory? Or is it not possible?
CPak 的回复解释了发生了什么;在单独的 R 会话中,您实际上是 运行 主脚本的多个副本 (=workers)。因为你在 Windows,正在呼叫
registerDoParallel(cores = n)
扩展为:
cl <- parallel::makeCluster(n, type = "PSOCK")
registerDoParallel(cl)
which what what sets n
独立的背景 R workers 有自己独立的内存地址空间。
现在,如果你使用的是类 Unix 系统,它会对应于使用 n
forked R worker,cf。 parallel::mclapply()
。 Windows 上的 R 不支持分叉进程。使用分叉处理,您将有效地得到您所要求的,因为分叉子进程将共享主进程已经分配的对象(只要这些对象未被修改),例如net
.