Meilleure façon d'amorcer N générateurs de nombres aléatoires indépendants à partir d'une valeur

10

Dans mon programme, je dois exécuter N threads séparés chacun avec leur propre RNG qui est utilisé pour échantillonner un grand ensemble de données. J'ai besoin de pouvoir semer tout ce processus avec une seule valeur afin de pouvoir reproduire les résultats.

Suffit-il d'augmenter simplement séquentiellement le germe pour chaque indice?

Actuellement , j'utilise numpy« s RandomStatequi utilise un générateur de nombres pseudo-aléatoires Mersenne Twister.

Extrait de code ci-dessous:

# If a random number generator seed exists
if self.random_generator_seed:
    # Create a new random number generator for this instance based on its
    # own index
    self.random_generator_seed += instance_index
    self.random_number_generator = RandomState(self.random_generator_seed)

Essentiellement, je commence par une graine entrée par l'utilisateur (si elle existe) et pour chaque instance / thread, j'ajoute séquentiellement l'index (0 à N-1) de l'instance en cours d'exécution. Je ne sais pas s'il s'agit d'une bonne pratique ou s'il existe une meilleure façon de procéder.

EricR
la source
1
Savez-vous à l'avance combien de valeurs pseudo-aléatoires chaque thread utilisera - ou au moins pouvez-vous obtenir une bonne estimation de la limite supérieure?
whuber
Non je ne peux pas. Il échantillonne les régions qui sont additionnées jusqu'à ce qu'un seuil soit atteint. La taille des régions peut varier considérablement.
EricR

Réponses:

9

Ce n'est certainement pas une excellente pratique. Par exemple, considérez ce qui se passe lorsque vous effectuez deux exécutions avec des racines racines 12345 et 12346. Chaque exécution aura des N-1flux en commun.

Les implémentations de Mersenne Twister (y compris numpy.randomet random) utilisent généralement un PRNG différent pour étendre la graine entière dans le vecteur à grand état (624 entiers 32 bits) que MT utilise; c'est le tableau de RandomState.get_state(). Un bon moyen de faire ce que vous voulez est d'exécuter ce PRNG, ensemencé avec votre entier d'entrée une fois, et d'en obtenir N*624des entiers 32 bits. Divisez ce flux en Nvecteurs d'état et utilisez RandomState.set_state()pour initialiser explicitement chaque RandomStateinstance. Vous devrez peut-être consulter les sources C de numpy.randomou à _randompartir de la bibliothèque standard pour obtenir ce PRNG (ce sont les mêmes). Je ne sais pas si quelqu'un a implémenté une version autonome de ce PRNG pour Python.

Robert Kern
la source
Je pense que cela pourrait être la meilleure solution que j'ai entendue jusqu'à présent. Je ne pense pas que cela ait beaucoup d'importance sur la façon dont je divise le flux, bien que ce soit correct? Il semble beaucoup plus improbable d'avoir une séquence en double sur 624 entiers 32 bits entre les instances, quelle que soit la façon dont elles sont sélectionnées à partir du PRNG initial et de la graine.
EricR
1
En fait, je vais revenir un peu en arrière. Il n'est pas clair pour moi que l'initialiseur PRNG est conçu pour avoir arbitrairement de nombreuses valeurs tirées de celui-ci. Envisagez d'utiliser un autre PRNG de qualité (de préférence sans rapport avec MT) pour générer le flux d'état. On peut implémenter un HMAC-DRBG (un PRNG utilisant un HMAC comme primitive cryptographique) en utilisant uniquement la bibliothèque standard de manière relativement simple. La sécurité cryptographique n'est pas une préoccupation; juste la facilité de mise en œuvre et la qualité du bitstream. Vous devrez vous assurer qu'aucun vecteur entièrement nul ne soit créé, sur la très rare chance.
Robert Kern
Ou utilisez simplement l'une des RandomStateimplémentations les plus récentes en développement qui utilise un algorithme qui a des flux configurables. Autrement dit, vous initialisez chaque RandomStateinstance avec la même graine et différents ID de flux (simplement incrémenté, c'est bien), et vous avez la garantie de flux indépendants. pypi.python.org/pypi/randomstate
Robert Kern
4

Φ(u)uN

  1. Φ(u),ΦN(u),Φ2N(u),...
  2. Φ2(u),Φ1+N(u),Φ1+2N(u),...
  3. ...
  4. ΦN-1(u),ΦN-1+N(u),ΦN-1+2N(u),...

Φn(u)=Φ(Φn-1(u))

Xi'an
la source
2

Il existe maintenant un package Python appelé RandomGen qui a des méthodes pour y parvenir.

Il prend en charge les flux indépendants créés à partir d'une seule graine, ainsi qu'un protocole de saut pour les anciens générateurs de nombres aléatoires tels que MT19937.

Praveen
la source
0

Certaines personnes affirment qu'il existe des corrélations dans les nombres aléatoires générés par les graines séquentielles. /programming/10900852/near-seeds-in-random-number-generation-may-give-similar-random-numbers Je ne sais pas si c'est vrai.

Si cela vous inquiète, pourquoi ne pas utiliser un seul générateur de nombres aléatoires pour choisir les graines de tous les autres générateurs?

Aaron
la source
Tout simplement parce que je ne veux pas avoir de chance de générer aléatoirement la même graine pour plus d'un générateur. Bien sûr, je pourrais faire un travail de programmation pour éviter que cela ne se produise, mais je ne sais pas comment cela serait mieux que de choisir des graines séquentielles en premier lieu.
EricR
1
Apparemment , des corrélations sont possibles avec des graines séquentielles ... Cependant, comme le montre l' article lié dans cette réponse du blog de John D Cook, l'utilisation d'un RNG pour générer des graines pour d'autres générateurs est bien pire, car vous rencontrez le problème d'anniversaire! Il dit que la génération aléatoire de 1000 graines non signées 16 bits a 99,95% de chances de se chevaucher!
Praveen