LLM Grundlagen, Teil 6: Das Herz der Aufmerksamkeit

Fortsetzung von hier. Nix mehr mit Metaphorik, jetzt wird gerechnet. Großes Finale. Die Mathematik steckt in Punkt 3 und wird vielleicht von manchen übersprungen werden, aber bitte wieder einsteigen spätestens zum Ausprobieren mit Klicki-bunti in Punkt 6.

1. Wo wir stehen geblieben sind

Ein Lesekopf, Head, ist das Herz des Aufmerksamkeits-Untermoduls eines Decoders. Wir beschäftigen uns mit reinen Decoder-Strukturen, da ist das noch einfacher als bei einem Encoder-Decoder-Transformer.

Der Lesekopf nimmt den Vektor eines Tokens und modifiziert ihn in Abhängigkeit von den 8.000 Nachbarvektoren im Kontext. Das war es eigentlich. Er modifiziert ihn so, dass danach mehr wichtige Information im Vektor für das entsprechende Token enthalten sind. Die Größe des Vektors ändert sich dabei nicht, wir gehen im Beispiel immer von 10.000 aus.

Der Lesekopf gibt das Ergebnis weiter an ein Neuronales Netz, und das produziert dann den Output als Input für die nächste Decoder-Schicht.

2. Metaphorische Aufmerksamkeit

Ich zitiere mich:

Nehmen wir als Input: „The dogs bark loudly.“ (Es gibt technische Gründe für die Unnatürlichkeit des Beispielsatzes.) Der Input sind ja eigentlich nicht diese Token, es geht hier nie um Token, sondern immer nur um deren Embedding, aber der Einfachkeit halber spreche ich hier ein Weilchen einfach von Token.

In jedem Durchgang wird jedes Input-Token mit allen anderen Input-Token verglichen. Nehmen wir zum Beispiel das Token „bark“, das hier also mit „The“, „dogs“, „loudly“ und „.“ verglichen wird. Das Token „bark“ sucht dabei besonders nach Token, die das Merkmal „Nomen im Plural“ und „ist ein Lebewesen“ tragen, oder auch „es geht um Bäume“, weil das ja auch „Baumrinde“ bedeuten kann. Das ist wie bei diesem Kartenspiel, wo man die anderen fragt: „Hast du eine Herz Sieben?“

Beim „.“ wird das „bark“ nicht fündig, bei „The“ nur ein wenig, aber als es zu „dogs“ kommt, schreit das sofort „biete Substantiv im Plural!“ und „biete Tier!“ Das ist das Zeichen für „bark“, dem Token „dogs“ besonders viel Aufmerksamkeit zu widmen.

Wenn für jedes Token ein Aufmerksamkeitswert ermittelt ist, geht es ans Modifizieren: das Token „dogs“ darf dann bestimmte Werte auf das Embedding von „bark“ übertragen, etwa Werte für „bin dein Subjekt“ und „es geht um Hunde“ und „du bist ein Verb und nicht etwa ein Substantiv“.

Beim nächsten Durchgang wird wieder jedes Input-Token modifiziert. Diesmal sucht „bark“ nicht mehr nach Bäumen. Ganz am Ende steckt dann im Embedding des letzten Tokens „.“ die Information „gerade eben haben Hunde laut gebellt“, und auf Basis dieses Embeddings wird dann das nächste Token vorausgesagt, möglicherweise: „They“.

3. Mathematische Aufmerksamkeit

Eigentlich passiert im Decoder nur das:

Und das ist eigentlich ganz einfach. Der blaue Rahmen, das ist ein Decoder-Modul. Der grüne Rahmen, das ist ein Attention-Submodul. Das ist der Lesekopf. Der nimmt einen Haufen Vektoren entgegen. Im Beispiel ist der Kontext nur 5 Token groß, das ist ein kleiner Haufen: The, dogs, bark, loudly, . (Statt: 8.000 wie in echt.) Jeder Vektor besteht aus 4 Zahlen. (Statt 10.000 wie in echt.) Statt einen Haufen sagt man technisch aus: eine Matrix. Man kann sich das wie eine kleine Tabelle vorstellen. Jede Zeile steht für ein Token-Embedding:

Die Zahlen habe ich mir einfach ausgedacht.

