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

Автор: Paolo Perrotta
Издательство: Bookwire
Серия:
Жанр произведения: Математика
Год издания: 0
isbn: 9783969100264
Скачать книгу
Mit einer solchen Funktion können wir verschiedene Geraden bewerten, bis wir eine mit einem ausreichend niedrigen Fehler finden; wobei ML-Experten jedoch nicht von »Fehler« sprechen, sondern von »Verlust«.

      Wie schreiben wir nun diese Verlustfunktion? Nehmen Sie an, wir haben Zufallswert für w, sagen wir 1.5. Versuchen wir nun, mit diesem w vorherzusagen, wie viele Pizzas wir verkaufen können, wenn wir beispielsweise 14 Reservierungen haben. Der Aufruf von predict(14, 1.5) liefert das Ergebnis ŷ = 21 Pizzas.

      Diese Vorhersage entspricht aber nicht der Grundwahrheit, also den realen Beispielen aus Robertos Datei. Betrachten Sie dazu noch einmal die ersten Beispiele:

       02_first/pizza.txt

Reservierungen Pizzas
13 33
2 16
14 32
23 51

      An dem Abend mit den 14 Reservierungen hat Roberto 32 Pizzas verkauft und nicht 21. Daraus können wir den Fehler als Differenz zwischen dem vorhergesagten Wert ŷ und der Grundwahrheit berechnen. Dieser Fehler ist der orangefarbene Balken im folgenden Graphen:

image

      Im Code sieht diese Berechnung wie folgt aus:

      error = predict(X, w) - Y

      Es gibt jedoch ein kleines Problem bei dieser Berechnung: error kann hier null, positiv oder negativ sein. Allerdings sollte ein Fehler immer positiv sein, denn wenn Sie mehrere Fehler addieren, wie wir es in Kürze tun werden, dann sollen sich zwei entgegengesetzte Fehler nicht ausgleichen. Um zu garantieren, dass der Fehler stets positiv ist, quadrieren wir ihn:

      squared_error = error ** 2

      Statt des Quadrats könnten wir auch den Absolutwert des Fehlers verwenden. Allerdings bietet die Quadrierung noch weitere Vorteile, wie Sie im nächsten Kapitel sehen werden.

      Wenn wir jetzt den Durchschnitt der quadrierten Fehler für alle Beispiele bilden, erhalten wir den Verlust. Diese Vorgehensweise zur Berechnung des Verlusts wird als mittlerer quadratischer Fehler bezeichnet und in der Statistik häufig verwendet. Im Code sieht dies wie folgt aus:

       02_first/linear_regression.py

      def loss(X, Y, w):

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

      Da sowohl X als auch Y NumPy-Arrays sind, können wir den Code ziemlich knapp halten. In loss() multiplizieren wir jedes Element von X mit w, was ein Array aus Vorhersagen ergibt, berechnen dann für jede Vorhersage den Fehler als Differenz zwischen der Vorhersage und der Grundwahrheit, quadrieren den Fehler mit dem Potenzoperator ** und weisen NumPy schließlich an, den Durchschnitt der quadrierten Fehler zu ermitteln. Das alles geschieht in einer einzigen Zeile! Und schon haben wir den mittleren quadratischen Fehler.

      Damit ist die Funktion loss() auch schon fertig, sodass wir uns der letzten Funktion unseres ML-Programms zuwenden können.

       Zu viel Jargon?

      »Mittlerer quadratischer Fehler«, »Modell«, »Verlust« … schon auf diesen paar Seiten werden Sie mit neuen Begriffen bombardiert. Eine Übersicht solcher Begriffe finden Sie in Anhang B, »Wörterbuch des Machine Learning«. Sollte ein Begriff dort nicht aufgeführt sein, schlagen Sie ihn im Index nach.

       Näher und näher

      Bei der Trainingsphase mit linearer Regression geht es darum, eine Gerade zur Annäherung der Beispiele zu finden. Mit anderen Worten, wir wollen w aus den Werten von X und Y berechnen. Dazu können wir einen iterativen Algorithmus verwenden:

       02_first/linear_regression.py

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

      w = 0

      for i in range(iterations):

      current_loss = loss(X, Y, w)

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

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

      w += lr

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

      w -= lr

      else:

      return w

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

      Die Funktion train() durchläuft immer wieder die Beispiele, bis sie gelernt hat, wie sie sie annähern kann. Ihre Argumente sind X, Y, die Anzahl der Iterationen (iterations) und der Wert lr (dessen Bedeutung ich in Kürze erklären werde). Zu Anfang initialisiert der Algorithmus w willkürlich mit dem Wert 0. Dieses w stellt eine Gerade im Diagramm dar. Es ist zwar unwahrscheinlich, dass sie eine gute Annäherung an die Beispiele darstellt, aber sie bildet wenigstens einen Ausgangspunkt.

      Anschließend tritt train() in eine Schleife ein. Jeder Durchlauf beginnt mit der Berechnung des aktuellen Verlusts. Anschließend wird eine alternative Gerade betrachtet, die dadurch zustande kommt, dass wir w um einen kleinen Betrag erhöhen. Dieser Betrag ist praktisch die »Schrittgröße«, allerdings verwende ich hier den Fachbegriff aus dem Bereich des Machine Learning, nämlich die Lernrate, was zu der Abkürzung lr führt.

      Wenn wir die Lernrate zu w addieren, erhalten wir eine neue Gerade. Nun fragen wir, ob diese zu einem geringeren Verlust führt als die bisherige Gerade. Wenn ja, machen wir w + lr zum neuen w und setzen die Schleife fort. Anderenfalls probiert der Algorithmus die Gerade w - lr aus. Auch hier wiederum wird w entsprechend aktualisiert, wenn diese neue Gerade zu einem geringeren Verlust führt als das bisherige w, und die Schleife fortgesetzt.

      Führen weder w + lr noch w -lr zu einem geringeren Verlust als das aktuelle w, sind wir fertig, denn dann haben wir die Beispiele bestmöglich angenähert. In diesem Fall geben wir w an den Aufrufer zurück.

      Anschaulich gesagt, dreht dieser Algorithmus die Gerade in beiden Richtungen und macht sie bei jedem Durchlauf ein kleines bisschen steiler oder flacher und untersucht dabei jeweils den Verlust. Je höher die Lernrate, umso schneller bewegt das System die Gerade. Das können Sie sich so ähnlich vorstellen wie einen Funker der alten Schule, der ganz langsam einen Regler dreht, um den Empfang immer ein kleines bisschen klarer zu machen, bis er schließlich so deutlich ist, wie er nur werden kann.

      Iterative Algorithmen können manchmal jedoch in einer Endlosschleife hängenbleiben (man sagt dann, dass sie nicht konvergieren). Informatiker können beweisen, dass dieses Problem bei dem vorliegenden Algorithmus nicht besteht. Nach ausreichend Zeit und Iterationen wird er stets konvergieren. Allerdings kann es sein, dass ihm schon vorher die Iterationsmöglichkeiten ausgehen. In einem solchen Fall gibt train() auf und endet mit einer Ausnahme.

      Sie brennen bestimmt schon darauf, den Code auszuführen. Dann also los!

      Der folgende Code lädt Robertos Beispiele und übergibt sie an train(). Zur klareren Darstellung werden dabei benannte Argumente verwendet (siehe die Erklärung im Abschnitt »Schlüsselwortargumente« auf Seite 334). Nach dem Aufruf von train() werden das ermittelte Gewicht und die Vorhersage für die Anzahl von Pizzas bei 20 Reservierungen ausgegeben.

       02_first/linear_regression.py

       #