2013-09-23 3 views
1

나는 명확한 질문이 있습니다. SourceCpp가 자동으로 RNG 상태를 전달하므로 set.seed (123)는 Rcpp 코드를 호출 할 때 재현 가능한 난수를 제공합니다. 패키지를 컴파일 할 때 set RNG 문을 추가해야합니다. 이제이 모든 것이 sourceCpp 또는 패키지 내에서 openMP와 어떻게 작동합니까?openMP와 Rcpp로 RNG 상태를 설정하십시오.

다음 Rcpp 코드를

#include <Rcpp.h> 
#include <omp.h> 

// [[Rcpp::depends("RcppArmadillo")]] 

// [[Rcpp::export]] 
Rcpp::NumericVector rnormrcpp1(int n, double mu, double sigma ){ 
    Rcpp::NumericVector out(n); 
     for (int i=0; i < n; i++) { 
      out(i) =R::rnorm(mu,sigma); 
     } 

    return(out); 
} 


// [[Rcpp::export]] 
Rcpp::NumericVector rnormrcpp2(int n, double mu, double sigma, int cores=1 ){ 
    omp_set_num_threads(cores); 
    Rcpp::NumericVector out(n); 
    #pragma omp parallel for schedule(dynamic) 
     for (int i=0; i < n; i++) { 
      out(i) =R::rnorm(mu,sigma); 
     } 

    return(out); 
} 

을 고려 그리고 A1과 A2는 동일하지만

set.seed(123) 
    a1=rnormrcpp1(100,2,3,2) 
    set.seed(123) 
    a2=rnormrcpp1(100,2,3,2) 
    set.seed(123) 
    a3=rnormrcpp2(100,2,3,2) 
    set.seed(123) 
    a4=rnormrcpp2(100,2,3,2) 
    all.equal(a1,a2) 
    all.equal(a3,a4) 

을 실행, A3와 A4는 없습니다. openMP 루프를 사용하여 RNG 상태를 어떻게 조정할 수 있습니까? 그럴 수있어?

답변

1

예, sourceCpp() 등이며 인스턴스화가 RNGScope이므로 RNG가 적절한 상태로 남습니다.

그렇습니다. OpenMP를 사용할 수 있습니다. 그러나 OpenMP 세그먼트 내에서 스레드가 실행되는 순서를 제어 할 수 없으므로 동일한 순서가 더 길어집니다. 나는 재현성있는 무승부를 원했지만 아직 OpenMP를 사용하고 싶은 개발중인 패키지와 같은 문제가있다. 그러나 그것은 당신이 할 수없는 것 같습니다.

+1

이것은 해결책이 아니지만 답변입니다. 감사. – Inferrator

2

Dirk Eddelbuettel이 이미 언급 한 것을 확장하기 위해 동일한 PRN 시퀀스를 병렬로 생성하는 것은 불가능합니다. 은 원하는 속도 향상을 제공합니다. 이것의 근본은 PRN 시퀀스의 생성은 본질적으로 각각의 상태가 이전의 상태에 의존하는 순차적 인 과정이며 이것은 초기의 시드 상태까지 되돌아 오는 후방 의존성 체인을 생성한다는 것입니다.

이 문제에 대한 두 가지 기본적인 해결책이 있습니다. 그 중 하나는 메모리를 많이 필요로하고 다른 하나는 CPU 시간을 많이 필요로하고 모두 더 진정한 솔루션보다 해결 방법처럼 실제로 :

미리 생성 PRN 순서 : 하나의 스레드가 순차적으로 생성 PRNS의 거대한 배열하고 모든 스레드는 순차적 인 경우와 일치하는 방식으로이 배열에 액세스합니다. 이 방법은 시퀀스를 저장하기 위해 많은 메모리가 필요합니다. 또 다른 옵션은 나중에 메모리 맵핑 된 디스크 파일에 시퀀스를 저장하는 것입니다. 후자의 방법은 계산 시간을 절약 할 수 있다는 장점이 있지만 일반적으로 I/O 작업은 느리기 때문에 처리 능력이 제한적인 컴퓨터 나 소량의 RAM이있는 컴퓨터에서만 의미가 있습니다.

미리 예고 된 PRNG : 이것은 작업이 스레드간에 정적으로 분산되는 경우에 효과적입니다. schedule(static). 각 스레드는 자체 PRNG를 가지며 모든 PRNG는 동일한 초기 시드로 시드됩니다. 그런 다음 각 스레드는 시작 반복으로 많은 더미 PRN을 그립니다. PRNG를 본래의 위치로 미리 되감습니다.

  • 스레드 0 : 예를 들어 다음 100 PRNS을 그리고 out(0:99)
  • 쓰레드 (1)를 채우고 0 더미 PRNS 무 100 더미 PRNS 무 후 100 PRNS을 그리고 out(100:199)
  • 스레드 2를 채우고 200 무 더미 PRN은 그 다음 100 개의 PRN 및 채우기를 가져옵니다. out(200:299)

등등.이 방법은 각 스레드가 PRNG를 그리는 것 외에 많은 계산을 할 때 잘 작동한다. PRNG를 미리 감기는 시간이 일부 경우에 상당 할 수 있기 때문이다 (예 : 많은 반복).

PRN을 그리는 것 외에 많은 데이터 처리가있는 경우 세 번째 옵션이 있습니다. 이것은 하나의 OpenMP는 (반복 청크 크기가 1로 설정되어 있습니다) 루프 정렬 사용 루프 순서가 본질적으로 계산 serialises

#pragma omp parallel for ordered schedule(static,1) 
for (int i=0; i < n; i++) { 
    #pragma omp ordered 
    { 
    rnum = R::rnorm(mu,sigma); 
    } 
    out(i) = lots of processing on rnum 
} 

있지만 lots of processing on rnum 병렬 따라서 병렬 고속화에 실행하는 것은 여전히 ​​허용 할 것이다 관찰 되야한다. 이유에 대한 자세한 설명은 this answer을 참조하십시오.

관련 문제