55 Min. Lesezeit

Einleitung: Der Transformer von Google

 Zurück zum Blog

In diesem Blogpost erfahren Sie, wie ein von Google im Jahr 2017 entwickeltes Modell, der Transformer (Research Paper: „Attention is all you need“Google AI Blog), von einer Sprache in eine andere Sprache übersetzt – und das lediglich mit Beispieldaten. Dabei sind Übersetzungen sehr komplex. Das erkennt man, wenn man die folgenden zwei Sätze ins Deutsche übersetzt möchte:

1: „The dog didn’t cross the street, because it was too tired“. ==> Der Hund hat die Straße nicht überquert, weil er zu müde war.

2: „The dog didn’t cross the street, because it was too wide“. ==> Der Hund hat die Straße nicht überquert, weil sie zu breit war.

Wenn wir das Wort „it“ im 1. Satz übersetzen wollen, übersetzten wir es mit „er“, weil sich „it“ auf „dog“ bezieht, und „dog“ ist „der Hund“ im Deutschen. Im 2. Satz hingegen, übersetzten wir „it“ mit „sie“, weil sich „it“ jetzt plötzlich auf „street“ bezieht und „street“ ist „die Straße“ im Deutschen. Für uns Menschen ist dies eine ziemlich leichte Aufgabe, da wir aus dem Kontext heraus erkennen können auf welches Wort sich „it“ bezieht. Denn jeder mit gesundem Menschenverstand weiß, dass Hunde nicht breit und Straßen nicht müde sein können.

Doch wie kann man einen Algorithmus entwickeln, der in der Lage ist, mit Beispieldaten die beiden oberen Sätze zu erlernen und „it“ dem korektem Geschlecht zuzuweisen? Bevor wir zur Antwort kommen, sollte man die Anwendungsmöglichkeiten des Transformers kennen.

Use Cases für den Transformer

Der Transformer wurde für Übersetzungen von einer beliebigen Sprache in eine andere entwickelt und sicher haben Sie ihn über Google Translate schon einmal genutzt. Man kann den angepassten Transformer aber auch für jegliche Art von Textklassifikationen einsetzen, z.B. für eine Sentiment Analyse oder ein POS Tagging.

Sentiment Analysen sind für Sie interessant, wenn Sie auf Ihrer Webseite ein Kommentarforum haben und sogenannte „Trolle“ (kontraproduktive Chatteilnehmer) erkennen wollen oder wenn Sie z.B. Bewertungen der Kunden schnell und automatisch auswerten wollen. Textklassifikationen helfen auch im juristischen Sektor weiter, wo große Mengen an Text ausgewertet werden müssen. Langweilige Aufgaben, die früher noch Praktikanten sehr langsam und mühselig ausgeführt haben, können mittlerweile sehr schnell mithilfe von Algorithmen ausgeführt werden. Und für Menschen stehen die höherwertigen Aufgaben bereit.

Wie funktioniert der Transformer?

Der Transformer ist ein neuronales Netz. Es legt den Grundstein für das momentane State-of-the-Art (SOTA) Modell im Bereich Natural Language Processing (NLP). Die Modellarchitektur des Transformers erlaubt eine deutlich kürzere Trainingszeit als die bisherigen SOTA NLP Modelle, da es teilweise parallelisiert arbeitet. Es setzt dazu keine Convolutional Zellenblöcke mehr ein und nur teilweise rekurrente, bzw. auto-regressive Zellenblöcke.

Grundsätzlich besteht der Transformer aus einem Encoder und einem Decoder, die jeweils in sechs Blöcke unterteilt sind. Der Encoder erzeugt eine Art Representation des Satzes in der Eingangssprache und der Decoder formt diese Representation in die Zielsprache um. Angenommen, dass man einen englischen Satz in einen deutschen Satz übersetzen will, wird der englische Satz in dem Encoder Abschnitt eingelesen und bis ans Ende durchgeschläust. Danach wird das Zwischenergebnis in dem Decoder Abschnitt eingelesen und das erste Wort in dem englischen Eingangssatz wird ins Deutsche übersetzt. Danach wird anhand des Zwischenergebnisses des Encoders und den bereits ins Deutsche übersetzten Wörtern Schritt für Schritt das nächste Wort in dem englischen Eingangssatz übersetzt.

Hierunter haben wir einmal eine Visualisierung des Datenflusses innerhalb des Transformers mit zwei Encoder und zwei Decoder Blöcken erstellt (aus Platzgründen konnten wir nicht alle sechs Blöcke visualisieren). Was die einzelnen Blöcke leisten, erfahren Sie weiter unten.

In [ ]:
# Abbildung 1
Image(os.path.join("images", "transformer.gif.png"), width=WIDTH, height=HEIGHT)
 
Output hidden; open in https://colab.research.google.com to view.
 

Wort-Embeddings

Die Wörter in der Eingangsprache (Englisch in unserem Fall) werden anhand eines Wort-Embeddings in Vektoren umgewandelt. Zur Erinnerung: Ein Wort-Embedding ist ein Mapping zwischen einer Kategorie, z.B. einem Wort, und einem Vektor von einer gewissen Länge. Die Wort-Embeddings von Abbilung 1 werden von 𝑥1,𝑥2x1,x2 und 𝑦̂ 1,𝑦̂ 2y^1,y^2 representiert und haben eine Länge von vier, während der eigentliche Transformer eine Embeddinglänge von 512 hat. Wort-Embeddings können erlernt werden, oder es können vortrainierte Wort-Embeddings benutzt werden, wie wir bereits in diesem und diesem Blogpost erläutert haben.

Positional Encoding (PE)

Weil der Transformer keine rekurrenten oder Convolutional Zellenblöcke im Encoder benutzt, muss er eine andere Methode benutzen, um die Reihenfolge der Wörter innerhalb eines Satzes zu modellieren. Die Entwickler des Transformers benutzen eine Methode, die sich „Positional Encoding“ (PE) nennt, welche von Sinus und Cosinus Wellen unterschiedlicher Frequenzen Gebrauch macht. 𝑃𝐸𝑡PEt, also der PE Vektor von Wort 𝑤𝑡wt in der Inputsequenz, kann anhand der folgenden zwei Gleichungen definiert werden:

𝑃𝐸𝑝𝑜𝑠,2𝑖=𝑠𝑖𝑛(𝑝𝑜𝑠100002𝑖/512)𝑃𝐸𝑝𝑜𝑠,2𝑖+1=𝑐𝑜𝑠(𝑝𝑜𝑠100002𝑖/512),PEpos,2i=sin(pos100002i/512)PEpos,2i+1=cos(pos100002i/512),

𝑝𝑜𝑠pos stellt die Position von 𝑤𝑡wt in dem Eingangssatz/Inputsequenz dar und 𝑖i die Dimenstion von 𝑃𝐸𝑡PEt. Also wird der PE Vektor von dem ersten Wort in der Inputequenz, nämlich 𝑃𝐸1PE1, wie folgt aussehen (Quelle):

𝑃𝐸1=[𝑠𝑖𝑛(11000020/512),𝑐𝑜𝑠(11000020/512),𝑠𝑖𝑛(11000021/512),𝑐𝑜𝑠(11000021/512),...,𝑠𝑖𝑛(1100002255/512),𝑐𝑜𝑠(1100002255/512)]PE1=[sin(1100002∗0/512),cos(1100002∗0/512),sin(1100002∗1/512),cos(1100002∗1/512),…,sin(1100002∗255/512),cos(1100002∗255/512)]

Wie man sehen kann, hat 𝑃𝐸1PE1 256 Elemente, die anhand von Sinus Wellen errechnet wurden und 256 Elemente, die anhand von Cosinus Wellen errechnet wurden. 𝑖i kann Werte zwischen inklusive 0 und inklusive 255 annehmen, also 256 verschiedene Werte insgesammt. Da jedes zweite Element von 𝑃𝐸1PE1 anhand von Sinus Wellen beschrieben ist und jedes andere zweite Element von Cosinus Wellen, ist auch sichergestellt, dass 𝑃𝐸1PE1 insgesammt 2×256=5122×256=512 Elemente hat.

Nachden alle PE Vektoren berechnet wurden, werden diese elementweise mit den Wort-Embedding Vektoren addiert und dann in den nächsten Zellenblock, nämlich dem Multi Head Self Attention Zellenblock, eingefüttert. Um zu verstehen was ein Multi Head Self Attention Zellenblock genau ist, muss man erst verstehen, was ein einzelner Self Attention Zellenblock macht.

Self Attention

Ein einzelner Self Attention Zellenblock bestimmt, wie viel „Aufmerksamkeit“ man jedem Wort in der Inputsequenz schenken soll, wenn man ein bestimmtes Wort in der Inputsequenz, z.B. 𝑤𝑡wt, übersetzen will. Wenn man z.B. „it“ übersetzen will, muss man bestimmen, wie viel Aufmerksamkeit man jedem einzelnen Wort in „The dog didn’t cross the street, because it was too tired“ schenken soll (siehe Beispiel in der Einleitung). Wie dies genau funktioniert versuchen wir anhand der folgenden Grafik zu erklären:

In [ ]:
# Abbildung 2
Image(os.path.join("images", "transformer_slides", "Transformer Modell-38.png"), width=WIDTH, height=HEIGHT)
Out[ ]:
Breos-Blog-Google-Transformer-Out-9


Zuerst wird der Embedding Vektor jedes Wortes (𝑥𝑡xt) elementweise mit dem dazugehörigen 𝑃𝐸𝑡PEt Vektor addiert wird. Das Ergebnis dieser Addition ist ein Vektor, den wir hier 𝑒𝑛𝑐𝑡enct genannt haben.

Danach wird für jedes Wort ein Query (𝑞𝑡qt), ein Key (𝑘𝑡kt) und ein Value (𝑣𝑡vt) Vektor berechnet. Um diese Vektoren zu errechnen, wird 𝑒𝑛𝑐𝑡enct mit drei verschiedenen, trainierbaren Gewichtsmatrizen multipliziert, nämlich jeweils mit 𝑊𝑄,𝑊𝐾WQ,WK und 𝑊𝑉WV.

Wenn man dann diese Query, Key und Value Vektoren auf eine ganz bestimmte Art und Weise miteinander kombiniert, kann man bestimmen, wie viel Aufmerksamkeit der Übersetzer jedem Wort in der Inputsequenz schenken soll, wenn man 𝑤𝑡wt übersetzt. Wie genau man diese Vektoren miteinander kombinieren muss wird in der folgenden Abbildung dargestellt.

In [ ]:
# Abbildung 3
Image(os.path.join("images", "transformer_slides", "Transformer Modell-39.png"), width=WIDTH, height=HEIGHT)
Out[ ]:

Breos-Blog-Google-Transformer-Out

Um die Erklärung so einfach wie möglich zu halten, nehmen wir an, dass wir „Thinking Machines“ ins Deutsche übersetzen wollen, und dass wir gerade herausfinden wollen, wie viel Aufmerksamkeit wir dem Wort „Thinking“ schenken sollen, wenn wir „Thinking“ selbst übersetzen müssen. Falls dieses Beispiel zu banal für Sie klingt, stellen Sie sich einfach vor, wir wollen gerade herausfinden wie viel Aufmerksamkeit man dem Wort „Street“ schenken soll, wenn man das Wort „it“ übersetzt (siehe Einleitung).

Um das herauszufinden, werden im ersten Schritt die Skalarprodukte zwischen dem Query Vektor von „Thinking“ (𝑞1q1) und den Key Vektoren aller Wörter in der Inputsequenz (𝑘1,𝑘2k1,k2) ausgerechnet. D.h. in unserem Fall rechnen wir 𝑞1𝑘1q1⋅k1 und 𝑞1𝑘2q1⋅k2 aus. Das Ergebnis jedes dieser Skalarprodukte ist dann eine sogenannte Score, die in etwa aussagt wie viel Aufmerksamkeit man demjenigen Wort in der Inputsequenz schenken soll, wenn man „Thinking“ übersetzten will. Da die Score für „Thinking“ (112) größer ist als die Score für „Machines“ (96), können wir folgern, dass wir dem Wort „Thinking“ mehr Aufmerksamkeit als „Machines“ schenken sollen, wenn wir „Thinking“ übersetzen.

Danach werden beide Scores durch acht geteilt/skaliert, um den Trainingsdurchlauf des Transformers besser kontrollieren zu können. Warum jetzt genau die Scores durch acht geteilt wurden ist momentan irrelevant, es ist nur wichtig, dass alle Scores durch acht geteilt werden, um diese miteinander vergleichbar zu halten.

Anschließend werden alle skalierten Score Werte durch eine Softmax Funktion geschläust, um aus den Scores sogenannte Pseudo-Wahrscheinlichkeiten zu generieren, die alle zusammen addiert 1 ergeben. Damit kann das Modell besser trainieren.

Nun wird für jedes Wort in der Inputsequenz der dazugehörende Value Vektor mit der dazugehörigen Pseudo-Wahrscheinlichkeit multipliziert. Also für das Wort „Thinking“ berechnen wir 𝑛1=𝑣1×0.88n1=v1×0.88 und für das Wort „Machines“ berechnen wir 𝑛2=𝑣2×0.12n2=v2×0.12. Falls das Wort „Thinking“ viel wichtiger ist, als das Wort „Machines“, sollten die Elemente von 𝑛1n1 auch viel größere Werte haben als die Elemente von 𝑛2n2. Man hebt damit wichtige Wörter hervor und blendet unwichtige Wörter aus. Am Schluss werden die 𝑛n Vektoren addiert, um einen Vektor 𝑧z zu erhalten (𝑧1=𝑛1+𝑛2z1=n1+n2). Wenn dann z.B. 𝑧1z1 sehr ähnlich wie 𝑣1v1 ist, dann wird das Wort „Thinking“ sehr wichtig in der Übersetzung sein.

Bis jetzt haben wir nur berechnet, wie viel Aufmerksamkeit man dem Wort „Thinking“ bei der Übersetzung schenken sollte. Allerdings haben wir zwei Wörter in der Inputsequenz und deshalb müssen wir auch ausrechnen, wie viel Aufmerksamkeit man jedem Wort in der Inputsequenz schenken soll, wenn man „Machines“ übersetzt. Im Prinzip folgen wir dem gleichen Muster wie oben. Da es aber eine wichtige Kleiningkeit zu beachten gibt, haben wir die obenstehende Grafik noch einmal für diesen Fall angepasst:

In [ ]:
# Abbildung 4
Image(os.path.join("images", "transformer_slides", "Transformer Modell-40.png"), width=WIDTH, height=HEIGHT)
Out[ ]:
Breos-Blog-Google-Transformer-Out-2

Wie vorher, werden für das Wort „Machines“ ein Wort-Encoding (𝑒𝑛𝑐2enc2), ein query (𝑞2q2), ein key (𝑘2k2) und ein value (𝑞2q2) Vektor ausgerechnet. Zu beachten ist nun, dass die Score Werte mit den Skalarprodukten von 𝑞2𝑘1q2⋅k1 und 𝑞2𝑘2q2⋅k2 ausgerechnet werden (siehe roter Pfeil) und nicht mehr mit 𝑞1𝑘1q1⋅k1 und 𝑞1𝑘2q1⋅k2. Angenommen dass die Score für „Thinking“ nun 24 ist und die Score für „Machines“ nun 72, kann man schließen, dass man „Machines“ mehr Aufmerksamkeit als „Thinking“ schenken soll, wenn man „Machines“ übersetzt. Die restlichen Operationen beliben genau die gleichen wie bereits in Abbildung 3 erklärt.

Self Attention mit Matrizen

In der Praxis wird die Self Attention Operation nicht für jedes Wort einzeln durchgeführt, sondern für alle Wörter in der Inputsequenz auf einmal, indem man Matrizenmultiplikation einsetzt (moderne Grafikkarten können dies nämlich verdammt schnell). Wir verdeutlichen dies anhand der untenstehenden Grafik:

In [ ]:
# Abbildung 5
Image(os.path.join("images", "transformer_slides", "Transformer Modell-42.png"), width=WIDTH, height=HEIGHT)
Out[ ]:
Breos-Blog-Google-Transformer-Out-3

Der Input von einem bestimmtem Zellenblock ist immer entweder eine Matrix, die die enkodierten Vektoren der Inputsequenz beinhaltet (𝑋𝑒𝑛𝑐Xenc) oder eine Matrix, die die Zwischenergebnisse des vorherigen Zellenblocks beinhaltet (𝑍𝑖𝑛Zin). Beide dieser Matrizen haben die gleichen Dimensionen, die Anzahl der Zeilen ist nämlich gleich der Inputsequenzlänge und die Anzahl der Spalten ist gleich der Wort-Embedding Größe. In Realität gibt es noch eine dritte Dimension (batch_size), aber um es einfach zu halten, haben wir diese Dimension auf den Abbildungen weggelassen.

Um Self Attention mithilfe von Matrizen auszurechnen, wird zuerst entweder 𝑋𝑒𝑛𝑐Xenc oder 𝑍𝑖𝑛Zin mit den jeweiligen Gewichtsmatrizen (𝑊𝑄WQ𝑊𝐾WK, und 𝑊𝑉WV), multipliziert, welches in den Query (𝑄Q), Key (𝐾K) und Value (𝑉V) Matrizen resultiert. Nachdem man 𝑄,𝐾Q,K und 𝑉V ausgerechnet hat, befinden sich die Query Vektoren (𝑞1,𝑞2q1,q2), Key Vektoren (𝑘1,𝑘2k1,k2) und Value Vektoren (𝑣1,𝑣2v1,v2) nun in jeder Zeile von jeweils 𝑄,𝐾Q,K und 𝑉V.

Dann wird 𝑄Q mit 𝐾𝑇KT multipliziert. 𝑇T bedeutet Transpose, also die Key Vektoren, die vorher in jeder Zeile von 𝐾K waren, sind nun in jeder Spalte von 𝐾K. D.h. durch die Matrizenmultiplikation von 𝑄×𝐾𝑇Q×KT rechnet man die Scores von allen Wörtern in der Inputsequenz zueinander aus, nämlich 𝑞1𝑘1, 𝑞1𝑘2q1⋅k1, q1⋅k2 und 𝑞2𝑘1, 𝑞2𝑘2q2⋅k1, q2⋅k2.

Nehmen wir für den Moment einfach mal an, dass 𝑃=𝑄×𝐾𝑇8P=Q×KT8. Nun wird 𝑃P in die Softmax Funktion eingefüttert, d.h. dass alle Zeilen von Softmax(𝑃)Softmax(P) aufaddiert 11 ergeben müssen. Am Schluss wird 𝑃P mit 𝑉V multipliziert, was dann 𝑍𝑜𝑢𝑡Zout ergibt. 𝑍𝑜𝑢𝑡Zout enthält dann 𝑧1z1 in der ersten Zeile und 𝑧2z2 in der zweiten Zeile.

Multi Head Self Attention

Was wir gerade unter Punkt 3.4. beschrieben haben geschieht in dem Transformer nicht nur einmal, sondern acht mal gleichzeitig. Würde man es nur einmal machen, könnte man dem zu übersetzenden Wort zu viel Aufmerksamkeit schenken. Also in unserem ersten Beisplielsatz in der Einleitung, könnte es sein, dass man „it“ zu viel Aufmerksamkeit schenkt, wenn man „it“ selbst übersetzen will, während man eigentlich „dog“ mehr Aufmerksamkeit hätte schenken sollen.

Wenn man die Schritte aus Sektion 3.4. acht mal ausführt, dann hat man allerdings auch 8 𝑍𝑜𝑢𝑡Zout Matrizen, wie man in der folgenden Grafik sehen kann:

In [ ]:
# Abbildung 6
Image(os.path.join("images", "transformer_slides", "Transformer Modell-44.png"), width=WIDTH, height=HEIGHT)
Out[ ]:
Breos-Blog-Google-Transformer-Out-4

