Zum Inhalt springen
3/30Kapitel 3 von 30

Bergab: Gradient Descent und die zwei Schritte, die alle überspringen

Berechne die exakte Obergrenze für die Lernrate und sieh, wie Brute Force über 3.600 Richtungen den Gradient neu findet.

Auf dieser Seite

Das vorige Kapitel endete mit einem Tal.

Nicht mit einem metaphorischen: mit einer echten Kurve, dem Loss gegen einen einzelnen Parameter aufgetragen, die nach unten abtaucht und wieder ansteigt. Und der Loss darunter wurde nicht gewählt, weil er sauber aussah — er wurde hergeleitet, aus einer Aussage über das Rauschen in den Messungen, und der quadrierte Fehler kam am anderen Ende als Konsequenz heraus, nicht als Konvention.

Wir haben also eine Landschaft mit einem Boden und einen Grund zu glauben, dass dieser Boden der richtige Ort ist. Was wir nicht haben, ist ein Weg dorthin.

Dieses Kapitel baut einen solchen Weg, und es ist der Algorithmus, der jedes Modell im Rest dieses Kurses trainiert — jedes einzelne, ohne Ausnahme, bis hin zu denen mit Hunderten Milliarden Parametern. Er passt in etwa zwanzig Zeilen. Die zwei schwierigen Teile stehen nicht in diesen zwanzig Zeilen, und es sind genau die zwei Dinge, die fast jede Erklärung überspringt:

  • Warum das Minuszeichen. Das Update subtrahiert den Gradient. Jedes Tutorial schreibt es hin; sehr wenige sagen, warum der Gradient die Richtung ist, die nach oben führt — und nur diese Tatsache macht das Minuszeichen zu mehr als einem Glaubensakt.
  • Wie groß ein Schritt sein darf. „Zu groß divergiert, zu klein ist langsam“ ist wahr und nutzlos. Es gibt eine exakte Zahl, sie lässt sich aus dem Loss berechnen, und dieses Kapitel berechnet sie zweimal — einmal für eine Spielzeugparabel und einmal für die echten Daten.

Der Aufbau und warum du nicht einfach suchen kannst

Link zum Abschnitt: Der Aufbau und warum du nicht einfach suchen kannst

Noch einmal so formuliert, dass dieses Kapitel für sich steht: die acht Teile vom Förderband aus Kapitel 1, aber mit einer anderen Frage. Nicht akzeptieren oder ablehnen — das kommt später zurück —, sondern das Gewicht eines Teils aus seiner Breite vorhersagen.

belt.pyPYTHON
import numpy as np

WIDTH  = np.array([18.0, 19.5, 20.2, 21.0, 24.0, 25.5, 23.0, 26.0])
WEIGHT = np.array([47.0, 52.0, 49.0, 55.0, 61.0, 66.0, 70.0, 58.0])

x = WIDTH  - WIDTH.mean()      # 22.15 mm
y = WEIGHT - WEIGHT.mean()     # 57.25 g

Die Messungen sind zentriert, genau wie in Kapitel 1 und aus einem Grund, der sich noch vor Ende dieses Kapitels auszahlt. Das Modell ist eine Gerade, y^=ax+b\hat{y} = a x + b, und der Loss ist der mittlere quadratische Fehler, den das vorige Kapitel hergeleitet hat:

L(a,b)=1ni=1n(axi+byi)2L(a, b) = \frac{1}{n} \sum_{i=1}^{n} \left(a x_i + b - y_i\right)^2

Zwei Parameter. Warum nicht einfach viele Werte ausprobieren? Machen wir das tatsächlich — ein Gitter von a=0a = 0 bis 55 und b=5b = -5 bis 55, in Schritten von 0.010.01:

TEXT
grid 501 x 1001 = 501,501 evaluations in 3.67 s
  best found: a = 2.1000, b = -0.0000, L = 24.592450

Eine halbe Million Auswertungen, um zwei Zahlen auf zwei Dezimalstellen festzunageln — und diese Sekunde ist Wanduhrzeit auf einer Maschine, daher landet ein neuer Lauf irgendwo zwischen drei und sechs; die Anzahl der Auswertungen und das Minimum sind der reproduzierbare Teil. Gradient descent, am Ende dieses Kapitels, erreicht vier Dezimalstellen in acht Schritten und die vollständige float64-Antwort in sechsunddreißig.

Aber Geschwindigkeit ist nicht das Argument, und das ist der Punkt, der den ganzen Kurs entscheidet. Gittersuche kostet kPk^P Auswertungen für PP Parameter mit jeweils kk Werten. Mit tausend Werten pro Achse:

ModellParameterGitterauswertungen
diese Gerade210610^{6}
das XOR-Netzwerk aus Kapitel 59102710^{27}
ein kleines mehrschichtiges Netzwerk20,0001060,00010^{60{,}000}

Die dritte Zeile ist keine große Zahl, sie ist eine bedeutungslose — im beobachtbaren Universum gibt es ungefähr 108010^{80} Atome. Suche wird nicht langsamer, wenn Modelle wachsen; sie hört auf zu existieren. Alles, was folgt, existiert wegen dieser Tabelle.

Eine Ableitung ist eine Messung, die du durchführen kannst

Link zum Abschnitt: Eine Ableitung ist eine Messung, die du durchführen kannst

Fixiere b=0b = 0 für einen Moment, sodass es einen Parameter und eine Kurve gibt — genau das Bild, mit dem dich das letzte Kapitel zurückgelassen hat. Nimm einen Punkt darauf, a=1a = 1, und frag: Wenn ich aa um einen kleinen Betrag hh anstoße, wie stark bewegt sich der Loss pro Einheit dieses Stoßes?

L(a+h)L(a)h\frac{L(a + h) - L(a)}{h}

Dieses Verhältnis ist Anstieg über Lauf — die Steigung der Geraden durch zwei Punkte auf der Kurve. Wenn hh schrumpft, rutschen die beiden Punkte zusammen und die Gerade wird zur Tangente. Ihre Steigung ist die Ableitung L(a)L'(a): die Rate, mit der sich der Loss pro Änderungseinheit in aa ändert. Keine Näherung von irgendetwas und keine unendlich kleine Größe. Ein Grenzwert gewöhnlicher Verhältnisse.

Es lohnt sich, das laufen zu lassen, weil die Zahlen etwas sagen, was die Definition nicht sagt:

slope.pyPYTHON
def loss1(a):
    return np.mean((a * x - y) ** 2)

for h in [1.0, 1e-2, 1e-4, 1e-6, 1e-8, 1e-10, 1e-12, 1e-14]:
    q = (loss1(1.0 + h) - loss1(1.0)) / h
    print(f"h = {h:<8.0e}   slope estimate = {q:.10f}   error = {abs(q + 16.385):.3e}")
TEXT
h = 1e+00      slope estimate = -8.9400000000    error = 7.445e+00
h = 1e-02      slope estimate = -16.3105500000   error = 7.445e-02
h = 1e-04      slope estimate = -16.3842555001   error = 7.445e-04
h = 1e-06      slope estimate = -16.3849925556   error = 7.444e-06
h = 1e-08      slope estimate = -16.3850003787   error = 3.787e-07
h = 1e-10      slope estimate = -16.3850444324   error = 4.443e-05
h = 1e-12      slope estimate = -16.3851154866   error = 1.155e-04
h = 1e-14      slope estimate = -17.0530256582   error = 6.680e-01

Hier passieren zwei Dinge, und beide tragen Gewicht.

Der Fehler ist nicht vage proportional zu hh — er ist exakt 7.445h7.445\,h. Teile hh durch hundert, und der Fehler teilt sich durch hundert, jedes Mal auf vier signifikante Stellen. Diese Konstante ist keine Dekoration: Sie ist die Hälfte der zweiten Ableitung des Loss und der erste Auftritt einer Idee, die in zwei Abschnitten zurückkehrt — dass eine Kurve nahe einem Punkt wie eine Gerade plus eine Korrektur proportional zu h2h^2 aussieht.

Und dann bricht das Muster. Unterhalb von h=108h = 10^{-8} wird die Schätzung schlechter, und bei 101410^{-14} ist sie schon in der zweiten Ziffer falsch. Mathematisch ist nichts passiert; die Floating-Point-Box aus dem letzten Kapitel ist passiert. L(a+h)L(a+h) und L(a)L(a) stimmen in ihren ersten zehn Ziffern überein, ihre Subtraktion zerstört diese Ziffern, und das Teilen der Trümmer durch eine winzige Zahl verstärkt, was übrig bleibt. Es gibt ein bestes hh — hier etwa 10810^{-8}, ungefähr die Quadratwurzel des machine epsilon — und kleiner zu werden ist nicht sorgfältiger, sondern weniger sorgfältig. Merk dir das; eine Funktion am Ende dieses Kapitels hängt davon ab.

Die exakte Steigung aus der Analysis statt aus Messung ist 16.385-16.385. Also können wir aufhören zu messen und anfangen herzuleiten.

Hier ist die Idee, auf der der Rest des Kurses aufbaut, einmal klar ausgesprochen.

Zwei Funktionen zu komponieren heißt, die eine in die andere einzusetzen: (fg)(x)=f(g(x))(f \circ g)(x) = f(g(x)). Mehr nicht.

Ein tiefes Netzwerk ist nicht wie eine Komposition. Es ist eine. Eine Schicht ist eine Funktion; Schichten zu stapeln heißt, sie zu komponieren; „Tiefe“ ist die Anzahl der Funktionen in der Kette. Wenn Kapitel 5 ein Netzwerk baut, baut es f4f3f2f1f_4 \circ f_3 \circ f_2 \circ f_1 und sonst nichts. Das bedeutet: Die für unsere Zwecke wichtigste Regel der Analysis ist die, die eine Komposition ableitet:

ddxf(g(x))=f(g(x))g(x)\frac{d}{dx} f(g(x)) = f'(g(x)) \cdot g'(x)

Raten multiplizieren sich. Wenn gg sich dreimal so schnell ändert wie xx und ff sich doppelt so schnell ändert wie gg, dann ändert sich ff sechsmal so schnell wie xx. Das ist der ganze Inhalt, und es ist der Grund, warum ein Signal, das durch zehn Schichten zurückläuft, mit zehn Zahlen multipliziert wird — weshalb Kapitel 6 einen Abschnitt darauf verwendet, was passiert, wenn diese Zahlen alle etwas kleiner als eins sind.

Wende sie auf unseren Loss an. Schreibe das Residuum ri=axi+byir_i = a x_i + b - y_i, sodass L=1nri2L = \frac{1}{n}\sum r_i^2. Jedes rir_i hängt über die innere Funktion axia x_i von aa ab, deren Ableitung xix_i ist. Kettenregel, Term für Term:

La=1ni2rixi,Lb=1ni2ri1\frac{\partial L}{\partial a} = \frac{1}{n}\sum_i 2 r_i \cdot x_i, \qquad \frac{\partial L}{\partial b} = \frac{1}{n}\sum_i 2 r_i \cdot 1

Diese geschweiften \partial-Symbole markieren eine partielle Ableitung: nach einer Variablen ableiten und jede andere als konstant behandeln. Es passiert nichts Neues — es ist derselbe Grenzwert wie zuvor, nur entlang einer Achse. Sammle die partiellen Ableitungen in einem Vektor, und du hast den Gradient:

L=(La, Lb)\nabla L = \left( \frac{\partial L}{\partial a},\ \frac{\partial L}{\partial b} \right)

Am Punkt (a,b)=(1,4)(a, b) = (1, 4) ist dieser Vektor (16.385, 8.0)(-16.385,\ 8.0). Zwei Zahlen. Die Frage ist, was sie bedeuten, und das ist der erste Schritt, den alle überspringen.

Der Gradient ist ein Vektor aus Steigungen entlang der Achsen. Das ist alles, was wir bewiesen haben. Es ist nicht offensichtlich — es sollte nicht offensichtlich sein —, dass das Zusammensetzen dieser Steigungen zu einem Vektor etwas erzeugt, das in irgendeine bestimmte Richtung zeigt.

Definieren wir also das, was wir tatsächlich wollen. Wähle einen Einheitsvektor u\mathbf{u}, eine Richtung. Die Richtungsableitung ist die Rate, mit der sich der Loss ändert, wenn du in diese Richtung gehst:

DuL=limh0L(θ+hu)L(θ)hD_{\mathbf{u}} L = \lim_{h \to 0} \frac{L(\boldsymbol{\theta} + h\mathbf{u}) - L(\boldsymbol{\theta})}{h}

Die Kettenregel verwandelt das in etwas Berechenbares. Beim Gehen entlang u\mathbf{u} ändert sich aa mit Rate u1u_1 und bb mit Rate u2u_2, und die Beiträge addieren sich:

DuL=Lau1+Lbu2=LuD_{\mathbf{u}} L = \frac{\partial L}{\partial a} u_1 + \frac{\partial L}{\partial b} u_2 = \nabla L \cdot \mathbf{u}

Die Änderungsrate in jeder Richtung ist das Skalarprodukt des Gradient mit dieser Richtung. Und jetzt die Pointe, eine Zeile Geometrie. Schreibe das Skalarprodukt mit dem Winkel ϕ\phi zwischen den Vektoren:

Lu=Lucosϕ=Lcosϕ\nabla L \cdot \mathbf{u} = \lVert \nabla L \rVert \, \lVert \mathbf{u} \rVert \cos\phi = \lVert \nabla L \rVert \cos\phi

da u\mathbf{u} die Länge 1 hat. Das Einzige, was du kontrollierst, ist cosϕ\cos\phi, das bei ϕ=0\phi = 0 am größten und bei einer halben Drehung, ϕ=180\phi = 180 Grad, am kleinsten ist. Also:

  • Der steilste Anstieg liegt entlang von L\nabla L selbst, und die Steigung dort ist exakt L\lVert \nabla L \rVert.
  • Der steilste Abstieg liegt entlang von L-\nabla L, und die Steigung dort ist L-\lVert \nabla L \rVert.
  • Senkrecht zum Gradient ändert sich der Loss überhaupt nicht. Deshalb schneiden die Linien einer Höhenlinienkarte den Gradient im rechten Winkel.

Das ist das Minuszeichen. Keine Konvention, kein Vorzeichenwechsel, den jemand gewählt hat: Die Richtung des schnellsten Abfalls ist der negative Gradient, weil cosϕ\cos\phi bei einer halben Drehung minimiert wird, und aus keinem anderen Grund.

Da dies eine Aussage über alle Richtungen ist, teste sie gegen alle Richtungen. Stichprobe 3.600 davon, eine pro Zehntelgrad, und miss jede durch einen kleinen Stoß:

directions.pyPYTHON
theta = np.array([1.0, 4.0])
g = grad(theta)
print("gradient      ", g)
print("its length    ", np.linalg.norm(g))
print("its angle     ", np.degrees(np.arctan2(g[1], g[0])) % 360, "degrees")

best = max(
    ((loss(theta + 1e-6 * u) - loss(theta - 1e-6 * u)) / 2e-6, np.degrees(ang))
    for ang, u in (
        (a, np.array([np.cos(a), np.sin(a)])) for a in np.arange(3600) * 2 * np.pi / 3600
    )
)
print("steepest slope", best[0], "at", best[1], "degrees")
TEXT
gradient       [-16.385   8.   ]
its length     18.23371122399386
its angle      153.97598928042032 degrees
steepest slope 18.233709624837502 at 154.0 degrees

Eine Suche, die nichts über Gradienten weiß, findet über 3.600 Richtungen ihren steilsten Anstieg bei 154,0 Grad — der eigenen Richtung des Gradient, bis auf die 0,1-Grad-Auflösung der Suche. Und die Steigung, die sie dort findet, 18,2337, ist die Länge des Gradient auf sechs Stellen. Der Satz ist keine Geschichte darüber, was Gradienten bedeuten; er ist eine messbare Tatsache, und das ist die Messung.

Warum ein kleiner Schritt bergab tatsächlich hilft

Link zum Abschnitt: Warum ein kleiner Schritt bergab tatsächlich hilft

Jetzt der zweite übersprungene Schritt. Wir wissen, welche Richtung nach unten führt. Daraus folgt nicht, dass ein Schritt in diese Richtung den Loss senkt, denn „nach unten“ ist eine Aussage über einen infinitesimalen Stoß, und ein Schritt ist nicht infinitesimal.

Die Brücke ist Linearisierung. In der Nähe eines Punkts ist eine glatte Funktion ihre Tangente plus eine Korrektur:

L(θ+δ)=L(θ)+Lδ+O(δ2)L(\boldsymbol{\theta} + \boldsymbol{\delta}) = L(\boldsymbol{\theta}) + \nabla L \cdot \boldsymbol{\delta} + O(\lVert\boldsymbol{\delta}\rVert^2)

Das ist die Taylor-Entwicklung erster Ordnung. Das verworfene O(δ2)O(\lVert\boldsymbol{\delta}\rVert^2) ist die Krümmung — derselbe Term, der die Schätzung in der Steigungstabelle um exakt 7.445h7.445\,h falsch gemacht hat. Setze den Schritt ein, den wir machen wollen, δ=ηL\boldsymbol{\delta} = -\eta \nabla L:

L(θηL)L(θ)ηL2L(\boldsymbol{\theta} - \eta \nabla L) \approx L(\boldsymbol{\theta}) - \eta \lVert \nabla L \rVert^2

Der Loss fällt um ηL2\eta \lVert \nabla L \rVert^2. Jeder Teil davon ist nichtnegativ, also ist das Versprechen real — für ein ausreichend kleines η\eta, denn der vernachlässigte Term wächst wie η2\eta^2 und frisst es irgendwann auf. Das ist die ganze Theorie. Hier wird das Versprechen gehalten und dann gebrochen:

TEXT
eta = 0.2       promised    66.49364500   delivered   -16.01619240   ratio -0.240868
eta = 0.1       promised    33.24682250   delivered    12.61936315   ratio  0.379566
eta = 0.01      promised     3.32468225   delivered     3.11840766   ratio  0.937957
eta = 0.001     promised     0.33246822   delivered     0.33040548   ratio  0.993796
eta = 0.0001    promised     0.03324682   delivered     0.03322620   ratio  0.999380
eta = 1e-05     promised     0.00332468   delivered     0.00332448   ratio  0.999938

Lies es von unten. Wenn η\eta schrumpft, konvergiert der tatsächliche Abfall gegen den versprochenen — Verhältnis 0,99938, dann 0,99994 —, was einfach Taylors Satz bei der Arbeit ist. Lies es von oben, und bei η=0.2\eta = 0.2 ist der tatsächliche „Abfall“ minus sechzehn. Der Schritt ging bergab, und der Loss ging nach oben.

Die Update-Regel lautet also

θθηL(θ)\boldsymbol{\theta} \leftarrow \boldsymbol{\theta} - \eta \nabla L(\boldsymbol{\theta})

und sie kommt mit einer Bedingung, die niemand ausspricht: η\eta muss klein genug sein. Klein genug im Vergleich zu was genau, ist der nächste Abschnitt.

Die Lernrate hat eine Obergrenze, und sie ist berechenbar

Link zum Abschnitt: Die Lernrate hat eine Obergrenze, und sie ist berechenbar

Beginne mit dem einfachsten Tal, das es gibt: f(x)=x2f(x) = x^2, wobei f(x)=2xf'(x) = 2x. Ein Schritt von gradient descent ist

xxη2x=x(12η)x \leftarrow x - \eta \cdot 2x = x\,(1 - 2\eta)

Die Position wird in jedem Schritt mit (12η)(1 - 2\eta) multipliziert. Das ist eine geometrische Folge, und geometrische Folgen haben genau eine Regel: Sie schrumpfen, wenn der Multiplikator dem Betrag nach kleiner als 1 ist, und wachsen sonst. Also 12η<1\lvert 1 - 2\eta \rvert < 1, also 0<η<10 < \eta < 1.

Die Grenze liegt exakt bei η=1\eta = 1. Nicht „ungefähr 1“, nicht „1 ist meistens zu groß“. Bei η=1\eta = 1 ist der Multiplikator 1-1, und der Punkt springt für immer zwischen xx und x-x hin und her, ohne sich zu nähern oder zu entkommen. Darunter: Konvergenz; darüber: Divergenz. Das Intervall teilt sich bei η=0.5\eta = 0.5 erneut, wo der Multiplikator das Vorzeichen wechselt: Darunter ist die Annäherung monoton, darüber schießt der Punkt über das Ziel hinaus und wechselt die Seiten, und bei exakt 0.50.5 ist der Multiplikator 0 und ein einziger Schritt landet im Minimum.

Vier Regime aus vier Zeilen Algebra. Überschreite die Grenzen selbst:

Schrittzahl: 14, Ende bei x = -0.0836.

Daten als Tabelle anzeigen
Schrittxf(x)
0⁨-1.9000⁩⁨3.6100⁩
1⁨-1.5200⁩⁨2.3104⁩
2⁨-1.2160⁩⁨1.4787⁩
3⁨-0.9728⁩⁨0.9463⁩
4⁨-0.7782⁩⁨0.6057⁩
5⁨-0.6226⁩⁨0.3876⁩
6⁨-0.4981⁩⁨0.2481⁩
7⁨-0.3985⁩⁨0.1588⁩
8⁨-0.3188⁩⁨0.1016⁩
9⁨-0.2550⁩⁨0.0650⁩
10⁨-0.2040⁩⁨0.0416⁩
11⁨-0.1632⁩⁨0.0266⁩
12⁨-0.1306⁩⁨0.0170⁩
13⁨-0.1045⁩⁨0.0109⁩
14⁨-0.0836⁩⁨0.0070⁩
Gradientenabstieg, interaktiv

Vierzehn Schritte mit einer Rate von 0,1, von x=1.9x = -1.9 aus, enden bei 0.0836-0.0836. Erhöhe die Rate auf 0,5, und der allererste Schritt landet auf dem Boden. Erhöhe sie auf 0,9, und sie endet beim selben 0.0836-0.0836 wie 0,1 — gleiche Entfernung, anderer Stil, weil 12η\lvert 1 - 2\eta \rvert für beide 0,8 ist —, aber sie kommt dort durch Zickzack über das Tal an, statt eine Seite hinabzugehen.

Und jetzt der interessante Fall:

Schrittzahl: 14, Ende bei x = -1.9000.

Daten als Tabelle anzeigen
Schrittxf(x)
0⁨-1.9000⁩⁨3.6100⁩
1⁨1.9000⁩⁨3.6100⁩
2⁨-1.9000⁩⁨3.6100⁩
3⁨1.9000⁩⁨3.6100⁩
4⁨-1.9000⁩⁨3.6100⁩
5⁨1.9000⁩⁨3.6100⁩
6⁨-1.9000⁩⁨3.6100⁩
7⁨1.9000⁩⁨3.6100⁩
8⁨-1.9000⁩⁨3.6100⁩
9⁨1.9000⁩⁨3.6100⁩
10⁨-1.9000⁩⁨3.6100⁩
11⁨1.9000⁩⁨3.6100⁩
12⁨-1.9000⁩⁨3.6100⁩
13⁨1.9000⁩⁨3.6100⁩
14⁨-1.9000⁩⁨3.6100⁩
Gradientenabstieg, interaktiv

Exakt auf der Grenze. Vierzehn Schritte mit einer Rate von 1, und er endet bei 1.9-1.9: genau dort, wo er begonnen hat, ohne etwas anderes zu tun als zu springen. Ein Stoß höher, und das Springen wächst, statt stabil zu bleiben; bei 1,2 ist es in vier Schritten außerhalb des Diagramms. Eine zu große Rate konvergiert nicht langsam. Sie konvergiert gar nicht.

Nun die allgemeine Regel, die aus demselben Argument herausfällt. Der Multiplikator 12η1 - 2\eta war in Wahrheit 1ηf1 - \eta f'', und nahe einem Minimum hat ein Loss mit mehreren Parametern eine solche Zahl pro Richtung — die Eigenwerte der Matrix der zweiten Ableitungen. Jede Richtung muss gleichzeitig stabil sein, also wird die Obergrenze durch den größten gesetzt:

η<2λmax\eta < \frac{2}{\lambda_{\max}}

Für f(x)=x2f(x) = x^2, f=2f'' = 2, Obergrenze 1, genau das, was wir gerade hergeleitet haben. Für unser Förderband ist die Matrix der zweiten Ableitungen 2nAA\frac{2}{n} A^{\top} A mit AA als zweispaltiger Eingabematrix, und ihre Eigenwerte sind 2 und 14,89, also ist die Obergrenze 2/14.89=0.134322 / 14.89 = 0.13432. Das ist eine Vorhersage mit fünf signifikanten Stellen. Teste sie:

TEXT
lr=0.1343    -> L =      24.5924
lr=0.13431   -> L =      24.5924
lr=0.13432   -> L =       4707.8       BLEW UP
lr=0.13433   -> L =  4.00452e+16       BLEW UP
lr=0.1344    -> L = 1.18229e+107       BLEW UP

Fünf Dezimalstellen Übereinstimmung zwischen einer Zeile linearer Algebra und hunderttausend Iterationen einer for-Schleife.

Und hier kommt Kapitel 1 zurück. Alles oben verwendete die zentrierten Messungen. Führe den identischen Code auf rohen Millimetern und Gramm aus, und die Eigenwerte sind 0,0298 und 998,1 statt 2 und 14,89. Die Obergrenze bricht von 0,134 auf 0,002004 ein — genauso exakt, konvergend bei lr=0.002003 und explodierend bei lr=0.002004.

Schlimmer als die Obergrenze ist das Verhältnis zwischen den Eigenwerten. Die Konditionszahl misst, wie weit das Tal von rund entfernt ist: Ein langer, dünner Graben erzwingt eine Rate, die klein genug für die steilen Wände ist, und dann wird der Boden des Grabens mit demselben Schneckentempo durchquert. Unsere geht von 7,44 zentriert auf 33.452 roh. Mit der besten Rate, die jede Version nehmen kann:

FeaturesKonditionszahlbeste RateSchritte bis auf 1% des Optimums
zentriert7,440,118410
rohe Millimeter und Gramm33.4520,002003779.513

Dieselben Daten, derselbe Code, am Ende dieselbe Antwort — und achttausendmal so viel Arbeit, weil niemand einen Mittelwert subtrahiert hat. In Kapitel 1 kostete dieselbe Auslassung den Perzeptron einen Faktor von sechstausend bei den Epochen, und die Diagnose dort war geometrisch: Die Daten schwebten weit vom Ursprung entfernt. Es ist dieselbe Geometrie hier im Optimierungsgewand, und deshalb ist Eingabenormalisierung kein Hygienehinweis, sondern Arithmetik.1

Nichts oben brauchte eine Bibliothek. Hier ist der ganze Optimierer.

descent.pyPYTHON
def loss(theta):
    a, b = theta
    return np.mean((a * x + b - y) ** 2)


def grad(theta):
    a, b = theta
    residual = a * x + b - y
    return np.array([np.mean(2 * residual * x), np.mean(2 * residual)])


def descend(theta, lr, steps):
    theta = np.array(theta, dtype=float)
    for _ in range(steps):
        theta = theta - lr * grad(theta)   
    return theta


theta = descend([0.0, 0.0], lr=0.05, steps=60)
print(theta, loss(theta))
TEXT
[ 2.10040296e+00 -2.76445533e-15] 24.592448791134984

Die geschlossene Least-Squares-Lösung für diese acht Punkte ist a=2.100403a = 2.100403, b=0b = 0, mit einem Loss von 24.59244924.592449. Die Schleife hat sie auf acht signifikante Stellen gefunden, ohne zu wissen, dass es eine geschlossene Form gibt — was wichtig ist, weil es ab Kapitel 5 keine mehr geben wird.

Die Trajektorie, denn ihr zuzusehen ist der Punkt:

TEXT
   0 a=0.000000 b=0.000000 L=57.437500
   1 a=1.563750 b=0.000000 L=26.736582
   2 a=1.963288 b=-0.000000 L=24.732418
   5 a=2.098116 b=-0.000000 L=24.592488
  10 a=2.100400 b=-0.000000 L=24.592449
  60 a=2.100403 b=-0.000000 L=24.592449

Der größte Teil der Strecke wird in den ersten zwei Schritten zurückgelegt, weil der Gradient am größten ist, wenn du am weitesten vom Boden entfernt bist, und schrumpft, wenn du dich näherst. Gradient descent verlangsamt sich nahe einem Minimum automatisch. Das ist ein Feature, und in Kapitel 6 ist es auch ein Problem.

Das bisherige Argument hat ein Loch. Der Schritt stoppt, wenn L=0\nabla L = \mathbf{0}, und wir haben das „das Minimum“ genannt. Ein Punkt mit Gradient null ist ein kritischer Punkt, und ein Minimum zu sein ist nur eine der Möglichkeiten, einer zu sein:

  • ein lokales Minimum: bergauf in jede Richtung, aber möglicherweise nicht der tiefste solche Punkt überhaupt;
  • ein lokales Maximum: bergab in jede Richtung;
  • ein Sattelpunkt: bergauf in manche Richtungen und bergab in andere. Die Fläche f(x,y)=x2y2f(x,y) = x^2 - y^2 hat f=(2x,2y)\nabla f = (2x, -2y), was am Ursprung null ist, wo die Funktion entlang der xx-Achse ein Minimum und entlang der yy-Achse gleichzeitig ein Maximum ist.

Gradient descent kann diese nicht unterscheiden, weil es immer nur auf den Gradient schaut, und der Gradient bei allen dreien null ist.

Unsere Gerade hat einen kritischen Punkt, und er ist die Antwort — ein Squared-Error-Loss über einem linearen Modell ist konvex, eine einzelne Schüssel, und descent darauf kann das globale Minimum nicht verfehlen. Diese Eigenschaft überlebt den Kontakt mit diesem Kurs nicht. Der Loss eines neuronalen Netzwerks ist nicht konvex, und ab Kapitel 5 ist „das Minimum“ kein Ding, das existiert: Es gibt viele, in unterschiedlichen Tiefen, und welches du bekommst, hängt davon ab, wo du gestartet bist. Das ist ein Satz und bleibt ein Satz, weil die Theorie groß und die praktische Konsequenz klein ist.

Du kannst die ganze Konsequenz an einer Kurve sehen. Nimm f(x)=x44x22+x10f(x) = \tfrac{x^4}{4} - \tfrac{x^2}{2} + \tfrac{x}{10}, das zwei Täler unterschiedlicher Tiefe hat:

TEXT
   x =  -1.046681   f(x) =  -0.352386   minimum
   x =   0.101031   f(x) =   0.005026   maximum
   x =   0.945649   f(x) =  -0.152639   minimum

Schrittzahl: 40, Ende bei x = 0.9456.

Daten als Tabelle anzeigen
Schrittxf(x)
0⁨0.1100⁩⁨0.0050⁩
1⁨0.1122⁩⁨0.0050⁩
2⁨0.1149⁩⁨0.0049⁩
3⁨0.1182⁩⁨0.0049⁩
4⁨0.1223⁩⁨0.0048⁩
5⁨0.1275⁩⁨0.0047⁩
6⁨0.1338⁩⁨0.0045⁩
7⁨0.1416⁩⁨0.0042⁩
8⁨0.1513⁩⁨0.0038⁩
9⁨0.1633⁩⁨0.0032⁩
10⁨0.1781⁩⁨0.0022⁩
11⁨0.1962⁩⁨0.0007⁩
12⁨0.2183⁩⁨-0.0014⁩
13⁨0.2453⁩⁨-0.0046⁩
14⁨0.2779⁩⁨-0.0093⁩
15⁨0.3170⁩⁨-0.0160⁩
16⁨0.3633⁩⁨-0.0253⁩
17⁨0.4172⁩⁨-0.0377⁩
18⁨0.4783⁩⁨-0.0535⁩
19⁨0.5455⁩⁨-0.0721⁩
20⁨0.6163⁩⁨-0.0922⁩
21⁨0.6869⁩⁨-0.1116⁩
22⁨0.7526⁩⁨-0.1277⁩
23⁨0.8092⁩⁨-0.1393⁩
24⁨0.8540⁩⁨-0.1463⁩
25⁨0.8868⁩⁨-0.1499⁩
26⁨0.9091⁩⁨-0.1516⁩
27⁨0.9236⁩⁨-0.1522⁩
28⁨0.9325⁩⁨-0.1525⁩
29⁨0.9379⁩⁨-0.1526⁩
30⁨0.9411⁩⁨-0.1526⁩
31⁨0.9430⁩⁨-0.1526⁩
32⁨0.9441⁩⁨-0.1526⁩
33⁨0.9448⁩⁨-0.1526⁩
34⁨0.9451⁩⁨-0.1526⁩
35⁨0.9454⁩⁨-0.1526⁩
36⁨0.9455⁩⁨-0.1526⁩
37⁨0.9455⁩⁨-0.1526⁩
38⁨0.9456⁩⁨-0.1526⁩
39⁨0.9456⁩⁨-0.1526⁩
40⁨0.9456⁩⁨-0.1526⁩
Gradientenabstieg, interaktiv

Vierzig Schritte von x=0.11x = 0.11 aus, Einpendeln bei 0.94560.9456 — dem flacheren der beiden Täler. Verschiebe den Startpunkt nun eine Kerbe nach links, auf 0.100.10. Gleiche Rate, gleiche vierzig Schritte, und es pendelt sich stattdessen bei 1.0461-1.0461 ein, wo der Loss 0.199747 niedriger ist. Die Wasserscheide ist der Hügel bei 0.1010310.101031, und der ganze Unterschied zwischen den beiden Antworten ist, auf welcher Seite davon du zufällig gestartet bist.

Im flachen Tal zu landen ist im Loss 56,7% schlechter, und der Algorithmus hat keine Möglichkeit, das zu wissen, weil aus dem Inneren eines Tals jede Richtung bergauf geht. Dafür gibt es in gradient descent keine Reparatur, und es wird keine kommen. Was es in der Praxis gibt, ist der Befund, dass es weit weniger zählt, als dieses Bild nahelegt — in den sehr hohen Dimensionen eines echten Netzwerks erweisen sich die meisten kritischen Punkte als Sättel statt als Fallen,2 und Kapitel 5 misst, wie oft ein kleines Netzwerk tatsächlich stecken bleibt.

Billigere Schritte: stochastisch, Minibatch, Momentum

Link zum Abschnitt: Billigere Schritte: stochastisch, Minibatch, Momentum

Eine Sache an grad oben sollte dich stören: Es summiert für jeden Schritt über den gesamten Datensatz. Acht Teile sind nichts. Eine Million sind eine Million Gradientenberechnungen, um die Parameter einmal zu bewegen.

Der Ausweg ist, dass der Gradient ein Durchschnitt ist, und ein Durchschnitt lässt sich aus einer Stichprobe schätzen. Berechne ihn auf einer zufälligen Handvoll — einem Minibatch — und mache darauf den Schritt. Die Schätzung ist verrauscht; sie ist aber auch unverzerrt, und Hunderte billige verrauschte Schritte schlagen einen teuren exakten. Auf hunderttausend synthetischen Teilen, gezählt in Gradienten pro Beispiel statt in Schritten:

MethodeSchritte bis auf 0,1% des OptimumsGradienten pro Beispiel
full batch7700.000
Minibatch von 321003.200
ein Beispiel auf einmal17.58017.580

Zweihundertneunzehnmal weniger Arithmetik, um denselben Ort zu erreichen. Und das Extrem — ein Beispiel auf einmal, die ursprüngliche stochastische Approximation von Robbins und Monro3 — ist nicht der Gewinner: Es ist fünfmal schlechter als Batches von 32, weil 32 Beispiele auf Hardware, die Matrizen multipliziert, fast nichts mehr kosten als eines, während das Rauschen mit der Quadratwurzel der Batch-Größe abfällt. Dieser Trade-off ist der Grund, warum jedes Trainingsskript, das du je lesen wirst, ein batch_size enthält.

Momentum ist die andere billige Korrektur, und sie zielt genau auf den Graben. In einem schlecht konditionierten Tal zickzacken die Schritte über die schmale Richtung, während sie in der langen langsam vorankriechen. Momentum hält einen laufenden Durchschnitt vergangener Gradienten, sodass die oszillierenden Komponenten sich aufheben und die konsistente sich ansammelt:4

vβv+L(θ),θθηv\mathbf{v} \leftarrow \beta \mathbf{v} + \nabla L(\boldsymbol{\theta}), \qquad \boldsymbol{\theta} \leftarrow \boldsymbol{\theta} - \eta \mathbf{v}

Zwei zusätzliche Zeilen. Auf dem rohen, unzentrierten Förderband — Konditionszahl 33.452, der schlimmste Fall, den wir haben — bei der besten Rate, die plain descent nehmen kann:

TEXT
momentum beta=0.0   ->    79,513 steps to 1%
momentum beta=0.9   ->     1,609 steps to 1%
momentum beta=0.99  ->       461 steps to 1%

Ein Faktor von 172 für zwei Codezeilen. Kapitel 6 macht daraus Adam; der Mechanismus ist schon hier.

Der Check, den du in Kapitel 5 brauchen wirst

Link zum Abschnitt: Der Check, den du in Kapitel 5 brauchen wirst

Jeder Gradient in diesem Kapitel wurde von Hand hergeleitet und könnte daher falsch sein. Die Korrektur ist die Steigungstabelle vom Anfang: Miss die Ableitung numerisch und vergleiche. Verwende die zentrale Differenz, L(θ+h)L(θh)2h\frac{L(\theta+h) - L(\theta-h)}{2h}, die den führenden Fehlerterm aufhebt und für dasselbe hh sehr viel genauer ist.

gradcheck.pyPYTHON
def numeric_grad(f, theta, h=1e-5):
    theta = np.asarray(theta, dtype=float)
    out = np.zeros_like(theta)
    for i in range(theta.size):
        bump = np.zeros_like(theta)
        bump[i] = h
        out[i] = (f(theta + bump) - f(theta - bump)) / (2 * h)     
    return out


def gradcheck(f, df, theta, h=1e-5):
    analytic = np.asarray(df(theta), dtype=float)
    numeric = numeric_grad(f, theta, h)
    return np.max(np.abs(analytic - numeric) / np.maximum(1e-8, np.abs(analytic) + np.abs(numeric)))

Die relative Form des Vergleichs ist wichtig: Eine absolute Differenz von 10410^{-4} ist bei einem Gradient der Größe 10310^{-3} eine Katastrophe und bei einem der Größe 10610^{6} irrelevant.

TEXT
relative error: 1.8929136036763527e-11
with 2 dropped: 0.33333333331650744

Die erste Zeile ist der oben von Hand hergeleitete Gradient. Die zweite ist dieselbe Funktion, bei der in einer Komponente der Faktor 2 fehlt — ein Tippfehler eines einzelnen Zeichens —, und der Check erwischt ihn sofort. Alles unter etwa 10710^{-7} ist Übereinstimmung; alles über 10410^{-4} ist ein Bug. Behalte diese Funktion: Kapitel 5 benutzt sie, um eine Automatic-Differentiation-Engine zu debuggen, und sie ist der einzige Grund, warum ein falscher Gradient überhaupt auffindbar ist.

Alles in diesem Kapitel beruhte auf einer Annahme, die nie ausgesprochen wurde: dass du L/θ\partial L / \partial \theta hinschreiben kannst.

Für eine Gerade mit zwei Parametern war das eine Zeile Algebra. Fast sofort ist es das nicht mehr. Bitte ein symbolisches Algebrasystem um die Ableitung des Loss eines Netzwerks nach einem einzigen Gewicht in der ersten Schicht, für ein einziges Beispiel, und zähle die Arithmetik in der Antwort:

NetzwerkOperationen in einer partiellen Ableitung
vier hidden units, eine Schicht40
vier hidden units, zwei Schichten301
vier hidden units, drei Schichten1.717

Die dritte Zeile ist ein Netzwerk mit 57 Parametern — ein Netzwerk, das so klein ist, dass es in Kapitel 6 eine Fußnote wäre —, und seinen Gradient von Hand auszuschreiben bedeutet etwa 97.869 Operationen für ein Trainingsbeispiel. Es gibt keine Notation, die das rettet. Was es rettet, ist die Beobachtung, dass die Kettenregel, angewendet auf eine Komposition, enorme Struktur hat, dass dieselben Zwischenwerte immer wieder auftauchen und dass ihre Berechnung in der richtigen Reihenfolge alle Ableitungen ungefähr zum Preis eines forward pass liefert. Das ist Kapitel 5.

Aber zuerst gibt es ein kleineres Problem, und es wartet unmittelbar.

Wir haben jetzt eine Maschine, die auf jedem differenzierbaren Loss bergab rollen wird. Richte sie auf die ursprüngliche Frage des Förderbands — akzeptieren oder ablehnen, ein Ziel, das 1 oder 0 ist —, setze ein Sigmoid auf die Ausgabe, sodass sie eine Wahrscheinlichkeit vorhersagt, und minimiere squared error. Sie wird laufen. Sie wird sich aber auch kaum bewegen, wenn sie am falschesten liegt, und der Gradient sagt warum:

Ausgabe zzVorhersageWahrheitGradient mit squared errorGradient mit Cross-Entropy
000.500012.5×1012.5 \times 10^{-1}5.0×1015.0 \times 10^{-1}
2-20.119211.850×1011.850 \times 10^{-1}8.808×1018.808 \times 10^{-1}
6-60.002514.921×1034.921 \times 10^{-3}9.975×1019.975 \times 10^{-1}
10-104.54×1054.54 \times 10^{-5}19.079×1059.079 \times 10^{-5}1.0001.000

Ein Modell, das selbstbewusst, katastrophal falsch liegt — es sagt 0,0000454 voraus, wenn die Antwort 1 ist —, erzeugt einen squared-error-Gradient von 9×1059 \times 10^{-5}. Es hat keine Ahnung, dass es in Schwierigkeiten steckt. Die andere Spalte, aus einem Loss, den wir noch nicht hergeleitet haben, meldet 1,0: maximale Dringlichkeit, genau dort, wo sie verdient ist.

Das wirft die Frage auf, mit der das nächste Kapitel beginnt. Das letzte Kapitel sagte, ein Loss sei eine Annahme über das Rauschen, und squared error nimmt Gaußsches Rauschen an. Welches Rauschmodell hat eine Ja-oder-Nein-Antwort — und welcher Loss kommt heraus, wenn du dieselbe Herleitung darauf anwendest?


Die Methode ist älter als all diese Quellen: Cauchy beschrieb sie 1847 in einer Notiz an die Académie des Sciences, als Verfahren zum Lösen von Gleichungssystemen, indem man auf der Summe ihrer quadrierten Residuen bergab geht. Ebenfalls lesenswert neben diesem Kapitel: Sebastian Ruders An overview of gradient descent optimization algorithms (arXiv:1609.04747), das Momentum bis Adam auf vierzehn gut lesbaren Seiten behandelt; Kapitel 3 von Nocedal und Wrights Numerical Optimization (2. Aufl., Springer, 2006), dessen Satz 3.3 die Konvergenzrate von steepest descent auf einer Quadrik in Bezug auf die Konditionszahl angibt — es ist die Theorie dahinter, warum die Konditionierung die Schrittzahl entscheidet, auch wenn es line search statt der oben gemessenen fixed-step-2/λmax2/\lambda_{\max}-Obergrenze behandelt —, oder §5.8 und §7.1 von Deisenroth, Faisal und Ongs Mathematics for Machine Learning für denselben Stoff mit weniger Maschinerie; §6.1 von Princes Understanding Deep Learning und §4.3 von Goodfellow, Bengio und Courvilles Deep Learning; Dive into Deep Learning §12.1–12.3, das die Minibatch-Analyse mit mehr Messungen enthält, als hier Platz haben; und Kapitel 4 von Géron's Hands-On Machine Learning (3. Aufl.), die praktischste Behandlung der Lernrate als etwas, das du abstimmst, statt herzuleiten. Die MIT-6.390-Notizen stellen gradient descent vor die Klassifikation, so wie dieser Kurs, und aus demselben Grund.

  1. LeCun, Y., Bottou, L., Orr, G. B. und Müller, K.-R. Efficient BackProp, in Neural Networks: Tricks of the Trade (Springer, 1998), S. 9–50. Abschnitt 4.3 gibt die Empfehlung und Abschnitt 5.1 das Argument, das in der Detailbox oben verwendet wurde: Zentrieren und Skalieren von Eingaben verändert die Eigenwerte der Matrix der zweiten Ableitungen und damit die Anzahl der Schritte, nicht nur den numerischen Komfort.

  2. Dauphin, Y. N., Pascanu, R., Gulcehre, C., Cho, K., Ganguli, S. und Bengio, Y. Identifying and attacking the saddle point problem in high-dimensional non-convex optimization, arXiv:1406.2572 (2014). Das Argument, dass kritische Punkte in hohen Dimensionen überwältigend oft Sättel statt lokale Minima sind, weil ein Minimum verlangt, dass jede einzelne von Tausenden Richtungen zugleich nach oben gekrümmt ist.

  3. Robbins, H. und Monro, S. A Stochastic Approximation Method. Annals of Mathematical Statistics 22(3), S. 400–407 (1951). Der Artikel, der etablierte, dass eine verrauschte Schätzung eines Gradient genügt, wenn die Schrittweite auf die richtige Weise schrumpft.

  4. Polyak, B. T. Some methods of speeding up the convergence of iteration methods. USSR Computational Mathematics and Mathematical Physics 4(5), S. 1–17 (1964). Die Heavy-Ball-Methode, also das Momentum-Update oben, zweiundzwanzig Jahre bevor backpropagation dieses Feld erreichte.

Bereit, LIA die Wahl zu überlassen?

Bau mit jedem KI-Modell an einem Ort — starte heute kostenlos.