9 Min. Lesezeit

Visualizing Embeddings: Visualisierung selbst trainierter Embeddings

 Zurück zum Blog

Bitte beachten Sie, dass dieser Blogartikel auf unserem vorherigen Blogpost „Sentiment Analyse“ aufbaut. Sie erfahren in diesem Teil, wie wir die Ergebnisse aus der Sentiment Analyse verwenden, um sowohl ein Wort- als auch ein Kommentar-Embedding unserer selbst trainierten Modelle zu visualisieren. Zur Widerholung: Ein Embedding ist ein Mapping zwischen einer Kategorie, also einem Wort oder einem Kommentar, und einem Vektor der Länge 𝑥x (in unserem Fall, 𝑥=100x=100). Dabei ist nicht wichtig, welche Zahlen in einem einzelnen Vektor stehen. Man erhofft sich durch das Embedding, dass die Vektoren bei häufig zusammen verwendete Wörter / Kommentare nah beieinander im 𝑥x dimensionalen Raum liegen.

Wort-Embeddings

Um die Wort-Embeddings zu erhalten, müssen wir auf die Zwischenergebnisse des Wort-Embedding Zellenblocks unseres bereits trainierten Modells zugreifen. Da dieser Zellenblock jedoch ein Wort-Embedding für jedes Wort in jedem Kommentar zurückgibt und da sich viele Wörter in vielen Kommentaren wiederholen, würden wir viele Wort-Embeddings doppelt und dreifach berechnen. Deshalb erzeugen wir ein zusätzliches Hilfsmodell, welches lediglich die Embeddings für jedes einzigartige Wort erzeugt. Diesem Hilfsmodell übergeben wir zunächst die Gewichte, die der Wort-Embedding Zellenblock von unserem bereits trainiertem Modell selbst erlernt hat und danach werden wir die Wortindices aller einzigartigen Wörter in dieses Hilfsmodell einfüttern. Das Ergebnis für jeden Wortindex ist dann ein Embedding-Vektor der Länge 100.

Wort-Embeddings visualisieren

Danach werden wir unsere selbst erlernten Wort-Embeddings grafisch darstellen. Auf der Webseite https://projector.tensorflow.org/ kann man eine Embedding Datei mit den dazu gehörenden Metainformationen (Wort und Frequenz in unserem Fall) hochladen und grafisch darstellen lassen. Da die Webseite nur Tab-Separated-Values (TSV) Dateien akzeptiert, müssen wir unsere Embeddingvektoren in eine TSV Datei umwandeln und abspeichern. Daraufhin laden wir diese TSV Dateien hoch und betrachten dann das Ergebnis.

In dem unteren Codeblock laden wir zuerst das Tokenizer Object von unserem ersten Blogpost ein, welches wir z.B. für die Generation der Metadaten benötigen. Es folgen beide Modelle. Damit erzeugen wir die Wort-Embedding Dateien unserer Funktion create_word_embedding_files().

In [ ]:
# Reading in the tokenizer object from the first blog post
with open(os.path.join("results", "tokenizer.pickledump"), "rb") as f:
tokenizer = pickle.load(f)

# Reading in the models from the first blogpost (optimal epochs of the naive model and the weighted model are 2 and 1 respectively)
naive_model = load_model(os.path.join("models", "naive_model", "weights.{:02d}.hdf5".format(2)), compile=False)
weighted_model = load_model(os.path.join("models", "0.1_0.9_model", "weights.{:02d}.hdf5".format(1)), compile=False)

# Creating word embeddings for the naive model and weighted model
create_word_embedding_files(tokenizer, model=naive_model, model_name="naive_model")
create_word_embedding_files(tokenizer, model=weighted_model, model_name="0.1_0.9_model")
 

Wort-Embeddings des naiven Modells

In [ ]:
### Abbildung 1
Image(os.path.join("images", "naive_model_word_embedding_1.png"), width=WIDTH, height=HEIGHT)
Out[ ]:
, breos
In [ ]:
### Abbildung 2
Image(os.path.join("images", "naive_model_word_embedding_2.png"), width=WIDTH, height=HEIGHT)
Out[ ]:
, breos
 

Auf dem Graphen oben sehen Sie unsere Wortembeddings. Die Embeddingvektoren hatten eine Länge von 100, also müssten wir eigentlich unsere Embeddings auch in 100 Dimensionen visualisieren. Da wir Menschen aber nicht so gut in 100 Dimensionen denken können, wurde unser Embedding mithilfe einer Hauptkomponentenanalyse von 100 Dimensionen auf 2 Dimensionen reduziert.

Alle schwarzen Punkte repräsentieren ein Wort, sodass man 20.000 Punkte auf diesem Graphen sehen müsste – entsprechend unsers Vokabulars, das aus 20.000 verschiedenen Wörtern besteht. Klicken wir ein Wort an (wie z. B. bullshit), wird der Name dieses Wortes angezeigt und gleichzeitig sehen wir die 35 nächsten Nachbarn dieses Wortes. Die Distanz aller Punkte zueinander haben wir in hier mit Hilfe des Euklidischen Abstands berechnen lassen. Auf der rechten Seite kann man sogar ein Ranking der nächsten Nachbarn zu unserem angeklicktem Wort sehen. Hier gilt, je kleiner der Wert (der euklidische Abstand), desto näher liegen die Embeddingvektoren beieinander und desto ähnlicher müssten die dazugehörenden Wörter sein.

Analyse unserer Wort-Embeddings

Die Visualisierung zeigt, dass die Embeddings für Schimpfwörter, wie z. B. bullshit, idiotic und stupid ziemlich gut sind, da diese Wörter sehr nah beieinander liegen (siehe Abbildung 1). Allerdings sind die Embeddings für eigentlich positive Wörter wie z.B. great, awesome und fantastic ziemlich schlecht, da bis auf ein paar Ausnahmen, neben diesen Wörtern ganz andere Wörter angesiedelt sind (siehe Abbildung 2).

Unsere Vermutung ist, dass Schimpfwörter in unserem Datensatz immer in einem negativen Kontext verwendet werden, also häufig zusammen mit anderen Schimpfwörtern, während der Kontext, in dem eigentlich positive Wörter verwendet werden, nicht immer eindeutig ist. Z. B., wenn jemand schreibt „Fantastic idea, you are the biggest idiot ever“, benutzt der Autor „fantastic“ auf eine sarkastische Art und Weise, also nicht in einem positiven Kontext. Da das Wort-Embedding kein Kontext zur Verfügung hat, ist das Wort-Embedding Modell also nicht in der Lage die eigentlich positiven Wörter richtig einzuordnen.

Weitere Gründe hierfür könnten sein, dass unser Modell nicht genügend Daten zu verfügung hatte. Zum Vergleich, es gibt frei verfügbare, bereits trainierte Wort-Embeddings, wie z.B. das Global Vectors for Word Representation, das auf mehr als 1 Milliarde Worten mit etwa 400.000 verschiedenen Wörtern trainiert wurde. Unsererm Datensatz standen „lediglich“ etwa 1,8 Millionen Kommentare mit 20.000 unterschiedlichen Wörtern zur Verfügung – ein winziger Ausschnitt der menschlichen Sprache. Darüber hinaus könnte es sein, dass unsere Modellarchitektur nicht komplex genug gewesen ist, oder dass wir die Hyper-Parameter in unserem Modell nicht optimal gesetzt haben. Hyper-Parameter sind Parameter, die der Nutzer eines Machine Learning Algorithmus „per Hand“ setzen muss, bevor der Algorithmus trainiert wird.

Kommentar-Embeddings

Man kann nicht nur Wort-Embeddings, sondern auch die Embeddings der einzelnen Kommentare erzeugen und visualisieren. Hierzu müsssen wir auf die Zwischenrgebnisse eines rekurrenten Zellenblocks zurückgreifen, denn in unserem Modell sind nur die rekurrenten Zellenblöcke in der Lage, sequentielle Abhängigkeiten zu modellieren. Danach müssen wir wieder ein Hilfsmodell erzeugen und die Daten in dieses Modell einfüttern. Da es sehr lange dauern könnte, 1,8 Millionen Kommentare grafisch darzustellen, werden wir zuerst eine Stichprobe von 10.000 Kommentaren nehmen, welche zu 50 Prozent aus OK und zu 50 Prozent aus toxic Kommentaren besteht. Am Schluss speichern wir wieder die Embeddings als TSV Dateien ab und laden diese Dateien auf https://projector.tensorflow.org/.

