Machine Learning für Softwareentwickler. Paolo Perrotta
Чтение книги онлайн.
Читать онлайн книгу Machine Learning für Softwareentwickler - Paolo Perrotta страница 12
Es gibt tatsächlich eine solche Formel, allerdings werden wir sie hier nicht benutzen, da sie eine Sackgasse darstellt. Wenn wir hier eine Formel anwenden, die die Datenpunkte mit einer geraden Linie annähert, dann kommen wir später nicht weiter, wenn wir mit Datenmengen zu tun haben, bei denen verzwicktere Modellierungsfunktionen erforderlich sind. Daher ist es besser, nach einer allgemeineren Lösung Ausschau zu halten, die bei jedem Modell funktioniert.
So viel zur mathematischen Vorgehensweise. Schauen wir uns stattdessen an, was Programmierer in einem solchen Fall tun.
Wie falsch liegen wir?
Welche Strategie können wir verfolgen, um die Gerade zu finden, die sich bestmöglich an die Beispiele annähert? Nehmen wir an, wir haben eine Funktion, die die Beispiele (X und Y) und eine Gerade (w) entgegennimmt und den Fehler dieser Geraden misst. Je besser die Annäherung, umso geringer der Fehler. 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:
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,