Eine Vielzahl von hochentwickelten Technologien für maschinelles Lernen ist als Open Source frei verfügbar. Dennoch zeigt sich, dass es nur vergleichsweise wenige Anwender gibt, die diese Technologie in Produkten erfolgreich einsetzen. Maschinelles Lernen ist ein sehr vielschichtiger und komplexer Bereich der Informatik und darüber hinaus ein Gebiet aktiver Forschung. Einsteiger können insbesondere im Bereich Deep Learning dadurch schnell den Eindruck gewinnen, dass eine Einarbeitung nur auf hohem wissenschaftlichen Niveau möglich ist. Es gibt jedoch durchaus auch praxisorientierte Quellen. Viele Informationen sind nur in englischer Sprache verfügbar, daher verweist der Artikel auf englische Quellen.

Szenario

Stellen wir uns Datenverarbeitung als ein System aus Eingabe, einem Algorithmus zur Verarbeitung und einer Ausgabe vor. Von der grundsätzlichen Struktur trifft diese Beschreibung auch auf Systeme zu, die mit Machine Learning arbeiten. Jedoch spricht man dann nicht von einem Algorithmus, der durch Programmierung in Form von Sourcecode Expertenwissen abbildet, sondern von einem Machine-Learning-Modell, das den Zusammenhang zwischen Ein- und Ausgabe selbstständig aus den Daten erlernt.

Die zentrale Frage ist, wie man zu einem solchen trainierten Modell kommt. Es gibt ausreichend Tutorials anhand derer man ohne jegliches Vorwissen Schritt für Schritt Definition und Training eines solchen Modells durchführen kann. Dies macht durchaus Sinn, um das Framework kennenzulernen. Ausserdem dient das Ergebnis als Spielwiese, um ein solches System zum ersten Mal hautnah zu erleben. Nach meinen Erfahrungen vermitteln solche Tutorials aber wenig Wissen, das auf andere Problemstellungen übertragen werden kann. Daher möchte ich Sie nun einladen, sich tiefer mit dem Thema auseinander zu setzen.

Um den Einstieg zu erleichtern, möchte ich die einzelnen notwendigen Schritte ansprechen, kurz erläutern und zu diesen jeweils Einstiegspunkte nennen, um sich damit näher zu befassen. Diese Schritte werden in einer Reihenfolge präsentiert, wie sie durchgeführt werden können. Sie sind jedoch nicht als abgeschlossene Phasen zu verstehen, denn in der Praxis wird man zwischen den einzelnen Tätigkeiten iterieren müssen, um ein gutes Ergebnis zu erzielen.

Orientierung

Einen Datensatz wird im Kontext von Machine Learning häufig auch Beobachtung bzw. Observation genannt. Ein Parameter (eine Spalte in tabellarischer Darstellung) eines Datensatzes wird als Feature bezeichnet.

Im maschinellen Lernen wird zwischen Supervised Learning und Unsupervised Learning unterschieden. Unsupervised Learning lernt vollständig, allein Strukturen in den Daten zu erkennen und braucht keine vorgegebenen Ergebnisse. Es wird häufig eingesetzt, um Daten zu segmentieren. So kann man beispielsweise eine Menge von Bildern, auf denen entweder Hunde oder Katzen zu sehen sind, in zwei Gruppen mit jeweils Bildern von Hunden oder Katzen aufteilen. Ein solches System ist nicht in der Lage, eine Gruppe mit dem Begriff „Katze“ zu benennen, aber kann die Segmentierung vornehmen.

Für Supervised Learning müssen die Testdaten “gelabelt“ vorliegen. Dies bedeutet, dass zu jedem Datentupel, das im Training als Eingangswert dient, bereits das gewünschte Ergebnis vorliegen muss. Diese Labels liegen entweder bereits vor oder müssen manuell erzeugt werden. Das System wird trainiert, um diese vorgegebenen Ergebnisse möglichst gut abzubilden.

