2012-03-28 8 views
28

Sto cercando di ottenere un numero casuale in OpenCL. Non deve essere casuale o addirittura casuale. Solo qualcosa di semplice e veloce.Come ottenere un numero di "random" in OpenCL

Vedo che in OpenCL ci sono una tonnellata di algoritmi casuali di pantaloni fantasia paralleli casuali che sono come migliaia e migliaia di linee. NON ho bisogno di nulla del genere. Un semplice 'random()' andrebbe bene, anche se è facile vedere dei pattern al suo interno.

Vedo che c'è una funzione di disturbo? Un modo semplice per usarlo per ottenere un numero casuale?

+3

si poteva passare un array con alcuni numeri casuali per il kernel, non che essere il più semplice? – eudoxos

+0

È vero, ma poi stai andando avanti e indietro da CPU-> GPU. L'INTERO punto di utilizzo di OpenCL è di rimanere sulla GPU. – user697111

+0

Dipende dall'applicazione e per alcuni tipi di attività (anche all'interno dello stesso problema) la CPU potrebbe essere ancora buona. Dipende da quanto tempo hai a disposizione, generando rande su CPU per lo sviluppo. – eudoxos

risposta

-2

non è possibile generare numeri casuali nel kernel, l'opzione migliore è generare il numero casuale nell'host (CPU) e trasferirlo alla GPU tramite i buffer e utilizzarlo nel kernel.

+8

puoi generare numeri casuali usando qualsiasi algoritmo di randomizzazione, ma il seme deve includere il global_id del thread in modo che ciascuno sia veramente casuale. – ther

+0

Ti sbagli, megharaj. – Tara

+0

@ther grazie per avermi corretto. Lo apprezzo. – Megharaj

1

perché no? potresti semplicemente scrivere un kernel che genera numeri casuali, difficili da richiedere più chiamate al kernel e passare i numeri casuali come argomento all'altro kernel che ne ha bisogno

1

GPU non hanno buone fonti di casualità, ma questo può essere facilmente superato seminando un kernel con un seme casuale dall'host. Dopo ciò, hai solo bisogno di un algoritmo che possa funzionare con un numero enorme di thread simultanei.

Questo collegamento descrive un'implementazione di Mersenne Twister utilizzando OpenCL: Parallel Mersenne Twister. È inoltre possibile trovare un'implementazione nell'SDK di NVIDIA.

3

Sembra OpenCL non fornisce tale funzionalità. Tuttavia, some people have done some research su questo e fornire BSD Codice concesso in licenza per la produzione di buoni numeri casuali sulla GPU.

11

Quello che segue è l'algoritmo utilizzato dalla classe java.util.Random secondo il doc:

(seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1) 

vedere la documentazione per le sue varie implementazioni. Passando id del lavoratore in per il seme e looping poco tempo dovrebbe produrre casualità decente

o nell'altro Metod sarebbe quello di avere alcune operazioni casuali verificarsi che sono abbastanza ceratain a traboccare:

long rand= yid*xid*as_float(xid-yid*xid); 
rand*=rand<<32^rand<<16|rand; 
rand*=rand+as_double(rand); 

con xid=get_global_id(0); e yid= get_global_id(1);

+1

Quanto sopra (java random) ha una correlazione drammaticamente elevata tra seed [n] e seed [n-1]. L'ho scoperto quando ho costruito un simulatore di dadi. Prendi l'output sopra, e fai il modulo 6. Non otterrai mai due 5 uno vicino all'altro! – crusaderky

9

