© DrHitch/Shutterstock.com
Einstieg ins Machine Learning

Mathematische Grundlagen für maschinelles Lernen


Machine Learning ist vor allem durch die Erfolge im Deep Learnig und durch das Potenzial populär geworden, große, unstrukturierte Datenmengen verarbeiten zu können. Die Technologie ist an sich aber nicht neu und hat dabei sehr viele Facetten, was das Thema manchmal unübersichtlich erscheinen lässt. Fundierte mathematische Grundlagen der wichtigsten Ansätze geben den Einstieg, um den Überblick zu behalten.

Machine Learning fasziniert, weil damit Lösungen gefunden werden können, die man vorher so nicht beschreiben konnte. So scheint es fast magisch zu funktionieren, was natürlich nicht der Fall ist, da man ja die Algorithmen programmieren muss. Wenn man neu in das Thema einsteigt, ist es schwierig, den Überblick zu behalten und zu verstehen, wann und warum einzelne Verfahren für bestimmte Aufgaben funktionieren und wann nicht. Darum veranschaulichen wir hier die wichtigsten Ansätze. Anstatt verschiedene Methoden völlig getrennt zu behandeln, gehen wir entlang der Gemeinsamkeiten vor, um dann die verschiedenen Ausprägungen darzustellen, ohne dabei bis ins letzte Detail zu gehen. Es wird überwachtes Lernen, unüberwachtes Lernen sowie Reinforcement-Lernen dargestellt werden.

Die Blackbox-Sicht

Der Einsatz von Machine Learning erfolgt meist nach dem folgenden Muster: Wir haben Eingangsdaten, das können Kameradaten, Börsendaten, Text oder Sonstiges sein. Das System soll diese Daten verarbeiten und dabei lernen, möglichst gut zu funktionieren (dazu später mehr). Die Ausgangsdaten können dann z. B. Klassifizierungen der Eingangsdaten sein, also beispielsweise angeben, ob ein Auto erkannt wurde, ein Fußgänger, oder man eine bestimmte Aktie kaufen sollte. Es wird meist Feedback gegeben, das lauten kann, dass der Ausgang falsch oder richtig gewählt wurde oder welcher Ausgang richtig gewesen wäre (Abb. 1.1). Wenn das Feedback t das gewünschte Ergebnis darstellt und die Differenz von tatsächlichem und gewünschtem Ergebnis zur Optimierung von M herangezogen wird, spricht man vom sogenannten überwachten Lernen (Supervised Learning), womit wir uns als Erstes beschäftigen wollen.

image

Abbildung 1.1: Ein Machine-Learning-System besitzt immer einen Input, einen Ausgang und bekommt optional Feedback zur Bewertung seiner Ausgaben

Mathematik

Was immer wir als mathematischen Algorithmus aufschreiben können, kann programmiert werden. Im Fall der obigen Zeichnung ist die Abbildung des Eingangs x (Kameradaten) auf den Ausgang y („Auto“ oder „Fußgänger“) am einfachsten wie folgt zu formulieren: y=f(x).

Das heißt, die Aufgabe des Machine-Learning-Systems f ist, sich selbst so zu verbessern (also zu lernen), dass die gewünschte Größe y erzielt wird. Die Ausgangsgröße y kann oftmals als binär angenommen werden. Wir können diese Aufgabe des Verbesserns auch als Optimierungsaufgabe auffassen, womit genau das wesentliche innere Prinzip des Machine Learnings beschrieben ist. Neben diesem inneren Prinzip sind allerdings viele weitere Dinge zu betrachten. Die Optimierung ist nämlich in komplexe Strukturen einzubauen, damit die gewünschten Resultate erreicht werden können, wie wir im Laufe dieses Kapitels sehen werden.

Die Optimierungen werden meist iterativ umgesetzt. In kleinen Schritten und mit einer Vielzahl von Beispieldaten lernen z. B. neuronale Netze, die ihnen gestellten Aufgaben zu lösen, indem sie sich im Mittel über die Zeit verbessern.

Etwas Mathematik zum Auffrischen:

Vektor

Ein Vektor x im n-dimensionalen Raum, vector_empty.pngvector_x-roboto.pngЄRn, hat die Form

image

Matrix

Eine m-x-n-Matrix W hat die Form

image

Skalarprodukt von Matrix und Vektor

Das Skalarprodukt aus einer m-x-n-Matrix W und einem n-dimensionalen Vektor x ist wieder ein Vektor und zwar m-dimensional. Für jedes Element dieses Ergebnisvektors y gilt:

image

Ableitung einer Funktion

Die Ableitung einer Funktion f(x) wird durch die Steigung der Tangente an diesem Punkt beschrieben. Für die Ableitung f‘(x) der Funktion f(x) kann man einen Satz von Regeln anwenden, z. B. für einfache Fälle die Potenzregel:

Für f(x)=xn gilt f'(x)=nxn-1

d. h. für f(x)=x2 gilt f'(x)=2x

Die Kettenregel:

Für die verkettete Funktion für f(x)=g(h(x)) gilt die Ableitung f'(x)=g'(h(x))h'(x), also das Produkt aus äußerer Ableitung g'(h(x)) und innerer Ableitung h'(x).

Partielle Ableitung

Die partielle Ableitung ist die Ableitung einer Funktion mit mehreren Argumenten nach einem der Argumente. Gekennzeichnet werden partielle Ableitungen mit , also z. B. ∂C(W)/∂wij, was bedeutet, dass C von der Matrix W abhängt, aber wir jetzt nur die einzelne Komponente wij betrachten.

Gradient

Als Gradienten bezeichnet man einen Vektor, wobei die ersten partiellen Ableitungen der Funktion die Einträge des Vektors bilden.

Neuronale Netze

Wie kann unser System f konkreter aussehen? Und wie kann es optimiert werden?

Ein besonders wichtiger Ansatz zur Optimierung des Systems ist von der Biologie inspiriert, d. h. von unserem Wissen darüber, wie Lebewesen lernen. Wir wissen, dass neuronale Verbindungen und ihre Anpassungen dabei eine zentrale Rolle spielen. So entstand ein gerade in jüngster Zeit erfolgreicher Ansatz bereits in den späten 1940er Jahren: die neuronalen Netze. Wir beschäftigen uns hier zunächst mit den einfachsten neuronalen Netzen, um das Grundprinzip zu verstehen, und machen dann weiter mit komplexeren Netzwerken. Das einfachste neuronale Netz ist das sogenannte Perzeptron [1]. Es besteht im einfachsten Fall aus einem Neuron mit mehreren Eingängen, wie in Abbildung 1.2 dargestellt.

image

Abbildung 1.2: Ein einfaches Modell eines Neurons, das Perzeptron, summiert die gewichteten Eingangssignale, und wenn diese einen Schwellwert überschreiten, wird eine 1 am Ausgang erzeugt; ansonsten bleibt der Ausgang auf 0 stehen

Das Neuron berechnet dabei die Summe der gewichteten Eingangsgrößen, wobei dann noch eine Sprungfunktion mit einem Schwellwert dafür sorgt, dass y binär ist (also 0 oder 1).

image

Zur Vereinfachung gehen wir zunächst von einem Schwellwert von 0 aus.

Es kann, wenn sämtliche xi = 0 sind, der Ausgang auch nicht größer 0 werden. Daher führt man eine Voreinstellung ein, Bias genannt. Das ist ein konstanter Eingangswert, sodass auch ein positiver Ausgangswert erzeugt werden kann, selbst wenn alle anderen Werte null sind. Wir nehmen hierzu einfach x0 und setzen es konstant auf 1.

Eine einfache Aufgabe

Um zu sehen, wie ein Perzeptron lernt, sei hier eine sehr einfache Beispielaufgabe dargestellt. Das Perzeptron soll die boolesche UND-Funktion lernen. Das heißt, wenn x1 = 1 UND x2 = 1 dann soll y = 1 sein, ansonsten soll y = 0 sein. Wir können dies grafisch darstellen (Abb. 1.3). Unsere veränderlichen Größen sind die Gewichte (w0, w1, w2), die so eingestellt werden sollen, dass, wenn die Eingangsgrößen x1 und x2 einen Punkt jenseits der eingezeichneten Gerade beschreiben, der Ausgang 1 sein soll. In unserem Fall soll die Gerade also den Punkt x1 = 1 UND x2 = 1 abtrennen.

image

Abbildung 1.3: Grafische Darstellung des „UND“-Problems; die Gewichte sind so einzustellen, dass der dargestellte Punkt von den anderen möglichen Eingangsmustern abgetrennt wird

Die Lernregel

Die Idee ist nun, den Gewichtsvektor so einzustellen, dass das gewünschte Ergebnis erreicht wird. Dieses Verbessern des Gewichtsvektors wird als Lernen bezeichnet. In unserem UND-Beispiel bedeutet das, dass die Gewichte erhöht werden, wenn y hätte 1 sein sollen, aber tatsächlich 0 ist. Wir haben also eine Abweichung vom gewünschten Wert (den wir t wie target nennen wollen) zum tatsächlichen Ausgangswert y.

Das heißt, was wir berechnen müssen, ist die Änderung des Gewichtsvektors Δwi=wneu - walt, indem wir dies für jede Eingangsdimension i tun:

Δwi=xi (t-y)

  • Wenn xi gleich null ist, ändert sich nichts (Ausnahme: x0 ist immer 1).
  • Wenn der Fehler t - y gleich null ist, ändert sich nichts.
  • Wenn y kleiner als t ist, wächst wi, damit wird y beim nächsten Mal, wenn xi größer 0 ist, auch größer. Damit wird der Fehler (t - y) kleiner. Das ist genau der Schritt der Optimierung bzw. des Lernens.

Der Ablauf

Die Schritte zum Trainieren des Netzes sind:

  • Initialisieren des Netzes, indem die Gewichte mit z. B. Zufallswerten belegt werden
  • Folgendes wiederholen, bis die Abbruchkriterien erfüllt sind:
    • Datensatz, Eingangsdaten und gewünschte Ausgabe auswählen
    • Ausgang bestimmen und den Fehler berechnen
    • Gewichte anpassen, um den Fehler zu verkleinern

Zur Praxis: Perzeptron in Python

Das Ziel ist immer, dass sich das System stabilisiert (davon ausgehend, dass die Aufgabe des Systems sich nicht ändert). Typischerweise besteht bei Systemen, die sich über die Zeit ändern, immer die Gefahr, dass zwischen verschiedenen Zuständen gesprungen und nicht auf die optimale Lösung hingesteuert wird. Damit man nicht gleich bei der ersten Anpassung über das Ziel hinausschießt, wird typischerweise noch eine Lernrate eingeführt, meist mit η (eta) bezeichnet:

Δwi=η xi (t-y)

Damit können wir jetzt die oben beschriebene Mathematik in den in Listing 1.1 zu sehenden Code umsetzen. Die Kommentare im Code geben dabei Hinweise, wie der Code variiert werden kann.

# Beispiel eines einfachen Perzeptrons, das die UND-Funktion lernt, getestet mit # Python 3.6
# Die Kommentare enthalten Hinweise zum Experimentieren

# Für Matritzen- und Vektoroperationen hilft NumPy, den Code übersichtlicher zu # gestalten
import numpy as np

# die Definition der Perzeptron-Klasse
class Perceptron(object):

# als Erstes der Konstruktor
def __init__(self, input_size, eta=0.02, iterations=10):
# input_size ist die Anzahl der Eingänge
# eta ist die Lernrate
# iterations ist die Anzahl der Lernschritte

# der Gewichtsvektor wird hier mit Nullen initialsiert
self.Weight = np.zeros(input_size)
# eine andere Option ist die Initialisierung mit Zufallswerten
# self.Weight = np.random.rand(3)
# auch mit festen Werten kann initialisiert werden, z. B.:
# self.Weight[0] = 0.11
# self.Weight[1] = 0.12
# self.Weight[2] = 0.12

self.iterations= iterations
self.eta = eta
self.input_size = input_size

def activation(self, x):
# die Aktivierungsfunktion ist hier die Schrittfunktion
return 1 if x >= 0 else 0
# es kann auch mit linearer Aktivierungsfunktion getestet werden:
# return x

def predict(self, x):
z = 0
# zur Berechnung des Ausgangs kann man kompakt schreiben
# z = self.Weight.T.dot(x)
# oder
for i in range(self.input_size):
z += self.Weight[i]*x[i]
a = self.activation(z)
return a

def learn(self, training_data, target):
for _ in range(self.iterations):
# pro Iteration werden alle Trainingsdaten genutzt, also ...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Gewinner-Teams

Wir bieten Lizenz-Lösungen für Teams jeder Größe: Finden Sie heraus, welche Lösung am besten zu Ihnen passt.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang