diff --git a/Dokumentation/silas/daten_analyse.tex b/Dokumentation/silas/daten_analyse.tex index 477bf4f99fd19b83fc3035381049fe60b3a2a8e8..13c4c579d57ba1e5887b0abb9a1c854bb0dd7d88 100644 --- a/Dokumentation/silas/daten_analyse.tex +++ b/Dokumentation/silas/daten_analyse.tex @@ -1,10 +1,14 @@ \subsection{Analyse des Datensatzes} -Ein wichtiger Schritt in jeder Aufgabe im Bereich des maschinellen Lernens ist es die Datenbasis zu analysieren und zu verstehen. +Ein wichtiger Schritt in jeder Aufgabe im Bereich des maschinellen Lernens ist es, die Datenbasis zu analysieren und zu verstehen. -Der Yelp-Datensatz besteht aus einer Ansammlung von json Dateien. Darunter jeweils eine Datei für businesses, reviews, user, checkins, sowie tips - quasi short-reviews - und photos, welche als Cross-Referenz für andere Datensätze fungiert. Für dieses Projekt interessiert jedoch nur die review Datei. +Der Yelp-Datensatz besteht aus einer Ansammlung von json Dateien. +Darunter befindet sich jeweils eine Datei für +businesses, reviews, user, checkins, sowie tips - quasi short-reviews - und photos, +welche als Cross-Referenz für andere Datensätze fungiert. +für dieses Projekt ist jedoch nur die review Datei interessant. -Die Yelp-Reviews befinden sich in einer 6GB großen json Datei. Diese Datei könnte mit einem leistungsstarken Computer vollständig in den Arbeitsspeicher geladen werden. Jedoch wird im Rahmen +Die Yelp-Reviews befinden sich in einer 6\,GB großen json Datei. Diese Datei könnte mit einem leistungsstarken Computer vollständig in den Arbeitsspeicher geladen werden. Jedoch wird im Rahmen dieser Arbeit die Datei zeilenweise verarbeitet. Das zeilenweise Verarbeiten der Datei ermöglicht es, die Systemanforderungen @@ -26,7 +30,7 @@ In Zeile 0 wird der Pfad des Datensatzes definiert. Danach wird in Zeile 2 mit einer for-Schleife über jede Zeile des Datensatzes iteriert, wobei die Funktion \lstinline{open} die Datei öffnet und ein iterierbares Objekt zurück liefert. -Durch das Benutzen der Funktion \lstinline{enumerate} erhalten wir den +Durch das Benutzen der Funktion \lstinline{enumerate} erhält man den aktuellen Index, sodass in der Variable \lstinline{index} die aktuelle Zeilennummer gespeichert ist und in der Variable \lstinline{line} die aktuelle Zeile selbst. @@ -34,7 +38,7 @@ Die if-Abfrage in Zeile 3 sorgt dafür, dass die for-Schleife vorzeitig abgebroc In Zeile 5 wird der Text der aktuellen Zeile ausgegeben. -Das Ausführen des Quellcodes im Listing \ref{list:four} führt zu folgender Ausgabe: +Das Ausführen des Quellcodes in Listing \ref{list:four} führt zu folgender Ausgabe: \begin{lstlisting}[numbers=none] {"review_id":"xQY8N_XvtGbearJ5X4QryQ", "user_id":"OwjRMXRC0KyPrIlcjaXeFQ", @@ -57,7 +61,9 @@ Das Ausführen des Quellcodes im Listing \ref{list:four} führt zu folgender Aus \end{lstlisting} -Hier ist zu erkennen, dass jede Zeile der review.json eine Rezension mit den Merkmalen \lstinline{review_id, user_id, business_id, stars, useful, funny, cool, text und date} enthält. Die meisten dieser Merkmale sind selbsterklärend. Erwähnenswert sind dabei jedoch die Merkmale \lstinline{useful, funny} und \lstinline{cool}, welche Reaktionen anderer Nutzer auf diese Review darstellen. Für dieses Projekt sind hingegen nur die beiden Punkte \lstinline{stars} und \lstinline{text} von Bedeutung. +Hier ist zu erkennen, dass jede Zeile der review.json eine Rezension mit den +Merkmalen \lstinline{review_id, user_id, business_id, stars, useful, funny, cool, text} und +\lstinline{date} enthält. Die meisten dieser Merkmale sind selbsterklärend. Erwähnenswert sind dabei jedoch die Merkmale \lstinline{useful, funny} und \lstinline{cool}, welche Reaktionen anderer Nutzer auf diese Review darstellen. Für dieses Projekt sind hingegen nur die beiden Punkte \lstinline{stars} und \lstinline{text} von Bedeutung. In diesem Datensatz sind Sonderzeichen mit einem Backslash escaped. \subsubsection{Anzahl der Reviews} @@ -71,7 +77,7 @@ for line in open(data_path,encoding="utf8"): print (nr_of_reviews)) \end{lstlisting} -Das Programm liefert \lstinline{8021122} zurück. +Das Programm liefert die Anzahl \lstinline{8021122} zurück. \subsubsection{Reviewlänge}\label{subsubsec:reviewlength} \begin{lstlisting}[inputencoding=latin1,caption={Programm zur Ermittlung der Reviewlänge},label={list:rev_len}] @@ -139,7 +145,7 @@ unter dem Alias \lstinline{plt} importiert. Danach werden in Zeile 9 mit der Funktion \lstinline{unique} von Numpy die verschiedenen Bewertungen in der Variable \lstinline{value} gespeichert. -Der Parameter \lstinline{return_counts=True} sorgt dafür, dass zusätzlich die Häufigkeit der +Der Parameter \lstinline{return_counts=True}sorgt dafür, dass zusätzlich die Häufigkeit der Bewertung zurückgegeben wird. Die Häufigkeit wird in der Variable \lstinline{count} gespeichert. In Zeile 11 bis 16 wird der Plot erstellt. diff --git a/Dokumentation/silas/gensim.tex b/Dokumentation/silas/gensim.tex index cde72dd934b580cb77aaec8f9bc9b342cb283af7..d9e70ad370daaaf30162f9a081f87a99e86a111b 100644 --- a/Dokumentation/silas/gensim.tex +++ b/Dokumentation/silas/gensim.tex @@ -4,8 +4,7 @@ Für das Trainieren des Word2Vec-Modells wird in dieser Arbeit die Open-Source-Library Gensim verwendet. Gensim bietet viele hilfreiche Funktionen und die Möglichkeit, Generatoren zu verwenden. - -Um bei Gensim Generatoren benutzen zu können schreiben wir die Klasse \lstinline{MyCorpus}. +Um bei Gensim Generatoren benutzen zu können wird die Klasse \lstinline{MyCorpus} geschrieben. \begin{lstlisting}[caption={Generator für Gensim},label={list:Corpus}] from gensim import utils import json @@ -56,6 +55,6 @@ Die Funktion erwartet den Pfad zum Word2Vec-Modell als ersten Parameter. Der zweite Parameter ist der Datensatzpfad und wird nur benötigt, falls noch kein Word2Vec-Modell gespeichert wurde. -Zuerst wird in Zeile 12 geprüft, ob bereits ein Word2Vec-Modell existiert, ist dies der -Fall wird dieses direkt zurückgegeben, gibt es kein Modell, so wird dieses im inneren try-Block +Zuerst wird in Zeile 12 geprüft, ob bereits ein Word2Vec-Modell existiert. Ist dies der +Fall, wird dieses direkt zurückgegeben, gibt es kein Modell, so wird dieses im inneren try-Block mithilfe der \lstinline{myCorpus} Klasse generiert, gespeichert und zurückgeben. \ No newline at end of file diff --git a/Dokumentation/silas/w2vCNN.tex b/Dokumentation/silas/w2vCNN.tex index 69427c2af235d7b34a64cf936f1d5ed8f0d01533..29ebff1f8a6fb852c3698e35763af81c249282cd 100644 --- a/Dokumentation/silas/w2vCNN.tex +++ b/Dokumentation/silas/w2vCNN.tex @@ -52,10 +52,10 @@ Dieses Numpy-Array speichert die ersten 72 Wortvektoren der Rezension, die Zahl 72 wurde aufgrund des im Kapitel \ref{subsubsec:reviewlength} berechneten Median der Reviewlänge gewählt. -Die for-Schleife in Zeile 11 durchläuft alle Wörter der Liste split und fügt diese, +Die for-Schleife in Zeile 11 durchläuft alle Wörter der Liste \lstinline{split} und fügt diese, falls sie im word2Vec-Modell vertreten sind, in das \lstinline{wordVecs} Array ein. -Sind mehr als 72 Wörter in der Liste \lstinline{Split} wird die Schleife abgebrochen, +Sind mehr als 72 Wörter in der Liste \lstinline{split} wird die Schleife abgebrochen, wenn das Array vollständig gefüllt ist. Sollten sich weniger als 72 Wörter in der Liste befinden, @@ -66,9 +66,9 @@ ist notwendig, da das CNN eine feste Dimension der Eingangsdaten benötigt. Anschließend wird in Zeile 18 geprüft, ob weniger als 5 Wortvektoren in dem Array -stehen, ist dies der Fall, wird eine Exception geworfen. +stehen. Ist dies der Fall, wird eine Exception geworfen. -Nach dem implementieren der Funktion \lstinline{getSentenceVectorCNN} muss das CNN erstellt werden. +Nach dem Implementieren der Funktion \lstinline{getSentenceVectorCNN} muss das CNN erstellt werden. \begin{lstlisting}[caption={CNN},label={list:modelCNN}] import numpy as np from tensorflow.keras.models import Sequential @@ -101,14 +101,14 @@ Die \noteable{MaxPooling1D-Schichten} dienen dazu die Informationen nach den Faltungen zu verdichten. Die Matrix, die als Ergebnis der zweiten \noteable{MaxPooling1D-Schicht} entsteht, -wird anschließend in Zeile 12 in einen Vektor umgewandelt, -dieser Vektor wird als Eingang des dichten neuronalen Netzes benutzt. +wird anschließend in Zeile 12 in einen Vektor umgewandelt. +Dieser Vektor wird als Eingang des dichten neuronalen Netzes benutzt. Für das dichte neuronale Netz wird hier wieder der Ansatz verfolgt, die Schichten inkrementell zu verkleinern, um eine Verdichtung der Information zu erzwingen. -Zuletzt muss das neuronale Netz noch kompiliert werden, dies geschieht in -Zeile 18. Hierbei wird wie gehabt der optimizer \lstinline{adam} gewählt und die +Zuletzt muss das neuronale Netz noch kompiliert werden, was in Zeile 18 +geschieht. Hierbei wird wie gehabt der optimizer \lstinline{adam} gewählt und die Fehlerfunktion \lstinline[literate={\_}{}{0\discretionary{\_}{}{\_}}]{sparse_categorical_crossentropy} sowie die Metrik \lstinline{sparse_categorical_accuracy} verwendet. @@ -165,8 +165,8 @@ modelNN.evaluate(testData) \end{lstlisting} Hierfür wird die Größe der Trainingsmenge durch die BatchSize geteilt (Zeile 24). -Um ein Overfitting zu verhindern, wird, wie beim Mean-Modell auch schon in -Zeile 25 ein Earlystop definiert. +Um ein Overfitting zu verhindern wird, wie beim Mean-Modell auch schon in +Zeile 25, ein Earlystop definiert. Dieser unterbricht das Training vorzeitig, falls acht Epochen lang keine Verbesserung auf der Validierungsmenge erzielt wird. @@ -186,7 +186,7 @@ Dafür wird in Zeile 34 zunächst wieder ein Generator angelegt. Mit dem Parameter \lstinline{loop=False} wird gewährleistet, dass der Generator den Datensatz nur einmal durchläuft. Dieser Generator kann nun in Zeile 35 an die Methode \lstinline{evaluate} übergeben werden. -Das Evaluieren zeigt, dass dieses Modell zu $81.44\%$ die Klassen der Testmenge richtig klassifiziert. +Das Evaluieren zeigt, dass dieses Modell zu $81.44\,\%$ die Klassen der Testmenge richtig klassifiziert. \begin{lstlisting}[caption={CNN - Klassengewichte},label={list:modelCNNWeights},numbers=none] Y_train=[] @@ -233,13 +233,13 @@ zurückliefert. \label{tab:conf_w_cnn} \end{table} -Aus der Tabelle \ref{tab:conf_w_cnn} lässt sich ablesen, dass negative Bewertungen zu $83.14\%$ richtig als -negative Bewertung klassifiziert werden, zu $13.77\%$ als neutrale Bewertung und zu $3.08\%$ +Aus der Tabelle \ref{tab:conf_w_cnn} lässt sich ablesen, dass negative Bewertungen zu $83.14\,\%$ richtig als +negative Bewertung klassifiziert werden, zu $13.77\,\%$ als neutrale Bewertung und zu $3.08\,\%$ als positive Bewertung. -Neutrale Bewertungen werden zu $63.54\%$ richtig als neutrale Bewertung klassifiziert, zu $19.70\%$ -als positive Bewertung und zu $16.76\%$ als negative Bewertung. +Neutrale Bewertungen werden zu $63.54\,\%$ richtig als neutrale Bewertung klassifiziert, zu $19.70\,\%$ +als positive Bewertung und zu $16.76\,\%$ als negative Bewertung. -Positive Bewertungen werden zu $83.67\%$ richtig -als positive Bewertung klassifiziert, zu $13.16\%$ als neutrale Bewertung und zu $3.16\%$ +Positive Bewertungen werden zu $83.67\,\%$ richtig +als positive Bewertung klassifiziert, zu $13.16\,\%$ als neutrale Bewertung und zu $3.16\,\%$ als negative Bewertung. \ No newline at end of file diff --git a/Dokumentation/silas/w2vMean.tex b/Dokumentation/silas/w2vMean.tex index 59bbdaba7413c4a5a5658b3468a3a4c314ec9d62..b6bedf6dcfd5fdd0c2e4fe47c7a7ed0eabb9c838 100644 --- a/Dokumentation/silas/w2vMean.tex +++ b/Dokumentation/silas/w2vMean.tex @@ -1,15 +1,15 @@ \newpage \subsection{Mean-Vektor-Klassifikationsmodell} %Durchschnittsvektor-Klassifkationsmodell ?? -Das Word2Vec-Modell bildet einen Vektorraum, indem ähnliche Wörter nahe +Das Word2Vec-Modell bildet einen Vektorraum, in dem ähnliche Wörter nahe beieinander liegen. Es ist somit naheliegend, dass Wörter, die mit einer negativen Rezension assoziiert werden, ein anderes Gebiet des Vektorraumes belegen als jene, die mit positiven Rezensionen assoziiert werden. -Der Gedanke für dieses Modell ist es, den Mittelwert aller Wortvektoren in -einer Rezension zu ermitteln und somit eine Art „Satzvektor“ zu erhalten. Diese Satzvektoren +Der Gedanke dieses Modell ist es, den Mittelwert aller Wortvektoren in +einer Rezension zu ermitteln und somit eine Art \textit{Satzvektor} zu erhalten. Diese Satzvektoren werden als Eingangswerte genutzt, um mithilfe eines neuronalen Netzes eine Klassifikation der Rezensionen durchzuführen. @@ -19,11 +19,12 @@ Somit ist es möglich, auf die Generatoren zu verzichten und die Trainingsdaten Arbeitsspeicher zu halten. Dies hilft, die benötigte Trainingszeit zu reduzieren. -Sollte die Arbeitsspeicherkapazität nicht ausreichen, befindet sich eine Implementierung die Generatoren benutzt im Anhang. -\wip{referenzieren und Tatsächlich einfügen} +Sollte die Arbeitsspeicherkapazität nicht ausreichen, +befindet sich eine Implementierung, welche Generatoren benutzt, im Git-Repository. +\wip{Link zu Gitlab?} -Um das Word2Vec-Modell zu erhalten, importieren wir die im Listing \ref{list:gw2v} geschriebene Funktion -\lstinline{getWordVecModel}. +Um das Word2Vec-Modell zu erhalten, wird die im Listing \ref{list:gw2v} geschriebene Funktion +\lstinline{getWordVecModel} importiert. \begin{lstlisting}[caption={Satzvektorfunktion},label={list:mean1}] from gensim import utils @@ -89,7 +90,7 @@ Sind keine Daten vorhanden, wird der gesamte Datensatz durchlaufen und für jede einzelne Rezension der Satzvektor ermittelt. Befindet sich kein Wort der Rezension im Word2Vec-Modell so wird diese Rezension in Zeile 33 übersprungen. -Die Bewertungen werden wie folgt codiert: Negativ (0), Neutral (1) und Positiv (2). +Die Bewertungen werden wie folgt codiert: negativ (0), neutral (1) und positiv (2). Anschließend werden die generierten Daten gespeichert, um bei mehrfacher Ausführung Zeit zu sparen. Danach werden die Daten in Zeile 45 in Trainings- und Testdaten aufgeteilt, hierfür wird die Funktion \lstinline{train_test_split} von \lstinline{sklearn} verwendet. @@ -106,8 +107,8 @@ modelNN.add(Dense(15,activation='relu')) modelNN.add(Dense(3,activation='softmax')) modelNN.compile(optimizer='adam',loss='sparse_categorical_crossentropy',metrics=["sparse_categorical_accuracy"]) \end{lstlisting} -Hier wurde ein dichtes mehrschichtiges neuronales Netzwerk verwendet, wobei die -Eingangsdimension, der Dimension der Satzvektoren (in diesem Fall 100) entspricht. +Hier wurde ein dichtes, mehrschichtiges neuronales Netzwerk verwendet, wobei die +Eingangsdimension der Dimension der Satzvektoren (in diesem Fall 100) entspricht. Bis auf die Ausgangsschicht wurde für alle Schichten des neuronalen Netzwerks die Aktivierungsfunktion \lstinline{relu} verwendet. Die Ausgangsschicht selbst verwendet die Aktivierungsfunktion @@ -118,11 +119,11 @@ Klassifikationen üblich, bewusst kleiner gewählt, um eine Verdichtung der Info Nachdem die Struktur des neuronalen Netzwerkes nun feststeht, muss das Netz noch kompiliert werden. Hierzu werden in Zeile 54 einige Parameter gesetzt. Für den Optimierungsalgorithmus wird \lstinline{adam} gewählt. -Für die Fehlerfunktion, hier loss genannt, wird \lstinline{sparse_categorical_crossentropy} benutzt. +Für die Fehlerfunktion, hier \lstinline{loss} genannt, wird \lstinline{sparse_categorical_crossentropy} benutzt. -Die Fehlerfunktion \lstinline{sparse_categorical_crossentropy} ermöglicht im Gegensatz zur -\lstinline{binary_crossentropy} mehr als zwei Klassen zu Klassifizieren. Eine weitere -mögliche Fehlerfunktion ist die \lstinline{categorical_crossentropy}, hierzu müssten +Die Fehlerfunktion \lstinline{sparse_categorical_crossentropy} ermöglicht es im Gegensatz zur +\lstinline{binary_crossentropy} mehr als zwei Klassen zu klassifizieren. Eine weitere +mögliche Fehlerfunktion ist die \lstinline{categorical_crossentropy}. Hierzu müssten bloß die Zielwerte \noteable{One-Hot-Encoded} werden. Zuletzt wird für den Parameter \lstinline{Metrics} der Wert \lstinline{sparse_categorical_accuracy} übergeben. @@ -146,10 +147,10 @@ dem vorzeitigen Stopp wieder hergestellt. In Zeile 59 findet das tatsächliche Training des neuronalen Netzes statt. Hierfür werden der Methode \lstinline{fit} die Trainingsdaten übergeben. Der Parameter -\lstinline{validation_split = 0.2} sorgt dafür, dass $20 \%$ der Trainingsdaten als +\lstinline{validation_split = 0.2} sorgt dafür, dass $20\,\%$ der Trainingsdaten als Validierungsmenge genommen werden. Hierbei ist aber anzumerken, dass es sich bei den -Trainingsdaten ohnehin schon nur um $80 \%$ des Datensatzes handelt, -weswegen die tatsächliche Validierungsmenge $16 \%$ des Datensatzes beinhaltet. +Trainingsdaten ohnehin schon nur um $80\,\%$ des Datensatzes handelt, +weswegen die tatsächliche Validierungsmenge $16\,\%$ des Datensatzes beinhaltet. Die \lstinline{batch_size} wird aufgrund des großen Datensatzes auf 2048 gesetzt, um das Optimieren der Gewichte zu beschleunigen. Eine kleinere \lstinline{batch_size} hat beim Experimentieren in diesem Fall nicht zu einer schnelleren Konvergenz @@ -162,8 +163,8 @@ die Methode \lstinline{fit} übergebenen, Klassengewichte. \begin{lstlisting}[caption={Neuronales Netz - Evaluieren},label={list:mean5},firstnumber=60] modelNN.evaluate(X_test,Y_test) \end{lstlisting} -Um das Modell zu evaluieren, wird in Zeile 60 die Methode evaluate mit den Testdaten aufgerufen. -Das hier trainierte neuronale Netzwerk klassifiziert $80.02 \%$ der Testdaten richtig. +Um das Modell zu evaluieren, wird in Zeile 60 die Methode \lstinline{evaluate} mit den Testdaten aufgerufen. +Das hier trainierte neuronale Netzwerk klassifiziert $80.02\,\%$ der Testdaten richtig. \subsubsection{Konfusionsmatrix} Die bereits berechnete Genauigkeit ist ein gutes erstes Leistungsmerkmal des Klassifikators. Um den Klassifikator noch besser einschätzen zu können, @@ -188,21 +189,22 @@ confusion_matrix(Y_test,y_pred,normalize='true') \label{tab:m_w} \end{table} -Wie in Tabelle \ref{tab:m_w} zu sehen ist, werden negative Bewertungen zu $80.46\%$ -richtig als negative Bewertung klassifiziert, $17.27\%$ werden als -neutral klassifiziert und $2.28\%$ werden als positiv klassifiziert. +Wie in Tabelle \ref{tab:m_w} zu sehen ist, werden negative Bewertungen zu $80.46\,\%$ +richtig als negative Bewertung klassifiziert, $17.27\,\%$ werden als +neutral und $2.28\,\%$ werden als positiv klassifiziert. -Neutrale Bewertungen werden zu $68.44\%$ richtig klassifiziert, -jedoch werden $16.82\%$ der neutralen Bewertungen falsch als -negativ klassifiziert und zu $14.74\%$ falsch als positiv klassifiziert. +Neutrale Bewertungen werden zu $68.44\,\%$ richtig klassifiziert, +jedoch werden $16.82\,\%$ der neutralen Bewertungen falsch als +negativ und zu $14.74\,\%$ falsch als positiv klassifiziert. -Die positiven Bewertungen werden zu $81.72\%$ richtig als positive -Bewertungen klassifiziert, zu $15.86\%$ als neutral und zu -$2.42\%$ als negativ klassifiziert. +Die positiven Bewertungen werden zu $81.72\,\%$ richtig als positive +Bewertungen klassifiziert, zu $15.86\,\%$ als neutral und zu +$2.42\,\%$ als negativ klassifiziert. Das gleiche Modell ohne die Gewichtung der Klassen erreicht eine Genauigkeit -von $85.7\%$. Betrachtet man jedoch die Konfusionsmatrix in Tabelle \ref{tab:conf_no_w}, so -sieht man, dass dort bloß $27\%$ der neutralen Rezensionen richtig klassifiziert wurden. +von $85.7\,\%$. Betrachtet man jedoch die Konfusionsmatrix in +Tabelle \ref{tab:conf_no_w} so +sieht man, dass dort bloß $27\,\%$ der neutralen Rezensionen richtig klassifiziert wurden. \begin{table}[ht] \def\arraystretch{1.3} \begin{center} diff --git a/Dokumentation/w2v.pdf b/Dokumentation/w2v.pdf index e8258f82a77de2459581a721169adf1c909cdc42..708fe2f48e9f7827548d31b630240872ec3bcd57 100644 Binary files a/Dokumentation/w2v.pdf and b/Dokumentation/w2v.pdf differ