Dieser Artikel konzentriert sich auf Supervised Learning mit Deep Feedforward Networks (auch FNN für Feedforward Neuronal Network). Sie verarbeiten Datensätze fixer Länge unidirektional vom Ein- zum Ausgang und haben in ihrem Inneren keine Rückkopplungsschleifen. Ein Satz von Eingangsdaten wird mit dem zugehörigen Ergebnis verknüpft, es werden aber keine Beziehungen zwischen einzelnen Datensätzen (wie z.B. eine zeitliche Abfolge) abgebildet. Recurrent Neuronal Networks (RNN) hingegen kann man einsetzen um Signale flexibler Länge zu verarbeiten, wie es z.B. bei Spracherkennung oder bei Zeitreihen notwendig ist.

Deep Feedforward Networks mit einer ausreichenden Tiefe weisen die Eigenschaften eines universellen Approximators auf, das heisst, sie sind prinzipiell in der Lage beliebig komplexe Zusammenhänge zwischen Ein- und Ausgangswerten in guter Näherung abzubilden. Diese Aussage deutet allerdings auch an, dass diese Systeme Näherungslösungen liefern und keine exakten Werte, wie es ein programmierter Algorithmus tun würde, der einen kausalen Zusammenhang exakt nachbildet. Das Ziel des Trainings eines solchen Modells sollte also sein, eine für die Anwendung ausreichende Genauigkeit zu erzielen.

Explorative Analyse: Erkunden der vorhandenen Daten

Grundsätzlich ist es sinnvoll, sich selbst zuerst einen Eindruck der Daten zu verschaffen, aus denen man lernen möchte. Um es nicht zu komplex zu gestalten, konzentriert man sich zuerst darauf die Parameter einzeln zu betrachten (univariate Analyse), und untersucht die Verteilung der Werte, so dass man den Wertebereich (Minimum, Maximum), und die Verteilung (Mittelwert, ggf. Abweichung etc) kennt. Ein Histogramm zeigt diese Informationen grafisch auf. „Google Cloud ML Dataprep“ ist ein fertiges Werkzeug im Betastatus, das u.a. Wertebereiche und Histogramme automatisch für alle Parameter erzeugt. Es geht zurück auf ein Tool der Uni Stanford namens DataWrangler, das leider aber nicht sehr ausgereift ist.

„A Comprehensive Guide to Data Exploration“ gibt werkzeugunabhängig mehr Informationen zu dem Thema. Es behandelt auch die Korrelationen zwischen zwei Parametern (bivariate Analyse). Ein weiterer sehr wichtiger Punkt ist, zu erkennen, welche Features kontinuierlich sind und welche diskret. Diskrete Werte sind in ihrer Art meist nicht numerisch, sondern eher als Kategorien zu verstehen, selbst wenn sie durch Integer repräsentiert werden.

Explorative Analyse findet in-memory statt. Sofern man sehr viele Datensätze hat, sollte man zufällig eine Teilmenge auswählen und in der Analyse mit der Teilmenge arbeiten. „Google Cloud ML Dataprep“ macht dies abhängig von der Datenmenge automatisch, die meisten Frameworks bieten dafür Tools wie z.B. ND4J oder SciKit-Learn.

Wenn man vermutet, dass sich in den Daten stereotypische Muster befinden, kann es aufschlussreich sein, eine automatisierte Segmentierung vorzunehmen, z.B. mit dem K-Means Algorithmus. Eine ausführliche Beschreibung und sowie eine Implementierung wird unter K-Means in SciKit-Learn angeboten.

Problemdefinition: Definition der Fragestellung sowie der Datentypen für Eingangsparameter und Ergebnis

