Générer des nombres aléatoires à partir d'une distribution gaussienne dans CUDA

StackOverflow https://stackoverflow.com/questions/4743755

  •  13-10-2019
  •  | 
  •  

Question

J'ai beaucoup cherché sur Internet pour trouver un moyen de générer des nombres aléatoires sur mon appareil CUDA, dans un noyau. Les chiffres doivent provenir d'une distribution gaussienne.

La meilleure chose que je trouve était de NVIDIA lui-même. Il est l'algorithme Wallace, qui utilise une distribution uniforme pour construire une gaussienne. Mais les exemples de code qu'ils donnent des explications et je manque vraiment besoin de comprendre comment l'algorithme va, en particulier sur l'appareil. Par exemple, ils donnent:

 __device__ void generateRandomNumbers_wallace(  
unsigned seed,  // Initialization seed  
 float *chi2Corrections,  // Set of correction values  
 float *globalPool,  // Input random number pool  
 float *output  // Output random numbers  


    unsigned tid=threadIdx.x;  
    // Load global pool into shared memory.  
     unsigned offset = __mul24(POOL_SIZE, blockIdx.x);  
    for( int i = 0; i < 4; i++ )  
      pool[tid+THREADS*i] = globalPool[offset+TOTAL_THREADS*i+tid];  
    __syncthreads();  
      const unsigned lcg_a=241;  
      const unsigned lcg_c=59;  
      const unsigned lcg_m=256;  
      const unsigned mod_mask = lcg_m-1;  
      seed=(seed+tid)&mod_mask ;  
      // Loop generating outputs repeatedly  
     for( int loop = 0; loop < OUTPUTS_PER_RUN; loop++ )  
      {  
        Transform();  
        unsigned intermediate_address;  
        i_a = __mul24(loop,8*TOTAL_THREADS)+8*THREADS *  
          blockIdx.x + threadIdx.x;  
        float chi2CorrAndScale=chi2Corrections[  
          blockIdx.x * OUTPUTS_PER_RUN + loop];  
        for( i = 0; i < 4; i++ )  
          output[i_a + i*THREADS]=chi2CorrAndScale*pool[tid+THREADS*i];  
    }  

D'abord, la plupart des variables déclarées ne sont même pas utilisées dans la fonction! Et je ne comprends vraiment pas ce que le « 8 » est dans la deuxième boucle. Je comprends le « 4 » dans les autres boucles ont quelque chose à voir avec le 4x4 bloc de matrice orthogonale, suis-je raison? Quelqu'un pourrait-il me donner une meilleure idée de ce qui se passe ici?

De toute façon, quelqu'un at-il de bons exemples de code que je pourrais utiliser? Ou est-ce que quelqu'un a une autre façon de générer des nombres aléatoires gaussiennes dans un noyau CUDA? Des exemples de code seront très appréciés.

Merci!

Était-ce utile?

La solution

Vous pouvez utiliser CURAND , qui est inclus dans la boîte à outils CUDA (version 3.2 et versions ultérieures). Ce serait beaucoup plus simple!

Quelques notes sur le code affiché:

  • Le générateur transforme Wallace gaussien gaussien (à savoir pas uniforme à gaussienne)
  • le code CUDA a deux variables implicites: blockIdx et threadIdx - ceux-ci définissent l'indice de bloc et l'indice de fil avec un bloc, voir le Guide de programmation CUDA pour plus d'informations
  • Le code utilise __mul24, sur sm_20 et plus tard c'est en fait plus lent que la multiplication 32 bits « ordinaire » donc je l'éviter (même sur des architectures anciennes pour la simplicité)

Autres conseils

Le méthode Box-Muller est également bon.

Le rapide Walsh Hadamard se fait par des motifs d'addition et de soustraction. D'où le théorème central limite applicable. Un tableau de nombres aléatoires uniformes qui subit une transformation de Walsh Hadamard aura une distribution gaussienne / Normal. Il y a quelques petits détails techniques à ce sujet. L'algorithme n'a pas été découvert par Wallace. Il a d'abord été publié dans le magazine Servo autour 1993/1994 par moi-même. J'ai le code de la Walsh Hadamard transformer à www.code.google.com/p/lemontree Cordialement, Sean O'Connor

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top