Skip to content
Snippets Groups Projects
Commit ac3df145 authored by Silas Dohm's avatar Silas Dohm
Browse files

Merge branch 'master' of gitlab.cvh-server.de:w2v/w2vp

parents dbb4648f 573b6709
No related branches found
No related tags found
No related merge requests found
......@@ -4,7 +4,7 @@
\input{silas/daten_analyse.tex}
\input{Herausforderungen}
\input{3_2_Datenauslagerung_Generator}
\input{Generatoren}
\input{silas/gensim.tex}
......
\subsection{Datenauslagerung / Generator
\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.
......@@ -22,6 +22,32 @@ Die Daten müssen bei der CNN-Methode also nur stückweise in den Arbeitsspeiche
\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.
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.
\begin{lstlisting}[label={lst:Aufteilung}]
val = open('val.json','w',encoding='utf8')
test = open('test.json','w',encoding='utf8')
train = open('train.json','w',encoding='utf8')
i = 0
for line in open(corpus_path,encoding="utf8"):
if(i<3): train.write(line)
elif(i==3): val.write(line)
else:
i = -1
test.write(line)
i += 1
val.close()
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.}
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?}
\begin{lstlisting}
import numpy as np
import json
......@@ -34,10 +60,10 @@ def generate_arrays_from_file(path, batchsize):
for line in f:
json_line = json.loads(line)
\end{lstlisting}
Zunächst ein wenig overhead, bevor wir dann die entsprechende Datei zeilenweise durchgehen. Die Zeile 7 mit \lstinline{while True:}{} ist notwendig um die Funktion dem Keras model als Parameter zu übergeben.
Zunächst ein wenig overhead, bevor wir dann die entsprechende Datei zeilenweise durchgehen. Die Zeile 7 mit \lstinline{while True:}{} wird dabei vom Keras Modell erwartet, denn das Trainieren soll nicht mitten in einer Epoche enden, weil das Ende der Trainingsdatendatei erreicht wurde.
\begin{lstlisting}
try:
inputs.append(getSentenceVector(json_line["text"]))
inputs.append(getSentenceVectorCNN(json_line["text"]))
y = float(json_line["stars"])
if(y <3):
targets.append([0,0,1])
......@@ -99,11 +125,11 @@ Zu Beginn initialisieren wir eine Zähler-variable auf 0, welche wir später fü
continue
y = float(json_line["stars"])
if y < 3:
yData = [0,0,1]
yData = 0
elif y == 3:
yData = [0,1,0]
yData = 1
else:
yData = [1,0,0]
yData = 2
\end{lstlisting}
Anschließend wird quasi identisch \wip{zu der anderen Methode (Ref?)}der rohe Datensatz ausgelesen und entsprechend in nutzbare x und y Daten umgewandelt.
\begin{lstlisting}
......@@ -119,8 +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. Dabei wird die zu Beginn besprochene Zähler variable genutzt um die ersten 3 Einträge dem Trainingsset, der nächste dem Validierungsset und abschließend dem Testset zugeordnet, bevor der Zähler wieder zurückgesetzt wird. Dadurch erfolgt die zuvor erwähnte 60-20-20 Aufteilung.\\
Diese Art der Aufteilung ist aber 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.
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}.
\begin{lstlisting}
if index == chunkSize - 1:
XTrain = hf.create_dataset("XTrain", data=xTrain, maxshape=(None, 72, 100), chunks=(trainChunk, 72, 100))
......@@ -173,15 +198,14 @@ Diese Datasets müssen aber zunächst erstellt werden. Dafür geben wir zum eine
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):
def hdf5Generator(filePath, batch_size, dataSet, loop=True):
with h5py.File(filePath, 'r') as hf:
L = len(hf["X" + dataSet])
while True:
batch_start = 0
batch_end = batch_size
while batch_start < L:
limit = min(batch_end, L)
while batch_end < L:
X = hf["X" + dataSet][batch_start:limit]
Y = hf["Y" + dataSet][batch_start:limit]
......@@ -189,9 +213,11 @@ def hdf5Generator(filePath, batch_size, dataSet):
batch_start += batch_size
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.\\
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*}
Das Erstellen dieser Datenmengen benötigt aber auch entsprechende Zeit. Dieses Vorgehen lohnt sich also besonders, wenn das Word2Vec Modell nicht mehr oder nur noch selten verändert wird und somit häufig auf dem gleichen Modell trainiert werden kann.
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment