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

Автор: Paolo Perrotta
Издательство: Bookwire
Серия:
Жанр произведения: Математика
Год издания: 0
isbn: 9783969100264
Скачать книгу
gradient(X, Y, w):

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

      Mit der Formel für den Gradienten können wir nun train() so umschreiben, dass die Funktion das Gradientenverfahren anwendet.

      Mit den Änderungen für das Gradientenverfahren sieht train() wie folgt aus:

       03_gradient/gradient_descent_without_bias.py

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

      w = 0

      for i in range(iterations):

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

      w -= gradient(X, Y, w) * lr

      return w

      Diese Version von train() ist viel knapper als die vorherige. Bei Anwendung des Gradientenverfahrens brauchen wir keine if-Anweisungen mehr. Wir müssen lediglich w initialisieren und dann wiederholt in die dem Gradienten entgegengesetzte Richtung gehen (da der Gradient aufwärts zeigt, wir uns aber abwärts bewegen wollen). Der Hyperparameter lr ist immer noch da, gibt jetzt aber an, wie groß jeder einzelne Schritt im Verhältnis zum Gradienten sein soll.

      Außerdem müssen wir entscheiden, wann wir aufhören wollen. Die alte Version von train() endete, wenn die Höchstzahl der Iterationen erreicht oder es nicht mehr möglich war, den Verlust weiter zu verringern. Beim Gradientenverfahren dagegen kann der Verlust theoretisch immer kleiner werden und sich in immer winzigeren Schritten dem Minimum nähern, ohne es jemals zu erreichen. Wann sollten wir diesen Vorgang abbrechen?

      Wir können aufhören, wenn der Gradient ausreichend klein geworden ist, da das bedeutet, dass wir dem Minimum schon sehr nahe gekommen sind. Der vorstehende Code dagegen verfolgt einen weniger raffinierten Ansatz: Wenn Sie train() aufrufen, geben Sie an, wie viele Iterationen die Funktion durchlaufen soll. Mehr Iterationen bedeuten einen geringeren Verlust, aber da der Verlust in immer geringem Maße sinkt, ist irgendwann ein Punkt erreicht, an dem eine größere Präzision den Aufwand nicht mehr lohnt.

      Weiter hinten in diesem Buch (in Kapitel 15, »Entwicklung«) erfahren Sie, wie Sie sinnvolle Werte für Hyperparameter wie iterations und lr auswählen. Vorläufig habe ich einfach verschiedene Werte ausprobiert und mich für diejenigen entschieden, die zu einem ausreichend geringen Verlust und genügender Genauigkeit führten:

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

      w = train(X, Y, iterations=100, lr=0.001)

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

      Bei der Ausführung dieses Codes ergibt sich Folgendes:

      Iteration 0 => Loss: 812.8666666667

      Iteration 1 => Loss: 304.3630879787

      Iteration 2 => Loss: 143.5265791020

      ...

      Iteration 98 => Loss: 69.1209628275

      Iteration 99 => Loss: 69.1209628275

      w=1.8436928702

      Wie beabsichtigt wird der Verlust mit jedem Durchlauf geringer. Nach 100 Iterationen kommt das Verfahren dem Minimum so nahe, dass wir schon keinen Unterschied mehr zwischen den beiden letzten Verlustwerten erkennen können. Unser Algorithmus scheint seine Aufgabe wie erwartet zu erfüllen.

      Aber halt – wir haben ja nur den Parameter w verwendet! Was passiert, wenn wir b wieder mit ins Spiel nehmen?

      Sehen wir uns die Verlustfunktion noch einmal in der mathematischen Schreibweise an:

image

      Bis jetzt haben wir bis auf w alle Werte in dieser Formel als Konstanten behandelt. Vor allem haben wir b auf 0 festgelegt. Wenn wir b wieder zu einer Variablen machen, dann ist der Verlust keine zweidimensionale Kurve mehr, sondern eine Oberfläche:

image

      Jetzt lebt unsere Wanderin nicht mehr im Plattland, sondern kann sich in drei Dimensionen bewegen. Die Werte von w und b bilden die beiden horizontalen Achsen und die Werte des Verlusts die vertikale. Anders ausgedrückt steht jeder Punkt auf dieser Oberfläche für den Fehler in einer Geraden unseres Modells. Wir wollen nun die Gerade mit dem geringsten Fehler finden: den mit dem Kreuz markierten Punkt.

      Auch wenn der Verlust jetzt eine Oberfläche ist, können wir das Minimum immer noch mit dem Gradientenverfahren erreichen, wobei wir allerdings den Gradienten einer Funktion mit mehreren Variablen berechnen müssen. Das können wir mit der Technik der partiellen Ableitung erreichen.

      Was ist eine partielle Ableitung, und wie kann sie uns weiterhelfen? Stellen Sie sich vor, dass Sie die Funktion mit einem Samuraischwert aufschlitzen und dann die Ableitung des Schlitzes berechnen. (Es muss kein Samuraischwert sein, aber damit sieht es besonders cool aus.) Beispielsweise haben wir bisher b auf 0 festgelegt und den Verlust damit wie folgt aufgeschlitzt:

image

      Dieser Schlitz ist genau die Verlustkurve, die wir bei der ersten Anwendung des Gradientenverfahrens behandelt haben. Sie sieht hier ein bisschen flachgedrückt aus, da ich andere Intervalle und Maßstäbe für die Achsen verwendet habe, aber es ist genau dieselbe Funktion. Für jeden Wert von b gibt es eine solche Kurve, deren einzige Variable w ist. Ebenso gibt es aber auch für jeden Wert von w eine Kurve mit der Variablen b. Für w = 0 sieht sie wie folgt aus:

image

      Für jeden dieser eindimensionalen »Schlitze« können wir den Gradienten berechnen, wie wir es bei unserer ursprünglichen Kurve getan haben. Das Schöne daran ist, dass wir die Gradienten dieser Schlitze kombinieren können, um die Gradienten der Oberfläche zu erhalten, wie die folgende Abbildung zeigt:

image

      Mithilfe von partiellen Ableitungen können wir unser Problem mit zwei Variablen in zwei Probleme mit einer Variablen aufteilen. Wir brauchen also keinen neuen Algorithmus, um das Gradientenverfahren auf einer Oberfläche anzuwenden, sondern können diese Oberfläche einfach mithilfe partieller Ableitungen aufteilen und auf jedem Teil unser bisheriges Verfahren nutzen.

       Mathematischer Hintergrund: Ableitungen und Analysis

      Der Zweig der Mathematik, der sich mit Gradienten, Ableitungen und partiellen Ableitungen beschäftigt, ist die Analysis. Wenn Sie sich intensiver damit beschäftigen wollen, werfen Sie einen Blick auf die Khan Academy.1 Auch zu diesem Thema finden Sie dort weit mehr Informationen, als Sie zum Verständnis dieses Buchs benötigen.

      Um die partiellen Ableitungen konkret zu berechnen, leiten Sie die Funktion jeweils nach einer der Variablen ab (in unserem Fall also w oder b) und tun dabei so, als ob dies die einzige Variable in der Funktion und jeder andere Wert konstant wäre. Die Hälfte dieser Arbeit haben wir bereits erledigt, als wir b auf 0 gesetzt und L nach w abgeleitet haben:

image

      Jetzt müssen wir das Gleiche noch einmal tun, dabei aber w als Konstante betrachten und L nach b ableiten. Wenn Sie mit Analysis vertraut sind, können Sie sich selbst daran versuchen. Ansonsten finden