So wählen Sie Rng-Seed für parallele Prozesse richtig aus

8

Ich arbeite gerade an einem C / C ++ Projekt, wo ich einen Zufallszahlengenerator verwende ( gsl ) oder Boost ). Die ganze Idee kann zu einem nicht-trivialen stochastischen Prozess vereinfacht werden, der einen Seed erhält und Ergebnisse liefert. Ich berechne Durchschnittswerte über verschiedene Realisierungen des Prozesses.

Der Samen ist also wichtig: Die Prozesse müssen mit verschiedenen Samen sein oder die Durchschnittswerte beeinflussen.

Bisher verwende ich time(NULL) , um einen Seed zu geben. Wenn jedoch zwei Prozesse in derselben Sekunde beginnen, ist der Seed identisch. Das passiert, weil ich die Parallelisierung verwende (mit openMP ).

Meine Frage ist also: Wie implementiert man einen "Seed Geber" auf C / C ++, der unabhängige Seeds liefert?

Ich benutzte zum Beispiel die Thread-Nummer ( thread_num ), seed = time(NULL)*thread_num . Dies bedeutet jedoch, dass die Samen korreliert sind: Sie sind mehrere von einander. Stellt das "Pseudozufalls" ein Problem dar oder ist es so gut wie sequenzielle Seeds?

Die Voraussetzungen sind, dass es sowohl auf Mac OS (mein PC) als auch auf Linux-Distribution ähnlich wie OS Cent (der Cluster) funktionieren muss (und natürlich unabhängige Realisierungen geben).

    
Jorge Leitão 08.10.2012, 09:50
quelle

9 Antworten

4

Wir hatten ein ähnliches Problem in einem Beowulf-Computing-Grid. Die Lösung, die wir verwendeten, bestand darin, das pid des Prozesses in den RNG-Seed zu integrieren:

%Vor%

Natürlich könnten Sie einfach aus / dev / urandom oder / dev / random in eine ganze Zahl lesen.

    
Gearoid Murphy 08.10.2012, 10:04
quelle
6

Ein häufig verwendetes Schema hierfür ist ein "Master" -RNG, der zum Erzeugen von Seeds für jeden prozessspezifischen RNG verwendet wird.

Der Vorteil eines solchen Schemas ist, dass die gesamte Berechnung nur von einem Seed bestimmt wird, den Sie irgendwo aufzeichnen können, um eine Simulation wiederzugeben (dies könnte nützlich sein, um böse Bugs zu debuggen).

    
Francesco 08.10.2012 12:41
quelle
3

Wenn ich mit diesem Problem konfrontiert werde, benutze ich oft seed_rng von Boost .Uuid. Es verwendet time , clock und zufällige Daten von /dev/urandom , um einen Seed zu berechnen. Sie können es wie

verwenden %Vor%

Beachten Sie, dass seed_rng von einem detail -Namespace kommt, so dass es ohne weitere Benachrichtigung entfernt werden kann. In diesem Fall sollte es nicht zu schwer sein, eine eigene Implementierung basierend auf seed_rng zu schreiben.

    
Benjamin Bannier 08.10.2012 10:13
quelle
1

Mac OS ist auch Unix, also hat es wahrscheinlich /dev/random . Wenn ja, das ist das beste Lösung für den Erhalt der Samen. Andernfalls falls der Generator ist Gut, nehmen Sie time( NULL ) einmal, und erhöhen Sie es dann für den Samen von jedem Generator, sollte ziemlich gute Ergebnisse geben.

    
James Kanze 08.10.2012 10:08
quelle
1

Wenn Sie x86 verwenden und den Code nicht portabel machen möchten, können Sie den Zeitstempel-Zähler (TSC) lesen, bei dem es sich um einen 64-Bit-Zähler handelt, der um die CPU-Taktrate (max.) hochzählt GHz) und benutze das als einen Samen.

%Vor%     
amdn 08.10.2012 10:16
quelle
1

Wenn wir zwei unendliche Zeitfolgen vergleichen, die von demselben Pseudozufallszahlengenerator mit verschiedenen Seeds erzeugt werden, können wir sehen, dass sie um einige Zeit tau gleich verzögert sind. Normalerweise ist diese Zeitskala viel größer als Ihr Problem, um sicherzustellen, dass die beiden zufälligen Wanderungen nicht korreliert sind.

Wenn Ihr stochastischer Prozess in einem hochdimensionalen Phasenraum ist, denke ich, dass ein guter Vorschlag sein könnte:

