0.1.2. Aufruf und Beispielausgabe
Der Referenzlauf startet im Verzeichnis MinimalesLLM:
go run ./cmd/minimalesllm
Ohne Argumente gelten die eingebauten Vorgaben: die Namensliste liegt in input.txt und wird beim ersten Mal geladen, 1000 Trainingsschritte, 20 Stichproben, Temperatur 0,5, Seed 1. Die Form des Netzes bleibt die Referenz aus model.Reference: Breite 16, eine Schicht, Kontextfenster 16, vier Attention-Köpfe.
go run ./cmd/minimalesllm -seed 2 -input andere-namen.txt
Ein anderer Seed ändert die Anfangsgewichte, die einmalige Mischreihenfolge und die Ziehungen. Dieselbe Datei und derselbe Seed ergeben denselben Bericht, Byte für Byte.
Nur zwei Flags sind verstellbar. Schrittzahl, Temperatur und die Breite des Netzes stehen im Programm fest.
| Flag | Vorgabe | Wirkung |
|---|---|---|
-seed |
1 |
Initialisierung, das einmalige Mischen und die Stichproben danach |
-input |
input.txt |
Datei mit kurzen Zeilen. Eine nicht leere Zeile ist ein Dokument |
Fehlt input.txt, lädt das Programm die englische Namensliste, die auch der Namensgenerator benutzt, wenn seine Datei fehlt. Eine vorhandene Datei bleibt unverändert.
Der Generator ist ein PCG. Seed und eine feste Stromkonstante legen die Zahlenfolge fest:
rand.New(rand.NewPCG(uint64(int64(seed)), 0x9e3779b97f4a7c15))
Der Lauf benutzt diese Folge in zwei getrennten Leben, beide bei Seed 1:
- Der Generator in
runzieht die 4192 Anfangsgewichte und mischt danach die Dokumente. Das Training verbraucht von da an keine Zufallszahlen. - Die Stichproben bauen einen neuen Generator aus demselben Seed. Zwei weitere Züge am Ende tun das noch einmal. Ein letzter Zug nimmt den nächsten Seed.
Der Bericht erscheint auf der Standardausgabe, Fehler auf der Standardfehlerausgabe. Er enthält:
- Dokumentzahl, Vokabulargröße,
ln(V)und die Token vonana - die Parameterzahl
- die Einbettungszeile von
avor und nach dem Training - den Verlust jeder Stufe, vor der Änderung der Gewichte
- den Vorwärtspass von
ana: Residualstrom, Logits, Ziel, eine Attention-Zeile - 20 Stichproben, die Verteilung am Anfang der ersten Stichprobe, die Attention-Zeile am zweiten Zeichen
- zwei weitere Züge mit demselben Seed und einen Zug mit dem nächsten Seed
Der erste Verlust liegt nahe bei ln(V). Danach fällt die Kurve im Trend und springt von Dokument zu Dokument. Die Einbettung von a hat sich verändert. Die Stichproben benutzen das Vokabular und sehen aus wie kurze Namen, auch solche, die nicht in der Datei standen.
Der folgende Auszug ist der Referenzlauf mit Seed 1 und input.txt. Die tausend Verlustzeilen sind gekürzt. Der vollständige Bericht liegt im Repository als example-output.md.
Dokumente: 32033
Vokabular: 27 (BOS=26), ln(V)=3.2958
ana: [26 0 13 0 26] → BOS a n a BOS
Parameter: 4192
Einbettung von "a" vor dem Training: -0.1869 -0.0725 0.0881 -0.0402 0.0873 0.0309 -0.1667 0.1212 -0.0450 -0.0868 0.0570 0.0764 -0.0067 -0.0885 0.0402 0.0821
Schritt 0 Verlust 3.2656
Schritt 1 Verlust 3.2705
Schritt 2 Verlust 3.0783
...
Schritt 53 Verlust 3.6368
...
Schritt 999 Verlust 2.2517
Einbettung von "a" nach dem Training: -0.6439 -0.1633 0.0494 0.0554 0.0679 0.2240 -0.1531 -0.0387 -0.4331 -0.1340 0.1724 0.2219 0.0251 -0.0217 0.1124 -0.2844
Vorwärtspass von ana nach dem Training
IDs: [26 0 13 0 26] → BOS a n a BOS
Residualstrom nach der Einbettung: -0.5835 -0.4634 -0.0066 0.0230 -0.0919 0.2744 -0.3749 0.2880 -0.3338 -0.0151 0.1371 0.4235 0.0490 -0.3021 0.0246 -0.2710
Residualstrom nach dem Block: -2.3910 -0.7844 -0.0479 0.2390 -0.5950 0.9303 -1.2029 0.9021 -0.3715 -0.1131 0.3040 1.0412 -0.0859 -0.9469 0.1770 -0.6553
Logits: -0.8944 -0.9592 -0.9049 -0.0650 -0.5379 -1.3709 -1.4786 -0.6957 0.2062 -2.0599 -0.8987 0.2138 0.0764 0.8114 -1.4610 -2.0884 -3.6535 0.6436 -0.2141 -0.5349 -1.7571 -0.4476 -1.8692 -1.2972 0.4187 -1.5407 -0.0066
Ziel: 26 (BOS)
Attention Kopf 0: 0.2785 0.1918 0.3010 0.2287 Summe 1.0000
Stichproben:
0: anare
1: misia
2: lelia
3: eleeli
4: vilemi
5: bayl
6: calelon
7: zielar
8: kasai
9: nevyla
10: ahona
11: uranin
12: byania
13: karia
14: soria
15: daonin
16: adonia
17: jarlen
18: jayten
19: daysa
Wahrscheinlichkeiten an Position 0: 0.1852 0.0372 0.0454 0.0978 0.0129 0.0016 0.0066 0.0096 0.0063 0.0842 0.1339 0.0274 0.1396 0.0219 0.0024 0.0059 0.0000 0.0572 0.0656 0.0199 0.0005 0.0038 0.0014 0.0005 0.0049 0.0275 0.0007
Attention am zweiten Zeichen: 0.5152 0.4848 Summe 1.0000
Gleicher Seed, Zug 1: anare
Gleicher Seed, Zug 2: anare
Nächster Seed: voriel
32033 ist die Zahl der Namen in input.txt. 27 sind die 26 Buchstaben plus BOS. ln(V) ist der natürliche Logarithmus von 27, etwa 3,2958. Ein Modell, das jeder ID dieselbe Wahrscheinlichkeit gäbe, hätte einen Next-Token-Verlust von diesem Wert. Die späteren Verluste liest man daran.
ana ist eine feste Prüfzeichenfolge. Das Programm kodiert sie vor dem Training und bewertet sie danach noch einmal. a ist die ID 0, n die ID 13, BOS die ID 26. BOS eröffnet jedes Trainingsdokument, und eine Stichprobe endet, wenn es gezogen wird.
4192 ist die Zahl der trainierbaren Skalare bei dieser Form und diesem Vokabular:
| Tabelle | Form | Skalare |
|---|---|---|
Token-Einbettung WTE |
27 × 16 | 432 |
Positions-Einbettung WPE |
16 × 16 | 256 |
Attention WQ, WK, WV, WO |
vier Matrizen 16 × 16 | 1024 |
Vorwärtsgerichtetes Netz FC1, FC2 |
64 × 16 und 16 × 64 | 2048 |
Ausgabe LMHead |
27 × 16 | 432 |
| Summe | 4192 |
Der Skalargraph eines Dokuments ist vorübergehend und zählt hier nicht mit. Die Adam-Momente ebenfalls nicht.
Die Zeile vor dem Training ist Zeile 0 von WTE, der Vektor des Buchstabens a, auf vier Stellen gedruckt. model.New füllte sie mit normalverteilten Zufallszahlen, Standardabweichung 0,08, aus dem Generator von Seed 1. Sechzehn Zahlen sind die Einbettungsbreite.
Nach Schritt 999 ist jede Koordinate eine andere. Die Zeile wurde geändert, wenn der Verlust eines Dokuments einen Gradienten durch eine Position schickte, deren Token a war.
Jede Zeile Schritt … Verlust … ist ein Adam-Schritt, bevor die Gewichte sich bewegen. Ein Schritt nimmt den nächsten Namen der gemischten Liste, kodiert ihn als BOS, Buchstaben, BOS und bildet den Mittelwert der negativen Logarithmen der Zielwahrscheinlichkeiten.
Schritt 0 liegt mit 3,2656 neben ln(27). Die Gewichte sind noch zufällig. Danach sinkt der Trend, einzelne Zeilen springen. Schritt 53 ist 3,6368, über der gleichverteilten Grundlinie, weil dieser Name für die Gewichte dieses Augenblicks überraschend war. Schritt 999 ist 2,2517. Über die Datei hinweg wandern die Werte von etwa 3,3 in ein Band um 2 bis 2,5.
Die Lernrate beginnt bei 0,01 und fällt linear. Bei Schritt 999 ist sie 0,01 * (1 - 999/1000). Die Betas sind 0,85 und 0,99.
Gedruckt ist die letzte bewertete Position der fünf IDs. Die Eingabe dort ist das zweite a, das Ziel ist das schließende BOS.
Der erste Vektor ist der Residualstrom nach der Einbettung: die Zeile für a plus die Zeile für Position 3. Der zweite Vektor ist dieser Strom nach dem einzigen Block. Beide haben die Länge 16.
Die 27 Logits stehen der Reihe nach für a bis z und dann BOS. Der größte ist 0.8114 an Index 13, der Buchstabe n. Der Logit des Ziels BOS ist -0.0066. Diese Inspektion ändert die Gewichte nicht.
Attention Kopf 0 sind vier Gewichte über die vier schon sichtbaren Token: BOS, a, n und das aktuelle a. Das größte Gewicht, 0.3010, liegt auf n. Die Summe ist 1.
Die Gewichte sind eingefroren. Jede Stichprobe beginnt mit leerem Cache und sieht die vorige nicht. Sie startet bei BOS, teilt die Logits durch die Temperatur 0,5, bildet den Softmax und zieht eine ID. BOS beendet die Zeichenfolge und wird nicht gedruckt.
Die zwanzig Namen kommen aus einem Generator, der bei Seed 1 neu begonnen hat. Sie unterscheiden sich, weil jede Ziehung Zufallszahlen verbraucht. Manche stehen in der Datei, manche sind neue Folgen aus demselben Alphabet.
Die 27 Wahrscheinlichkeiten an Position 0 gehören zu Stichprobe 0, vor der ersten Ziehung. Der größte Eintrag ist 0.1852 auf a. Deshalb beginnt Stichprobe 0 mit a und setzt mit nare fort. 0.0000 ist eine Wahrscheinlichkeit unter 0,00005, auf vier Stellen gerundet.
Am zweiten Zeichen sieht Kopf 0 zwei Token: das eröffnende BOS und das gezogene a. Die Gewichte sind 0.5152 und 0.4848.
Gleicher Seed, Zug 1 und Zug 2 sind je eine einzelne Stichprobe aus einem frisch mit Seed 1 gebauten Generator. Die ersten Zufallszahlen sind dieselben wie bei Stichprobe 0, deshalb steht beide Male anare.
voriel kommt aus denselben Gewichten mit Seed 2. Die Verteilung an Position 0 ist dieselbe. Eine andere Ziehung nimmt eine andere ID, und der Name geht von dort auseinander. Die Gewichte speichern die Verteilung. Der Seed wählt den Weg hindurch.
- 0.1.3. Namensgenerator setzt eingegebene Anfänge fort.
- 0.1.4. Token beginnt die Implementation.