2014-01-19 3 views
0

저는 cuRAND 라이브러리를 사용하여 생성기 및 상태의 개념을 이해했습니다. 용어 state은 아직 나를 혼란스럽게 만들었으므로 일부 코드의 도움으로 내 이해를 명확히하고 싶습니다.CUDA : PRNG 생성기 및 상태

int main() { 

float *hData, *dData; 
curandState *devState; 

size_t nThreads = 4; 
size_t nRows = 10; 
size_t n  = nRows * nThreads; 

hData = new float[n]; 
cudaMalloc((void**)&dData, n * sizeof(float)); 
cudaMemset(dData, 0, n * sizeof(float)); 

cudaMalloc((void**)&devState, nThreads * sizeof(curandState)); 
initCurand <<< 1, nThreads >>> (devState, 1234); 
cudaDeviceSynchronize(); 

testrand <<< 1, nThreads >>> (devState, dData, nRows); 
cudaDeviceSynchronize(); 
cudaMemcpy(hData, dData, n*sizeof(int), cudaMemcpyDeviceToHost); 

cudaFree(devState); 
cudaFree(dData); 
free(hData); 
} 

다음은 커널입니다.

__global__ void initCurand(curandState *state, unsigned long seed) 
{ 
    curand_init(seed, threadIdx.x, 0, &state[threadIdx.x]); 
} 

__global__ void testrand(curandState *state, float *d1, int rows) 
{ 

    int idx = threadIdx.x; 
    int stride = blockDim.x; 
    for (int i = 0; i < rows; i++) 
    { 
     d1[idx + i * stride] = curand_uniform(&state[idx]); 
    } 
} 

간단히 말해, 스레드 수만큼 상태가 있습니다. 각 쓰레드는 각각의 상태에서 10 개의 난수를 소비합니다. 출력은 다음과 같습니다.

0.145468 0.820181 0.550399 0.294830 
0.434899 0.926417 0.811845 0.308556 
0.870710 0.511765 0.782640 0.620706 
0.455165 0.537594 0.742539 0.535606 
0.857093 0.809246 0.541354 0.497212 
0.582418 0.017524 0.195556 0.898062 
0.201404 0.449338 0.006050 0.041652 
0.786745 0.799349 0.093755 0.994597 
0.300772 0.136307 0.648018 0.970036 
0.366787 0.377424 0.096621 0.495483 

따라서 상태는 실제로 자체 생성기입니다. 각 생성자/상태는 균일 한 난수 분포를 생성하고 다른 상태는 생성 된 수가 반복되지 않도록 거리를 유지합니다. ==> Q1

cuRAND 가이드에서 많은 상태를 생성하는 것이 계산 집약적이라는 것을 알게되었습니다. 또한 그것을 실험하기 위해 실험했습니다. 어떻게 하나의 state (변수)를 사용하여 각 스레드가 주어진 (단일) 분포에서 다른 난수 (또는 다음 난수가 대기열)를 소비하도록 난수를 생성 할 수 있습니다. ==> Q2

예 : I 네 개의 쓰레드가 다음과 같이 하나의 상태 변수가되는 난수 (가상) 분포를 생성

2-6 100 26 81 72 78 21 33 57 19 32 ...

------ - 1st Cycle ------ 2nd Cycle ------

Thread_1 : - 2 --------- 81 -
Thread_2 : - 6 -------
Thread_3 - - - 100 72 ------ 78은 -
Thread_4 - 26 -------- 21 -

이 PO는 단일 상태 변수를 사용하는 것이 가능한가?

답변

0

1 : state은 데이터입니다. 난수를 생성하는 데 필요한 모든 데이터 (예 : 시드, 시퀀스 위치, 하위 시퀀스 위치 등)를 나타냅니다.

generator은 기능입니다. state 인스턴스에서 작동하고 생성자 유형에 따라 임의의 숫자를 만들고 state을 업데이트 (수정)합니다.

질문 2 : 여러 스레드가 동시에 난수를 생성 할 수 있도록 여러 상태를 생성합니다. 스레드가 임의의 숫자를 병렬로 생성하는 경우 여러 스레드를 처리하는 단일 상태에 대해 이야기하는 것이 타당하지 않습니다. 상태가 RNG 프로세스 중에 생성기에 의해 업데이트되기 때문에 (Q1 참조), 상태 및 다른 스레드가 상태에 기록하는 일부 스레드가 경쟁 조건이되어 상태가 손상 될 수 있습니다 .

스레드 1-4가 첫 번째 사이클에서 단일 state에서 2,6,100 및 26을 생성하는 경우 설명하는 내용은 설명 할 수 없습니다.

+0

따라서 상태 수는 항상 이러한 난수를 소비 할 커널에 대해 시작하는 스레드와 동일해야합니다. 따라서 각 스레드가 자체 배포 (균일, 정상 등)를 수행한다고 말할 수 있습니다. 응용 프로그램에서 난수 생성 스레드를 소비하려는 커널과 별도로 유지해야한다고 말할 수 있습니까? 지금까지 위의 예에서도'testrand'를'curand()'에서 생성 된 숫자를 사용하는 커널로 가져 왔습니다. – Psypher

+0

일반적인 사용 사례 중 하나는 RNG를 즉석에서 수행하는 것입니다. 생성 된 난수는 생성 된 난수에 의해 소비됩니다. 아무것도 분리 할 필요가 없습니다. 만약 당신이 선행 세대 (아마도 별도의 커널에 의해) 그렇다면, 당신은 그들을 소비하기 전에 숫자가 생성되었는지 확인해야합니다. –