Die Menge aller möglichen Features wird Feature Space genannt. Die Menge der Parameter entsprechen den Dimensionen des Feature Space. Als hypothetisches Beispiel betrachten wir ein System, das aus dem Umfang und dem Gewicht eines Apfels den Reifegrad bestimmen soll. Der Feature Space ist dann zwei-dimensional und deckt alle beliebigen Kombinationen von Umfang und Gewicht ab. Die explorative Analyse sollte allerdings gezeigt haben, dass die vorhandenen Daten den Feature Space nicht gleichmässig füllen. Das ist völlig in Ordnung. Um bei unserem Beispiel zu bleiben wird es selten Äpfel geben, die mehr als 500g wiegen, auch wenn der Datentyp z.B. ein Integer in Gramm ist und das Modell demnach auch Äpfel mit 232 g darstellen könnte. Genauso verhält es sich mit den üblichen Datentypen zu Text, Bildern und Tönen. Der grösste Teil des Raums, den diese Datentypen abbilden können, ist inhaltlich ungültig („kzpölhsfd“ ist z.B. kein Wort). Wichtig ist zu erkennen, welche Bereiche die Trainingsdaten abdecken. Bestimmte Zusammenhänge wird das Modell interpolieren können, andere aber nicht. Wenn wir mit unserem Modell alle Reifegrade erkennen wollen, müssen wir wahrscheinlich auch zu allen Reifegraden ausreichend Beispiele in den Daten haben. Sofern wir feststellen, dass die Sorte des Apfels für die Prognose relevant ist, wird man das Modell mit allen Apfelsorten trainieren müssen, für die man es verwenden möchte.

Grundsätzlich unterscheidet man bei den Problemstellungen zwischen Klassifikation und Regression. Regression erzeugt Ergebnisse in Form von kontinuierlichen Werten, Klassifikation dagegen diskrete Werte im Sinne von Kategorien. Unser oben erwähntes Beispiel passt nach der textuellen Formulierung in beide Formen, je nachdem, ob wir uns den Reifegrad als kontinuierlichen Wert mit beliebigen Abstufungen zwischen unreif über reif nach verdorben vorstellen oder eben in Form von beispielsweise drei Kategorien. Um die Fragestellung zu konkretisieren und zu formalisieren, ist es sehr wichtig, die Datentypen des Ergebnisses klar zu definieren. Auch die exakten Datentypen der Features müssen definiert werden, dazu sollte die explorative Analyse und die konkretisierte Fragestellung Indizien liefern.

Kategorien sollten nicht in Form von skalaren Typen modelliert werden, da die arithmetischen Eigenschaften für diese Daten inhaltlich keinen Sinn ergeben. Ein 1-aus-n-Code bzw. One-Hot-Vector ist ein Bit-Vektor, in dem ein Element 1 ist und alle anderen 0. Ein solcher Vektor ist ein sehr geeignetes Format für Kategorien im Zusammenhang mit Machine Learning. Viele Frameworks wie z.B. DeepLearning4J (DL4J) bieten Transformationen in One-Hot-Vectors direkt an.

Ein weiterer zu beachtender Aspekt ist der „Fluch der Dimensionalität“. Bei gleicher Menge an Datensätzen und steigender Anzahl Features sinkt die Dichte der Daten im Feature Space exponentiell. Die Trainingsdaten füllen den Raum nur noch sehr spärlich aus und reichen gegebenenfalls nicht mehr aus, um ein Modell trainieren zu können. Es ist jedoch schwierig zu quantifizieren, wie viele Trainingsdaten man benötigt. In Bengio et. al. wird [1] angegeben, dass unter optimalen Bedingungen für einen hochdimensionalen Feature Space mit k Regionen mindesten log2(k) Datensätze nötig sind. Regionen entsprechen dabei den „Unit Cubes“ aus dem oben erwähnten Fluch.

Modell-Architektur: Definition der Architektur des Machine Learning Modells

Die innere Struktur eines Deep Feedforward Networks wird u.a. durch die Anzahl der Eingangsknoten, Anzahl der Layer und die Verschaltung zwischen den Layern bestimmt. Das Verhalten wird massgeblich durch die Aktivierungsfunktion, die Transformationsfunktion des Output-Layers und die Verlustfunktion (Loss Function) bestimmt. Für spezifische Anwendungen wie Textverarbeitung oder Bildverarbeitung gibt es spezifische Systeme wie OpenCV und Best Practices. Diese sind gute Startpunkte.

Für Bildverarbeitung hat sich ausserdem das Convolutional Neural Network als Strukturarchetyp etabliert. Die meisten Deep Learning Frameworks bieten solche vordefinierten Netze an. Darüber hinaus gibt es High-Level-APIs wie z.B. Keras oder die Estimator in TensorFlow TensorFlow.

Struktur eines Fully-Connected Deep Feedforward Networks 13 mit 3-dimensionalem Input, 2-dimensionalem Output und drei 14 Hidden Layern
Struktur eines Fully-Connected Deep Feedforward Networks 13 mit 3-dimensionalem Input, 2-dimensionalem Output und drei 14 Hidden Layern

Alle Modelle benötigen eine Verlustfunktion, um später trainiert werden zu können. Selbst wenn man diese ggf. nicht selbst auswählen muss, sollte man sich der Bedeutung dieser Funktion bewusst werden. Die Verlustfunktion bestimmt die Differenz zwischen der Prognose, die das Modell liefert, und dem vorgegebenen Label. Sie muss für die Menge aller Daten berechnet werden und beschreibt damit, wie gut das Modell die Daten abbildet. Die Euklid-Distanz im Vektorraum (auch L2-Norm oder Least Squares) ist ein anschaulicher und verbreiteter Ansatz, um den Abstand zwischen zwei Werten zu berechnen. Die Summe dieser Abstände für alle Datensätze kann als Verlustfunktion genutzt werden. Im Umgang mit Kategorien wird der 0–1-Verlust angewendet. Maximum Log Likelyhood oder Cross-Entropy sind allgemein verwendbare Alternativen – siehe auch LossFunction.

Praktische konkrete Tipps für den Einstieg abseits der vordefinierten Modelle sind ausserdem: RELU als Aktivierungsfunktion ist immer eine gute Option für den Start. Die Funktion des Outputlayers hängt wesentlich mit dem Datentyp des Outputs zusammen. Linear Unit für Regression, Sigmoid Unit für binäre Klassifikation und Softmax Unit für Klassifikation mit mehr als zwei Klassen.

Pre-Processing & Cleanup: Vorverarbeitung und Säuberung der Daten

Um Machine Learning professionell einsetzen zu können, ist es nötig, eine Data Pipeline aufzubauen. Auch wenn dies zu Beginn nicht sehr wichtig erscheint, rate ich dringend dazu, die Vorverarbeitung nachvollziehbar zu gestalten und niemals die Rohdaten direkt zu ändern. Sie sollten jederzeit in der Lage sein, aus den originalen Rohdaten wieder zum aktuellen Stand zu gelangen, um z.B. mit dem Preprocessing experimentieren oder mit neuen Daten arbeiten zu können.

Grundsätzliches zum Preprocessing behandelt dieser Artikel, vor allem der Umgang mit fehlenden Werten ist von Interesse. Feature Engineering ist für Deep Learning Systeme hingegen nicht nötig.

Die Normalisierung der Daten ist ein weiterer Aspekt, den man betrachten sollte. Bei Bildern kann dies z.B. die Skalierung auf eine fixe Auflösung sowie die Anpassung der durchschnittlichen Helligkeit sein. Auch dafür bieten die meisten Frameworks fertige Tools, z.B. DL4J.

Falls zu wenige Beobachtungen vorliegen, kann Augmentation eine Lösung sein. Die Datenmenge lässt sich damit um bis zu Faktor 10 erhöhen.

Training: Training und Validierung des Machine Learning Modells

Um das Modell trainieren zu können, muss man zuerst die vorhandenen Daten in Trainings- und Testdaten splitten. Die Testdaten werden weder im Training noch zur manuellen Optimierung des Systems verwendet und dienen dazu, das fertige System gegen unbekannte Daten zu testen, mit denen es nicht trainiert wurde. 10 - 20% der Daten als Testdaten zu reservieren ist ein guter Schätzwert. Wichtig ist, diese zufällig auszuwählen. Auch dafür gibt es fertige Funktionen wie ND4J.

Um während des Trainings- und Optimierungsprozesses prüfen zu können, ob sich die Qualität der Ergebnisse verbessert, ist es sinnvoll einen weiteren Teil der Daten als Validierungsdaten zu reservieren. Dies reduziert allerdings die Datenmenge, die zum Training zur Verfügung steht, und macht den Trainingsprozess eventuell anfällig gegenüber der zufälligen Auswahl der Validierungsdaten. Eine andere Variante ist, Cross-Validation für diesen Zweck zu verwenden.

Ziel des Trainings ist es, die o.g. Verlustfunktion zu minimieren. Dies wird als Optimierungsproblem betrachtet und in kleinen Schritten einer besseren Lösung angenähert. Dazu durchlaufen Datensätze das Neuronale Netz und erzeugen eine Prognose. Über die Verlustfunktion wird die Abweichung vom Sollwert berechnet und diese Abweichung wird dann in umgekehrter Richtung, vom Ausgang zurück bis zum Eingang, durch das Netz propagiert. Diesen Vorgang nennt man Back-Propagation. Dabei wird an jedem Knoten des Netzes eine Optimierung der Gewichte durchgeführt und dabei die Gewichte ein kleines Stück verändert, was den eigentlichen Lerneffekt erzeugt. Das Maß der Veränderung ist die Lernrate, die man häufig als Hyperparameter für den Trainingsprozess angeben muss. Ein bekanntes Verfahren ist der Gradient Descent, bzw. Stochastic Gradient Descent (SGD). Weitere Tipps zum Trainingsprozess liefert dieser Artikel. Dort wird SGD als etwas altmodisch dargestellt. Wenn, wie in DL4J, neuere Alternativen verfügbar sind, kann man sie nutzen. Aber in der Praxis wird SGD für den Start auch brauchbare Ergebnisse liefern.

Das Modell muss zu Beginn des Trainings initialisiert werden. Wenn alle Gewichte Null sind, findet der Trainingsalgorithmus keine Gradienten, daher hat es sich bewährt die Modelle mit kleinen zufälligen Werten zu initialisieren. Auch dafür gibt es in den Frameworks fertige Methoden nach Best Practices, z.B. WeightInit.XAVIER in DL4J.

Sofern das trainierte System mit den Validierungsdaten keine guten Ergebnisse erzielt, spricht man von Underfitting. Das Modell bildet die Trainingsdaten dann nicht gut ab. Dies kann an schlechten oder schlecht aufbereiteten Daten liegen, an zu geringer Kapazität des Modells oder an den Parametern des Trainingsprozesses.

Sind die Ergebnisse mit den Validierungsdaten gut, aber mit den Testdaten signifikant schlechter, spricht man von Overfitting. Das Modell ist zwar trainiert, um die Trainingsdaten korrekt abzubilden, aber es generalisiert nicht. Mögliche Ursachen dafür sind zu wenige oder nicht repräsentative Trainingsdaten, also dass der Feature Space durch die Trainingsdaten nicht ausreichend gefüllt ist.

Referenzen

  1. Bengio Y., Larochelle H and Vincent P. Non–local manifold Parzen windows. In NIPS‘2005, MIT Press  ↩

Fazit

Ich hoffe, mit den Informationen die Lücke zwischen der komplexen Materie aus der AI-Forschung und den sehr einfachen Tutorials etwas füllen zu können. Es zeigt sich jedoch auch, dass durch die Komplexität des Themas eine gewisse Einarbeitungszeit nicht zu vermeiden ist. Das No-Free-Lunch-Theorem sagt aus, dass kein System für alle Probleme geeignet sein kann. Es ist zwar eine sehr theoretische Aussage, aber es braucht etwas Erfahrung um die vielversprechenden Ansätze zu finden.

Die verwendeten Links in der hier vorgestellten Struktur sowie noch einige mehr habe ich auch bei Github zusammengestellt.

Ein letzter Hinweis noch: Das Training selbst recht einfacher Netze erfordert oft grosse Rechenleistung. Am effizientesten ist die Ausführung auf GPUs, die für parallele Matrizenoperationen entwickelt wurden. Aus eigener Erfahrung musste ich schon feststellen, dass eine Mittelklasse-Grafikkarte einen Core i7 um Faktor 100 schlagen kann. Aber welche Hardware Sie auch nutzen, experimentieren Sie!