Im folgenden Codeblock laden wir zuerst die Kommentar Metadaten ein und die vektorisierten Textdaten, die wir im ersten Blogpost erzeugt haben. Danach werden die Kommentar-Embedding Dateien in der von uns erstellten Funktion create_comment_embedding_files() erzeugt.

In [ ]:
# Loading the comment metadata which were created in the first blogpost
comment_metadata_df = pd.read_csv(os.path.join("data", "comment_metadata_df.csv"))

# Loading the vectorized text sequences
with open(os.path.join("results", "X.pickledump"), "rb") as file:
X = pickle.load(file)

# Creating the comment embeddings for both models
create_comment_embedding_files(comment_metadata_df, X, model=naive_model, model_name="naive_model")
create_comment_embedding_files(comment_metadata_df, X, model=weighted_model, model_name="0.1_0.9_model")
 
/usr/local/lib/python3.6/dist-packages/numpy/core/fromnumeric.py:56: FutureWarning: Series.nonzero() is deprecated and will be removed in a future version.Use Series.to_numpy().nonzero() instead
return getattr(obj, method)(*args, **kwds)
 

Kommentar-Embedding des naiven Modells

In [ ]:
Image(os.path.join("images", "naive_model_comment_embedding.png"), width=WIDTH, height=HEIGHT)
Out[ ]:
, breos
 

Die gelben Punkte in der Abbildung oben sind die toxic Kommentare und die blauen Punkte sind die OK Kommentare.

Analyse unserer Kommentar-Embeddings

Man kann erkennen, dass die meisten Kommentare relativ gut voneinander separiert sind. Allerdings gibt es auch viele Kommentare in der Mitte, die nicht eindeutig voneinander getrennt wurden. Teilweise sind das Kommentare, die selbst von Menschen nicht eindeutig als OK oder toxic eingestuft werden konnten. Da diese Kommentare target scores von rund 0,5 haben. Zur Erinnerung: Die target score ist der Anteil an Menschen, die einen Kommentar als toxic eingestuft haben, während der Datensatz erstellt wurde. Wenn die target score also um 0,5 liegt, dann war man sich nicht wirklich einig, ob der Kommentar OK oder toxic ist. Deshalb ist es logisch, dass unser Modell Schwierigkeiten hat, jene Kommentare zu klassifizieren.

Eine Möglichkeit, dieses Problem zu umgehen, wäre die Aufgabenstellung in der zugehörenden Kaggle Challenge zu ändern und nicht mehr Kommentare als entweder OK oder toxic zu klassifizieren, sondern die target score vorherzusagen. Wahrscheinlich würde unser Modell dann befriedigende Ergebnisse erzielen, da wir dem Modell mehr Freiheiten geben würden. Ob es bessere Ergebnisse als unser jetziges Modell liefern wird, kann man allerdings nicht vorhersagen, da wir dann nicht mehr ein Klassifikationsproblem, sondern eine Regressionproblem lösen müssten und die Evaluierungsmetriken für Regressionen andere sind.

Zugegebenermaßen, gibt es Kommentare in der Mitte der obigen Visualisierung, die relativ eindeutige target scores haben, also entweder target scores gegen 1 oder gegen 0. Wie bereits oben erwähnt, könnten die Gründe hierfür sein: Die Modellarchitektur ist nicht gut genug oder wir hatten nicht genug Daten zur Verfügung.

Zusammenfassung

In diesem Blogpost haben Sie gelernt, wie man Embeddings visualisieren kann. Während es für unser Modell sehr schwierig war, eigentlich positiv wirkende Wörter wie awesome, fantastic und great zu embedden, war es trotzdem in der Lage, Schimpfwörter zu embedden. Darüber hinaus sieht es so aus, als ob es die meisten OK Kommentare von den toxic Kommentaren separieren kann. Allerdings hatte es Schwierigkeiten, Kommentare mit einem target score von 0,5 voneinander zu unterscheiden.

BEITRÄGE NACH THEMA

Melde dich hier für Updates an