2016-10-19 1 views
0

디바이스 펑터 내에서 스러스트와 함께 CURAND를 사용할 수 있습니까? 최소 코드 예제가 될 수 있습니다스러스트 펑터 내에서 CURAND 사용

#include <thrust/device_vector.h> 

struct Move 
{ 
    Move() {} 

    using Position = thrust::tuple<double, double>; 

    __host__ __device__ 
    Position operator()(Position p) 
    { 
     thrust::get<0>(p) += 1.0; // use CURAND to add a random N(0,1) 
     thrust::get<1>(p) += 1.0; // use CURAND to add a random N(0,1) 
     return p; 
    } 
}; 

int main() 
{ 
    // Create vectors on device 
    thrust::device_vector<double> p1(10, 0.0); 
    thrust::device_vector<double> p2(10, 0.0); 

    // Create zip iterators 
    auto pBeg = thrust::make_zip_iterator(thrust::make_tuple(p1.begin(), p2.begin())); 
    auto pEnd = thrust::make_zip_iterator(thrust::make_tuple(p1.end(), p2.end() )); 

    // Move points in the vectors 
    thrust::transform(pBeg, pEnd, pBeg, Move()); 

    // Print result (just for debug) 
    thrust::copy(p1.begin(), p1.end(), std::ostream_iterator<double>(std::cout, "\n")); 
    thrust::copy(p2.begin(), p2.end(), std::ostream_iterator<double>(std::cout, "\n")); 

    return 0; 
} 

연산자 함수 내에서 난수를 생성하는 올바른 방법은 무엇입니까?

+0

여기에 설명 된 cuRAND 장치 API를 사용해야합니다. http://docs.nvidia.com/cuda/curand/device-api-overview.html#device-api-overview –

답변

3

장치 펑터에서 Thrust와 함께 CURAND를 사용할 수 있습니까?

예, 가능합니다. @ m.s에 표시된대로. curand에서 필요한 것 대부분은 curand 문서의 curand device api example에서 가져올 수 있습니다. (실제로는 추력/모퉁이 샘플 코드도 있습니다. here)

추력 알고리즘 호출과 함께 표시된 설정 커널의 동작을 모방 할 수 있습니다 (예 : thrust::for_each_n을 사용하여 각 장치 벡터 요소의 초기 상태 상태 변수를 설정합니다.

그 후에는 지터 반복기에서 추가 반복자를 통해 초기화 된 오염 상태를 Move 펑터로 전달한 다음 펑터에서 curand_uniform (예 :)을 호출하면됩니다. 여기

은 당신의 코드를 완벽하게 일을 예를 기반으로합니다

$ cat t20.cu 
#include <thrust/device_vector.h> 
#include <curand_kernel.h> 
#include <iostream> 
#include <thrust/iterator/counting_iterator.h> 
#include <thrust/transform.h> 
#include <thrust/for_each.h> 

const int seed = 1234; 
const int ds = 10; 
const int offset = 0; 

struct Move 
{ 
    Move() {} 

    using Position = thrust::tuple<double, double, curandState>; 

    __device__ 
    Position operator()(Position p) 
    { 
     curandState s = thrust::get<2>(p); 
     thrust::get<0>(p) += curand_uniform(&s); // use CURAND to add a random N(0,1) 
     thrust::get<1>(p) += curand_uniform(&s); // use CURAND to add a random N(0,1) 
     thrust::get<2>(p) = s; 
     return p; 
    } 
}; 

struct curand_setup 
{ 
    using init_tuple = thrust::tuple<int, curandState &>; 
    __device__ 
    void operator()(init_tuple t){ 
     curandState s; 
     int id = thrust::get<0>(t); 
     curand_init(seed, id, offset, &s); 
     thrust::get<1>(t) = s; 
     } 
}; 

int main() 
{ 
    // Create vectors on device 
    thrust::device_vector<double> p1(ds, 0.0); 
    thrust::device_vector<double> p2(ds, 0.0); 
    thrust::device_vector<curandState> s1(ds); 

    // Create zip iterators 
    auto pBeg = thrust::make_zip_iterator(thrust::make_tuple(p1.begin(), p2.begin(), s1.begin())); 
    auto pEnd = thrust::make_zip_iterator(thrust::make_tuple(p1.end(), p2.end(), s1.end() )); 
    auto pInit = thrust::make_zip_iterator(thrust::make_tuple(thrust::counting_iterator<int>(0), s1.begin())); 
    // initialize random generator 
    thrust::for_each_n(pInit, ds, curand_setup()); 
    // Move points in the vectors 
    thrust::transform(pBeg, pEnd, pBeg, Move()); 

    // Print result (just for debug) 
    thrust::copy(p1.begin(), p1.end(), std::ostream_iterator<double>(std::cout, "\n")); 
    thrust::copy(p2.begin(), p2.end(), std::ostream_iterator<double>(std::cout, "\n")); 

    return 0; 
} 
$ nvcc -arch=sm_61 -std=c++11 t20.cu -o t20 -lcurand 
$ ./t20 
0.145468 
0.820181 
0.550399 
0.29483 
0.914733 
0.868979 
0.321921 
0.782857 
0.0113023 
0.28545 
0.434899 
0.926417 
0.811845 
0.308556 
0.557235 
0.501246 
0.206681 
0.123377 
0.539587 
0.198575 
$ 

이 질문에 대해서는 :

연산자 함수 내에서 난수를 생성하는 올바른 방법은 무엇입니까?

은 추력에 curand를 사용하여 아무 문제가 없다, 그러나 당신은 또한 추력은이 RNG facility 내장하고 완벽하게 일을 사용 예를 here가 있음을 인식 할 수 있습니다.

+0

완벽하게 작동합니다. 나는 다른 씨앗 대신에 시퀀스를 사용하여 좋은 품질의 난수를 보장하기 때문에 CURAND를 선호합니다. 그러나, 나는'ds = 1000000'을 사용해 보았는데 프로그램이 충돌했다. 메모리 문제가 있어서는 안됩니다 (각 curandState는 48b입니다). – GerryR

+0

ds = 1000000으로 나를 추락시키지 않습니다. 어떤 OS, GPU, CUDA 버전 및 GPU 아치를 컴파일하고 있습니까? Windows Visual Studio를 사용하는 경우 64 비트 (x64) 릴리스 프로젝트를 빌드하고 Win32 프로젝트가 아니라 디버그 프로젝트를 빌드해야합니다. 그런데 CURAND 문서 자체에는 [추력 + CURAND 예제 코드]가 있습니다 (http://docs.nvidia.com/cuda/curand/device-api-overview.html#thrust-and-curand-example) –

+0

I 우분투 16.04, 지포스 GTX 745/PCIe/SSE2, CUDA 8.0, arch = sm_50을 사용하고 있습니다. 오류 :'thrust :: system :: system_error '인스턴스를 던진 후에 호출 종료() : 실행 시간이 초과되었습니다. 끝내고 종료되었습니다 ' – GerryR