运行 使用 for 或 foreach 和带有 Rcpp 的 C++ 函数内存不足
Running out of Memory using for or foreach and a C++-function with Rcpp
我想生成一个大矩阵(大约 300.000 * 5000)并用来自给定观察向量的随机样本填充它。
R 代码如下所示:
library(foreach)
elements <- as.numeric(1:1000)
result_list <- foreach(i=(1:50)) %do% {
mypackage::rddrawmatrixC2(n_bootstrap = 100,
n_obs_censusdata = 300000,
elements_to_draw_from = elements))))
}
rddrawmatrixC2 是一个 C++ - 使用 Rcpp 导出的函数。我写了它,因为 sample() 似乎慢得多。
因为我正在优化速度,所以我尝试了不同的方法:
- 使用 foreach。顺序和并行。
- 在先前初始化的列表上使用简单的 for 循环
result_list <- vetor("list", 50)
- 使用 data.table 并使用
:=
或 set()
添加列而不是行
- 将结果写入临时文件是可行的,但速度非常慢。
每个方法都会导致错误
cannot allocate Vector of n mb
n 在 1.6 mb 和 200 mb 之间变化。
我想这与我的功能无关,因为在这个简单的例子中发生了同样的事情,第一行工作正常,但循环没有:
m <- matrix(1:6000*5000, nrow = 6000, ncol = 5000)
result_list <- foreach(i=(1:50)) %do% {
matrix(1:6000*5000, nrow = 6000, ncol = 5000)
}
据我所知,更改列表的项目不应导致整个列表在内部被复制,data.table 中的 := 运算符绝对应该避免访问不必要的信息。您有任何解释/解决方法吗?这可能是与 Rcpp 有关的问题吗?有没有一种方法可以使用 Rcpp 创建整个列表来避免问题,然后 return 列表而不会使 R 的内存再次崩溃?
我正在研究 Windows 10,R 3.4.4。如果需要其他信息,我很乐意提供。
非常感谢任何帮助(以及对我的代码的反馈),谢谢!
这是 C++ 的代码 - 函数:
#include <RcppEigen.h>
#include <random>
using namespace Rcpp;
// [[Rcpp::export]]
SEXP rddrawmatrixC2(const int n_bootstrap,
const Eigen::Map<Eigen::VectorXd> elements_to_draw_from,
const int n_obs_censusdata)
{
const int upper = elements_to_draw_from.size();
std::random_device rd; // used to obtain a seed for the number engine
std::mt19937 gen(rd()); // Mersenne Twister engine
std::uniform_int_distribution<> dis(1, upper);
// initialise matrix that can be filled
NumericMatrix returnmatrix(n_obs_censusdata, n_bootstrap);
const int matrixsize = n_obs_censusdata * n_bootstrap;
for (int i=0; i<matrixsize; ++i)
returnmatrix[i] = elements_to_draw_from[dis(gen)-1]; // subtract 1 because in C++ indices start with 0
return Rcpp::wrap(returnmatrix);
}
(这个函数还有一个版本没有使用Rcpp::Eigen,但错误是一样的)
编辑/补充:
问题显然不在于使用 for/foreach/Rcpp。更确切地说,即使一次只访问一小部分,R 仍然必须将整个列表/data.table 保存在内存中。一种解决方案是将数据写入文件或使用包 bigstatsr 中提供的基于文件的矩阵。
正如 Ralf Stubner 和 Florian Privé 指出的那样,好的起点是:
https://privefl.github.io/blog/a-guide-to-parallelism-in-r/#filling-something-in-parallel https://github.com/privefl/bigstatsr
代表
elements <- as.numeric(1:1000)
my_fun <- function(n_bootstrap,
n_obs_censusdata,
elements_to_draw_from) {
replicate(n_bootstrap, sample(elements_to_draw_from, n_obs_censusdata, TRUE))
}
FBM 的 Foreach 解决方案
library(bigstatsr)
X <- FBM(300000, 5000)
library(doParallel)
registerDoParallel(cl <- makeCluster(nb_cores()))
foreach(i = 1:50, .combine = 'c') %dopar% {
cols <- 1:100 + (i - 1) * 100
X[, cols] <- my_fun(n_bootstrap = 100,
n_obs_censusdata = 300000,
elements_to_draw_from = elements)
NULL
}
stopCluster(cl)
注意 foreach
returns 的东西,这就是我使用 NULL
的原因,因为我们只想在这里分配。
直接与big_apply
big_apply
为您处理拆分/并行。
big_apply(X, a.FUN = function(X, ind, my_fun, elements) {
X[, ind] <- my_fun(n_bootstrap = length(ind),
n_obs_censusdata = 300000,
elements_to_draw_from = elements)
NULL
}, a.combine = 'c', ncores = nb_cores(), block.size = 100,
my_fun = my_fun, elements = elements)
我想生成一个大矩阵(大约 300.000 * 5000)并用来自给定观察向量的随机样本填充它。
R 代码如下所示:
library(foreach)
elements <- as.numeric(1:1000)
result_list <- foreach(i=(1:50)) %do% {
mypackage::rddrawmatrixC2(n_bootstrap = 100,
n_obs_censusdata = 300000,
elements_to_draw_from = elements))))
}
rddrawmatrixC2 是一个 C++ - 使用 Rcpp 导出的函数。我写了它,因为 sample() 似乎慢得多。
因为我正在优化速度,所以我尝试了不同的方法:
- 使用 foreach。顺序和并行。
- 在先前初始化的列表上使用简单的 for 循环
result_list <- vetor("list", 50)
- 使用 data.table 并使用
:=
或set()
添加列而不是行 - 将结果写入临时文件是可行的,但速度非常慢。
每个方法都会导致错误
cannot allocate Vector of n mb
n 在 1.6 mb 和 200 mb 之间变化。
我想这与我的功能无关,因为在这个简单的例子中发生了同样的事情,第一行工作正常,但循环没有:
m <- matrix(1:6000*5000, nrow = 6000, ncol = 5000)
result_list <- foreach(i=(1:50)) %do% {
matrix(1:6000*5000, nrow = 6000, ncol = 5000)
}
据我所知,更改列表的项目不应导致整个列表在内部被复制,data.table 中的 := 运算符绝对应该避免访问不必要的信息。您有任何解释/解决方法吗?这可能是与 Rcpp 有关的问题吗?有没有一种方法可以使用 Rcpp 创建整个列表来避免问题,然后 return 列表而不会使 R 的内存再次崩溃?
我正在研究 Windows 10,R 3.4.4。如果需要其他信息,我很乐意提供。
非常感谢任何帮助(以及对我的代码的反馈),谢谢!
这是 C++ 的代码 - 函数:
#include <RcppEigen.h>
#include <random>
using namespace Rcpp;
// [[Rcpp::export]]
SEXP rddrawmatrixC2(const int n_bootstrap,
const Eigen::Map<Eigen::VectorXd> elements_to_draw_from,
const int n_obs_censusdata)
{
const int upper = elements_to_draw_from.size();
std::random_device rd; // used to obtain a seed for the number engine
std::mt19937 gen(rd()); // Mersenne Twister engine
std::uniform_int_distribution<> dis(1, upper);
// initialise matrix that can be filled
NumericMatrix returnmatrix(n_obs_censusdata, n_bootstrap);
const int matrixsize = n_obs_censusdata * n_bootstrap;
for (int i=0; i<matrixsize; ++i)
returnmatrix[i] = elements_to_draw_from[dis(gen)-1]; // subtract 1 because in C++ indices start with 0
return Rcpp::wrap(returnmatrix);
}
(这个函数还有一个版本没有使用Rcpp::Eigen,但错误是一样的)
编辑/补充: 问题显然不在于使用 for/foreach/Rcpp。更确切地说,即使一次只访问一小部分,R 仍然必须将整个列表/data.table 保存在内存中。一种解决方案是将数据写入文件或使用包 bigstatsr 中提供的基于文件的矩阵。
正如 Ralf Stubner 和 Florian Privé 指出的那样,好的起点是: https://privefl.github.io/blog/a-guide-to-parallelism-in-r/#filling-something-in-parallel https://github.com/privefl/bigstatsr
代表
elements <- as.numeric(1:1000)
my_fun <- function(n_bootstrap,
n_obs_censusdata,
elements_to_draw_from) {
replicate(n_bootstrap, sample(elements_to_draw_from, n_obs_censusdata, TRUE))
}
FBM 的 Foreach 解决方案
library(bigstatsr)
X <- FBM(300000, 5000)
library(doParallel)
registerDoParallel(cl <- makeCluster(nb_cores()))
foreach(i = 1:50, .combine = 'c') %dopar% {
cols <- 1:100 + (i - 1) * 100
X[, cols] <- my_fun(n_bootstrap = 100,
n_obs_censusdata = 300000,
elements_to_draw_from = elements)
NULL
}
stopCluster(cl)
注意 foreach
returns 的东西,这就是我使用 NULL
的原因,因为我们只想在这里分配。
直接与big_apply
big_apply
为您处理拆分/并行。
big_apply(X, a.FUN = function(X, ind, my_fun, elements) {
X[, ind] <- my_fun(n_bootstrap = length(ind),
n_obs_censusdata = 300000,
elements_to_draw_from = elements)
NULL
}, a.combine = 'c', ncores = nb_cores(), block.size = 100,
my_fun = my_fun, elements = elements)