Für jeden dieser 5 Vektoren werden anhand von drei vorgefertigten Tabellen neue Vektoren erstellt. Das sind die drei vorgefertigten Tabellen; und weil das Embedding aus 4 Zahlen besteht, sind die Tabellen 4 x 4 groß:

Die Zahlen habe ich mir ausgedacht. Tatsächlich werden sie trainiert, und eben diese drei 10.000 x 10.000 großen Tabellen auf geeignete Werte hin zu trainieren, und das für 120 Decoder-Schichten, ist eine der Hauptarbeiten beim Trainieren des LLM. Das sind dann dann schon mal 36 Milliarden Parameter; GPT-4 soll 1800 Milliarden Parameter haben insgesamt; es kommen ja noch ein paar dazu später. Wie gut jedenfalls, dass das P in GPT für „pre-trained“ heißt, dann müssen wir nur noch mit diesen fertigen Tabellen rechnen und sie nicht trainieren. Kostet immer noch genug Strom auch so.

Diese Tabellen werden benutzt, um aus den 5 Eingangsvektoren jeweils einen Query-, einen Key- und einen Value-Vektor zu erzeugen. Sie sind hier wieder als Haufen Tabelle Matrix dargestellt:

Die markierten Zeilen sind jeweils die Q-, K- und V-Vektoren für das Token „bark“ von oben. Nur mit denen wird weitergerechnet, die alten Inputwerte können wir vergessen. Wie diese Vektoren entstehen, zum, Beispiel der Q-Vektor für „bark“ ganz links: Die vierstellige Input-Zeile für pos2 wird multipliziert mit der gesamten Q-Tabelle, und das Ergebnis ist die vierstellige Query-Zeile für pos2. Wie kann man eine Zeile mit einer Tabelle multiplizieren, höre ich die fragen, die damals im Mathematikunterricht beim Herrn Gerigk nicht aufgepasst haben: Ah, Matrizenmultiplikation, und mehr sage ich dazu nicht. Das ist jedenfalls keine besonders komplizierte Rechenaufgabe für einen Computer.

Jetzt wird für jeder Q-Vektor mit jedem K-Vektor multipliziert. Wenn man einen Vektor mit einem anderen Vektor multipliziert (Herr Gerigk!) kommt eine simple Zahl heraus. Wenn ich also 5 Q-Vektoren jeweils mit 5 K-Vektoren multipiziere, kriege ich 25 Zahlen, und zwar diese hier:

(Tatsächlich rechnet man, also in Libre Office Calc zum Beispiel, nicht 25 mal den einen mal den anderen Vektor, sondern man multipliziert die ganze Tabelle Matrix mit der ganzen anderen Tabelle Matrix, und da ist sie dann noch noch einmal, unsere Matritzenmultiplikation.)

Die gelbe Zeile in der Ergebnismatrix, die jetzt nicht mehr vier, sondern fünf Spalten breit ist, gibt an, wie viel Aufmerksamkeit von pos2 aus auf alle anderen 5 Positionen, sich selber eingeschlossen, zu richten ist: Von pos2 auf pos0 am wenigsten, von pos2 auf pos1 bis pos4 dreimal so viel, von pos2 auf pos4 doppelt so viel.

Diese Zahlen werden aus technischen Gründen noch ein bisschen verändert und sozusagen vergleichbarer gemacht, das heißt hier: Skalierung und Softmax. Diese Attention-Tabelle wird dann mit der Values-Tabelle, die ganz oben erstellt worden ist, multipliziert, und damit hat das Attention-Submodul im Decoder seine Aufgabe erledigt:

Warum werden diese Matrizen multipliziert? Wenn man sich jeweils einzelne Vektoren anschaut, wird es ein bisschen klarer:

  • Die gelb markierte Zeile in der Softmax-Tabelle gibt an, wie viel Aufmerksamkeit von pos2 auf die anderen Token richtet. (Modifiziert von Query x Key.).
  • Dieser Vektor wird multipliziert mit der entsprechen Values-Spalte im Values-Vektor oben.
  • Der Values-Vektor oben, das sind die (modifizierten) ursprünglichen Beziehungen zu allen anderen 5 Vektoren.
  • Diese Werte zu multiplizieren mit dem Attention-Vektor heißt, eine gewichtete Addition durchzuführen: die alten Werte werden durch den Aufmerksamkeitsfaktor modifiziert und dann addiert; 0,0 * 0,81 + 0,37 * 7,60 + 0,50 * 6,08 + 0,11 * 3,68 + 0,02 * 35, was ungefähr 6,33 ergibt (Rundungsabweichungen sind ein paar drin).
  • Das ergibt den einen markierten Wert unten; das heißt, dass in den dritten (von vier) Embedding-Wert von pos2 alle alten Werte aller Token eingeflossen sind, und für die anderen Embedding-Werte natürlich ebenso.

