hintergrundbild

Autoencoder und Empfehlungssysteme

Hab Ihr Euch schon mal gefragt, woher Netflix, Amazon oder YouTube zu wissen scheint welche Filme, Produkte oder Videos für Euch als Nächstes von Interessen sein könnten. Die Empfehlungen dieser Webseiten scheinen auf Euch persönlich zugeschnitten zu sein und tatsächlich stellt man öfter als selten fest, dass diese Empfehlungen den eigenen persönlich Geschmack treffen und man ertappt sich dabei, dass man sich doch noch, das von YouTube vorgeschlagene Video anschaut oder das Produkt auf Amazon bestellt. Hinter diesem Empfehlungssystem verbirgt sich sog. Kollaboratives Filtern auf Basis von Deep Autoencoder.


Das Wichtigste auf einen Blick

  • Kollaboratives Filtern ist eine Technik für die Implementierung eines Empfehlungssystems
  • Empfehlungssysteme basieren oft auf neuronalen Netzen und Deep Learning
  • Deep Autoencoder können beim kollaborativen Filtern als Empfehlungssysteme verwendet werden
  • Als Empfehlungssysteme erzielen Deep Autoencoder state-of-the-art Performance

1. Einführung

Kollaboratives Filtern ist eine Methode, bei der Verhaltensmuster von Benutzergruppen ausgewertet werden, um auf die Interessen Einzelner zu schließen. Diese wird u. a. von Empfehlungssystemen verwendet, um Vorhersagen über das Interesse einer bestimmten Person zu treffen, indem Geschmacks- oder Präferenzinformationen von vielen anderen Personen gesammelt und ausgewertet werden.

Der Technik des Kollaborativen Filterns liegt die Annahme zugrunde, dass, wenn eine Person A den gleichen Geschmack oder die gleiche Meinung zu einem Thema hat wie die Person B, es wahrscheinlicher ist, dass die Person A die gleiche Meinung zu einem anderen Thema hat, wie die Person B.

Heutzutage basieren die effizientesten Methoden des kollaborativen Filterns auf Deep Learning und neuronalen Netzen, insbesondere den tiefen Autokodierern (engl: Deep Autoencoder). Ein Autoencoder bezeichnet in Deep Learning eine Architektur der neuronalen Netze.

Autoencoder erreichen beim kollaborativen Filtern, verglichen mit anderen Methoden in diesem Bereich, state-of-the art Performance.

In diesem Artikel stelle ich Ihnen vor, wie Sie mittels Autoencoder und Deep Learning Bewertungen vorhersagen können, die eine Person einem Film geben würde, basierend auf der Präferenzen dieser Person sowie den Präferenzen anderer Personen, die bereits den gleichen sowie andere Filme gesehen und bewertet haben.

Im ersten Teil des Artikels gebe ich Ihnen einen theoretischen Überblick über die einfachen Autoencoder sowie deren Erweiterung, den Deep-Autoencodern. Eine detailliertere Beschreibung der Autoencoder und wie diese zu implementieren sind, habe ich bereits in dem Artikel „Deep Autoencoder in TensorFlow 2.0“ dargestellt.

Im zweiten Teil werden wir in die Praxis eintauchen und ich werde Ihnen zeigen, wie Sie diese Technik in TensorFlow Schritt für Schritt implementieren können. In diesem Artikel werde ich nur die wichtigsten Teile des Modells vorstellen und kommentieren. Das gesamte Modell, die Eingabe-Pipeline und das Preprocessing können im entsprechenden GitHub Repository eingesehen werden.


2. Deep Autoencoder

2.1 Autoencoder

Bevor wir uns mit den Deep Autoencodern beschäftigen, sollten wir einen Blick auf die einfachere Version dieser neuronalen Netze werfen. Ein Autoencoder ist ein künstliches neuronales Netzwerk, das zum Erlernen einer Repräsentation (Kodierung) für einen Satz von Eingabedaten verwendet wird, normalerweise um eine Dimensionsreduktion zu erreichen.

Architektonisch ist die Struktur eines Autoencoders ein sog. „Feedforward“-Neuronales Netz. Dieser weist eine Eingabeschicht, eine versteckte Schicht sowie eine Ausgabeschicht auf (vgl. Abb.1). Die Ausgabeschicht weist die gleiche Anzahl von Neuronen wie die Eingabeschicht auf, um ihre eigenen Eingaben zu rekonstruiere zu können. Das macht einen Autoencoder zu einem Modell des unüberwachten Lernens, was bedeutet, dass keine gelabelten Daten notwendig sind – nur ein Satz von Eingabedaten anstelle von Eingabe-Ausgabe-Paaren.

Autoencoder
Abb. 1 Autoencoder

Es ist notwendig, dass der Autoencoder eine versteckte Schicht hat, die weniger Neuronen als die Eingabeschicht aufweist. Dieser Effekt zwingt das neuronale Netz dazu, eine komprimierte Repräsentation der Daten in der versteckten Schicht zu erstellen, indem das Netz eine Korrelationen in den Eingabedaten lernt.

Der Übergang von der Eingabe- zur versteckten Schicht wird als der Kodierungsschritt und der Übergang von der versteckten zur Ausgabeschicht als der Dekodierungsschritt bezeichnet. Wir können diese Übergänge auch mathematisch als ein Mapping definieren:

Kodierung- und Dekodierungsschritt im Autoencoder.
Formel 1. Kodierung- und Dekodierungsschritt im Autoencoder.

Das Mapping wird realisiert, indem man den Eingangsdatenvektor \vec{x} mit einer Gewichtsmatrix W multipliziert, einen Bias-Term b hinzufügt und auf den resultierenden Vektor eine nicht lineare Operation \sigma wie z. B. Sigmoid, tanh oder ReLU Einheit anwendet. In dem Artikel „Aktivierungsfunktionen in Neuronalen Netzen“ finden Sie eine detailliertere Beschreibung der einzelnen nicht linearen Funktionen sowie deren Vor- und Nachteile.


2.2 Training eines Autoencoders

Während der Trainingszeit nimmt der Encoder ein Eingangsdatenmuster x und bildet es auf die sog. versteckte oder latente Repräsentation z, in der versteckten Schicht, ab. Im Anschluss bildet der Decoder z auf den Ausgangsvektor x‚ (in der Ausgabeschicht) ab, der (im besten Fall) die exakte Repräsentation der Eingangsdaten x darstellt. Bitte beachten Sie, dass eine exakte Nachbildung der Eingangsdaten x in der Regel nicht möglich ist.

Mit der Ausgabe x‚ besteht das Training aus der Anwendung des stochastischen Gradientenabstiegs, um eine vordefinierten Verlustfunktion, z. B. einen mittleren quadratischen Fehler, zu minimieren, vgl. Formel 2. (Für mehr Informationen zum Training der neuronalen Netze bitte lesen Sie sich den Artikel „Training der Künstlichen Neuronalen Netze“ an)

Def. der Verlustfunktion beim Training des Autoencoders.
Formel 2. Def. der Verlustfunktion beim Training des Autoencoders.

3. Deep Autoencoder

Die Erweiterung des einfachen Autoencoders ist der Deep Autoencoder (Abb. 2). Wie in Abb. 2 zu sehen ist, besteht der einzige Unterschied zu seinem einfacheren Gegenstück in der Anzahl der versteckten Schichten.

Architektur des tiefen Autokodierers (Deep Autoencoder).
Abb. 3 Architektur des tiefen Autokodierers (Deep Autoencoder).

Die zusätzlichen versteckten Schichten ermöglichen es dem Autoencoder, mathematisch komplexere zugrunde liegende Muster in den Eingabedaten zu lernen.

Die erste Schicht des Deep Autoencoder kann Merkmale erster Ordnung in der Roheingabe lernen (z. B. Kanten oder Ecken in einem Bild). Die zweite Schicht kann Merkmale zweiter Ordnung lernen, die Mustern im Erscheinungsbild von Merkmalen erster Ordnung entsprechen (z. B. in Bezug darauf, welche Kanten dazu neigen, zusammen aufzutreten). Tiefere Schichten des Deep Autoencoders neigen dazu, sogar Features höherer Ordnung zu lernen.

Um alles zusammenzufassen: Wir brauchen zusätzliche Schichten, um mit komplexeren Daten umgehen zu können – Daten, die wir beim kollaborativen Filtern verwenden.


4. Implementierung

Wie bereits erwähnt, werden wir lernen, die Bewertung vorherzusagen, die eine Person einem Film geben würde. Hierfür werden wir den berühmten MovieLens-Datensatz verwenden. MovieLens ist ein webbasiertes Empfehlungssystem und eine Online-Community, die ihren Benutzern Filme zum Anschauen empfiehlt.

Genauer gesagt werden wir den ml-1m.zip-Datensatz verwenden, der 1.000.209 anonyme Bewertungen von ca. 3.900 Filmen enthält, die von 6.040 MovieLens-Benutzern abgegeben wurden. Die Importdatei, die wir benötigen, ist ratings.dat. Diese Datei enthält 1.000.209 Zeilen, die alle das folgende Format haben:

user_id::movie_id::rating:time_stamp.

Zum Beispiel die erste Zeile in ratings.dat:

1::595::5::978824268 

bedeutet, dass die Person Nr. 1 dem Film Nr. 595 eine Fünf-Sterne-Bewertung gegeben hat. Der Zeitstempel kann ignoriert werden, da er nicht verwendet wird.

Das Deep-Learning-Modell, das wir implementieren, benötigt eine bestimmte Datenstruktur für das Training und das Testen. Diese Datenstruktur ist eine UxM-Matrix, wobei U die Anzahl der Benutzer und M die Anzahl der Filme darstellt. Jede Zeile i ∈ U ist eine eindeutige Benutzer-ID und jede Spalte j ∈ M eine eindeutige Film-ID. Eine Visualisierung für eine solche Matrix ist in Abb. 3 zu sehen.

Visualisierung einer möglichen User-Movie Matrix.
Abb. 4 Visualisierung einer möglichen User-Movie Matrix.

Jeder Eintrag in dieser Matrix ist eine Bewertung, die eine Person einem bestimmten Film gegeben hat. Ein Eintrag von 0 bedeutet, dass die Person diesem Film keine Bewertung gegeben hat. Bspw. hat die Person Nr. 1 dem Film Nr. 3 eine Bewertung von 4 Sternen gegeben, während Film Nr. 1 überhaupt nicht bewertet wurde.

Da sich dieses Tutorial auf die Implementierung des Deep Learning-Modells konzentriert, wird der Schritt der Erstellung der User-Movie-Matrix aus der Datei ratings.dat an dieser Stelle nicht behandelt. Für weitere Fragen zu diesem Thema möchte ich Sie auf mein GitHub-Repository verweisen, wo Sie das entsprechende Python-Skript untersuchen können.


4.1 Trainings- und Testdatensätze

Bevor das Modell implementiert und trainiert werden kann, ist ein weiterer Aufbereitungsschritt der Daten notwendig – die Aufteilung der Daten in Trainings- und Testdatensätze. Dieser Schritt ist ziemlich einfach. Bisher haben wir eine User-Movie-Matrix, bei der jede Zeile eine Liste von Bewertungen ist. Um die Trainings- und Testdatensätze aus dieser Liste zu erhalten, müssen wir eine Teilmenge der Bewertungen aus jeder Zeile nehmen und diese nur für das Training verwenden, während wir die verbleibende Teilmenge nur für das Testen verwenden wird.

Als Beispiel für die beschriebene Vorgehensweise betrachten wir einen viel kleineren Datensatz, der nur aus 15 Filmen besteht. Eine bestimmte Person könnte diesen Filmen die folgenden Bewertungen gegeben haben:

Movie Nr. : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Rating:     5 0 2 4 0 0 2 1 5  1  0  4  5  1  3

Denken Sie bitte daran, dass 0 bedeutet, dass der Film nicht bewertet wurde. Nun nehmen wir eine Teilmenge, die aus den ersten 10 Filmen besteht, als Trainingsmenge und tun so, als ob die restlichen Filme noch nicht bewertet wurden:

Movie Nr. : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Rating:     5 0 2 4 0 0 2 1 5  0  0  0  0  0  0

Entsprechend werden die letzten 5 Filmbewertungen der Originaldaten als Testdaten verwendet, während die Filme 1-10 als nicht bewertet maskiert werden:

Film Nr. : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Bewertung:     0 0 0 0 0 0 0 0 0 1 0 4 5 1 3

Dies war nur eine einfache Demonstration, wie die verschiedenen Sätze erhalten wurden. Im ursprünglichen MovieLens-Datensatz verwende ich für jeden Benutzer nur 10 Filmbewertungen für das Testen, während der Rest (die große Mehrheit) für das Training des Modells verwendet wurde.


4.2 TensorFlow-Implementierung

Neuronales Netz

Der Deep Autoencoder ist als Klasse implementiert mit allen notwendigen Operationen wie Training, Inferenz, Optimierung, etc. innerhalb der Klasse.

Im Konstruktor werden Kernel-Initialisierer für die Gewichte und Biases gesetzt. Im nächsten Schritt werden alle Gewichte und Biases im Netz initialisiert. Die Gewichte sind normalverteilt mit einem Mittelwert von 0,0 und einer Varianz von 0,02, während die Biases zu Beginn alle auf 0,0 gesetzt werden.

In diesem speziellen Beispiel hat das Netzwerk drei versteckte Schichten, die jeweils 128 Neuronen enthalten. Die Größe der Eingabeschicht (und der Ausgabeschicht) entspricht der Anzahl aller vorhandenen Filme im Datensatz (3900).

Training

Bei einem Eingabedatenmuster x (eine Zeile der Benutzer-Film-Matrix) wird ein Vorwärtsdurchlauf durchgeführt, der die Ausgaben des Netzwerks berechnet. Die versteckten Schichten verwenden Sigmoid als Aktivierungsfunktion. Bitte beachten Sie, dass die letzte Schicht weder eine Nicht-Linearität noch einen Bias-Term aufweist.

