2009-05-08 20 views
14

J'ai lutté avec cela toute la journée, j'essaie d'obtenir un générateur de nombres aléatoires pour les threads dans mon code CUDA. J'ai regardé à travers tous les forums et oui ce sujet monte un peu, mais j'ai passé des heures à essayer de démêler toutes sortes de codes en vain. Si quelqu'un connaît une méthode simple, probablement un périphérique noyau qui peut être appelé pour retourner un flottant aléatoire entre 0 et 1, ou un entier que je peux transformer, je serais très reconnaissant.Générateur de nombre aléatoire dans CUDA

Encore une fois, j'espère utiliser le nombre aléatoire dans le noyau, tout comme rand() par exemple.

Merci à l'avance

+0

Quelques informations utiles: http://http.developer.nvidia.com/GPUGems3/gpugems3_ch37.html – Jesper

Répondre

5

Je ne suis pas sûr que je comprends pourquoi vous avez besoin quelque chose de spécial. N'importe quel PRNG traditionnel devrait porter plus ou moins directement. Un linear congruential devrait fonctionner correctement. Avez-vous des propriétés spéciales que vous essayez d'établir?

+0

Je pense qu'il cherche une bibliothèque qu'il pourrait appeler, pas pour l'implémenter lui-même. Encore une bonne réponse pour le diriger vers une solution. – lothar

+0

La congruence linéaire est très simple à mettre en œuvre. Vous pouvez le faire avec CUDA en ayant un PRNG séparé avec son propre état dans chaque thread. –

+0

C'est ce qui m'a un peu troublé. Chaque fil dirait être ensemencé à partir de son identifiant de fil, mais ils ne commenceraient-ils pas à se chevaucher assez tôt? – zenna

2

Il existe un package MDGPU (GPL) qui inclut une implémentation de la fonction GNU rand48() pour CUDA here.

Je l'ai trouvé (assez facilement, en utilisant Google, ce que je suppose que vous avez essayé :-) sur les forums NVidia here.

+0

Ouais je l'ai trouvé aussi .. mais j'ai eu du mal à le faire pour faire ce que je veux .. Je pense que je suis juste un jour stupide .. Je vais vérifier à nouveau, merci – zenna

+0