Und das sind fast – nur fast! – schon unsere neuen Werte für den nächsten Decoder. Aber zuvor geht das ganze noch in das zweite Submodul des Decoders, ein Neuronales Netz, wo unser eigener Computer wieder ein bisschen mehr rechnen muss als bisher. Richtig viel gerechnet wurde allerdings wieder beim Training des Netzes, dessen versteckte Ebene vermutlich aus etwa 40.000 Knoten besteht, was wieder zu zusätzlichen Parametern führt.

Das Neuronale Netz verarbeitet nach und nach, unabhängig voneinander, jeden Vektor und modifiziert ihn weiter.

Noch einmal zusammen, damit man nicht hochblättern muss:

Das Diagramm stellt den Vorgang immer mit ganzen Haufen von Vektoren dar, also Matrizen. In vielen Darstellungen wird das auch mit einzelnen Vektoren erklärt, also das 1 Token-Vektor reingeht, und für den Anfang 1 Q-Vektor und für das Ende 1 V-Vektor erstellt wird (aber K-Vektoren für alle Token im Kontext!). Dann wird der eine Q-Vektor mit allen K-Vektoren multipliziert, das Ergebnis skaliert und mit dem 1 V-Vektor multipliziert, was den vorläufigen neuen Token-Vektor ergibt. Ich habe überlegt, ob ich das so darstellen soll, mich aber dagegen entschieden; nicht verwirren lassen, wenn man bei Erklärungen auf beides stößt.

4. Was ich weggelassen habe

  • Was das FFNN am Ende eigentlich macht, weil mir das selber noch nicht klar ist.
  • Vor allem: Dass es nicht nur einen Lesekopf gibt, sondern 8 oder 12 oder 120, die sich die Arbeit teilen und unterschiedliche Schwerpunkte setzen können.
  • Wie die Parameter für die drei Matrizen und das Neuronale Netz erstellt werden, also wie trainiert wird.
  • Zur Erinnerung: Das ist self-attention, nicht cross attention; die ist noch ein klein wenig komplizierter.
  • Nicht klar ist mir, ob Maskierung nicht doch eine Rolle spielt; ich lese da immer wieder Verschiedenes. Maskierung hieße hier, dass nur die vorhergehenden Token ausgewertet werden, die späteren Token sozusagen ausgeblendet werden. Ich glaube, manche Modelle machen das so, andere so.
  • Überhaupt, ist das nur eine Überblick, und es gibt auch andere Modelle mit Encoder-Decoder-Transfornern, und viele Details mehr: aber es ging mir nur ums Prinzip, und mehr könnte ich auch gar nicht.

5. Was Q und K und V bedeuten

Das oben war die Rechnerei, die, wenn man nach und nach Blogeinträge darüber schreibt, sogar nachvollziehbar ist. Damit ist noch nicht gesagt, was man sich bei diesem Entwurf gedacht hat, was Query, Key und Value überhaupt bedeuten.

Query, das ist das metaphorische „Suche Subjekt. Suche Singular.“ Man kann aber nicht wirlich sagen, wie die Eigenschaft heißt, nach der gesucht wird; das sind alles abstrakte, von der Maschine selbst angelegte Attribute.

Key, das ist das metaphorische „Biete Subjekt. Biete Singular. Biete Tier.“

Value, das bestimmt am Ende den Wert, der in der nächsten Runde für die neuen Q- und K-Werte zuständig ist.

Kontraintuitiv finde ich, dass es in jeder neuen Decoder-Schicht erst einmal fast neue Embbeddings für alle Token gibt. Die alten Embeddings werden durch die für diese Schicht gültige Value-Werte-Matrix modifiziert. Das heißt, diese Schicht hat schon spezielle Wünsche, was die die zukünftigen Werte betrifft, wonach gesucht wird und was dann herauskommen könnte. Diese Werte ihrerseits werden jetzt mehr oder weniger abgeschwächt, je nachdem, wie viel Aufmerksamkeit erforderlich ist.

Der Query-Vektor des aktuellen Tokens wird separat mit den Key-Vektoren aller anderen Token multipliziert, das gibt jeweils eine einzelne Zahl, die niedrig ist, wenn das System keinen großen Zusammenhang zwischen dem aktuellen Token und dem anderen erkennt und hoch, wenn es einen Zusammenhang sieht. Diese Zahl kann auch künstlich auf 0 oder einen sehr negativen Wert gesetzt werden, wenn aus anderen Gründen dieses Token nicht mitverrechnet werden soll – das ist diese Maskierung, von der ab und zu die Rede war.

(Hier müsste ich noch mehr schreiben und noch mehr verstehen. Aber ich will fertig werden, also lasse ich das mal.)

6. Visualisierung

6.1 BertViz

BertViz ist ein Werkzeug zur Visualisierung von Attention. Dort gibt es eine PDF-Anleitung und Jupyter Notebooks zum Kopieren, und das funktioniert bei mir auch! (Ich muss das erwähnen, weil ich oft Schwierigkeiten habe, weil doch irgendein Paket nicht erreichbar oder eine falsche Python-Version und so weiter.)

Mit BertViz kann man verschiedene Modelle herunterladen, zum Beispiel:

BERT (2018)

  • encoder-only, 2, 12 oder 24 Schichten (je nach Version)
  • 12 Attention Heads; Embedding-Größe 768 – 1024
  • 30,000 Wortschatz, 110 – 340 Millionen Parameter
  • trainiert auf 330 Millionen Wörtern (Bücher, Wikipedia)
  • arbeitet mit Token links und rechts der Lücke

GPT-2 (2019)

  • decoder-only; 12 – 48 Schichten (je nach Version)
  • 12 Attention Heads; Embedding-Größe 768 – 1600
  • 50.257 Wortschatz, 117 – 1.542 Millionen Parameter
  • trainiert auf 40 GB Text (Webseiten)
  • maskiert nachfolgende Token

Ich finde es schön, dass mir diese Zahlen jetzt etwas sagen!

6.2 Funktionsweise

Dann kann man Sätze eingeben und auswerten lassen und sich zeigen lassen, welches Token wie aufmerksam zu anderen Token ist, und zwar unterschiedlich detailliert, bis hin dazu, wie der Q-Vektor für ein konkretes Token in einem bestimmten Head in einem bestimmten Layer ist, ditto der K-Vektor der anderen Token, und das Produkt Q x K dazu, das ja die Aumerksamkeit repräsentiert.

Manche Heads achten vor allem auf das vorhergehende Wort, andere auf alle vorhergehenden Wörter, dritte wiederum achten vor allem auf Verben, vierte auf zusammengehörende Aufzählungen, fünfte auf Klammerungen, und so weiter (Jesse Vig 2019). Hier Illustrationen aus dem kurzen und gut lesbaren Aufsatz:

Vig, Jesse. „A Multiscale Visualization of Attention in the Transformer Model“, in: Proceedings of the 57th Annual Meeting of the Association for Computational Linguistics: System Demonstrations. Florence, Italy: Association for Computational Linguistics 2019, p. 37-42. https://www.aclweb.org/anthology/P19-3007

  • Links oben sieht man einen Head, der Äpfel, Orangen und Bananen als Teil einer Aufzählung erkennt; rechts oben werden Akronyme auf Schlüsselwörter bezogen.
  • Unten sieht man in den beiden linken Spalten, wie „she/he“ auf Eigennamen oder gegenderte Begriffe bezogen werden, und in der rechten Spalte, wie der gleiche, einmal gefolgt von „she“ und einmal von „he“ unterschiedlich fortgesetzt wird (nicht im Bild), weil „she“ und „he“ einmal auf „nurse“ und einmal auf „doctor“ bezogen werden. Vig nennt das als Beispiel für Bias im Modell.

