Automatisches Differenzieren
aus Wikipedia, der freien Enzyklopädie
Das automatische Differenzieren bzw. Differenzieren von Algorithmen ist ein Verfahren der Informatik und angewandten Mathematik. Zu einer Funktion in mehreren Variablen, die als Prozedur in einer Programmiersprache oder als Berechnungsgraph gegeben ist, wird eine erweiterte Prozedur erzeugt, die sowohl die Funktion als auch einen oder beliebig viele Gradienten, bis hin zur vollen Jacobi-Matrix, auswertet. Wenn das Ausgangsprogramm Schleifen enthält darf die Anzahl der Schleifendurchläufe nicht von den unabhängigen Variablen abhängig sein.
Diese Ableitungen werden z.B. für das Lösen von nichtlinearen Gleichungssystemen mittels Newton-Verfahren und für Methoden der nichtlinearen Optimierung benötigt.
Das wichtigste Hilfsmittel dabei ist die Kettenregel sowie die Tatsache, dass zu den im Computer verfügbaren Elementarfunktionen wie sin, cos, exp, log die Ableitungen bekannt und genauso exakt berechenbar sind. Damit wird der Aufwand zur Berechnung der Ableitungen proportional (mit kleinem Faktor) zum Aufwand der Auswertung der Ausgangsfunktion.
Inhaltsverzeichnis |
[Bearbeiten] Berechnung von Ableitungen
Aufgabe: Gegeben eine Funktion

Wie erhält man Code/Funktion für
![{\partial f \over \partial x}=\left[ \left( {\partial y_i \over \partial x_j} \right)_{i=1..m, j=1..n} \right]](../../../math/3/a/1/3a1f74739f9ea0329f57bc77e3c30066.png)
Verschiedene Ansätze hierfür sind:
- Versuche eine geschlossene, analytische Form für f zu finden und bestimmt
durch Differentiation. Implementiere dann den Code für
von Hand. Problem: Zu schwierig, zeitaufwendig, fehleranfällig
- Importiere den Code für f in ein Computeralgebrasystem und wende die dort zur Verfügung stehenden Mittel an. Exportiere dann den Code für
in seine eigentliche Umgebung. Problem: Zeitaufwendig, skaliert nicht, zu kompliziert für größerer Programme/Funktionen
- Versuche eine numerische Approximation der Ableitung zu bestimmen. Es gilt

. Problem: wie findet man eine optimale Schrittweite h?
- Versuche den Code durch Verwendung der Kettenregel zu transformieren, so daß man
erhält.
[Bearbeiten] Die Idee der Automatischen Differentiation (AD)
Gegeben ein Programm das eine Funktion berechet. AD beschreibt eine Menge von Verfahren, deren Ziel es ist ein neues Programm zu erzeugen welches die Jacobimatrix von f
beinhaltet. Die Eingabevariablen von x heißen unabhängige Variablen, die Ausgabevariable(n) y abhängige Variablen. Bei AD unterscheidet man mindestens zwei Verschiedene Modi.
- Vorwärtsmodus (FM engl Forward Mode)
- Rückwärtsmodus (BM engl Backward Mode)
[Bearbeiten] Vorwärtsmodus
Im Vorwärtsmodus berechnet man eine Matrix

mit einer beliebigen Matrix S (Seedmatrix) und einem näher zu bestimmenden Parameter p
[Bearbeiten] Beispiel
AD berechnet J
Im Vorwärtsmodus werden Richtungsableitungen entlang des Kontrollflusses der Berechnung von f transportiert. Für jede skalare Variable v wird in dem AD-erzeugten Code ein Vektor g_v, dessen i-te Komponente die Richtungsableitung entlang der i-ten unabhängigen Variablen enthält.
[Bearbeiten] Beispiel
Berechne eine Funktion
b = x1 + x2
y2 = by1
Eine Automatische Differentiation im Vorwärtsmodus hätte eine Funktion
![[g\_y_1, y_1, g\_y_2, y_2, b ] = g\_f\left( g\_x_1, x_1, g\_x_2, x_2, \right)](../../../math/3/c/8/3c87d2447ba79fdfbbf7a01554174514.png)
zum Ergebnis. Der Funktionsrumpf von g_f:
g_b = g_x1 + g_x2
b = x1 + x2
g_y2 = g_by1 + bg_y1
y2 = by1
[Bearbeiten] Rückwärtsmodus
Der Rückwärtsmodus besteht aus zwei Phasen.
- Das Originalprogramm wird ausgeführt und gewisse Daten werden abgespeichert
- Das Originalprogramm wird Rückwärts ausgeführt. Dabei werden Richtungsableitungen transportiert und es werden die Daten aus Phase 1 verwendet.
In Phase 2 wird für jede skalare Variable v ein Vektor a_v eingeführt. Dieser Vektor enthält in der i-ten Komponente die i-te Richtungsableitung (in Richtung von v). Die Saatmatrix erscheint als Object a_y. Im Rückwärtsmodus erhält man als Ergebnis ein Produkt

[Bearbeiten] Beispiel 1
AD berechnet J
[Bearbeiten] Beispiel 2
b = x1 + x2![]()
a_b = a_b + y1 + a_y2
![]()
a_x1 = a_x1 + a_b a_x1 = a_x2 + a_b
[Bearbeiten] Effizienzbetrachtungen
Die Effizienz von AD-Algorithmen hängt vom Modus und dem Parameter p ab. Die Wahl des Modus und des Parameters p hängt davon ab, wofür die Jacobimatrix berechnet wird. Es gelte
Tf | die Zeit f zu berechnen |
Mf | der Speicherbedarf dieser Rechnung |
TJS | die Zeit f und JS zu berechnen |
MJS | der Speicherbedarf dieser Rechnung |
TSJ | die Zeit f und SJ zu berechnen |
MSJ | der Speicherbedarf dieser Rechnung |
Für die beiden vorgestellten Modi gilt
- Vorwärtsmodus:
- Rückwärtsmodus:
[Bearbeiten] Die Berechnung als Kette von Berechnung
Gegeben: , Frage: Wie verändert sich die Ableitug von s während der 2ten Phase, um die Ableitungen von u und v zu erhalten?
f(x) wird als Sequenz von Programmen interpretiert. Im Beispiel "Optimierung eines Tragflügels" umfasst die Berechnung die folgenden Schritte.
- Überlagerung des Tragflügels mit sogenannten "Mode-Funktionen"

- Berechnung eines Gitters, das um den Tragflügel herum gelegt wird

- Lösung der Navier-Stokes-Gleichungen auf dem Gitter und Berechnung der Integrals der selbigen.

.
Insgesamt ergibt sich die Funktion
Mit einem naivem Ansatz würde man drei Matrizen ,
,
berechnen und dann zwei Matrix-Matrix Multiplikationen durchführen. Der Nachteil des Vorwärtsmodus ist allerdings:
im Rückwärtsmodus würde analog
gelten. Ein besserer Ansatz ist, das Ergebnis einer Berechnung jeweils als Saatzmatrix der folgenden einzusetzen.
- Wähle
als Saatmatrix der ersten Rechnung
- Das Ergebnis der ersten Rechnung als Saatmatrix der zweiten Rechnung
- Das Ergebnis der zweiten Rechnung als Saatmatrix der dritten Rechnung
also
Da die Zeilenzahl jeder Matrix 8 (p=8) ist erhöht sich der Zeit- und Speicherbedarf ebenfalls um höchstens 8.
[Bearbeiten] Weblinks
- Programmierwerkzeuge zum Thema
- Andreas Griewank: Evaluating Derivatives: Principles and Techniques of Algorithmic Differentiation, Frontiers in applied mathematics 19, ISBN 0-89871-451-6
- Autodiff