Selon les commentaires dans le NVidia forum (y compris de l'auteur) la mise en œuvre ne fonctionne pas bien. –

2

Je n'ai pas trouvé un bon générateur de nombres parallèle CUDA, mais je ne trouve un générateur de nombres aléatoires parallèle basé sur la recherche universitaire ici: http://sprng.cs.fsu.edu/

+0

Quelqu'un sait-il une version CUDA de cet algorithme? –

+0

Que voulez-vous dire par "bon"? Selon vos besoins, un simple hachage MD5 (voir cuDPP) peut suffire. Dans certains cas, plusieurs Twisters Mersenne peuvent être meilleurs car ils ont une très longue période et une bonne indépendance entre les flux. NAG a le MRG32k3a de l'Ecuyer qui fonctionne très bien si vous avez besoin d'un flux unique sur plusieurs threads/blocs. – Tom

+0

Un bon début serait un générateur de nombres pseudo-aléatoires répétés avec une faible dépendance entre les cellules - pour créer un ensemble de tableaux de nombres aléatoires, remplir le contenu de chaque tableau avec plusieurs threads, mais créer les tableaux les uns après les autres. –

4

En fonction de votre application, vous devez être prudent d'utiliser LCGs sans tenir compte si les flux (un flux par thread) se chevaucheront. Vous pourriez implémenter une saute-mouton avec LCG, mais alors vous devriez avoir un LCG de période suffisamment long pour vous assurer que la séquence ne se répète pas.

Un saute-mouton par exemple pourrait être:

template <typename ValueType> 
__device__ void leapfrog(unsigned long &a, unsigned long &c, int leap) 
{ 
    unsigned long an = a; 
    for (int i = 1 ; i < leap ; i++) 
     an *= a; 
    c = c * ((an - 1)/(a - 1)); 
    a = an; 
} 

template <typename ValueType> 
__device__ ValueType quickrand(unsigned long &seed, const unsigned long a, const unsigned long c) 
{ 
    seed = seed * a; 
    return seed; 
} 

template <typename ValueType> 
__global__ void mykernel(
    unsigned long *d_seeds) 
{ 
    // RNG parameters 
    unsigned long a = 1664525L; 
    unsigned long c = 1013904223L; 
    unsigned long ainit = a; 
    unsigned long cinit = c; 
    unsigned long seed; 

    // Generate local seed 
    seed = d_seeds[bid]; 
    leapfrog<ValueType>(ainit, cinit, tid); 
    quickrand<ValueType>(seed, ainit, cinit); 
    leapfrog<ValueType>(a, c, blockDim.x); 

    ... 
} 

Mais la période de ce générateur est probablement insuffisant dans la plupart des cas.

Pour être honnête, je regarderais en utilisant une bibliothèque tierce telle que NAG. Il y a aussi des générateurs de lots dans le SDK, mais ce n'est probablement pas ce que vous recherchez dans ce cas.

EDIT

Depuis ce vient de se lever, a voté, je figure, il vaut la peine de la mise à jour de mentionner que cuRAND, comme l'a mentionné des réponses plus récentes à cette question, est disponible et fournit un certain nombre de générateurs et distributions. C'est certainement l'endroit le plus facile à commencer.

4

La meilleure façon pour cela est l'écriture de votre propre fonction appareil, voici une

void RNG() 
{ 
    unsigned int m_w = 150; 
    unsigned int m_z = 40; 

    for(int i=0; i < 100; i++) 
    { 
     m_z = 36969 * (m_z & 65535) + (m_z >> 16); 
     m_w = 18000 * (m_w & 65535) + (m_w >> 16); 

     cout <<(m_z << 16) + m_w << endl; /* 32-bit result */ 
    } 
} 

Il va vous donner 100 nombres aléatoires, avec un résultat de 32 bits.

Si vous voulez des nombres aléatoires entre 1 et 1000, vous pouvez aussi prendre la result%1000, que ce soit au point de consommation, ou au point de génération:

((m_z << 16) + m_w)%1000 

Modification des valeurs de départ m_w et m_z (dans l'exemple, 150 et 40) vous permet d'obtenir des résultats différents à chaque fois. Vous pouvez utiliser threadIdx.x comme l'un d'entre eux, ce qui devrait vous donner différentes séries pseudo-aléatoire à chaque fois.

Je voulais ajouter que cela fonctionne 2 fois plus rapide que la fonction rand(), et fonctionne très bien;)

+3

Commentaire de l'éditeur: C'est un petit RNG, mais il est loin d'être utilisable pour le calcul où de bons nombres aléatoires sont nécessaires. Il a une période de 2^16, il ne peut pas couvrir tout l'espace des nombres de 32bit, et il est assez facilement réversible en raison d'un simple pas et d'une petite période. – qdot

4

Je pense que toute discussion de cette question doit répondre à la demande orginal de Zenna et qui est un niveau de fil mise en œuvre. Plus précisément, une fonction de périphérique pouvant être appelée depuis un noyau ou un fil . Désolé si j'ai surdosé les phrases "en gras" mais je pense vraiment que les réponses jusqu'à présent ne répondent pas tout à fait ce qui est recherché ici.

La bibliothèque cuRAND est votre meilleur choix. J'apprécie que les gens veuillent réinventer la roue (cela fait apprécier et utiliser plus correctement les bibliothèques tierces) mais les générateurs de haute qualité et de haute qualité sont nombreux et bien testés. La meilleure information que je peux vous recommander est sur la documentation de la bibliothèque GSL sur les différents générateurs ici: http://www.gnu.org/software/gsl/manual/html_node/Random-number-generator-algorithms.html

Pour tout code sérieux, il est préférable d'utiliser l'un des algorithmes principaux que les mathématiciens/informaticiens ont dans le sol et plus à la recherche de faiblesses systémiques. Le "mersenne twister" est quelque chose avec une période (repeat loop) de l'ordre de 10^6000 (l'algorithme MT19997 signifie "Mersenne Twister 2^19997") qui a été spécialement adapté pour Nvidia à utiliser au niveau thread dans les threads du même distorsion en utilisant des identifiants de threads comme des graines. Voir le papier ici: http://developer.download.nvidia.com/compute/cuda/2_2/sdk/website/projects/MersenneTwister/doc/MersenneTwister.pdf. Je travaille actuellement à l'implémentation de somehting en utilisant cette librairie et SI je la fais fonctionner correctement, je posterai mon code. Nvidia a quelques exemples sur son site de documentation pour la boîte à outils CUDA actuelle.

NOTE: Pour l'anecdote, je ne travaille pas pour Nvidia, mais je reconnais que leur conception de documentation et d'abstraction pour CUDA est quelque chose que j'ai déjà été impressionné.


0

Vous pouvez essayer Mersenne Twister for GPUs

Il est basé sur rapide Mersenne Twister orienté SIMD (SFMT) qui est un générateur de nombres aléatoires assez rapide et fiable. Il passe les tests de Marsaglias DIEHARD pour les générateurs de nombres aléatoires.

+0

cuRAND déjà [fournit mersenne twister] (http://docs.nvidia.com/cuda/curand/acknowledgements.html#acknowledgements) implémenté pour le GPU. –