본문 바로가기

Parallel 연산에서 Rcpp::function 호출하기

R Programming/Rcpp by Mandarim_ 2023. 10. 6.

R에서의 연산속도를 향상시키기 위해, Parallel 연산과 Rcpp를 고려하게 될 것이다.

이 포스팅에선 Rcpp::function은 이미 다 짠 상태인데 Parallel 연산 안에서 어떻게 Rcpp를 다룰지에 대해 이야기하겠다.

 

여기서 이야기하는 R에서의 Parallel 연산이란,

Parallel 연산을 도와주는 패키지를 사용하여 main session 이 아닌 추가적인 session 을 생성하고 각 session 에서 작동시킨 결과를 다시 main session 에서 통합시켜서 계산하는 방법을 의미한다.

 

이 때 한 명이 4개의 일을 처리하는게 아닌, 4명이 일을 1개씩 처리하기 때문에 계산속도가 빨라진다.

(단, 일을 전달하고 각 일의 결과를 받는 과정 또한 시간이 걸릴 수 있음) 

 

Parallel Processing
Parallel 연산하기

 

문제는 각각의 Session 들이 중간 과정에서 생성된 변수들을 공유하지 않기 때문에, 각각의 Session에서 모든 변수를 추가로 정의해주어야 한다.

 

Rcpp 함수 또한 각 Session 마다 실행시켜주어야 하는데, 

(1) 각 session 마다 Rcpp 파일을 불러오거나 (이 때 library를 통해 직접 Rcpp 패키지를 로딩해야 에러가 발생하지 않는다.),

(2) 각 session 마다 Rcpp 함수를 직접 정의해야 한다.

(1) 세션마다 .cpp 파일 불러오기

(1-1) foreach 사용시 { } 안에 사용하고자 하는 함수를 불러오는 코드를 함께 작성한다.

# Parallel Session 생성
num_cl <- 10
registerDoParallel(cl <- makeCluster(num_cl))

final_list <- foreach(i=1:10) %dopar% {
  library(RcppArmadillo);
  library(Rcpp);
  library(RcppEigen);
  Rcpp::sourceCpp("user_defined_function.cpp")
 	
}

stopCluster(cl)

 

(1-2) parLapply 사용시 (1-1)처럼 모든 반복마다 불러오게끔 작성해도 되고, clusterEvalQ()를 사용하여 미리 정의할 수도 있다.

cl <- makeCluster(num_cl)
clusterExport(cl, varlist= c("nn", "p",
                           "K", "lambda", "tr_beta"))
clusterEvalQ(cl, {
    library(RcppArmadillo);
    library(Rcpp);
    library(RcppEigen);
    Rcpp::sourceCpp("user_defined_function.cpp")})
  
la_results <- parLapply(cl, 1:R, function(r) {
	## user_defined_function.cpp 에서 정의된 function을 사용하는 코드 작성  ##
  })
 
  
 stopCluster(cl)

(2) 직접 정의

sourceCpp( )과 cppFunction 을 (1-2) 처럼 사용해도 된다.

단, code 가 너무 긴 경우 (1)이 편할 것이고 짧은 경우 (2)가 편한데, rcpp_code 또한 각 session 마다 정의되어야 하기 때문에 sourceCpp() 이나 cppFunction() 안에서 직접 정의하는 방법도 있다.

rcpp_code <-
"
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
double user_defined( ) {
	### fill ###
}
}"

# we can defined rcpp_code as follows:
sourceCpp(code = rcpp_code);
cppFunction(rcpp_code);

 

반응형