Dass man nun acht 𝑍Z Matrizen hat, stellt ein kleines Problem dar, da der Add & Normalize Zellenblock, der dem Multi Head Self Attention Block folgt, nur mit einer einzigen Matrix umgehen kann. Wie man aus 8 Matrizen eine einzige macht, wird in der folgenden Grafik verdeutlicht:

In [ ]:
# Abbildung 7
Image(os.path.join("images", "transformer_slides", "Transformer Modell-45.png"), width=WIDTH, height=HEIGHT)
Out[ ]:
Breos-Blog-Google-Transformer-Out-5

Allerdings ist dieses kleine Problem ziemlich leicht zu beheben. Zuerst werden alle 𝑍𝑜𝑢𝑡Zout Matrizen horizontal konkateniert und dann mit einer weiteren, trainierbaren Matrix 𝑊0W0 multipliziert, was in einer, sozusagen „finalen“ 𝐙𝑜𝑢𝑡Zout Matrix resultiert. Die Anzahl Zeilen von 𝑊0W0 muss gleich der Anzahl Spalten von den konkatenierten 𝑍𝑜𝑢𝑡Zout Matrizen sein, und die Anzahl der Spalten von 𝑊0W0 muss gleichgroß wie die Wort-Embedding Größe sein (also 512 in der Realität und 4 in unserer Grafik). Die finale 𝐙𝑜𝑢𝑡Zout Matrix hat genauso viele Zeilen, wie die konkatenierten 𝑍Z Matrizen und genauso viele Spalten wie 𝑊0W0.

Add & Normalize und Residual Connections

Für die folgende Grafik haben wir die Output Matrix des Multi Head Self Attention Zellenblocks 𝑍𝑙=1Zl=1 genannt und die Output Matrix des Add & Normalize Zellenblocks 𝑍𝑙=2Zl=2, um zwischen den Output Matrizen der folgenden Codeblöcken besser unterscheiden zu können.

In [ ]:
# Abbildung 8
Image(os.path.join("images", "transformer_slides", "Transformer Modell-49.png"), width=WIDTH, height=HEIGHT)
Out[ ]:
 
 
Breos-Blog-Google-Transformer-Out-6

Wie man in der oberen Grafik sehen kann, wird in dem Add & Normalize Zellenblock nicht nur 𝑍𝑙=1Zl=1, sondern auch der Input zu dem Multi Head Self Attention Zellenblock (entweder 𝑋𝑒𝑛𝑐Xenc oder 𝑍𝑖𝑛Zin) eingefüttert. Die Tatsache, dass 𝑋𝑒𝑛𝑐Xenc oder 𝑍𝑖𝑛Zin sozusagen einen Zellenblock überspringt nennt man Residual Connection. Dann werden diese beiden Inputs elementweise addiert, normalisiert und dann an den nächsten Zellenblock weitergegeben.

Encoder Decoder Multi Head Self Attention

Wenn Sie bis hierhin durchgehalten haben, können Sie schon ziemlich stolz auf sich sein, das Schwierigste haben Sie bereits verstanden! Nun müssen wir nur noch zwei weitere Zellenblöcke erklären und dann haben wir es geschafft!

Wir springen jetzt einmal zu dem dem ersten Multi Head Self Attention Zellenblock in dem Decoder, nämlich dem Encoder Decoder Multi Head Self Attention Zellenblock. Dieser Zellenblock funktioniert genauso wie der bereits erklärte Multi Head Self Attention Zellenblock, hat aber eine kleine Besoderheit. Schauen wir uns erst einmal einen einzigen Self Attention Head in diesem Zellenblock an:

In [ ]:
# Abbildung 9
Image(os.path.join("images", "transformer_slides", "Transformer Modell-51.png"), width=WIDTH, height=HEIGHT)
Out[ ]:
 
Breos-Blog-Google-Transformer-Out-7

Wie vorher bereits erklärt, wird anhand von 𝑄,𝐾Q,K und 𝑉V Matrizen eine Output Matrix (𝑍𝑜𝑢𝑡Zout) generiert. Die Besonderheit ist nun aber, dass die 𝑄Q und 𝐾K Matrizen anhand der Output Matrizen des letzten Encoder Blocks errechnet werden und dass 𝑉V anhand von den bislang übersetzten Wörtern, also den bisherigen Outputs des Decoders errechnet werden. Dadurch hat der Transformer nicht nur Informationen aus der gesamtem Inputsequenz in der Eingangsprache zur Verfügung um das nächste Wort zu übersetzen, sondern auch die bisher übersetzten Wörter in der Zielsprache!

Nehmen wir einmal an, dass die bislang übersetzen Wörter werden in Matrix 𝑌̂ Y^ gesammelt werden. In jeder Zeile von 𝑌̂ Y^ steht also ein Wort-Embedding Vektor, der mit seinem dazugehörigen PE Vektor elementweise addiert wurde. Für Wörter, die noch nicht übersetzt wurden, hat 𝑌̂ Y^ Zeilen, die komplett aus Werten bestehen, die dem Modell signalisieren, dass jenes Wort noch nicht übersetzt wurde, nämlich minus unendlich (−∞).

Nun, wie in den vorher bereits erklärten Multi Head Self Attention Zellenblöcken, wird das ganze nicht nur einmal ausgeführt, sondern acht Mal gleichzeitig. Dann werden auch hier die acht Output Matrizen jedes einzelnen Self Attention Heads (𝑍𝑜𝑢𝑡Zout) horizontal konkateniert und mit einer weiteren, trainierbaren 𝑊0W0 Matrix multipliziert, was in einer finalen 𝐙𝑜𝑢𝑡Zout Matrix resultiert.

Linear & Softmax Zellenblock

Die letzten zwei Zellenblöcke (Linear und Softmax) haben wir in der folgenden Grafik veranschaulicht:

In [ ]:
# Abbildung 10
Image(os.path.join("images", "transformer_slides", "Transformer Modell-53.png"), width=WIDTH, height=HEIGHT)
Out[ ]:
Breos-Blog-Google-Transformer-Out-8

 

Die Output Matrix des letzten Decoder Blocks (𝑍𝑑𝑒𝑐Zdec) wird „geflattet“, d.h. dass alle Zeilen von 𝑍𝑑𝑒𝑐Zdec horizontal aneinander in einen langen Vektor gereiht werden. Jedes Element dieses Vektors ist dann mit jedem Element eines sogenannten Logit Vektoren verbunden. Dieser Logit Vektor hat genau ein Element für jedes Wort in dem Vokabular des Netzwerks. Am Schluss wird dieser Logit Vektor dann in eine Softmax Funktion gefüttert, was dafür sorgt, dass alle Elemente von dem resultierenden Vektor aufaddiert eins ergeben. Danach wird geschaut, welcher Index dieses Vektors den höchsten Wert hat, und dann wird das dazugehörende Wort vorhergesagt.

Zusammenfassung

Wenn Sie es durchgehalten haben, können Sie sich auf die Schulter klopfen. Falls Sie noch nicht alles auf Anhieb verstanden haben, seien Sie nicht enttäuscht, tiefgündiges Verständnis kommt mit der Zeit. Wir bei breos mussten uns auch mehrere Blogposts ein paar mal durchlesen, bis wir ein gutes Verständis des Transformers hatten.

Falls dieser Blogpost Ihr Interesse geweckt hat, können wir Ihnen noch die folgenden Tutorials oder Blogposts empfehlen:

https://www.tensorflow.org/beta/tutorials/text/transformer

http://mlexplained.com/2017/12/29/attention-is-all-you-need-explained/

http://nlp.seas.harvard.edu/2018/04/03/attention.html

http://jalammar.github.io/illustrated-transformer/ (Soweit wir wissen, hat dieser Blogpost momentan leider einen Fehler bei Positional Encoding. Ansonsten hat dieser Blog aber excellente Visualisierungen!)

BEITRÄGE NACH THEMA

Melde dich hier für Updates an