Ich versuche, einige nichtlineare Optimierungsprobleme mit der GPU (CUDA) zu lösen.
Die Zielfunktion ist eine glatte nichtlineare Funktion, und ihr Gradient ist relativ billig zu berechnen, so dass ich mich nicht mit der numerischen Approximation befassen muss.
Ich möchte dieses Problem hauptsächlich mit fp32 maths ops lösen (aus verschiedenen Gründen). Welche nichtlineare Optimierungsmethode ist also robuster gegen Aufrundungsfehler bei guter Leistung? (zB konjugierter Gradient / Quasi-Newton / Vertrauensbereich), hat jemand BFGS auf der GPU mit guten Ergebnissen ausprobiert?
Übrigens ist der Hessische bei Bedarf in meinem Fall relativ klein (normalerweise <64 x 64), aber ich muss Tausende dieser kleinen Optimierungsprobleme gleichzeitig lösen.
quelle
Antworten:
Ich habe eine ganze Reihe nichtlinearer Löser auf der GPU implementiert, einschließlich LBFGS, Barzilai Borwein-Gradientenabstieg und nichtlinearer konjugierter Gradient.
Dafür war der nichtlineare konjugierte Gradient von Dai & Yuan der effizienteste. Im Allgemeinen kann eine andere Version des nichtlinearen konjugierten Gradienten effizienter sein (wie z. B. CG-DESCENT), aber auch schwieriger zu implementieren sein.
LBFGS ist im Allgemeinen eine sehr solide Wahl, und es sei denn, Sie sind wirklich in Erinnerung geblieben, ist es wahrscheinlich der beste Ort, um anzufangen.
Sowohl der konjugierte Gradient als auch BFGS erfordern jedoch eine Zeilensuche, bei der fp32 zum Problem wird. Anstatt die Standard-Wolfe-Bedingungen für die Liniensuche zu verwenden, würde ich vorschlagen, die hier vorgeschlagene ungefähre Wolfe-Bedingung zu verwenden . Das Papier ist ein wenig umständlich, aber das Wichtigste ist Gleichung 4.1. Im Wesentlichen führen sie explizit die Genauigkeit ein, mit der Sie Ihre Funktion berechnen können.
Überlegungen zur GPU:
Sie haben viele kleine Probleme, was sich geringfügig von meinem Anwendungsfall eines großen Problems unterscheidet. Ziehen Sie in Betracht, 1 Problem pro GPU-Block (oder eher Warp) auszuführen, wenn Sie Funktions- und Verlaufsbewertungen parallelisieren können, um alle Threads in einem Block zu verwenden. Auf diese Weise ist es kein Problem, wenn unterschiedliche Probleme eine unterschiedliche Anzahl von Iterationen erfordern.
Wenn dies keine Option ist, würde ich mit dem LBFGS-Solver gehen. Wenn sich Ihre Funktion gut verhält, müssen Sie möglicherweise nicht nur eine Schrittgröße von 1 verwenden (um die Zeilensuche zu vermeiden) und alle Probleme nur für eine feste Anzahl von Iterationen ausführen.
quelle
Ich empfehle Ihnen, Levenberg Marquardt (eine Trust-Region-Variante) zu verwenden, da es in vielen praktischen Anwendungen verwendet wird und eine sehr gute Geschwindigkeit-gegen-Genauigkeit-Leistung aufweist. Außerdem gibt es für GPU einige Bibliotheken (zB cuLM https://github.com/zitmen/cuLM ), die Sie ausprobieren können. Wenn sie den Job nicht erledigen, stehen Ihnen unzählige Ressourcen zur Verfügung. Die Implementierung von LM ist überhaupt nicht schwierig. Sie sollten nur darauf achten, die GPU-Kommunikation zu minimieren. Um eine kurze Vorstellung zu bekommen:
http://on-demand.gputechconf.com/gtc/2012/presentations/S0231-Levenberg-Marquardt-Using-Block-Sparse-Matrices-on-CUDA.pdf
quelle
Möglicherweise kann ein simulierter Glühvorgang Abrundungsfehler besser behandeln (und ist leicht parallelisierbar).
Sie beginnen mit einem groben Raster des Suchbereichs und einem anfänglichen "Temperatur" -Parameter
Bei jedem Schritt berechnen Sie mögliche Lösungspunkte (man kann auch Nichtlösungspunkte akzeptieren, mit einiger Wahrscheinlichkeit umgekehrt analog zur Temperatur).
Behalten Sie dann nur die Lösungen in diesem Schritt bei und erhöhen Sie die Temperatur, um ein feinkörnigeres Gitter für die nächste Iteration zu erhalten
Tun Sie dies, bis die Temperatur <einer bestimmten Grenze / Genauigkeitsschwelle ist
quelle