Skip to content
Snippets Groups Projects
Commit 16824c85 authored by Joel Vongehr's avatar Joel Vongehr
Browse files

spelling in Felix & Joels Teil

parent 8c2e21ca
No related branches found
No related tags found
No related merge requests found
......@@ -15,7 +15,7 @@ Für den Anfang gilt es, die Wörter eines Textes einzeln und unabhängig vonein
Im nächsten Schritt geht es darum, alle Großbuchstaben in Kleinbuchstaben umzuwandeln. Gerade im Englischen werden fast ausschließlich Wörter an Satzanfängen großgeschrieben. Ein kontextueller Unterschied besteht nur in seltenen Ausnahmefällen. Im selben Zuge können auch Satzzeichen entfernt werden, da es für den Computer keinen Unterschied macht, ob ein Wort in einem Teilsatz oder am Satzende steht. Durch das Entfernen von Großbuchstaben und Satzzeichen kann die Größe des Datensatzes zumindest etwas verringert werden.
Um den Korpus weiter zu verkleinern, werden anschließend die sogenannten \textbf{Stoppwörter} (engl. \textit{stoppwords}) entfernt. Ein Stoppwort zeichnet sich dadurch aus, dass es zum einen häufig vorkommt und zum anderen eine geringe Bedeutung vorweist. Im Deutschen trifft das beispielsweise auf Präpositionen wie \textit{an} oder \textit{in} zu. Im Englischen können es Wörter wie \textit{the} oder \textit{of} sein. Es gibt keine allgemeingültige Sammlung von Stoppwörtern, da diese immer auch auf den Kontext abgestimmt werden müssen. \cite[S.242]{krohn_beyleveld_bassens_2020}
Um den Korpus weiter zu verkleinern, werden anschließend die sogenannten \textbf{Stoppwörter} (engl. \textit{stop words}) entfernt. Ein Stoppwort zeichnet sich dadurch aus, dass es zum einen häufig vorkommt und zum anderen eine geringe Bedeutung vorweist. Im Deutschen trifft das beispielsweise auf Präpositionen wie \textit{an} oder \textit{in} zu. Im Englischen können es Wörter wie \textit{the} oder \textit{of} sein. Es gibt keine allgemeingültige Sammlung von Stoppwörtern, da diese immer auch auf den Kontext abgestimmt werden müssen. \cite[S.242]{krohn_beyleveld_bassens_2020}
Meist sind diese Techniken schon ausreichend um den Datensatz bedeutend zu reduzieren und zu bereinigen, ohne jedoch den Kontext zu verfälschen. Es gibt darüber hinaus noch das \textbf{Stemming} und die sogenannten \textbf{N-Gramme}. Beides komplexere Methoden, die in dieser Ausarbeitung allerdings keine Anwendung finden, dennoch erwähnt werden sollten. Ersteres ist \glqq die Zurückführung von Wörtern auf ihren Wortstamm.\grqq{ \cite[S.242]{krohn_beyleveld_bassens_2020}} Letzteres beschreibt Wörter, die überwiegend zusammen vorkommen. Als Beispiele eignen sich das \textit{Bigramm} \textit{New York} beziehungsweise das \textit{Trigramm} \textit{New York City}, welche sich zu einem Token zusammenfassen lassen.
......@@ -43,8 +43,8 @@ $n$ & & & & & &
\subsubsection{Wortvektoren}
Das Einbetten von Wörtern in Wortvektoren bietet gegenüber dem One-Hot-Encoding den entscheidenden Vorteil, dass die Wortbedeutung über die Daten erlernt wird und abgelesen werden kann. Bei der Erstellung von Wortvektoren werden zunächst die eindeutigen Wörter an eine beliebige Stelle eines \textit{Vektorraums} überführt. Dabei verschiebt sich die Position der Wörter so lange, bis der gesamte Datensatz eingelesen ist. Durch die Betrachtung zusätzlicher \textit{Kontextwörter} kann die Bedeutung des eigentlichen \textit{Zielwortes} im Wortvektor repräsentiert werden. Bei beispielsweise drei Kontextwörtern werden die drei Wörter vor und nach dem Zielwort betrachtet. Am Ende bekommt eine Position im Vektorraum eine bestimmte Bedeutung zugeordnet.
Im so entstehenden $n$-dimensionalen Vektorraum finden sich die einzelnen Wörter des Datensatzes wieder, wobei jedes durch einen Vektor (bspw. $\vec{king}$) beschrieben wird. Der Spaltenvektor der Dimension $n\times1$ bestimmt den Ort des Wortes in allen verfügbaren Dimensionen. Aufgrund fehlendem Vorstellungsvermögen ist es für den Menschen schwierig sich mehr als drei Dimensionen vorzustellen. Ein zweidimensionales Beispiel für einen Vektorraum findet sich in Abbildung \ref{fig:scratch}. Allgemein gilt, dass \glqq je enger zwei Wörter im Vektorraum beieinander stehen, umso ähnlicher ist auch ihre Bedeutung, was durch die Ähnlichkeit der Kontextwörter bestimmt wird, die ihnen in der natürlichen Sprache nahe sind.\grqq{ \cite[S.35]{krohn_beyleveld_bassens_2020}} So liegen Synonyme und Falschschreibungen eng beisammen. Wortgruppen mit ähnlichem Kontext bilden Cluster und Subcluster innerhalb eines großen Vektorraumes.
Im so entstehenden $n$-dimensionalen Vektorraum finden sich die einzelnen Wörter des Datensatzes wieder, wobei jedes durch einen Vektor (bspw. $\vec{king}$) beschrieben wird. Der Spaltenvektor der Dimension $n\times1$ bestimmt den Ort des Wortes in allen verfügbaren Dimensionen. Aufgrund fehlendem Vorstellungsvermögens ist es für den Menschen schwierig sich mehr als drei Dimensionen vorzustellen. Ein zweidimensionales Beispiel für einen Vektorraum findet sich in Abbildung \ref{fig:scratch}. Allgemein gilt, dass \glqq je enger zwei Wörter im Vektorraum beieinander stehen, umso ähnlicher ist auch ihre Bedeutung, was durch die Ähnlichkeit der Kontextwörter bestimmt wird, die ihnen in der natürlichen Sprache nahe sind.\grqq{ \cite[S.35]{krohn_beyleveld_bassens_2020}} So liegen Synonyme und Falschschreibungen eng beisammen. Wortgruppen mit ähnlichem Kontext bilden Cluster und Subcluster innerhalb eines großen Vektorraumes.
Für Wortvektoren gilt: \glqq Die geometrischen Beziehungen zwischen Wortvektoren sollten die semantische Beziehungen zwischen den Wörtern widerspiegeln.\grqq{} und \glqq Wortvektoren haben die Aufgabe, die menschliche Sprache auf einen geometrischen Raum abzubilden.\grqq{} Ein Vektor von einem Wort zu einem anderen repräsentiert die \glqq semantische Beziehung zwischen diesen Wörtern.\grqq{ \cite[S.238f]{chollet_francois_2018}} Ein bekanntes Beispiel dafür ist die Hauptstadt-Land-Beziehung, bei der Abstand und Orientierung von einem Land zu seiner Hauptstadt im Vektorraum auf andere Länder übertragen werden können, sodass der Vektor immer auf die zugehörige Hauptstand zeigt. Eine konkrete Anwendung mit dem ebenso bekannten \glqq \textit{king-queen}\grqq -Beispiel ist im nächsten Abschnitt unter Gleichung \ref{eqn:kingqueen} zu sehen.
Für Wortvektoren gilt: \glqq Die geometrischen Beziehungen zwischen Wortvektoren sollten die semantische Beziehungen zwischen den Wörtern widerspiegeln.\grqq{} und \glqq Wortvektoren haben die Aufgabe, die menschliche Sprache auf einen geometrischen Raum abzubilden.\grqq{} Ein Vektor von einem Wort zu einem anderen repräsentiert die \glqq semantische Beziehung zwischen diesen Wörtern.\grqq{ \cite[S.238f]{chollet_francois_2018}} Ein bekanntes Beispiel dafür ist die Hauptstadt-Land-Beziehung, bei der Abstand und Orientierung von einem Land zu seiner Hauptstadt im Vektorraum auf andere Länder übertragen werden können, sodass der Vektor immer auf die zugehörige Hauptstadt zeigt. Eine konkrete Anwendung mit dem ebenso bekannten \glqq \textit{king-queen}\grqq -Beispiel ist im nächsten Abschnitt unter Gleichung \ref{eqn:kingqueen} zu sehen.
\input{w2vFromScratch}
\ No newline at end of file
\subsection{Generatoren
\label{subsec:Generator}}
%Problemstellung
Spätestens wenn mit etwas größeren Datenmengen trainiert wird stellt sich bei einer unserer Methoden ein neues Problem dar. Während die mean-Methode ohne Probleme durchläuft bricht die CNN-Methode aufgrund mangelnden Arbeitsspeicher ab. %beschwert sich die CNN-Methode, dass nicht genug Arbeitsspeicher vorhanden ist.
Spätestens wenn mit etwas größeren Datenmengen trainiert wird stellt sich bei einer unserer Methoden ein neues Problem dar. Während die mean-Methode ohne Probleme durchläuft bricht die CNN-Methode aufgrund mangelnden Arbeitsspeichers ab. %beschwert sich die CNN-Methode, dass nicht genug Arbeitsspeicher vorhanden ist.
Dies lässt sich auch ganz leicht nach folgender Formel nachrechnen:
%Vlt mit Formelzeichen, welche vorher im text definiert werden?
% => Kürzere Formel & Mehr Text
......@@ -17,13 +17,13 @@ Dies könnte mit 8GB RAM etwas knapp werden, jedoch stellt es bei 16GB gar kein
8,000,000 \times 72 \times 100 \times 8 \approx 430\text{ GB}
\end{equation}
Das Problem ist recht deutlich. Viele Personen hätten auf ihrem privaten PC vermutlich nicht einmal genug Festplattenspeicher für diese Datenmenge, geschweige denn Arbeitsspeicher. \\
Die Daten müssen bei der CNN-Methode also nur stückweise in den Arbeitsspeicher geladen werden, dann wird mit diesen trainiert und anschließend werden sie wieder aus dem Arbeitsspeicher gelöscht um Platz für die nächsten Daten zu machen. Dabei gibt es wieder verschiedene Ansätze.
Die Daten müssen bei der CNN-Methode also nur stückweise in den Arbeitsspeicher geladen werden, dann wird mit diesen trainiert und anschließend werden sie wieder aus dem Arbeitsspeicher gelöscht, um Platz für die nächsten Daten zu machen. Dabei gibt es wieder verschiedene Ansätze.
\subsubsection{Erster Generator}\label{subsubsec:simpleGen}
%Erster Ansatz, sehr lange validierungszeit
Ein möglicher Ansatz ist die rohen Daten nur schrittweise einzulesen und diese dann erst dem word2vec model zu übergeben um daraus einen Vektor zu machen. Dafür wird eine Funktion geschrieben, welche dann der fit Methode des eigentlichen machine learning models als Datensatz-parameter übergeben wird. Dabei wird in der Funktion die batchsize berücksichtigt, sodass stets die gewünschte Menge an Daten gleichzeitig in das model geladen werden.
Ein möglicher Ansatz ist die rohen Daten nur schrittweise einzulesen und diese dann erst dem word2vec model zu übergeben, um daraus einen Vektor zu machen. Dafür wird eine Funktion geschrieben, welche dann der fit Methode des eigentlichen machine learning models als Datensatz-parameter übergeben wird. Dabei wird in der Funktion die batchsize berücksichtigt, sodass stets die gewünschte Menge an Daten gleichzeitig in das Modell geladen werden.
Um dies jedoch zu erfüllen müssen die Daten nach ihren Nutzen in verschiedene Dateien aufgeteilt werden. Dementsprechend eine Trainings-, Validierungs- und Test-Datei.
Um dies jedoch zu erfüllen müssen die Daten nach ihrem Nutzen in verschiedene Dateien aufgeteilt werden. Dementsprechend eine Trainings-, Validierungs- und Test-Datei.
\begin{lstlisting}[label={lst:Aufteilung}]
val = open('val.json','w',encoding='utf8')
test = open('test.json','w',encoding='utf8')
......@@ -43,7 +43,7 @@ test.close()
train.close()
\end{lstlisting}
Das Aufteilen wird durch ein einfaches Zählen und Sortieren gelöst. Dabei zählt eine Variable, hier \lstinline{i}{}, hoch und je nachdem welchen Wert diese Variable hat werden die Daten in die entsprechende Datei sortiert. Das Ziel ist eine 60-20-20 Aufteilung der Daten. Dafür werden bei den Werten \lstinline{0, 1}{} und \lstinline{2}{} die Daten in die Trainingsdatei geschrieben und dementsprechend bei den Werten \lstinline{3}{} und \lstinline{4}{} in die Validierungs-, bzw.\@ Testdatei.
Wenn in die Testdatei geschrieben wird, wird auch gleichzeitig die Zählervariable zurückgesetzt, sodass mit den gleichen Werten von vorne begonnen werden kann. Hier wurde sich bewusst für ein Zurücksetzen der Variable entschieden und gegen ein kontinuierliches Hochzählen und der Sortierung durch Modulo: Auf diese Weise werden bedenkenlos Overflow- und Signifikanzprobleme verhindert ohne einen deutlichen Verlust der Lesbarkeit des Codes hinnehmen zu müssen. \wip{Da der genutzte Datensatz nur etwas über 8 Millionen Einträge besitzt und mit Ganzzahlen gearbeitet wird wären beide Probleme zu vernachlässigen gewesen.}
Wenn in die Testdatei geschrieben wird, wird auch gleichzeitig die Zählervariable zurückgesetzt, sodass mit den gleichen Werten von vorne begonnen werden kann. Hier wurde sich bewusst für ein Zurücksetzen der Variable entschieden und gegen ein kontinuierliches Hochzählen und der Sortierung durch Modulo: Auf diese Weise werden bedenkenlos Overflow- und Signifikanzprobleme verhindert, ohne einen deutlichen Verlust der Lesbarkeit des Codes hinnehmen zu müssen. \wip{Da der genutzte Datensatz nur etwas über 8 Millionen Einträge besitzt und mit Ganzzahlen gearbeitet wird wären beide Probleme zu vernachlässigen gewesen.}
Diese Art der Aufteilung ist jedoch nur bedenkenlos einzusetzen in diesem Projekt, da die Daten ohnehin unabhängig sind und ebenfalls unsortiert vorliegen. Aus diesen Gründen sind die drei Datensätze auch ohne extra shuffle zufällig genug.
\wip{Überleitung zum Generator? Oder das Aufteilen der Daten in eigenes Kapitel?}
......@@ -75,7 +75,7 @@ Zunächst ein wenig overhead, bevor wir dann die entsprechende Datei zeilenweise
except:
continue
\end{lstlisting}
Anschließend wird aus dem eigentlichen Text der review ein Wortvektor für das CNN gemacht, \wip{wie zuvor in dem Kapitel X.X (Referenz) beschrieben}. Das Ergebnis ob diese review als positiv, negativ oder neutral gelten soll wird in diesem Beispiel One-Hot-Encoded abgespeichert. Sollte eine Exception geschmissen werden, weil z.B. kein einziges Wort, welches in der review vorkommt im word2vec model vertreten sein wird diese review einfach übersprungen.
Anschließend wird aus dem eigentlichen Text der Review ein Wortvektor für das CNN gemacht, \wip{wie zuvor in dem Kapitel X.X (Referenz) beschrieben}. Das Ergebnis ob diese review als positiv, negativ oder neutral gelten soll wird in diesem Beispiel One-Hot-Encoded abgespeichert. Sollte eine Exception geschmissen werden, weil z.\,B.\@ kein einziges Wort, welches in der Review vorkommt im word2vec model vertreten sein, wird diese Review einfach übersprungen.
\begin{lstlisting}
if batchcount > batchsize:
X = np.array(inputs)
......@@ -85,16 +85,16 @@ Anschließend wird aus dem eigentlichen Text der review ein Wortvektor für das
targets = []
batchcount = 0
\end{lstlisting}
Abschließend werden die beiden Listen returned und die entsprechenden Variablen zurückgesetzt. Yield entspricht dabei in Python einem return, welches den dazugehörigen Code erst ausführt wenn die Daten gebraucht werden. Die Ansprüche an den Arbeitsspeicher werden auf diese Weise deutlich gesenkt. Es müssen für das Training also nur so viele Daten gleichzeitig im Arbeitsspeicher gehalten werden wie es die batchsize vorgibt. Wenn diese z.B. 512 entspricht fallen dabei, an folgender Formel zu erkennen, lediglich 28 MB an Daten an.
Abschließend werden die beiden Listen returned und die entsprechenden Variablen zurückgesetzt. Yield entspricht dabei in Python einem return, welches den dazugehörigen Code erst ausführt wenn die Daten gebraucht werden. Die Ansprüche an den Arbeitsspeicher werden auf diese Weise deutlich gesenkt. Es müssen für das Training also nur so viele Daten gleichzeitig im Arbeitsspeicher gehalten werden wie es die batchsize vorgibt. Wenn diese z.\,B.\@ 512 entspricht fallen dabei, an folgender Formel zu erkennen, lediglich 28 MB an Daten an.
\begin{equation}
512 \times 72 \times 100 \times 8 \approx 28\text{ MB}
\end{equation}
Ein deutlicher Nachteil bei diesem Vorgehen ist jedoch, dass dies sehr zeitaufwändig ist. Nicht nur müssen die Daten während des Trainings von der Festplatte anstelle des Arbeitsspeichers gelesen werden. Sondern diese Daten müssen zunächst auch noch in das word2vec model überführt werden. Beides sind verhältnismäßig langsame Prozesse, wodurch die Trainingszeit enorm steigt. Aber auch die Validierung benötigt nun in etwa genau so viel Zeit wie das Training an sich.
Dafür ist diese Methode recht simpel und sie benötigt keinen zusätzlichen Festplattenspeicher. Jedoch muss hierfür der Datensatz für Tranings-, Validierungs- und Testmenge in verschiedene Dateien aufgeteilt werden. Sollte also der Festplattenspeicher und nicht so sehr die Zeit ein begrenzender Faktor sein, ist dies ein durchaus valider Ansatz.
Ein deutlicher Nachteil bei diesem Vorgehen ist jedoch, dass dies sehr zeitaufwändig ist. Nicht nur müssen die Daten während des Trainings von der Festplatte anstelle des Arbeitsspeichers gelesen werden. Sondern diese Daten müssen zunächst auch noch in das word2vec Modell überführt werden. Beides sind verhältnismäßig langsame Prozesse, wodurch die Trainingszeit enorm steigt. Aber auch die Validierung benötigt nun in etwa genau so viel Zeit wie das Training an sich.
Dafür ist diese Methode recht simpel und sie benötigt keinen zusätzlichen Festplattenspeicher. Jedoch muss hierfür der Datensatz für Trainings-, Validierungs- und Testmenge in verschiedene Dateien aufgeteilt werden. Sollte also der Festplattenspeicher und nicht so sehr die Zeit ein begrenzender Faktor sein, ist dies ein durchaus valider Ansatz.
\subsubsection{hdf5}
%Bessere Zeiten, aber hoher Speicherplatz
Ein weiterer Ansatz ist die bereits in das word2vec model überführten Wörter, also die Vektoren an sich abzuspeichern. Dafür eignen sich z.B. hdf5 files, welche einen weiteren Vorteil besitzen auf den später eingegangen wird. Das Prinzip ist bei dieser Methode nahezu identisch zu der zuvor besprochenen, auch hier wird der Fit-Methode ein Generator gegeben, dieser liest jedoch nur die entsprechende Datei. Zunächst muss aber der Datensatz in das word2vec model überführt und entsprechend abgespeichert werden. Dies beginnt auch hier wieder mit ein wenig overhead:
Ein weiterer Ansatz ist die bereits in das Word2Vec Modell überführten Wörter, also die Vektoren an sich abzuspeichern. Dafür eignen sich z.\,B.\@ hdf5 Dateien, welche einen weiteren Vorteil besitzen auf den später eingegangen wird. Das Prinzip ist bei dieser Methode nahezu identisch zu der zuvor besprochenen, auch hier wird der Fit-Methode ein Generator gegeben, dieser liest jedoch nur die entsprechende Datei. Zunächst muss aber der Datensatz in das Word2Vec Modell überführt und entsprechend abgespeichert werden. Dies beginnt auch hier wieder mit ein wenig overhead:
\begin{lstlisting}
import h5py
......@@ -113,7 +113,7 @@ with h5py.File(path + "w2vCNN.hdf5", "w") as hf:
xTest = []
yTest = []
\end{lstlisting}
Zu Beginn initialisieren wir eine Zähler-variable auf 0, welche wir später für unsere Aufteilung in Trainings-, Validierungs- und Testmenge nutzen. Für diese Mengen und ihren jeweiligen Input- und Output-daten bereiten wir auch ein paar Listen vor. In hdf5 Dateien kann man die Daten in so genannte Chunks aufteilen, welche das schrittweise speichern möglich macht, aber auch das laden verbessern soll. Die Größe dieser Chunks legen wir zunächst auf 10.000 fest. Da wir einen 60-20-20 split unseres Datensatzes haben wollen speichern wir uns ebenfalls die Größe dieser einzelnen Chunks.
Zu Beginn initialisieren wir eine Zähler-Variable auf 0, welche wir später für unsere Aufteilung in Trainings-, Validierungs- und Testmenge nutzen. Für diese Mengen und ihre jeweiligen Input- und Outputdaten bereiten wir auch ein paar Listen vor. In hdf5 Dateien kann man die Daten in sogenannte Chunks aufteilen, welche das schrittweise speichern möglich macht, aber auch das laden verbessern soll. Die Größe dieser Chunks legen wir zunächst auf 10.000 fest. Da wir einen 60-20-20 split unseres Datensatzes haben wollen speichern wir uns ebenfalls die Größe dieser einzelnen Chunks.
\begin{lstlisting}
for index, line in enumerate(open(corpus_path,encoding="utf8")):
json_line = json.loads(line)
......@@ -145,7 +145,7 @@ Anschließend wird quasi identisch \wip{zu der anderen Methode (Ref?)}der rohe D
i = -1
i += 1
\end{lstlisting}
Als nächstes werden die Daten den entsprechenden Listen angehangen. Das vorgehen hier orientiert sich dabei an der zuvor besprochenen Aufteilung aus aus dem Code-Schnipsel \ref{lst:Aufteilung}.
Als nächstes werden die Daten den entsprechenden Listen angehangen. Das Vorgehen hier orientiert sich dabei an der zuvor besprochenen Aufteilung aus dem Code-Schnipsel \ref{lst:Aufteilung}.
\begin{lstlisting}
if index == chunkSize - 1:
XTrain = hf.create_dataset("XTrain", data=xTrain, maxshape=(None, 72, 100), chunks=(trainChunk, 72, 100))
......@@ -166,7 +166,7 @@ Als nächstes werden die Daten den entsprechenden Listen angehangen. Das vorgehe
yTest = []
\end{lstlisting}
Wenn das erste mal genug Daten in den buffer-listen liegen können diese noch nirgends appended werden, da in der entsprechenden Datei noch nichts vorliegt wo diese appended werden können. Damit kommen wir auch zu einem weiteren Vorteil der hdf5 Dateien: Wir können verschiedene Datasets, mit entsprechenden Labeln, in der gleichen Datei speichern und diese später auch einfach wieder auslesen. \\
Diese Datasets müssen aber zunächst erstellt werden. Dafür geben wir zum einen das Label des Datasets an; die dimensionen der maxshape, welche als Anzahl der Datensätze den Eintrag None bekommt, da wir einfach alle Daten die wir haben speichern wollen; die Dimensionen der chunks, wofür wir die eingangs berechneten Chunkgrößen nun nutzen; und zu guter letzt natürlich die tatsächlichen Daten, welche stets die gleichen Dimensionen haben müssen wie die Chunks. Abschließend resetten wir die buffer-listen um keine Daten mehrfach zu speichern.
Diese Datasets müssen aber zunächst erstellt werden. Dafür geben wir zum einen das Label des Datasets an; die Dimensionen der maxshape, welche als Anzahl der Datensätze den Eintrag None bekommt, da wir einfach alle Daten die wir haben speichern wollen; die Dimensionen der chunks, wofür wir die eingangs berechneten Chunkgrößen nun nutzen; und zu guter Letzt natürlich die tatsächlichen Daten, welche stets die gleichen Dimensionen haben müssen wie die Chunks. Abschließend resetten wir die buffer-listen um keine Daten mehrfach zu speichern.
\begin{lstlisting}
if (index+1) % chunkSize == 0 and index > chunkSize:
XTrain.resize(XTrain.shape[0]+trainChunk, axis=0)
......@@ -195,7 +195,7 @@ Diese Datasets müssen aber zunächst erstellt werden. Dafür geben wir zum eine
xTest = []
yTest = []
\end{lstlisting}
Für das appenden der Daten im Folgenden Verlauf müssen die Datasets stets um die entsprechende Größe resized werden. Anschließend werden die neuen Felder entsprechend aufgefüllt und zu guter Letzt wieder die buffer-listen resetted.\\
Für das appenden der Daten im folgenden Verlauf müssen die Datasets stets um die entsprechende Größe resized werden. Anschließend werden die neuen Felder entsprechend aufgefüllt und zu guter Letzt wieder die buffer-listen resetted.\\
Das Auslesen der Daten erfolgt letztlich ähnlich wie bei dem anderen vorgestellten Generator:
\begin{lstlisting}
def hdf5Generator(filePath, batch_size, dataSet, loop=True):
......@@ -215,8 +215,8 @@ def hdf5Generator(filePath, batch_size, dataSet, loop=True):
batch_end += batch_size
if not loop: break
\end{lstlisting}
Die Hauptunterschiede sind dabei das hier entsprechend anfallende Zugreifen des passenden Datasets, das Wegfallen der word2vec Überführung und der zusätzliche check ob \lstinline{batch_size}{} über das Ende der Datasets gehen würde.\\
Der Vorteil bei diesem Vorgehen ist eine bessere Trainingszeit und vor allem eine bessere Validierungszeit gegenüber dem zuvor besprochenen Generator. Jedoch braucht diese Variante ein vielfaches mehr Festplattenspeicher und zwar so viel wie in der zuvor berechneten Gleichung \ref{eq:430GB}:
Die Hauptunterschiede sind dabei das hier entsprechend anfallende Zugreifen des passenden Datasets, das Wegfallen der word2vec Überführung und der zusätzliche Check ob \lstinline{batch_size}{} über das Ende der Datasets gehen würde.\\
Der Vorteil bei diesem Vorgehen ist eine bessere Trainingszeit und vor allem eine bessere Validierungszeit gegenüber dem zuvor besprochenen Generator. Jedoch braucht diese Variante ein vielfaches mehr Festplattenspeicher und zwar so viel, wie in der zuvor berechneten Gleichung \ref{eq:430GB}:
\begin{equation*}
8,000,000 \times 72 \times 100 \times 8 \approx 430\text{ GB}\tag{\ref{eq:430GB} revisited}
\end{equation*}
......
......@@ -29,19 +29,19 @@ Zum Anderen gibt es die Möglichkeit, die Klassen beim Trainieren zu gewichten.
Im Rahmen dieser Arbeit wurde der zweite Ansatz gewählt.
\subsubsection{Zeichensatz}
Zuerst sollte der Datensatz in lowercase konvertiert werden, da bei den Wordvektoren sonst ein Unterschied zwischen z.B. \noteable{good} und \noteable{Good} besteht. Dabei könnte sogar zufallsbedingt durch die Anwendung in leicht verschiedenen Kontexten und die generelle unterschiedliche Häufigkeit die Interpretation dieser Wörter auseinandergehen.
Zuerst sollte der Datensatz in lowercase konvertiert werden, da bei den Wordvektoren sonst ein Unterschied zwischen z.B. \noteable{good} und \noteable{Good} besteht. Dabei könnte sogar zufallsbedingt, durch die Anwendung in leicht verschiedenen Kontexten und die generelle unterschiedliche Häufigkeit, die Interpretation dieser Wörter auseinandergehen.
In eine ähnliche Richtung gehen auch die Satzzeichen. Hier werden zwar Informationen gespeichert, welche durchaus die Bedeutung eines Satzes verändern können, aber dieser Unterschied ist in der Regel zu komplex um ihn in den meisten Verfahren sinnvoll zu berücksichtigen. Eine Sonderbehandlung wäre dabei ohnehin von Nöten. Weiterhin kann man davon ausgehen, dass in der Regel sich die Bedeutung nicht so gravierend ändert, als dass man diese review in eine andere Kategorie einordnen würde. Dadurch ist die effizienteste Methode die Satzzeichen einfach zu entfernen.
In eine ähnliche Richtung gehen auch die Satzzeichen. Hier werden zwar Informationen gespeichert, welche durchaus die Bedeutung eines Satzes verändern können, aber dieser Unterschied ist in der Regel zu komplex, um ihn in den meisten Verfahren sinnvoll zu berücksichtigen. Eine Sonderbehandlung wäre dabei ohnehin von Nöten. Weiterhin kann man davon ausgehen, dass sich in der Regel die Bedeutung nicht so gravierend ändert, als dass man diese Review in eine andere Kategorie einordnen würde. Dadurch ist die effizienteste Methode die Satzzeichen einfach zu entfernen.
Es gibt aber noch weitere Sonderzeichen, die Probleme bereiten. Darunter z.B. das Apostrophe. Da die reviews in der Regel englisch sind finden sich häufiger Wörter wie \noteable{didn't} oder \noteable{we've}.
Es gibt aber noch weitere Sonderzeichen, die Probleme bereiten. Darunter z.B. das Apostroph. Da die Reviews in der Regel englisch sind finden sich häufiger Wörter wie \noteable{didn't} oder \noteable{we've}.
Wir befinden uns jedoch im Internet und hier werden neben Satzzeichen auch Apostrophe gerne einmal weggelassen, schließlich weiß mit \noteable{didnt} jeder was gemeint ist. Aber auch hier werden diese Versionen als unterschiedliche Wörter interpretiert.
Die simpelste Methode ist auch hier einfach das Apostrophe zu entfernen. In diesem Falle werden aber zum Teil Wörter zusammengefasst, welche durchaus verschieden sind, wie z.\,B. \noteable{its} und \noteable{it's}. Das selbe gilt dann auch für andere Sprachen bei denen solche Vorkommnisse möglicherweise üblicher sind. Jedoch wird auch bei Wörtern wie \noteable{it's} gerne mal das Apostrophe weggelassen, da häufig aus dem Kontext ersichtlich ist, welche Variante gemeint ist. Dadurch wird für den Algorithmus der Unterschied zwischen diesen Wörtern nicht klar und sie werden letztlich im Vektorraum recht nah aneinander liegen. Dies lässt sich auch aus der folgenden Ausgabe anhand des genutzten Modells ablesen.
Die simpelste Methode ist auch hier einfach das Apostrophe zu entfernen. In diesem Falle werden aber zum Teil Wörter zusammengefasst, welche durchaus verschieden sind, wie z.\,B.\@ \noteable{its} und \noteable{it's}. Dasselbe gilt dann auch für andere Sprachen bei denen solche Vorkommnisse möglicherweise üblicher sind. Jedoch wird auch bei Wörtern wie \noteable{it's} gerne mal das Apostroph weggelassen, da häufig aus dem Kontext ersichtlich ist, welche Variante gemeint ist. Dadurch wird für den Algorithmus der Unterschied zwischen diesen Wörtern nicht klar und sie werden letztlich im Vektorraum recht nah aneinander liegen. Dies lässt sich auch aus der folgenden Ausgabe anhand des genutzten Modells ablesen.
\begin{verbatim}
In: model0.similarity("it's", "its")
Out: 0.8579778
\end{verbatim}
\subsubsection{Sprachen}
Wie zuvor erwähnt besteht der Datensatz nicht nur aus englischen reviews, sondern aus verschiedenen Sprachen. Oberflächlich gesehen stellt dies in der Theorie erstmal kein Problem dar, abgesehen von den unterschiedlichen Mengen an data-samples in den jeweiligen Sprachen. Wie durch den vorherigen Abschnitt jedoch zu erahnen ist benötigen verschiedene Sprachen verschiedene Nuancen an Vorverarbeitung. Von Sonderzeichen die ggf. anders behandelt werden müssen je nach Sprache bis hin zum fehlen ebendieser. In dem Datensatz sind z.B. auch Japanische reviews enthalten, eine Sprache ohne Leerzeichen, was das isolieren einzelner Wörter erheblich erschwert. Um bei dem Beispiel Japanisch zu bleiben: Hier kommt noch hinzu, dass dies eine sehr kontextuelle Sprache ist. Das bedeutet, dass Wörter die für das Verständnis des Satzes wichtig wären aus dem Kontext als gegeben und gewusst angesehen werden, etwas was ein Code in der Regel nicht leisten kann.\\
Es stellt sich also die Frage ob der Datensatz von anderen Sprachen bereinigt werden sollte. Ein möglicher Ansatz dafür wäre z.B. nur reviews zu behalten, welche ausschließlich Zeichen in einer bestimmten (kleinen) utf-8 Reichweite enthalten. Während das Entfernen bei einigen asiatischen Sprachen noch verhältnismäßig einfach erscheint, wird dies bei z.B. europäischen Sprachen wie Französisch oder Spanisch ohne großen Mehraufwand nahezu unmöglich. \\
Aufgrund dessen verzichten wir darauf solche Sprachen zu entfernen. Aber auch asiatische Sprachen werden wir nicht extra entfernen. Wir können zwar überwiegend keine nützlichen Daten aus diesen reviews gewinnen, jedoch wird der nützliche part unseres Datensatzes auch nicht dadurch beeinflusst, da die asiatischen Sprachen mit ziemlicher Sicherheit einen eigenen, eher abgeschiedenen, Wortcluster bilden werden. Weiterhin treten diese reviews selten genug auf, dass man davon ausgehen kann, dass das Entfernen dieser Datenpunkte keinen merklichen Einfluss auf die Trainingszeiten haben wird. Daher ist es sinnvoller die Zeit, welche in die saubere Entfernung dieser reviews investiert werden würde hier einzusparen.
\ No newline at end of file
Wie zuvor erwähnt besteht der Datensatz nicht nur aus englischen Reviews, sondern aus verschiedenen Sprachen. Oberflächlich gesehen stellt dies in der Theorie erstmal kein Problem dar, abgesehen von den unterschiedlichen Mengen an data-samples in den jeweiligen Sprachen. Wie durch den vorherigen Abschnitt jedoch zu erahnen ist benötigen verschiedene Sprachen verschiedene Nuancen an Vorverarbeitung. Von Sonderzeichen, die je nach Sprache ggf.\@ anders behandelt werden müssen bis hin zum fehlen ebendieser. In dem Datensatz sind z.B. auch japanische Reviews enthalten, eine Sprache ohne Leerzeichen, was das Isolieren einzelner Wörter erheblich erschwert. Um bei dem Beispiel Japanisch zu bleiben: Hier kommt noch hinzu, dass dies eine sehr kontextuelle Sprache ist. Das bedeutet, dass Wörter die für das Verständnis des Satzes wichtig wären aus dem Kontext als gegeben und gewusst angesehen werden, etwas was ein Code in der Regel nicht leisten kann.\\
Es stellt sich also die Frage ob der Datensatz von anderen Sprachen bereinigt werden sollte. Ein möglicher Ansatz dafür wäre z.B. nur Reviews zu behalten, welche ausschließlich Zeichen in einer bestimmten (kleinen) utf-8 Reichweite enthalten. Während das Entfernen bei einigen asiatischen Sprachen noch verhältnismäßig einfach erscheint, wird dies bei z.B. europäischen Sprachen wie Französisch oder Spanisch ohne großen Mehraufwand nahezu unmöglich. \\
Aufgrund dessen verzichten wir darauf solche Sprachen zu entfernen. Aber auch asiatische Sprachen werden wir nicht extra entfernen. Wir können zwar überwiegend keine nützlichen Daten aus diesen Reviews gewinnen, jedoch wird der nützliche Part unseres Datensatzes auch nicht dadurch beeinflusst, da die asiatischen Sprachen mit ziemlicher Sicherheit einen eigenen, eher abgeschiedenen, Wortcluster bilden werden. Weiterhin treten diese Reviews selten genug auf, dass man davon ausgehen kann, dass das Entfernen dieser Datenpunkte keinen merklichen Einfluss auf die Trainingszeiten haben wird. Daher ist es sinnvoller die Zeit, welche in die saubere Entfernung dieser Reviews investiert werden würde, hier einzusparen.
\ No newline at end of file
......@@ -7,7 +7,7 @@ Der Yelp-Datensatz besteht aus einer Ansammlung von json Dateien. Darunter jewei
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
dieser Arbeit die Datei zeilenweise verarbeitet.
Das zeilenweise verarbeiten der Datei ermöglicht es, die Systemanforderungen
Das zeilenweise Verarbeiten der Datei ermöglicht es, die Systemanforderungen
gering zu halten und bringt den zusätzlichen Vorteil,
dass der in dieser Arbeit erarbeitete Ansatz
problemlos auf größere Datensätze angewendet werden kann.
......
\subsubsection{w2v from scratch
\label{subsec:w2vfs}}
Da Word2Vec ein großer Bestandteil dieser Ausarbeitung ist, jedoch durch einen Import gelöst wurde wird in diesem Kapitel anhand eines simplen Beispiels das Prinzip dahinter erklärt. Dabei werden hier keine hochdimensionalen Wort-Vektoren verwendet, welche letztlich durch ihre Cluster ausgeprägte Bedeutungsräume bilden. Sondern es werden die Beziehungen der Wörter zu ihren Nachbarn dargestellt, indem anhand eines Wortes das Nachbarwort bestimmt werden soll.
Da Word2Vec ein großer Bestandteil dieser Ausarbeitung ist, jedoch durch einen Import gelöst wurde, wird in diesem Kapitel anhand eines simplen Beispiels das Prinzip dahinter erklärt. Dabei werden hier keine hochdimensionalen Wort-Vektoren verwendet, welche letztlich durch ihre Cluster ausgeprägte Bedeutungsräume bilden. Sondern es werden die Beziehungen der Wörter zu ihren Nachbarn dargestellt, indem anhand eines Wortes das Nachbarwort bestimmt werden soll.
\begin{lstlisting}
corpus = ['king is a strong man',
'queen is a wise woman',
......@@ -62,7 +62,7 @@ df = pd.DataFrame(data, columns = ['input', 'neighbour'])
\end{lstlisting}
Als nächstes erstellen wir ein \lstinline{OrderedSet}{}, welches alle Wörter nur ein einziges Mal enthält und nummerieren dieses durch. Dies wird im späteren Verlauf noch benötigt, wobei die Reihenfolge wichtig für die korrekte Visualisierung ist. Anschließend erstellen wir ein Datenset, welches alle Wörter mit ihren jeweiligen Nachbarn enthält. Dabei entspricht die \lstinline{WINDOW_SIZE}{} in Zeile 17 wie viele Nachbarwörter betrachtet werden sollen. Schließlich haben in langen Sätzen Wörter, welche zum Ende eines Nebensatzes stehen, häufig eine eher schwache oder gar keine Bindung zu den ersten Wörtern des Hauptsatzes. Die ideale Größe der \lstinline{WINDOW_SIZE}{} hängt dabei individuell vom Text ab. Jedoch ist in der Regel eine eher kleine \lstinline{WINDOW_SIZE}{} zu empfehlen, +-2 bis 3 Wörter sind in vielen Fällen genug.
% Die +- 2 bis 3 hab ich mir ausgedacht und kann sie dementsprechend nicht belegen%
Abschließend wird das Datenset in ein pandas Dataframe überführt, wodurch das Arbeiten mit diesem erleichtert wird. Weiterhin sind noch 2 Aspekte des Datensets auffällig. Zum einen werden die Wörter mit ihren Nachbarn zwangsweise bidirektional abgespeichert. Die Erklärung dafür ist simpel: Die Beziehung zwischen den Wörtern ist schließlich auch bidirektional und so wird sichergestellt, dass im späteren Verlauf des Codes diese Bidirektionalität auch eingehalten wird, ohne dass darauf explizit geachtet werden muss. Zum anderen werden mehrfach auftretende Kombinationen auch mehrfach abgespeichert und nicht im nach hinein wieder auf ein unique-dataset bereinigt. Das kommt daher, dass diese Häufigkeit essenzielle Daten enthält. Man geht letztlich davon aus, dass Wörter, die häufig zusammen vorkommen eine stärkere Bindung haben und auch außerhalb des benutzten Datensets verstärkt gemeinsam auftreten.
Abschließend wird das Datenset in ein pandas Dataframe überführt, wodurch das Arbeiten mit diesem erleichtert wird. Weiterhin sind noch 2 Aspekte des Datensets auffällig. Zum einen werden die Wörter mit ihren Nachbarn zwangsweise bidirektional abgespeichert. Die Erklärung dafür ist simpel: Die Beziehung zwischen den Wörtern ist schließlich auch bidirektional und so wird sichergestellt, dass im späteren Verlauf des Codes diese Bidirektionalität auch eingehalten wird, ohne dass darauf explizit geachtet werden muss. Zum anderen werden mehrfach auftretende Kombinationen auch mehrfach abgespeichert und nicht im Nachhinein wieder auf ein unique-dataset bereinigt. Das kommt daher, dass diese Häufigkeit essenzielle Daten enthält. Man geht letztlich davon aus, dass Wörter, die häufig zusammen vorkommen eine stärkere Bindung haben und auch außerhalb des benutzten Datensets verstärkt gemeinsam auftreten.
\begin{lstlisting}
import tensorflow as tf
import numpy as np
......@@ -123,7 +123,7 @@ plt.rcParams["figure.figsize"] = (10,10)
plt.show()
\end{lstlisting}
Die eigentliche Arbeit ist damit bereits getan. Da dieses Beispiel jedoch zur Veranschaulichung gedacht ist fehlt noch die Visualisierung. Dafür werden die Gewichte der jeweiligen Vektoren zunächst zusammen mit den entsprechenden Wörtern in ein Dataframe gespeichert. Anschließend wird der Plot vorbereitet und die Wörter werden anhand ihrer zweidimensionaler Vektoren auf einem Koordinatensystem verteilt. Das hier verwendete Beispiel ist insgesamt sehr akademisch gestaltet. Dadurch, dass zwei Dimensionen für Wortvektoren ziemlich gering ist, das Modell nicht ausführlich optimiert und auch die Ausgangsdaten relativ spärlich sind können die Ergebnisse stark voneinander variieren. Eine sinnvolle Verteilung ist jedoch in Abbildung \ref{fig:scratch} zu sehen.
Die eigentliche Arbeit ist damit bereits getan. Da dieses Beispiel jedoch zur Veranschaulichung gedacht ist fehlt noch die Visualisierung. Dafür werden die Gewichte der jeweiligen Vektoren zunächst zusammen mit den entsprechenden Wörtern in ein Dataframe gespeichert. Anschließend wird der Plot vorbereitet und die Wörter werden anhand ihrer zweidimensionalen Vektoren auf einem Koordinatensystem verteilt. Das hier verwendete Beispiel ist insgesamt sehr akademisch gestaltet. Dadurch, dass zwei Dimensionen für Wortvektoren ziemlich gering ist, das Modell nicht ausführlich optimiert und auch die Ausgangsdaten relativ spärlich sind, können die Ergebnisse stark voneinander variieren. Eine sinnvolle Verteilung ist jedoch in Abbildung \ref{fig:scratch} zu sehen.
\begin{figure}
\includegraphics[width=\linewidth]{bilder/scratch.png}
\caption{Wort-Vektoren Verteilung}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment