Wie löst man nichtlineare Optimierungsprobleme mit Ceres?

8

Ich muss eine Oberfläche optimieren, die durch ein 2D-Gitter von Punkten dargestellt wird, um normale Vektoren der Oberfläche zu erzeugen, die mit den vorgesehenen Zielnormalenvektoren ausgerichtet sind. Die Rastergröße liegt wahrscheinlich zwischen 201x201 und 1001x1001. Das bedeutet, dass die Anzahl der Variablen 40.000 bis 1.000.000 beträgt, da ich nur die Z-Koordinaten der Gitterpunkte modifiziere.

Ich benutze das Ceres-Framework, da es sich bei großflächigen nichtlinearen Optimierungsproblemen auszeichnen soll. Ich habe MATLABs fmincon bereits ausprobiert, aber es verbraucht unglaublich viel Speicher. Ich habe eine Zielfunktion geschrieben, die für kleine Netze funktioniert (erfolgreich bei 3x3 und 31x31). Wenn ich jedoch versuche, den Code mit einer großen Mesh-Größe (157 x 200) zu kompilieren, sehe ich den Fehler unten. Ich habe gelesen, dass dies eine Einschränkung von Eigen ist. Wenn ich Ceres jedoch sage, LAPACK anstelle von Eigen zu verwenden, bekomme ich den gleichen Fehler für große Matrizen. Ich habe diese Zeilen ausprobiert:

%Vor%

Diese sagen dem Löser, LAPACK und DENSE_QR zu verwenden, da die Ausgabe mit einem 3x3-Mesh zeigt:

%Vor%

Wenn ich jedoch große Parameter verwende, bekomme ich immer noch die Fehler für Eigen.

Wie auch immer, ich könnte wirklich etwas Hilfe dabei gebrauchen. Wie kann ich Ceres dazu bringen, eine große Anzahl von Variablen (& gt; 30.000) zu optimieren? Vielen Dank im Voraus

Link zu Ceres: Ссылка

Link zu Eigen: Ссылка

Fehler:

%Vor%

Mein Code sieht so aus (abgekürzt, um irrelevantes Material herauszunehmen):

%Vor%     
Eric 13.10.2014, 08:47
quelle

3 Antworten

7

Zwei Dinge

  1. Sie verwenden DENSE_QR als linearen Solver, was zu einem dichten Jacobi führt. Das ist eine schlechte Idee. Ändern Sie Ihren linearen Solver in SPARSE_NORMAL_CHOLESKY und Sie können Probleme dieser Größe ziemlich einfach lösen.

Wenn Sie Version 1.9 oder älter verwenden, benötigen Sie SuiteSpare / CXSparse. Wenn Sie den neuesten Release Candidate oder die git Version verwenden, sollten Sie in der Lage sein, mit Eigen die spärliche lineare Algebra auszuführen.

  1. Sie erstellen eine einzige Kostenfunktion für das gesamte Problem. Das bedeutet, dass Sie dem Problem keine Seltenheit aussetzen. Das verursacht das Stapelzuordnungsproblem, da die automatische Differenzierung Daten auf dem Stapel enthält.

Sehen Sie sich den Beispielcode an, der mit ceres ausgeliefert wird, zum Beispiel denoising.cc, der ein ganzes Bild demoziert und eine ähnliche gitterähnliche Struktur hat.

Erstellen Sie im Allgemeinen einen einzelnen Restblock für jeden Knoten in Ihrem Problem.

    
Sameer Agarwal 13.10.2014, 20:32
quelle
2

Peter, Ja, technisch kann man die dynamische Autodiff-Kostenfunktion verwenden, aber es wird unglaublich langsam und es wird das ganze Problem als ein einziges Residuum für den Solver darstellen, also keine Sparsity und schlecht Rang mangelnde Jacobi.

Sie sollten darüber nachdenken, einen Rest pro Rasterpunkt hinzuzufügen, der nur von Nachbarknoten abhängig ist.

Wenn Sie weiterhin einen Kosten-Restblock verwenden, wird es immer noch Probleme geben.

    
Sameer Agarwal 14.10.2014 13:17
quelle
1

Diese Antwort basiert vollständig auf meinen Erfahrungen mit C ++ und Eigen (ich kenne Ceres nicht):

Die Option. * Zeilen scheinen das Laufzeitverhalten zu steuern, aber die Fehlermeldung ist ein Kompilierzeitfehler.

Der relevanteste Teil des Fehlers, der für mich herausragt, ist:

  

/usr/include/eigen3/Eigen/src/Core/DenseStorage.h:79:5: Fehler: 'OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG' ist kein Mitglied von 'Eigen :: internal :: static_assertion'    EIGEN_STATIC_ASSERT (Größe * Größe von (T) & lt; = 128 * 128 * 8, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG);

Eigen wird oft feste Matrizen auf dem Stack zuweisen und ich denke, das ist was hier passiert. Bei Matrizen, mit denen Sie arbeiten, müssen sie auf dem Heap zugewiesen werden. Um dies zu erzwingen, wählen Sie dynamisch große Matrizen aus. Nach dem Kompilieren sollten Sie es mit oder ohne Eigen ausführen können, indem Sie die gefundenen Optionen verwenden.

Die spezifische Lösung scheint DynamicAutoDiffCostFunction anstelle von AutoDiffCostFunction zu verwenden. Ein relevanter Ausschnitt der Dokumentation:

  

AutoDiffCostFunction erfordert, dass die Anzahl der Parameterblöcke und ihre Größen zur Kompilierungszeit bekannt sind. Es hat auch eine Obergrenze von 10 Parameterblöcken.

Ссылка

    
Eider 13.10.2014 19:45
quelle