Der beste Weg, um N unabhängige Zufallszahlengeneratoren aus 1 Wert zu setzen

10

In meinem Programm muss ich N separate Threads mit jeweils einem eigenen RNG ausführen, mit dem ein großer Datensatz abgetastet wird. Ich muss in der Lage sein, diesen gesamten Prozess mit einem einzigen Wert zu versehen, damit ich Ergebnisse reproduzieren kann.

Reicht es aus, den Startwert für jeden Index einfach nacheinander zu erhöhen?

Derzeit verwende ich numpy‚s , RandomStatedie einen Mersenne - Twister Pseudo-Zufallszahlen - Generator verwendet.

Codeausschnitt unten:

# 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)

Im Wesentlichen beginne ich mit einem vom Benutzer eingegebenen Startwert (falls vorhanden) und füge für jede Instanz / jeden Thread nacheinander den Index (0 bis N-1) der ausgeführten Instanz hinzu. Ich weiß nicht, ob dies eine gute Praxis ist oder ob es einen besseren Weg gibt, dies zu tun.

EricR
quelle
1
Wissen Sie im Voraus, wie viele Pseudozufallswerte jeder Thread verwenden wird - oder können Sie zumindest eine gute Schätzung der Obergrenze erhalten?
whuber
Nein ich kann nicht. Es werden Bereiche abgetastet, die summiert werden, bis ein Schwellenwert erreicht ist. Die Größen der Regionen können erheblich variieren.
EricR

Antworten:

9

Es ist sicherlich keine großartige Übung. Überlegen Sie beispielsweise, was passiert, wenn Sie zwei Läufe mit Root-Seeds von 12345 und 12346 ausführen. Jeder Lauf hat gemeinsame N-1Streams.

Mersenne Twister-Implementierungen (einschließlich numpy.randomund random) verwenden normalerweise ein anderes PRNG, um den ganzzahligen Startwert in den von MT verwendeten großen Zustandsvektor (624 32-Bit-Ganzzahlen) zu erweitern. Dies ist das Array von RandomState.get_state(). Eine gute Möglichkeit, das zu tun, was Sie möchten, besteht darin, dieses PRNG auszuführen, das einmal mit Ihrer Eingabe-Ganzzahl gesetzt wurde, und N*62432-Bit-Ganzzahlen daraus abzurufen. Teilen Sie diesen Stream in NStatusvektoren auf und RandomState.set_state()initialisieren Sie jede RandomStateInstanz explizit . Möglicherweise müssen Sie die C-Quellen der numpy.randomoder _randomaus der Standardbibliothek konsultieren , um diese PRNG zu erhalten (sie sind identisch). Ich bin nicht sicher, ob jemand eine eigenständige Version dieses PRNG für Python implementiert hat.

Robert Kern
quelle
Ich denke, dies könnte die beste Lösung sein, die ich bisher gehört habe. Ich denke nicht, dass es wichtig ist, wie ich den Stream aufteile, obwohl es richtig ist? Es ist viel unwahrscheinlicher, dass zwischen Instanzen eine doppelte Sequenz mit 624 32-Bit-Ganzzahlen vorliegt, unabhängig davon, wie sie aus dem anfänglichen PRNG und dem Startwert ausgewählt werden.
EricR
1
Eigentlich werde ich das ein bisschen zurückgehen. Mir ist nicht klar, dass der Initialisierer PRNG so ausgelegt ist, dass beliebig viele Werte daraus gezogen werden. Erwägen Sie die Verwendung eines PRNG anderer Qualität (vorzugsweise ohne Bezug zu MT), um den Zustandsstrom zu erzeugen. Man kann ein HMAC-DRBG (ein PRNG, das ein HMAC als kryptographisches Grundelement verwendet) relativ einfach nur unter Verwendung der Standardbibliothek implementieren. Die kryptografische Sicherheit ist kein Problem. Nur die einfache Implementierung und Qualität des Bitstreams. Sie müssen sicherstellen, dass bei der sehr seltenen Off-Chance keine All-Zero-Vektoren erstellt werden.
Robert Kern
Oder verwenden Sie einfach eine der neueren RandomStateImplementierungen in der Entwicklung, die einen Algorithmus mit einstellbaren Streams verwendet. Das heißt, Sie initialisieren jede RandomStateInstanz mit demselben Startwert und unterschiedlichen Stream-IDs (nur inkrementiert ist in Ordnung), und Ihnen werden unabhängige Streams garantiert. 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
quelle
2

Es gibt jetzt ein Python-Paket namens RandomGen , das Methoden hat, um dies zu erreichen.

Es unterstützt unabhängige Streams, die aus einem einzelnen Startwert erstellt wurden, sowie ein Sprungprotokoll für ältere Zufallszahlengeneratoren wie MT19937.

Praveen
quelle
0

Einige Leute behaupten, dass es Korrelationen in den Zufallszahlen gibt, die durch aufeinanderfolgende Samen erzeugt werden. /programming/10900852/near-seeds-in-random-number-generation-may-give-similar-random-numbers Ich bin mir nicht sicher, wie wahr das ist.

Wenn Sie sich darüber Sorgen machen, warum nicht einen einzigen Zufallszahlengenerator verwenden, um die Startwerte für alle anderen Generatoren auszuwählen?

Aaron
quelle
Einfach, weil ich keine Chance haben möchte, zufällig den gleichen Startwert für mehr als einen Generator zu generieren. Natürlich könnte ich einige Programmierarbeiten durchführen, um dies zu verhindern, aber dann weiß ich nicht, wie das besser wäre, als Samen nacheinander zu pflücken.
EricR
1
Anscheinend sind Korrelationen mit sequentiellen Samen möglich ... Wie der Artikel in dieser Antwort aus John D Cooks Blog zeigt, ist die Verwendung eines RNG zum Generieren von Samen für andere Generatoren weitaus schlimmer, da Sie auf das Geburtstagsproblem stoßen! Es heißt, dass das zufällige Generieren von 1000 16-Bit-Seeds ohne Vorzeichen eine 99,95% ige Überlappungswahrscheinlichkeit hat!
Praveen