Machine Learning für Softwareentwickler. Paolo Perrotta. Читать онлайн. Newlib. NEWLIB.NET

Автор: Paolo Perrotta
Издательство: Bookwire
Серия:
Жанр произведения: Математика
Год издания: 0
isbn: 9783969100264
Скачать книгу
alt="image"/>

      Wie funktioniert das Gradientenverfahren nun auf einer zweidimensionalen Verlustfläche? Unsere Wanderin steht an einem Punkt mit einem gegebenen Wert von w und b und hat die Formeln für die Berechnung der partiellen Ableitung von L nach w und b. Sie gibt die aktuellen Werte von w und b in diese Formeln ein und erhält dadurch einen Gradienten für jede Variable. Anschließend wendet sie das Gradientenverfahren auf beide Gradienten an – und schon kann sie dem Gradienten der Oberfläche folgend absteigen.

      Das reicht erst einmal an Mathematik für dieses Kapitel. Jetzt wollen wir den Algorithmus in Code umsetzen.

      In der Version mit zwei Variablen sieht unser Code für das Gradientenverfahren wie folgt aus, wobei die geänderten Zeilen wiederum durch kleine Pfeile gekennzeichnet sind:

       03_gradient/gradient_descent_final.py

       import numpy as np

      def predict(X, w, b):

      return X * w + b

      def loss(X, Y, w, b):

      return np.average((predict(X, w, b) - Y) ** 2)

      def gradient(X, Y, w, b): <

      w_gradient = 2 * np.average(X * (predict(X, w, b) - Y)) <

      b_gradient = 2 * np.average(predict(X, w, b) - Y) <

      return (w_gradient, b_gradient) <

      def train(X, Y, iterations, lr):

      w = b = 0 <

      for i in range(iterations):

      print("Iteration %4d => Loss: %.10f" % (i, loss(X, Y, w, b))) <

      w_gradient, b_gradient = gradient(X, Y, w, b) <

      w -= w_gradient * lr <

      b -= b_gradient * lr <

      return w, b <

      X, Y = np.loadtxt("pizza.txt", skiprows=1, unpack=True)

      w, b = train(X, Y, iterations=20000, lr=0.001) <

      print("\nw=%.10f, b=%.10f" % (w, b))

      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:

image

      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.

      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?

image

      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.

image

      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.

      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