Machine Learning für Softwareentwickler. Paolo Perrotta
Чтение книги онлайн.
Читать онлайн книгу Machine Learning für Softwareentwickler - Paolo Perrotta страница 18
print("Prediction: x=%d => y=%.2f" % (20, predict(20, w, b)))
Die Funktion gradient() gibt jetzt die partiellen Ableitungen des Verlusts nach w und b zurück. Anhand dieser Werte verändert train() gleichzeitig w und b. Außerdem habe ich die Anzahl der Iterationen heraufgesetzt, da das Programm jetzt zwei Variablen optimieren muss und daher länger benötigt, um in die Nähe des Minimums zu gelangen.
Um diese neue Version des Programms unter gleichartigen Bedingungen mit derjenigen aus dem vorherigen Kapitel zu vergleichen, führen wir zunächst Letztere mit einer großen Anzahl von Iterationen und einer ziemlich niedrigen lr von 0,0001 aus, sodass wir eine Genauigkeit auf vier Dezimalstellen erhalten:
...
Iteration 157777 => Loss: 22.842737
w=1.081, b=13.171
Prediction: x=20 => y=34.80
Unsere neue Implementierung mit Gradientenverfahren nähert sich dem Ergebnis auf spiralförmigem Kurs. Nach nur 20.000 Iterationen erhalten wir folgendes Resultat:
...
Iteration 19999 => Loss: 22.8427367616
w=1.0811301700, b=13.1722676564
Prediction: x=20 => y=34.79
Höhere Genauigkeit mit einem Zehntel an Iterationen – großartig! Für unser Pizzavorhersageproblem mag dieses schnellere und genauere ML-Programm zu viel des Guten sein, denn schließlich kauft niemand eine Hundertstel Pizza. Der Geschwindigkeitsgewinn jedoch wird sich bei anspruchsvolleren Problemen noch als äußerst wichtig erweisen.
Abschließend habe ich noch ein kurzes Visualisierungsprogramm geschrieben, um den Pfad auszugeben, den der Algorithmus von einem willkürlichen Ausgangspunkt zum Minimum des Verlusts nimmt. Sie wissen inzwischen zwar schon, wie das Gradientenverfahren abläuft, aber nichts geht über eine grafische Darstellung:
Die Wanderin hat nicht den kürzesten Weg zum Lager genommen, da sie die Route schließlich nicht im Voraus kannte. Stattdessen hat sie sich bei jedem Schritt an der Verlustfunktion orientiert. Nach zwei abrupten Richtungswechseln hat sie endlich die Talsohle erreicht und ist dem sanft absteigenden Pfad zum Lager gefolgt.
Probleme beim Gradientenverfahren
Bei der Anwendung des Gradientenverfahrens gibt es keine Erfolgsgarantie. Die gefundene Route ist nicht unbedingt die kürzeste. Es kann auch sein, dass wir am Lager vorbeigehen und wieder zurückmarschieren müssen oder dass wir uns sogar vom Lager entfernen.
Außerdem gibt es einige unglückselige Fälle, bei denen das Gradientenverfahren das Ziel völlig verfehlt. Einer davon hat mit der Lernrate zu tun. Wir werden ihn uns in der praktischen Übung am Ende dieses Kapitels noch genauer ansehen. Die meisten Probleme beim Gradientenverfahren gehen jedoch auf die Form der Verlustoberfläche zurück.
Mit etwas Fantasie lassen sich durchaus Oberflächen denken, auf denen unsere Wanderin auf dem Weg zum Lager zu Fall kommt. Was passiert, wenn die Verlustoberfläche wie in der folgenden Abbildung einen abrupten Absturz enthält, über dem die Wanderin wie Wile E. Coyote mit den Beinen rudernd in der Luft hängt?
Ein anderes Problem besteht darin, dass die Wanderin statt des globalen Minimums, zu dem sie unterwegs ist, nur ein lokales Minimum wie in der folgenden Abbildung erreicht.
Am Boden des lokalen Minimums beträgt die Steigung null. Wenn das Gradientenverfahren dort hingelangt, steckt es fest.
Langer Rede kurzer Sinn: Das Gradientenverfahren funktioniert gut, solange die Verlustoberfläche bestimmte Eigenschaften aufweist. Mathematisch ausgedrückt, muss eine gute Verlustfunktion konvex sein (keine lokalen Minima aufweisen), stetig (frei von Lücken und Abstürzen) und differenzierbar (glatt, also ohne Spitzen und andere eigentümliche Stellen, an denen es nicht möglich ist, die Ableitung zu berechnen). Unsere jetzige Verlustfunktion erfüllt alle drei Voraussetzungen, ist also ideal für den Gradientenabstieg geeignet. Wir werden das Verfahren später noch auf andere Funktionen anwenden, die wir dabei zunächst auf die genannten Voraussetzungen überprüfen müssen.
Das Gradientenverfahren ist auch der Hauptgrund dafür, dass wir den Verlust als mittleren quadratischen Fehler implementiert haben. Wir hätten auch den mittleren Absolutwert des Fehlers nehmen können, allerdings ist diese Funktion nicht gut für das Gradientenverfahren geeignet, da sie beim Wert 0 eine nicht differenzierbare Spitze aufweist. Außerdem werden die Fehlerwerte durch das Quadrieren noch größer, was dazu führt, dass die Oberfläche sehr steil wird, wenn wir uns vom Minimum entfernen. Umgekehrt bringt dieser steile Verlauf es natürlich mit sich, dass sich das Gradientenverfahren dem Minimum rasant nähert. Aufgrund der Glätte und Steilheit ist der mittlere quadratische Fehler sehr gut für dieses Verfahren geeignet.
Zusammenfassung
In diesem Kapitel haben wir uns mit dem Gradientenverfahren beschäftigt, dem am häufigsten verwendeten Algorithmus zur Minimierung des Verlusts. Wie kompliziert unser Modell und die Datenmenge auch sein mögen, das Gradientenverfahren funktioniert immer auf die gleiche Weise: Es geht immer einen Schritt in die entgegengesetzte Richtung des Verlustgradienten, bis dieser Gradient sehr klein geworden ist. Um den Gradienten zu finden, berechnen wir die partiellen Ableitungen des Verlusts nach w und b.
Das Gradientenverfahren hat jedoch seine Grenzen. Da es auf Ableitungen basiert, muss die Verlustfunktion glatt und lückenlos sein, damit die Ableitung überall berechnet werden kann. Des Weiteren ist es möglich, dass das Verfahren in einem lokalen Minimum stecken bleibt und das globale Minimum nicht mehr erreicht. Um diese Probleme zu vermeiden, verwenden wir glatte Verlustfunktionen mit einem einzigen Minimum.
Das Gradientenverfahren ist nicht das Nonplusultra der Algorithmen zur Verlustminimierung. Forscher suchen nach anderen Algorithmen, die für bestimmte Umstände besser geeignet sind. Es gibt auch Variationen des regulären Verfahrens, von denen wir in diesem Buch noch einige kennenlernen werden. Nichtsdestoweniger ist das Gradientenverfahren im modernen ML von entscheidender Bedeutung und wird es auch noch lange bleiben.
Wappnen Sie sich jetzt für eine Herausforderung! Zu Beginn des Kapitels habe ich gesagt, dass es durch Anwendung des Gradientenverfahrens möglich wird, unseren Code auch auf interessantere Modelle zu übertragen und eine Annäherung an kompliziertere Datenmengen zu erreichen. Im nächsten Kapitel werden wir uns ein solches Modell ansehen.
Praktische Übung: Über das Ziel hinaus
Kommen wir noch einmal auf die Lernrate zurück. Im letzten Beispiel dieses Kapitels haben wir eine Lernrate von 0,001 verwendet. Wenn Sie die Lernrate erhöhen, werden Sie feststellen, dass der Verlust schließlich zu steigen beginnt anstatt weiter zu sinken. Können Sie sich denken, warum das so ist?
Wenn Sie den Grund durch abstraktes Nachdenken nicht herausfinden können, versuchen Sie, die Verlustfunktion aufzuzeichnen. Was geschieht bei einer sehr großen Lernrate? Die Antwort finden Sie im Verzeichnis 03_gradient/solution.