Nachdem wir die Vorhersagen des Netzwerks erhalten haben, können wir den Verlust zwischen diesen Vorhersagen und den entsprechenden Labels (Netzwerkeingänge x) berechnen. Um den Mittelwert des Verlustes zu berechnen, müssen wir auch die Anzahl der Labels kennen, die nicht Null sind – in anderen Worten die Anzahl der Gesamtbewertungen eines Benutzers in der Trainingsmenge.

Der Optimierungs-/Trainingsschritt des Netzwerks mag ein wenig knifflig erscheinen, besprechen wir diesen Schritt für Schritt. Ausgehend von einer Eingabe x werden die entsprechenden Ausgaben berechnet. Wie Sie wahrscheinlich schon bemerkt haben, sind die meisten Werte in der Eingabe x Nullwerte, da ein Benutzer mit Sicherheit nicht alle 5953 Filme, die im Datensatz enthalten sind, gesehen und bewertet hat.

Folglich ist es ratsam, die rohen Vorhersagen des Netzwerks nicht direkt zu verwenden. Stattdessen müssen wir die Indizes der Nullwerte in der Dateneingabe x identifizieren und die Werte im Ausgabevektor, die diesen Indizes entsprechen, ebenfalls auf null setzen. Diese Manipulation der Vorhersage reduziert die Trainingszeit des Netzes massiv und gibt dem Netz die Möglichkeit, sich beim Training nur auf die Bewertungen zu konzentrieren, die der Benutzer tatsächlich abgegeben hat.

Nach diesem Schritt kann der Verlust berechnet werden, ebenso wie der Regularisierungsverlust (optional). Die Verlustfunktion wird durch den AdamOptimizer minimiert. Bitte beachten Sie, dass die Methode einen mittleren quadratischen Fehler (Root Mean Squared Error, RMSE) anstelle eines mittleren quadratischen Fehlers (Mean Squared Error, MSE) zurückgibt, um die Genauigkeit besser messen zu können.

Testen

Nach einigen Epochen der Trainingsphase hat das neuronale Netz alle Bewertungen im Trainingsdatensatz von jeder Person mehrfach gesehen. Zu diesem Zeitpunkt sollte das Modell die zugrundeliegenden Muster in den Daten und die entsprechenden kollaborativen Filmpräferenzen der Personen gelernt haben. Bei einer Trainingsstichprobe x für eine Benutzerbewertung sagt das Modell eine Ausgabe x‚ voraus.

Dieser Vektor besteht aus der Rekonstruktion der Eingabe x, (wie erwartet) enthält x‚ nun aber auch Werte für die zuvor Null-Bewertung in der Eingabe x. Das bedeutet, dass das Modell noch nicht bewertete Filme mit einer Bewertung versehen hat. Diese Bewertung entspricht der Präferenz des Benutzers – der Präferenz, die das Modell in den Daten identifiziert hat.

Damit wir die Genauigkeit des Modells messen können, benötigen wir sowohl den Trainings- als auch den Testdatensatz. Basierend auf dem Trainingsdatensatz wird eine Vorhersage getroffen. Analog zur Trainingsphase betrachten wir nur die Ausgabewerte, die den Indizes der Nicht-Null-Werte im Testsatz entsprechen.

Nun können wir den Verlust des mittleren quadratischen Fehlers (RMSE) zwischen den vorhergesagten und den tatsächlichen Bewertungen berechnen. Der RMSE stellt die Stichproben-Standardabweichung der Differenzen zwischen vorhergesagten Werten und beobachteten Werten dar. Bspw. bedeutet ein RMSE von 0,5, dass die vorhergesagte Bewertung im Durchschnitt um 0,5 Sterne von der tatsächlichen Bewertung abweicht, die die Person dem Film gegeben hat.


5. Ergebnisse

Der letzte Schritt besteht darin, den Trainingsprozess auszuführen und die Leistung des Modells zu untersuchen. An dieser Stelle werde ich nicht näher auf den Aufbau der Dateneingabe-Pipeline etc. eingehen, da diese Schritte allgemein bekannt sind. Leser, die an diesem Thema interessiert sind, können diese Schritte in meinem GitHub-Repository einsehen.

Hier können Sie die Trainings- und Testleistung für die ersten 50 Epochen beobachten. Nach 30 Epochen erhalten wir eine Abweichung von 0,929 Sternen zwischen den vorhergesagten und tatsächlichen Bewertungen auf dem Testset.

epoch_nr: 0, train_loss: 1.169, test_loss: 1.020
epoch_nr: 10, train_loss: 0.936, test_loss: 0.959
epoch_nr: 20, train_loss: 0.889, test_loss: 0.931

epoch_nr: 30, train_loss: 0.873, test_loss: 0.923

@KI-Tutorials

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert