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 kannstNoch 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.
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 gDie 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, , und der Loss ist der mittlere quadratische Fehler, den das vorige Kapitel hergeleitet hat:
Zwei Parameter. Warum nicht einfach viele Werte ausprobieren? Machen wir das tatsächlich — ein Gitter von bis und bis , in Schritten von :
grid 501 x 1001 = 501,501 evaluations in 3.67 s
best found: a = 2.1000, b = -0.0000, L = 24.592450Eine 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 Auswertungen für Parameter mit jeweils Werten. Mit tausend Werten pro Achse:
| Modell | Parameter | Gitterauswertungen |
|---|---|---|
| diese Gerade | 2 | |
| das XOR-Netzwerk aus Kapitel 5 | 9 | |
| ein kleines mehrschichtiges Netzwerk | 20,000 |
Die dritte Zeile ist keine große Zahl, sie ist eine bedeutungslose — im beobachtbaren Universum gibt es ungefähr 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 kannstFixiere 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, , und frag: Wenn ich um einen kleinen Betrag anstoße, wie stark bewegt sich der Loss pro Einheit dieses Stoßes?
Dieses Verhältnis ist Anstieg über Lauf — die Steigung der Geraden durch zwei Punkte auf der Kurve. Wenn schrumpft, rutschen die beiden Punkte zusammen und die Gerade wird zur Tangente. Ihre Steigung ist die Ableitung : die Rate, mit der sich der Loss pro Änderungseinheit in ä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:
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}")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-01Hier passieren zwei Dinge, und beide tragen Gewicht.
Der Fehler ist nicht vage proportional zu — er ist exakt . Teile 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 aussieht.
Und dann bricht das Muster. Unterhalb von wird die Schätzung schlechter, und bei ist sie schon in der zweiten Ziffer falsch. Mathematisch ist nichts passiert; die Floating-Point-Box aus dem letzten Kapitel ist passiert. und 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 — hier etwa , 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 . Also können wir aufhören zu messen und anfangen herzuleiten.
Komposition und die Kettenregel
Link zum Abschnitt: Komposition und die KettenregelHier 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: . 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 und sonst nichts. Das bedeutet: Die für unsere Zwecke wichtigste Regel der Analysis ist die, die eine Komposition ableitet:
Raten multiplizieren sich. Wenn sich dreimal so schnell ändert wie und sich doppelt so schnell ändert wie , dann ändert sich sechsmal so schnell wie . 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 , sodass . Jedes hängt über die innere Funktion von ab, deren Ableitung ist. Kettenregel, Term für Term:
Diese geschweiften -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:
Am Punkt ist dieser Vektor . Zwei Zahlen. Die Frage ist, was sie bedeuten, und das ist der erste Schritt, den alle überspringen.
Warum der Gradient bergauf zeigt
Link zum Abschnitt: Warum der Gradient bergauf zeigtDer 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 , eine Richtung. Die Richtungsableitung ist die Rate, mit der sich der Loss ändert, wenn du in diese Richtung gehst:
Die Kettenregel verwandelt das in etwas Berechenbares. Beim Gehen entlang ändert sich mit Rate und mit Rate , und die Beiträge addieren sich:
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 zwischen den Vektoren:
da die Länge 1 hat. Das Einzige, was du kontrollierst, ist , das bei am größten und bei einer halben Drehung, Grad, am kleinsten ist. Also:
- Der steilste Anstieg liegt entlang von selbst, und die Steigung dort ist exakt .
- Der steilste Abstieg liegt entlang von , und die Steigung dort ist .
- 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 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ß:
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")gradient [-16.385 8. ]
its length 18.23371122399386
its angle 153.97598928042032 degrees
steepest slope 18.233709624837502 at 154.0 degreesEine 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 hilftJetzt 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:
Das ist die Taylor-Entwicklung erster Ordnung. Das verworfene ist die Krümmung — derselbe Term, der die Schätzung in der Steigungstabelle um exakt falsch gemacht hat. Setze den Schritt ein, den wir machen wollen, :
Der Loss fällt um . Jeder Teil davon ist nichtnegativ, also ist das Versprechen real — für ein ausreichend kleines , denn der vernachlässigte Term wächst wie und frisst es irgendwann auf. Das ist die ganze Theorie. Hier wird das Versprechen gehalten und dann gebrochen:
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.999938Lies es von unten. Wenn 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 ist der tatsächliche „Abfall“ minus sechzehn. Der Schritt ging bergab, und der Loss ging nach oben.
Die Update-Regel lautet also
und sie kommt mit einer Bedingung, die niemand ausspricht: 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 berechenbarBeginne mit dem einfachsten Tal, das es gibt: , wobei . Ein Schritt von gradient descent ist
Die Position wird in jedem Schritt mit 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 , also .
Die Grenze liegt exakt bei . Nicht „ungefähr 1“, nicht „1 ist meistens zu groß“. Bei ist der Multiplikator , und der Punkt springt für immer zwischen und hin und her, ohne sich zu nähern oder zu entkommen. Darunter: Konvergenz; darüber: Divergenz. Das Intervall teilt sich bei 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 ist der Multiplikator 0 und ein einziger Schritt landet im Minimum.
Vier Regime aus vier Zeilen Algebra. Überschreite die Grenzen selbst:
Und jetzt der interessante Fall:
Nun die allgemeine Regel, die aus demselben Argument herausfällt. Der Multiplikator war in Wahrheit , 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:
Für , , Obergrenze 1, genau das, was wir gerade hergeleitet haben. Für unser Förderband ist die Matrix der zweiten Ableitungen mit als zweispaltiger Eingabematrix, und ihre Eigenwerte sind 2 und 14,89, also ist die Obergrenze . Das ist eine Vorhersage mit fünf signifikanten Stellen. Teste sie:
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 UPFü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:
| Features | Konditionszahl | beste Rate | Schritte bis auf 1% des Optimums |
|---|---|---|---|
| zentriert | 7,44 | 0,1184 | 10 |
| rohe Millimeter und Gramm | 33.452 | 0,0020037 | 79.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
Zwanzig Zeilen
Link zum Abschnitt: Zwanzig ZeilenNichts oben brauchte eine Bibliothek. Hier ist der ganze Optimierer.
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))[ 2.10040296e+00 -2.76445533e-15] 24.592448791134984Die geschlossene Least-Squares-Lösung für diese acht Punkte ist , , mit einem Loss von . 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:
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.592449Der 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.
Wo die Steigung sonst noch null ist
Link zum Abschnitt: Wo die Steigung sonst noch null istDas bisherige Argument hat ein Loch. Der Schritt stoppt, wenn , 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 hat , was am Ursprung null ist, wo die Funktion entlang der -Achse ein Minimum und entlang der -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 , das zwei Täler unterschiedlicher Tiefe hat:
x = -1.046681 f(x) = -0.352386 minimum
x = 0.101031 f(x) = 0.005026 maximum
x = 0.945649 f(x) = -0.152639 minimumIm 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, MomentumEine 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:
| Methode | Schritte bis auf 0,1% des Optimums | Gradienten pro Beispiel |
|---|---|---|
| full batch | 7 | 700.000 |
| Minibatch von 32 | 100 | 3.200 |
| ein Beispiel auf einmal | 17.580 | 17.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
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:
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 wirstJeder 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, , die den führenden Fehlerterm aufhebt und für dasselbe sehr viel genauer ist.
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 ist bei einem Gradient der Größe eine Katastrophe und bei einem der Größe irrelevant.
relative error: 1.8929136036763527e-11
with 2 dropped: 0.33333333331650744Die 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 ist Übereinstimmung; alles über 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.
Wohin es als Nächstes geht
Link zum Abschnitt: Wohin es als Nächstes gehtAlles in diesem Kapitel beruhte auf einer Annahme, die nie ausgesprochen wurde: dass du 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:
| Netzwerk | Operationen in einer partiellen Ableitung |
|---|---|
| vier hidden units, eine Schicht | 40 |
| vier hidden units, zwei Schichten | 301 |
| vier hidden units, drei Schichten | 1.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 | Vorhersage | Wahrheit | Gradient mit squared error | Gradient mit Cross-Entropy |
|---|---|---|---|---|
| 0.5000 | 1 | |||
| 0.1192 | 1 | |||
| 0.0025 | 1 | |||
| 1 |
Ein Modell, das selbstbewusst, katastrophal falsch liegt — es sagt 0,0000454 voraus, wenn die Antwort 1 ist —, erzeugt einen squared-error-Gradient von . 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?
Quellen und Methode
Link zum Abschnitt: Quellen und MethodeDie 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--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.
Referenzen
Link zum Abschnitt: Referenzen-
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. ↩
-
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. ↩
-
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. ↩
-
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. ↩