Ich habe ein wenig mit BertViz herungespielt, denn wie gesagt, das funktioniert; aber es ist gar nicht leicht, so schöne Beispiele wie in dem Aufsatz zu finden. Es ist ja nicht so, dass man vorher weiß, welcher Head wofür zuständig ist und in welcher Schicht interessante Erkentnisse zu gewinnen sind. Dafür müsste ich mehr Zeit haben.

6.3 Ausprobieren

Aber dennoch habe ich etwas zum Ausprobieren vorbereitet:

Dazu einfach mit der Maus über die Token fahren. Voreingestellt ist Layer 5, Aufmerksamkeitskopf 10, das ist das Beispiel aus dem Aufsatz; aber man kan auch die anderen Köpfe dazu klicken oder das Layer wechsen.

Wer die Schichten und Heads im Überblick sehen möchte, kann den model view ausprobieren; (dort auf die einzelnen Grafiken klicken).

Die Q- und K-Vektoren kriegt man mit dem neuron view (dort auf das Plus-Zeichen klicken, das beim Mouseover links neben den Token erscheint). Blau bedeutet einen positiven Wert, orange einen negativen.

Andere Beispielsätze kann ich natürlich auch ausprobieren, oder andere Modelle, dazu habe ich mir eine Jupyter-Notebook-Datei angelegt, aber das kann ich technisch nicht hier im Blog zeigen.

7. Links und Ausprobieren

Ja, und das war es auch schon. Ein bisschen antiklimatikisch, ist es nicht? Ein paar einfache Tabellen und ein paar Neuronale Netze. Wo ist der Zauber hin, die Magie? Für Zauber hielt ich es ohnehin nie, und auch nicht für Intelligenz, auch wenn mir noch immer genug unklar ist. Aber ich denke, wenn ich mich da auch noch reinknie, verliere ich den letzten Respekt davor.

Fortsetzung folgt. Aber nur noch eine Rückschau und ein Überblick, wegen closure.

***

Nachtrag: Na gut, einen habe ich noch. Ich habe mir in der Tabellenkalkulation mal etwas zusammengebaut. Links oben das graue, das sind die Embeddings für die Token „She eats chips and pie.“ Rechts daneben sind die gelernten Matrizen für Queries, Keys und Values in dieser Ebene.

Die Query-Matrix erzeugt zusammen mit diesem Input Suchvektoren mit dem Inhalt „Ich habe einen hohen Wert bei emb0 und suche nach emb1,“ was so viel heißen könnte wie „hier sucht ein Prädikat nach Objekten,“ wenn emb0 für „potentielles Prädikat“ und emb1 für „potentielles Objekt“ steht. Die Key-Matrix erzeugt Key-Vektoren mit „Ich habe einen hohen Wert bei emb1“, also „ich bin ein potentielles Objekt.“

Der orange Q-Vektor für „eats“ (aber auch alle anderen) wird mit allen Key-Vektoren, zum Beispiel dem blauen für „pie“ (aber auch allen anderen) multipliziert, das gibt dann die rote Aufmerksamkeitsmatrix. (Davor muss aus rechnerischen Gründen die Keys-Matrix transponiert, quasi gekippt werden.) Man sieht daran, dass in dieser Ebene vor allem „eats“ auf „pie“, aber auch „chips“ aufmerksam gemacht worden ist.

Klar, denn sowohl „pie“ als auch „chips“ haben einen hohen Wert bei emb1. Aufgabe dieser Ebene: finde heraus, was als Objekt für ein Verb in Betracht kommt. Diese Aufgabe ist in den gelernten Matrizen kodiert.

Das ist natürlich grob vereinfacht. Die Zahlenwerte sind nicht realistisch, und die Embeddings bedeuten nicht so einfach etwas, das sich leicht verstehen lässt. Und es fehlt völlig, was dann mit den neuen Values passiert, die durch die Aufmerksamkeitsmatrix entstehen und die dann in das Neuronale Netz kommen, weil ich das nicht weiß. Ich weiß auch nicht, ob das Beispiel zu vereinfacht ist, aber es repräsentiert das mentale Modell, das ich im Moment im Kopf davon habe, wie das funktioniert.

In der Praxis: Mit der Maus über das rechte „eats“ fahren:


Beitrag veröffentlicht am

in

Kommentare: 0

Schlagwörter:

Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert