0 Daumen
853 Aufrufe

Ich habe mir in Matlab einen Levenberg-Marquardt-Algorithmus geschrieben. Die Funktion funktioniert auch und je nachdem was ich optimieren will auch richtig.

Im Moment versuche ich gerade eine nichtlineare Funktion mit einer linearen Funktion zu approximieren. Genau gesagt, ich versuche mir mittels der Funktionen einen Materialparameter zu schätzen. Und genau hier liegt mein Problem. Irgendwie schafft es der Algorithmus nicht auf ein sinnvolles Ergebnis zu kommen. Ich bekomme immer kleinere Werte für meinen Parameter heraus.

Nun meine Frage: Kann ich denn eine untere Schranke in meinen Algorithmus einbauen, damit mein Parameter nicht kleiner werden kann als dieser Wert? Oder verfälscht das meine Optimierung?

Code:

function [a_est,v,error] = levmarq_unAd(predicted,a0,b0,x,un_1)

a0 = a0(:);
un_1 = un_1(:);

y_input = un_1;
v = zeros(1,30);
error = zeros(4,30);

Nparameters = length(a0);
n_iter = 30; % Anzahl der Iterationen
lambda = 0.01; % Anfangswert für den Dämpfungsfaktor
updateJ = 1;
h0 = 0.02; % Schrittweite

format long e;
a_est = a0;
a_est = a_est(:);

function r = res(x,a)
r = y_input - predicted(x,a);
r = r'*r;
end

for it = 1:n_iter

if updateJ == 1
% Auswertung der Jacobi-Matrix an den momentanen Parametern a_est
J = zeros(1, Nparameters);
E = eye(Nparameters);

% Auswertung des Totalen Fehlers (Abstand) an den momentanen
% Parametern
if it > 1
d = d_lm;
else
d = res(x,a_est);
end

for j = 1:Nparameters % spaltenweise durchlaufen
h = max(1, abs(a_est(j)) + 1e-2).*h0;
FDupper = res(x,(a_est + h.*E(:,j)));
FDlower = d;
J(:,j) = (1/h).*(FDupper - FDlower);
end

% Schrittweitenoptimierung
if norm(J(:,j))*h < norm(FDlower)*h0
h_neu = 0.5.*h;
J(:,j) = (1/h_neu).*(res(x,a_est + h_neu.*E(:,j)) - FDlower);
fprintf('h_neu = %.15f\n', h_neu);
end

% Berechnung der approximierten Hesse-Matrix, J' ist die
% Transponierte von J
H = J'*J;

if it == 1 % erste Iteration berechnet den Gesamtfehler
err = dot(d, d);
end

end

% fügt den Dämpfungsfaktor zur Hesse-Matrix hinzu
H_lm = H + (lambda.*diag(diag(H))); %eye(Nparameters, Nparameters));

% Berechnung der aktualisierten Parameter
dp = -inv(H_lm)*(J'*d(:));
a_lm = a_est + dp(:);

% Auswertung des Totalen Fehlers (Abstand) an den neuen Parametern
d_lm = res(x,a_lm);
err_lm = dot(d_lm, d_lm);

% Ist der Fehler der aktualisierten Parameter kleiner als der vorherige, dann
% mach sie zu den momentanen Parametern und reduziere den Dämpfungsfaktor
if err_lm < err
var = abs(a_lm - a_est);

if var < 1e-4
return;
end

if a_lm >= 500
lambda = lambda/10;
a_est = a_lm;
v(:,it) = a_est;
error(1,it) = err_lm;
error(2,it) = err;
error(3,it) = lambda;
error(4,it) = h;
err = err_lm;
fprintf('err = %.15f\n', err);
fprintf('a_est = %.15f\n', a_lm);
fprintf('it = %.15f\n', it);
updateJ = 1;
end

else % sonst erhöhe den Dämpfungsfaktor
updateJ = 0;
lambda = lambda.*10;
v(:,it) = a_est;
error(1,it) = err_lm;
error(2,it) = err;
error(3,it) = lambda;
error(4,it) = h;
fprintf('a_est = %.15f\n', a_lm);
fprintf('it = %.15f\n', it);
end

end

end

Ich hoffe das verwirrt jetzt nicht noch mehr. die if-Anweisung (a_lm >= 500) habe ich jetzt neu eingefügt, sozusagen als untere Schranke. Geht das? Oder muss ich das irgendwie anders lösen?


Nachtrag:

ich hab mir jetzt noch einmal ein paar gedanken gemacht... das mit der unteren Schranke ist natürlich Quatsch. Ich kann ja nicht bei einem lokalen minimierungsverfahren einfach werte "abschneiden"... mittlerweile vermute ich, dass es mit der fehlerberechnung zusammenhängt. also, dass ich wohl den fehler"falsch" berechne. im moment mache ich das ja über r = r'*r bzw. über err = dot(d, d);

Müsste ich eine andere Fehlernorm verwenden? Weiß da vielleicht jemand näheres?

Avatar von

1 Antwort

0 Daumen

Antwort mit KI erzeugt

Der optimierte Wert meines Optimierungsalgorithmus macht keinen Sinn (Matlab)

Es scheint, als ob du beim Versuch, einen Parameter durch die Approximation einer nichtlinearen Funktion mittels einer linearen Funktion zu bestimmen, auf Schwierigkeiten gestoßen bist. Dein Anliegen bezüglich der Einrichtung einer unteren Schranke für den zu optimierenden Parameter ist verständlich, besonders wenn der Algorithmus Werte liefert, die weit außerhalb eines sinnvollen Bereichs liegen.

Einbau einer unteren Schranke

Die direkte Implementierung einer unteren (oder oberen) Grenze in den Optimierungsalgorithmus könnte tatsächlich die Ergebnisse verzerren, insbesondere bei lokalen Optimierungsmethoden wie dem Levenberg-Marquardt-Algorithmus. Bei solchen Methoden wird angenommen, dass alle möglichen Lösungen innerhalb des gesamten Parameterbereichs liegen können. Das willkürliche Zuschneiden oder Begrenzen von Werten kann die Konvergenz des Algorithmus stören oder zu einer Lösung führen, die nicht dem tatsächlichen globalen (oder einem sinnvollen lokalen) Minimum entspricht.

Behebung des eigentlichen Problems

Dein Nachtrag deutet darauf hin, dass das Problem möglicherweise in der Art und Weise liegt, wie du den Fehler berechnest, und das ist ein sehr guter Ansatzpunkt. Die Verwendung von \(r = r'*r\) bzw. \(\text{err} = \text{dot}(d, d)\) berechnet den quadratischen Fehler, was eine gängige Praxis ist. Allerdings hängt die geeignete Wahl der Fehlermetrik stark von deiner spezifischen Anwendung und den Charakteristiken deiner Daten bzw. Funktion ab.

Hier einige Punkte, die du beachten solltest:
- Fehlermetrik: Verschiedene Problemstellungen benötigen unterschiedliche Fehlermetriken. Der quadratische Fehler funktioniert gut, wenn alle Fehler gleichgerichtet sind und große Abweichungen stärker bestraft werden sollen. In Fällen, wo Ausreißer vorhanden sind oder die Fehlerverteilung nicht uniform ist, könnten andere Metriken (z.B. absoluter Fehler oder Huber-Loss) besser geeignet sein.
- Skalierung der Parameter: Eine weitere häufige Fehlerquelle kann die Skalierung der Parameter sein. Stelle sicher, dass die Parameter, die du optimierst, ähnliche Größenordnungen haben, um numerische Probleme zu vermeiden.
- Initialisierung der Parameter: Die Wahl des Startpunkts (hier a0 und b0) kann die Konvergenz des Algorithmus erheblich beeinflussen. Eine gründliche Untersuchung der Anfangsbedingungen kann notwendig sein, um sicherzustellen, dass der Algorithmus in einem sinnvollen Bereich des Parameterraums startet.

Bezüglich der unteren Schranke

Wenn du dennoch entscheidest, eine untere Schranke für deinen Parameter einzuführen, solltest du in Betracht ziehen, dies als einen "sanften" Constraint zu implementieren, anstatt Werte abzuschneiden. Eine Möglichkeit wäre die Verwendung einer Straffunktion, die zum Gesamtfehler hinzugefügt wird, wenn der Parameter unter die gewünschte Schranke fällt. Diese Methode verfälscht die Optimierung weniger und erlaubt es dem Algorithmus immer noch, in Richtung der Grenze zu konvergieren, ohne sie zu überschreiten.

Schlussfolgerung

Dein intuitiver Ansatz, die Fehlerberechnung zu überdenken, ist korrekt. Untersuche die Charakteristiken deiner spezifischen Anwendung und erwäge die Anpassung oder Wechsel der Fehlermetrik. Achte ebenfalls auf die Skalierung der Parameter und ihre Initialisierung. Für die Einrichtung einer unteren Schranke solltest du eher eine Methode verwenden, die deinen Parameterraum nicht unnatürlich einschränkt.
Avatar von

Ein anderes Problem?

Stell deine Frage

Willkommen bei der Mathelounge! Stell deine Frage einfach und kostenlos

x
Made by a lovely community