Wie kann die numerische Nichtassoziativität für die parallele Reduktion angegangen werden?

17

Eine parallele Reduktion setzt voraus, dass die entsprechende Operation assoziativ ist. Diese Annahme wird beim Hinzufügen von Gleitkommazahlen verletzt. Sie könnten fragen, warum mir das wichtig ist. Nun, es macht die Ergebnisse weniger reproduzierbar. Und es wird schlimmer, wenn simuliertes Tempern verwendet wird, um Subroutinen zu optimieren (oder Parameter anzupassen), was zu solchen nicht reproduzierbaren Ergebnissen führt.

Was sind die gebräuchlichen Methoden, um mit diesem Problem umzugehen? Was kann über die folgenden Strategien gesagt werden?

  • Kümmere dich nicht um die Nichtreproduzierbarkeit.
  • Verwenden Sie keine parallele Reduktion mit Gleitkommazahlen und Addition.
  • Erstellen Sie auf reproduzierbare Weise Arbeitspakete mit geeigneter Größe und führen Sie die endgültige Reduzierung von Hand durch.
  • Verwenden Sie für die Addition eine höhere Genauigkeit (jedoch bieten nicht alle Compiler Gleitkommatypen mit höherer Genauigkeit an).
Thomas Klimpel
quelle
Sind Sie besorgt über die Reproduzierbarkeit auf der gleichen Anzahl von Prozessen oder die Reproduzierbarkeit auf einer anderen Anzahl von Prozessoren? Wie viel von einem Leistungstreffer sind Sie bereit, für bitweise Reproduzierbarkeit zu sorgen? Interessieren Sie sich nur für das simulierte Glühen?
Jed Brown
@JedBrown Ich mache mir Sorgen über die Möglichkeit, reproduzierbare Ergebnisse zu erhalten, um beispielsweise potenzielle Probleme zu beheben. Es ist in Ordnung für mich, wenn es eine Möglichkeit gibt, die Ergebnisse zu reproduzieren, z. B. durch die Verwendung der gleichen Anzahl von Prozessoren (oder indem man einfach die Anzahl der ursprünglich verwendeten Prozessoren "kennt"). Ich wäre bereit, den mit der Verwendung von Gleitkommatypen mit höherer Genauigkeit verbundenen Leistungstreffer für die Addition selbst in Kauf zu nehmen. Meine konkreten Probleme betrafen hauptsächlich simuliertes Tempern und unerwartete Unterschiede, die sich jedoch als echte Fehler herausstellten.
Thomas Klimpel

Antworten:

15

Eine mit implementierte Reduzierung MPI_Allreduce()ist reproduzierbar, solange Sie dieselbe Anzahl von Prozessoren verwenden, sofern die Implementierung den folgenden Hinweis in Abschnitt 5.9.1 des MPI-2.2-Standards beachtet.

Ratschläge für Implementierer . Es wird dringend empfohlen, MPI_REDUCEdiese Methode so zu implementieren, dass dasselbe Ergebnis erhalten wird, wenn die Funktion auf dieselben Argumente angewendet wird, die in derselben Reihenfolge angezeigt werden. Beachten Sie, dass dies Optimierungen verhindern kann, die den physischen Standort der Prozessoren ausnutzen. ( Ende der Ratschläge für Implementierer .)

Wenn Sie die Reproduzierbarkeit unbedingt gewährleisten müssen, können Sie die Richtlinien im nächsten Absatz befolgen:

Hinweise für Benutzer . Einige Anwendungen können möglicherweise den nicht assoziativen Charakter von Gleitkommaoperationen nicht ignorieren oder benutzerdefinierte Operationen (siehe Abschnitt 5.9.5) verwenden, die eine spezielle Verkleinerungsreihenfolge erfordern und nicht als assoziativ behandelt werden können. Solche Anwendungen sollten die Reihenfolge der Bewertung ausdrücklich durchsetzen. Zum Beispiel könnte im Fall von Operationen, die eine strikte Auswertungsreihenfolge von links nach rechts (oder von rechts nach links) erfordern, dies durch Sammeln aller Operanden in einem einzigen Prozess (z. B. mit MPI_GATHER) unter Anwendung der Reduktionsoperation erfolgen MPI_REDUCE_LOCALSenden Sie das Ergebnis in der gewünschten Reihenfolge (z. B. mit ) und übertragen Sie es bei Bedarf auf die anderen Prozesse (z MPI_BCAST. B. mit ). ( Ende der Beratung für Benutzer .)

