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

Автор: Paolo Perrotta
Издательство: Bookwire
Серия:
Жанр произведения: Математика
Год издания: 0
isbn: 9783969100264
Скачать книгу
Y = np.loadtxt("pizza.txt", skiprows=1, unpack=True)

       # Trainiert das System

      w = train(X, Y, iterations=10000, lr=0.01)

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

       # Sagt die Anzahl der Pizzas vorher

      print("Prediction: x=%d => y=%.2f" % (20, predict(20, w)))

      Beim Aufruf von train() müssen wir Werte für iterations und lr bereitstellen. Vorläufig bestimmen wir sie durch Ausprobieren. Ich habe hier 10.000 Iterationen verlangt, was nach einem guten Ausgangswert aussieht. Für lr, also die Stärke der Änderung von w bei jedem Trainingsschritt, habe ich 0,01 angegeben, was genau genug erscheint, um Pizzas zu zählen.

      Wenn wir das Programm ausführen, konvergiert train() bereits nach 200 Iterationen:

      Iteration 0 => Loss: 812.866667

      Iteration 1 => Loss: 804.820547

      Iteration 2 => Loss: 796.818187

      ...

      Iteration 184 => Loss: 69.123947

      w=1.840

      Prediction: x=20 => y=36.80

      Der Verlust ist bei jeder Iteration geringer geworden, bis der Algorithmus schließlich nicht mehr versucht hat, ihn noch weiter einzuschränken. An diesem Punkt beträgt das Gewicht 1,84. Das ist die Anzahl der Pizzas, die Roberto für jede Reservierung zu verkaufen erwarten darf. Bei 20 Reservierungen können wir also mit etwa 36,80 Pizzas rechnen. (Roberto verkauft zwar keine Bruchteile von Pizzas, ist aber der genaue Typ, der lieber eine Dezimalstelle zu viel als zu wenig berücksichtigt.)

      Mit der Berechnung von w hat unser Code gewissermaßen eine Gerade in das Diagramm eingezeichnet wie im folgenden Graphen. (Den Code für die Diagrammausgabe finden Sie wie immer im Begleitcode zu diesem Buch.)

image

      Das ist schon ein schönes Ergebnis. Wir können es aber noch verbessern.

      Wenn Sie sich das vorstehende Diagramm ansehen, können Sie erkennen, dass unsere Gerade nicht die beste Annäherung an die Beispiele darstellt. Die ideale Gerade würde flacher sein und nicht durch den Ursprung gehen, sondern die Pizza-Achse etwa beim Wert 10 schneiden.

      Bis jetzt haben wir dafür gesorgt, dass die Gerade durch den Ursprung verläuft, um unser Modell so einfach wie möglich zu halten. Allerdings sollten wir diese Einschränkung jetzt lieber aufgeben. Um eine Gerade zu zeichnen, die nicht durch den Ursprung geht, müssen wir unserem Modell einen weiteren Parameter hinzufügen:

      ŷ = x * w + b

      Das kommt Ihnen vielleicht bekannt vor. Es handelt sich hierbei um die klassische lineare Funktion, die Sie im Mathematikunterricht in der Mittelstufe kennengelernt haben, gewöhnlich in der Form y = m * x + t, wobei m als Steigung und t als y-Achsenabschnitt bezeichnet wird. Hier wollen wir jedoch die ML-Terminologie verwenden und w das Gewicht und b den Bias nennen (eigentlich die »systematische Abweichung«).

      Anschaulich betrachtet ist der Bias ein Maß dafür, wie weit die Gerade nach oben oder unten verschoben wird (siehe die folgende Abbildung). Die Gerade schneidet die y-Achse beim Wert b. Bei b = 0 ergibt sich wieder unser vorheriger Fall einer Geraden, die durch den Ursprung verläuft.

image

      Unter Verwendung des neuen Modells mit zwei Parametern sieht das komplette Programm zur linearen Regression nun wie folgt aus (wobei die kleinen Pfeile die geänderten Zeilen kennzeichnen):

       02_first/linear_regression_with_bias.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 train(X, Y, iterations, lr):

      w = b = 0 <

      for i in range(iterations):

      current_loss = loss(X, Y, w, b) <

      print("Iteration %4d => Loss: %.6f" % (i, current_loss))

      if loss(X, Y, w + lr, b) < current_loss: <

      w += lr

      elif loss(X, Y, w - lr, b) < current_loss: <

      w -= lr

      elif loss(X, Y, w, b + lr) < current_loss: <

      b += lr <

      elif loss(X, Y, w, b - lr) < current_loss: <

      b -= lr <

      else:

      return w, b <

      raise Exception("Couldn't converge within %d iterations" % iterations)

       # Importiert den datensatz

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

       # Trainiert das System

      w, b = train(X, Y, iterations=10000, lr=0.01) <

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

       # Sagt die Anzahl der Pizzas vorher

      print("Prediction: x=%d => y=%.2f" % (20, predict(20, w, b))) <

      Die meisten Zeilen haben sich geändert, aber all diese Änderungen betreffen nur die Einführung des neuen Parameters b. Von besonderer Bedeutung sind die Änderungen in der Funktion predict(), die jetzt das neue Modell nutzt, und train(), in der b jetzt auf die gleiche Weise unter Berücksichtigung des Verlusts erhöht und erniedrigt wird wie w. Es war mir nicht ganz klar, wie ich w und b gleichzeitig verändern sollte, weshalb ich einen dieser provisorischen Hacks verwendet habe, die wir alle so lieben: Ich habe einfach ein paar neue Zweige zu der if-Anweisung hinzugefügt.

      Probieren wir das Programm nun aus! Die Funktion train() braucht jetzt länger, um zu konvergieren, kommt aber schließlich doch zum Ziel:

      Iteration 0 => Loss: 812.867

      Iteration 1 => Loss: 804.821

      Iteration 2 => Loss: 796.818

      ...

      Iteration 1551 => Loss: 22.864

      w=1.100, b=12.930

      Prediction: x=20 => y=34.93

      Der Graph mit der Näherungsgeraden sieht wie folgt aus:

image

      Jetzt nähert sich die Gerade den Beispielen schon viel besser an! Vor allem ist der resultierende Verlust geringer als zuvor, was bedeutet, dass wir die Pizzaverkäufe auch viel genauer vorhersagen können. Roberto wird sich freuen.

      Das war eine Menge Arbeit für die erste Version unseres Programms. Halten wir kurz inne, treten wir einen Schritt zurück und sehen wir uns das Gesamtbild an.

      Beim überwachten Lernen resultiert die Trainingsphase in einem Satz von Werten, die wir im Modell verwenden können. In unserem Fall handelt es sich dabei um