%Vor%

Beachten Sie, dass Sie mit dem Schema nicht garantieren, dass die Zeit tau groß ist!

Wenn Sie etwas über Ihre Systemzeitskala wissen, können Sie Ihren Zufallszahlengenerator eine beliebige Anzahl mal aufrufen, um Samen zu erzeugen, die um ein Zeitintervall äquidistant sind.

    
João Lopes 08.10.2012 10:33
quelle
1

Vielleicht könntest du std :: chrono high resolution clock von C ++ 11 ausprobieren:

  

Klasse std :: chrono :: high_resolution_clock repräsentiert die Uhr mit dem   kleinste Tick-Periode, die auf dem System verfügbar ist. Es kann ein Alias ​​von sein   std :: chrono :: system_clock oder std :: chrono :: steady_clock, oder ein drittes,   unabhängige Uhr.

Ссылка

ABER tbh Ich bin mir nicht sicher, ob irgendwas mit srand falsch ist (0); Srand (1), Srand (2) .... aber mein Wissen über Rand ist sehr, sehr einfach. : /

Für verrückte Sicherheit beachten Sie dies:

  

Beachten Sie, dass alle unten beschriebenen Pseudozufallszahlengeneratoren sind   CopyConstructible und Zuweisbar. Kopieren oder Zuweisen eines Generators   kopiert seinen gesamten internen Zustand, also das Original und die Kopie   erzeuge die identische Folge von Zufallszahlen.

Ссылка

Da die meisten Generatoren verrückte lange Zyklen haben, könnten Sie einen erzeugen, als ersten Generator kopieren, X-Nummern mit Original erzeugen, als zweiten kopieren, X-Nummern mit Original erzeugen, als dritten kopieren ... Wenn Ihre Benutzer weniger als X Mal ihren eigenen Generator anrufen, werden sie sich nicht überschneiden.

    
NoSenseEtAl 08.10.2012 13:28
quelle
1

So, wie ich Ihre Frage verstanden habe, haben Sie mehrere Prozesse, die denselben Pseudozufallszahlengenerierungsalgorithmus verwenden, und Sie möchten, dass jeder "Strom" von Zufallszahlen (in jedem Prozess) unabhängig voneinander ist. Habe ich Recht?

In diesem Fall haben Sie recht, wenn Sie den Verdacht haben, dass die Vergabe anderer (korrelierter) Samen Ihnen nichts garantiert, es sei denn, der Rng-Algorithmus sagt dies. Sie haben grundsätzlich zwei Lösungen:

Einfache Version

Verwenden Sie eine einzelne Quelle von Zufallszahlen mit einem einzelnen Seed. Fädeln Sie dann für jeden Prozess Zufallszahlen in einer Round-Robin-Art ein.

Diese Lösung ist langsam, bietet aber eine gewisse Garantie, dass die Anzahl, die Sie Ihren Prozessen geben, in Ordnung ist.

Sie können dasselbe tun, aber alle Zufallszahlen, die Sie benötigen, gleichzeitig erzeugen und diese Menge in so viele Schichten aufteilen, wie Sie Prozesse haben.

Verwenden Sie einen für diesen Zweck entwickelten RNG

In Papieren und im Internet finden Sie verschiedene Algorithmen, die speziell entwickelt wurden, um unabhängige Ströme von Zufallszahlen aus einem einzigen Ausgangszustand zu erzeugen. Sie sind kompliziert, aber die meisten stellen Quellcode zur Verfügung. Die Idee ist allgemein, den RNG-Raum (Werte, die man aus dem Anfangszustand erhalten kann) in verschiedene Teile wie oben zu "teilen". Sie sind nur schneller, weil der verwendete Algorithmus es ermöglicht, leicht zu berechnen, was der Zustand des RNG wäre, wenn Sie eine bestimmte Anzahl von Werten überspringen würden.

Diese Generatoren werden allgemein als "parallele Zufallszahlengeneratoren" bezeichnet. Die beliebtesten sind wahrscheinlich diese beiden:

Überprüfen Sie ihre Handbücher, um zu verstehen, was sie tun, wie sie es tun und ob es wirklich das ist, was Sie brauchen.

    
swann 11.10.2012 06:20
quelle
-1

Sie könnten std::random_device verwenden, um nicht-deterministische Zufallszahlen zu erzeugen.

    
Quantifeye 03.11.2016 08:21
quelle

Tags und Links