Im weiteren Sinne nutzen effiziente Algorithmen für die meisten Anwendungen die Lokalität. Da der Algorithmus bei einer anderen Anzahl von Prozessen sehr unterschiedlich ist, ist es einfach nicht praktikabel, die Ergebnisse bei einer anderen Anzahl von Prozessen exakt zu reproduzieren. Eine mögliche Ausnahme ist Multigrid mit gedämpften Jacobi- oder Polynomglättern (z. B. Chebyshev), bei denen diese einfache Methode sehr gut funktioniert.

Bei der gleichen Anzahl von Prozessen ist es für die Leistung häufig vorteilhaft, Nachrichten in der Reihenfolge zu verarbeiten, in der sie empfangen werden (z. B. unter Verwendung von MPI_Waitany()), was einen Nichtdeterminismus einführt. In solchen Fällen können Sie zwei Varianten implementieren, die schnelle, die in einer beliebigen Reihenfolge empfangen wird, und eine "Fehlerbehebung", die in einer statischen Reihenfolge empfangen wird. Dies setzt voraus, dass alle zugrunde liegenden Bibliotheken ebenfalls so geschrieben sind, dass sie dieses Verhalten bieten.

In einigen Fällen können Sie zum Debuggen einen Teil einer Berechnung, die dieses reproduzierbare Verhalten nicht bietet, isolieren und redundant ausführen. Je nachdem, wie die Komponenten entworfen wurden, kann diese Änderung eine geringe Menge an Code oder sehr aufdringlich sein.

Jed Brown
quelle
6

Zum größten Teil habe ich auch Jeds Antwort. Es gibt jedoch einen anderen Ausweg: Angesichts der Größe normaler Gleitkommazahlen können Sie jede Zahl in einer Festkommazahl mit etwa 4000 Bit speichern. Wenn Sie also die so eingebetteten Gleitkommazahlen reduzieren, erhalten Sie eine genaue Berechnung, unabhängig von der Assoziativität. (Entschuldigung, ich habe keinen Hinweis darauf, wer auf diese Idee gekommen ist.)

Victor Eijkhout
quelle
1
Ich glaube nicht, dass er der erste war, aber Ihr Kollege Dr. Bandwidth hat mit Sicherheit eine nette Zusammenfassung zu diesem Thema: sites.utexas.edu/jdm4372/2012/02/15/…
Jeff
5

Sie können einen numerisch stabilen Reduktionsalgorithmus in MPI implementieren, genauso wie Sie es in serieller Form tun können. Natürlich kann es zu einem Leistungseinbruch kommen. Wenn Sie es sich leisten können, den Vektor zu replizieren, verwenden Sie einfach MPI_Gather und führen Sie die numerisch stabile Reduzierung der Seriennummer im Stammverzeichnis durch. In einigen Fällen ist der Leistungsverlust möglicherweise keine große Sache.

Eine andere Lösung besteht darin, breite Akkumulatoren wie hier beschrieben zu verwenden . Sie können dies mit MPI als benutzerdefinierte Reduzierung tun, obwohl dies viel mehr Bandbreite beansprucht.

Ein Kompromiss für das oben Gesagte ist die Verwendung einer kompensierten Summierung. Siehe Referenzen “Kahan Summation” für Details. Highams " Genauigkeit und Stabilität numerischer Algorithmen " ist eine hervorragende Ressource zu diesem Thema.

Jeff
quelle
2

Ich möchte darauf hinweisen, dass anstelle einer präziseren Addition eine kompensierte Summation möglich ist (siehe [1]). Dies könnte die Genauigkeit der Summierung erhöhen, ohne auf größere Datentypen zurückgreifen zu müssen.

[1] Higham, NJ Die Genauigkeit der Gleitkommasummierung. SIAM Journal on Scientific Computing 14, 783–799 (1993).

Juan M. Bello-Rivas
quelle