Attualmente sto implementando un Tracer di percorso in tempo reale. Potresti già sapere che Path Tracing richiede molti numeri casuali.
Prima di generare numeri casuali sulla GPU ho semplicemente generato sulla CPU (utilizzando rand(), che aspira) e passato alla GPU.
Questo è diventato rapidamente un collo di bottiglia.
ora sono la generazione dei numeri casuali sulla GPU con il Parco-Miller Pseudorandom Number Generator (PRNG).
È estremamente semplice da implementare e raggiunge ottimi risultati.
Ho preso migliaia di campioni (nell'intervallo da 0,0 a 1,0) e li ho calcolati insieme.
Il valore risultante era molto vicino a 0,5 (che è quello che ti aspetteresti). Tra diverse corse la divergenza da 0,5 era intorno a 0,002. Pertanto ha una distribuzione molto uniforme.

Ecco un articolo che descrive l'algoritmo:
http://www.cems.uwe.ac.uk/~irjohnso/coursenotes/ufeen8-15-m/p1192-parkmiller.pdf
Ed ecco un articolo su l'algoritmo sopra ottimizzato per CUDA (che può essere facilmente portato su OpenCL): http://www0.cs.ucl.ac.uk/staff/ucacbbl/ftp/papers/langdon_2009_CIGPU.pdf

Ecco un esempio di come sto usando iT:

int rand(int* seed) // 1 <= *seed < m 
{ 
    int const a = 16807; //ie 7**5 
    int const m = 2147483647; //ie 2**31-1 

    *seed = (long(*seed * a))%m; 
    return(*seed); 
} 

kernel random_number_kernel(global int* seed_memory) 
{ 
    int global_id = get_global_id(1) * get_global_size(0) + get_global_id(0); // Get the global id in 1D. 

    // Since the Park-Miller PRNG generates a SEQUENCE of random numbers 
    // we have to keep track of the previous random number, because the next 
    // random number will be generated using the previous one. 
    int seed = seed_memory[global_id]; 

    int random_number = rand(&seed); // Generate the next random number in the sequence. 

    seed_memory[global_id] = *seed; // Save the seed for the next time this kernel gets enqueued. 
} 

Il codice serve solo per fare un esempio. Non l'ho provato
L'array "seed_memory" viene riempito con rand() solo una volta prima della prima esecuzione del kernel. Dopo di ciò, tutta la generazione di numeri casuali sta accadendo sulla GPU. Penso che sia anche possibile usare semplicemente l'id del kernel invece di inizializzare l'array con rand().

+0

Grazie per il collegamento, vorrei sottolineare che il documento in realtà propone un'implementazione diversa per le GPU. Quello che hai postato è solo il riferimento di Park & ​​Miller. Il documento viene fornito con la fonte per GPU e le fonti per un esempio e il caso di test sono collegati in astratto. – Armin

+0

Sì, l'implementazione è leggermente diversa. Ma i risultati sono gli stessi. – Tara

14

mi è stato la soluzione di questo "no casuale" problema per ultimi giorni e mi si avvicinò con tre diversi approcci:

  1. Xorshift - ho creato generatore in base a questo. Tutto quello che dovete fare è fornire una uint2 numero (seme) per l'intero kernel e ogni elemento di lavoro calcolerà il proprio numero di rand

    // 'randoms' is uint2 passed to kernel 
    uint seed = randoms.x + globalID; 
    uint t = seed^(seed << 11); 
    uint result = randoms.y^(randoms.y >> 19)^(t^(t >> 8)); 
    
  2. Java random - ho usato il codice da .next(int bits) metodo per generare numeri casuali. Questa volta devi fornire un numero ulong come seme.

    // 'randoms' is ulong passed to kernel 
    ulong seed = randoms + globalID; 
    seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1); 
    uint result = seed >> 16; 
    
  3. Basta generare tutto su CPU e passarlo al kernel in un unico grande buffer.

Ho testato tutti e tre gli approcci (generatori) nel calcolo dell'algoritmo di elaborazione. Set minimo di dominazione nei grafici.

Mi piacciono i numeri generati dal primo, ma sembra che il mio algoritmo di sviluppo non lo faccia.

Il secondo generatore genera numeri che hanno qualche schema visibile ma il mio algoritmo di evoluzione piace così in ogni caso e l'intera cosa funziona poco più velocemente rispetto al primo generatore.

Ma il terzo approccio mostra che è assolutamente bene fornire solo tutti i numeri dall'host (cpu). Per prima cosa ho pensato che la generazione (nel mio caso) dei numeri 1536 int32 e il loro passaggio alla GPU in ogni chiamata del kernel sarebbe stata troppo costosa (da calcolare e trasferire in GPU). Ma si scopre, è veloce come i miei precedenti tentativi. E il carico della CPU rimane sotto il 5%.

BTW, ho provato anche MWC64X Random ma dopo aver installato il nuovo driver GPU la funzione mul_hi inizia a causare errori di compilazione (anche l'intero Kernel Analyer AMD si è bloccato).

3

chiusura del ciclo su una discussione devgurus AMD [link morto] e announcement:

https://github.com/clMathLibraries/clRNG

+1

Non si dovrebbero pubblicare risposte di solo collegamento. Inoltre, il tuo primo link punta alla pagina principale ora (che è esattamente la ragione per cui non dovresti pubblicare risposte solo per link). – Tara

+1

@dudeson Non sono d'accordo, penso che questo post sia perfettamente valido e utile come deve essere. Quindi cosa succede se un forum cambia e quel link muore. –

+1

"Che cosa succede se un forum cambia e quel collegamento muore", quindi la tua risposta in fondo non contiene informazioni. Inoltre, non essere d'accordo con me, in disaccordo con questo: http://meta.stackexchange.com/questions/92505/should-i-flag-answers-which-contain-only-a-link-as-not-an- risposta e questo http://meta.stackexchange.com/questions/8231/are-answers-that-just-contain-links-elsewhere-really-good-answers – Tara

Problemi correlati