---
title: "Anatomia LLM: tokeny i embeddingi"
date: 2026-06-11
description: "Sieć nie widzi liter - widzi wektory. Jak tekst rozbija się na tokeny, dlaczego nie na słowa ani nie na znaki, jak algorytmy subword (BPE, WordPiece, Unigram) budują słownik, i jak rodzi się słynna geometria znaczeń, w której „król - mężczyzna + kobieta ≈ królowa” - razem z uczciwą krytyką tej analogii i z kodowaniem pozycji, o którym elementarze milczą."
tags: ["anatomia llm", "ai", "llm", "nlp", "deep-dive"]
---

## 🚀 Intro

W [poprzednim przystanku tej serii](/posty/llm-sieci-parametry-trening) - jednej z gałęzi [przeglądowego wpisu „Anatomia LLM"](/posty/anatomia-llm) - złożyliśmy z neuronów całą sieć i pokazaliśmy, jak trening zamienia losowy szum w model rozumiejący język. Cały czas mówiliśmy jednak o „przetwarzaniu tokenów" i „przewidywaniu następnego tokenu", przemilczając pytanie najbardziej podstawowe: **czym właściwie jest token i jak słowo staje się liczbą**, którą da się mnożyć?

Bo sieć nie widzi liter. Nie widzi słów. Widzi **wektory** - ciągi liczb. Zanim jakiekolwiek mnożenie macierzy z poprzedniego wpisu w ogóle ruszy, tekst musi przejść przez dwa etapy: najpierw zostać **pocięty na kawałki** (tokeny), a potem każdy kawałek musi dostać swój **wektor** (embedding). To jest most między światem znaków a światem liczb - i ten most ma zaskakująco bogatą konstrukcję.

W tym wpisie zobaczymy, dlaczego nowoczesne modele nie tną tekstu ani na słowa, ani na pojedyncze znaki, tylko na coś pomiędzy. Prześledzimy, jak rodzi się ta słynna **geometria znaczeń**, w której kierunki w przestrzeni odpowiadają pojęciom, a odejmowanie wektorów daje analogie. I - w duchu całej serii - przyjrzymy się temu krytycznie: bo przykład „król - mężczyzna + kobieta ≈ królowa" jest piękną intuicją, ale bywa nadinterpretowany. Na koniec dotkniemy rzeczy, którą elementarze zwykle pomijają: skąd model w ogóle wie, w jakiej **kolejności** padły słowa.

> 💡 **Jak czytać ten tekst.** Główny wątek jest opisowy i samowystarczalny. Wzory chowam w rozwijanych blokach „dla dociekliwych" - jeśli lubisz matematykę, rozwiń; jeśli nie, pomiń bez straty dla zrozumienia. Wszystkie twierdzenia mają przypisy do prac źródłowych na końcu.


## 📋 TL;DR

- **Token to nie słowo.** Dzielenie na pełne słowa rozsadza słownik (zwłaszcza w językach fleksyjnych jak polski) i potyka się o słowa nieznane; dzielenie na znaki robi sekwencje rozpaczliwie długie. Standardem jest **tokenizacja subword** - częste słowa to jeden token, rzadkie rozpadają się na znane kawałki.
- **Algorytmy subword:** **BPE** (scala najczęstsze pary - rdzeń GPT), **WordPiece** (kryterium probabilistyczne - BERT), **Unigram/SentencePiece** (przycina duży słownik - niezależny od języka).
- **Ile tokenów?** Słowniki współczesnych modeli liczą od ok. 50 tys. do ok. 200 tys. tokenów. Reguła kciuka: ok. 4 znaki na token w angielskim - w polskim znacznie mniej, więc ten sam tekst „kosztuje" więcej tokenów.
- **Embedding to wektor znaczenia.** Każdy token dostaje wiersz w trenowanej **macierzy embeddingów** $E$. Powstaje przestrzeń, w której bliskość = podobieństwo znaczenia, a kierunki bywają interpretowalne.
- **Słynna analogia z krytycznym okiem.** „Król - mężczyzna + kobieta ≈ królowa" pokazuje liniową strukturę przestrzeni, ale **nie dowodzi**, że model „rozumie" relacje - to częściowo artefakt metryki i doboru przykładów (Linzen; Drozd i in.).
- **Statyczne vs kontekstowe.** word2vec/GloVe dają jeden wektor na słowo (to samo „zamek" w „zamek królewski" i „zamek błyskawiczny"). Transformery dają reprezentacje **kontekstowe** - wektor zależy od zdania.
- **Pozycja.** Uwaga sama nie zna kolejności tokenów - trzeba ją **wstrzyknąć**: kodowanie sinusoidalne, uczone tabele, a dziś najczęściej **RoPE** (obrót) i **ALiBi** (liniowa kara za odległość).

👉 **Pobaw się:** na stronie interaktywnej masz [sekcję tokenów i embeddingów](/llm/anatomia#tokeny) - zobacz, jak tekst rozpada się na kawałki i jak wektory układają się w przestrzeni znaczeń.


## ✂️ Dlaczego nie słowa ani nie litery

Wydawałoby się, że najnaturalniej jest podzielić tekst na **słowa**. Problem w tym, że język jest „otwarty" - wciąż powstają nowe słowa, nazwy własne, zlepki, błędy. Słownik musi być skończony, więc cokolwiek do niego nie trafi, ląduje w jednym koszu „nieznane" (token `<UNK>`, od *unknown*). To tak zwany problem **OOV** (*out-of-vocabulary*, czyli „spoza słownika").

W językach **fleksyjnych** - jak polski, fiński czy turecki - to boli podwójnie. Jeden wyraz ma dziesiątki form: *kot, kota, kotu, kotem, kotów, kotami...* Gdyby każda forma miała być osobnym tokenem, słownik eksplodowałby, a i tak rzadsze formy byłyby modelowi nieznane. Język polski jest tu wręcz podręcznikowym przeciwnikiem podejścia „słowo = token".

Druga skrajność to dzielenie na pojedyncze **znaki**. OOV znika (alfabet jest mały i zamknięty), ale pojawia się inny kłopot: sekwencje robią się **wielokrotnie dłuższe**. Słowo „kotami" to jeden-dwa tokeny subword, ale sześć znaków. A koszt mechanizmu uwagi rośnie z **kwadratem** długości sekwencji (wrócimy do tego w następnym wpisie) - dłuższe sekwencje to wyraźnie droższe obliczenia. Dodatkowo cały ciężar złożenia znaków w sens spada wtedy na samą sieć.

**Tokenizacja subword** (czyli „pod-słowna") to złoty środek: częste słowa zostają jednym tokenem, a rzadkie i nieznane rozbijają się na mniejsze, znane kawałki. Słownik ma kontrolowany rozmiar, OOV praktycznie znika, a sekwencje pozostają krótkie. To dziś standard we wszystkich dużych modelach językowych.


## 🧩 Algorytmy subword: BPE, WordPiece, Unigram

Jak właściwie zdecydować, **które** kawałki powinny być tokenami? Tu wchodzą trzy rodziny algorytmów.

**Byte-Pair Encoding (BPE).** Co ciekawe, narodził się jako algorytm **kompresji** danych - Philip Gage opisał go w 1994 roku[^gage]. Pomysł jest banalnie prosty: znajdź najczęściej sąsiadującą parę symboli i zastąp ją jednym nowym symbolem; powtarzaj. Sennrich, Haddow i Birch (2016) przenieśli ten pomysł do przetwarzania języka[^sennrich]: zaczynamy od pojedynczych znaków i w kolejnych krokach **scalamy** najczęściej współwystępującą parę, aż słownik osiągnie zadany rozmiar. Lista tych scaleń („merge'ów") staje się przepisem na tokenizację dowolnego nowego tekstu.

GPT-2 dorzucił sprytny wariant: **byte-level BPE**, działający na **bajtach** UTF-8 zamiast na znakach[^gpt2]. Ponieważ każdy możliwy bajt (jest ich 256) jest w bazowym alfabecie, **dowolny** ciąg Unicode da się zakodować bez `<UNK>` - zerowy OOV z samej konstrukcji. To podejście króluje w rodzinie GPT.

**WordPiece.** Wariant Google'a (Schuster i Nakajima, 2012)[^schuster], spopularyzowany przez ich system tłumaczeń[^gnmt] i użyty w **BERT**[^bert]. Różni się od BPE kryterium scalania: zamiast po prostu „najczęstsza para", WordPiece scala parę, która **najbardziej zwiększa prawdopodobieństwo** korpusu według prostego modelu statystycznego. To kryterium probabilistyczne, nie czysto częstościowe.

**Unigram LM i SentencePiece.** Kudo (2018) podszedł do sprawy od drugiej strony[^kudo-unigram]: zamiast budować słownik od dołu przez scalanie, zaczyna od **dużego** zbioru kandydatów i **przycina** go, usuwając te tokeny, których brak najmniej zaszkodzi. **SentencePiece** (Kudo i Richardson, 2018) to popularna implementacja, która traktuje tekst jako surowy strumień znaków - nawet spację koduje jako zwykły symbol (`▁`)[^sentencepiece]. Dzięki temu jest **niezależna od języka**, co jest kluczowe dla języków bez spacji między słowami, jak japoński czy chiński.

W praktyce każdy wielki model ma swój tokenizator o konkretnym rozmiarze słownika. Dla rodziny OpenAI (biblioteka `tiktoken`)[^tiktoken-vocab]:

| Tokenizator | Rozmiar słownika | Przykładowe modele |
|---|---|---|
| `gpt2` / `r50k_base` | 50 257 | GPT-2, dawne GPT-3 |
| `p50k_base` | 50 281 | Codex |
| `cl100k_base` | ~100 277 | GPT-3.5-turbo, GPT-4 |
| `o200k_base` | ~200 019 | GPT-4o, o1 |

Praktyczna reguła kciuka z dokumentacji `tiktoken`: jeden token to średnio **około 4 znaki** tekstu angielskiego[^tiktoken-readme]. Tu jest haczyk istotny dla nas: większość słowników jest zoptymalizowana głównie pod angielski, więc tekst polski - z całą jego fleksją i ogonkami - rozpada się na **więcej** tokenów niż angielski o tej samej treści. To realny powód, dla którego ta sama treść po polsku bywa droższa i wolniejsza w obróbce niż po angielsku. *(To obserwacja ogólna, nie zmierzona liczba z konkretnej pracy.)*

<details>
<summary>📐 Dla dociekliwych: BPE krok po kroku</summary>

Załóżmy maleńki korpus i chwilowo zapiszmy słowa jako ciągi znaków, gdzie `·` oznacza koniec słowa:

```
l o w ·        (×5)
l o w e r ·    (×2)
n e w e s t ·  (×6)
w i d e s t ·  (×3)
```

Liczymy częstości par sąsiednich. Para `e s` pojawia się 6 + 3 = 9 razy - najwięcej. Scalamy ją w `es`:

```
n e w es t ·   (×6)
w i d es t ·   (×3)
```

Teraz najczęstsza para to `es t` (9 razy) - scalamy w `est`. Potem `est ·`, i tak dalej. Każde scalenie to jeden wpis na liście merge'ów. Tokenizując nowe słowo, stosujemy te scalenia w tej samej kolejności, w jakiej powstały.

Sednem jest tu, że **częste** sekwencje (jak końcówka `-est`) awansują do roli pojedynczych tokenów, a rzadkie zostają rozłożone na drobniejsze, wciąż znane kawałki. Stąd kompromis: krótkie sekwencje dla częstych słów, zerowy OOV dla rzadkich.

</details>


## 🗺️ Embeddingi: od liczby do znaczenia

Mamy tokeny. Ale token to wciąż tylko etykieta - numer wiersza w słowniku. Sam numer nic nie znaczy: to, że „kot" ma indeks 4711, a „pies" 4712, nie mówi, że są blisko znaczeniowo. Potrzebujemy zamienić każdy token na **wektor** - ciąg liczb, który niesie informację o znaczeniu. To jest **embedding** (czyli „zanurzenie" słowa w przestrzeni liczb).

Przełomem był **word2vec** (Mikolov i in., 2013). Pomysł: ucz się wektorów słów tak, by przewidywać, jakie słowa pojawiają się **w sąsiedztwie**. Dwie odmiany[^mikolov-arch]: **CBOW** (z kontekstu zgadnij brakujące słowo środkowe) i **Skip-gram** (z jednego słowa zgadnij jego kontekst; lepszy dla słów rzadkich). Druga praca tego zespołu dorzuciła wydajną metodę uczenia i - co rozpaliło wyobraźnię - pokazała **analogie wektorowe**[^mikolov-neurips]. Okazało się, że w wyuczonej przestrzeni $\text{wektor}(\text{„król"}) - \text{wektor}(\text{„mężczyzna"}) + \text{wektor}(\text{„kobieta"})$ ma jako najbliższego sąsiada $\text{wektor}(\text{„królowa"})$. Kierunek „męskość → kobiecość" stał się niemal stałym przesunięciem w przestrzeni. To właśnie ta słynna geometria znaczeń, którą pokazuje strona interaktywna.

**Ale tu trzeba uczciwości** - i to jest moment, w którym popularne opowieści o LLM-ach często przesadzają. Klasyczny przykład bywa **nadinterpretowany**. Po pierwsze, standardowa metoda szukania odpowiedzi **z założenia wyklucza** z wyniku same słowa wejściowe („król", „mężczyzna", „kobieta") - gdyby ich nie wykluczyć, najbliższym sąsiadem bywałoby po prostu jedno z nich. Linzen (2016) pokazał, że proste punkty odniesienia bywają zaskakująco mocne, a metoda **myli „spójność przesunięcia" ze zwykłą strukturą sąsiedztwa**[^linzen]. Drozd, Gladkova i Matsuoka (2016) dorzucili, że liniowe przesunięcie jest wrażliwe na idiosynkrazje pojedynczych słów i działa nierówno dla różnych typów relacji[^drozd].

Wniosek, który warto zapamiętać: analogia „król - mężczyzna + kobieta ≈ królowa" to dobra **intuicja** o tym, że przestrzeń ma liniową strukturę - ale **nie dowód**, że embeddingi „rozumieją" relacje. Częściowo to artefakt metryki i starannego doboru przykładów. Strona interaktywna pokazuje ten przykład bezkrytycznie (bo jest świetną wizualizacją intuicji) - tu warto dodać ten przypis na marginesie.

<details>
<summary>📐 Dla dociekliwych: offset wektorowy i metryka cosinusowa</summary>

Analogię „a jest do b jak c jest do ?" rozwiązuje się metodą **offsetu wektorowego** (przesunięcia). Szukamy słowa $d$, którego wektor jest najbliższy złożeniu $\text{wektor}(b) - \text{wektor}(a) + \text{wektor}(c)$ w sensie podobieństwa **cosinusowego** (cos - cosinus kąta między wektorami):

$$ d^{*} = \arg\max_{w}\ \cos\!\big(\text{wektor}(w),\ \text{wektor}(b) - \text{wektor}(a) + \text{wektor}(c)\big) $$

Symbol $\arg\max$ (czytamy „argument maksimum") oznacza: „to słowo $w$, które daje największą wartość". Cosinus mierzy **kierunek**, ignorując długość wektorów - dwa wektory wskazujące w tę samą stronę mają cosinus bliski 1.

Kluczowy haczyk z głównego tekstu: $\arg\max$ tradycyjnie **pomija** w poszukiwaniu same słowa $a, b, c$. To pozornie techniczny szczegół, ale to właśnie on sprawia, że „królowa" wygrywa - bez tego wykluczenia zwycięzcą bywałoby jedno ze słów wejściowych. Dlatego krytycy mówią, że metoda mierzy raczej strukturę lokalnego sąsiedztwa niż prawdziwe „rozumienie" relacji.

</details>

Inną drogą poszedł **GloVe** (Pennington, Socher, Manning, 2014)[^glove]. Zamiast przesuwać się lokalnym oknem po tekście, GloVe uczy się od razu z **globalnej** statystyki: jak często słowo $i$ współwystępuje ze słowem $j$ w całym korpusie. Efekt jest podobny - przestrzeń o interpretowalnej geometrii - ale droga inna.

<details>
<summary>📐 Dla dociekliwych: cel optymalizacji GloVe</summary>

GloVe buduje macierz współwystąpień $X$, gdzie $X_{ij}$ to liczba przypadków, gdy słowo $j$ pojawiło się w kontekście słowa $i$. Następnie dopasowuje wektory tak, by ich iloczyn skalarny przybliżał logarytm tej liczby. Minimalizowany cel to ważona suma kwadratów błędów:

$$ J=\sum_{i,j} f(X_{ij})\big(w_i^{\top} \tilde{w}_j + b_i + \tilde{b}_j - \log X_{ij}\big)^2 $$

Symbol $\top$ (transpozycja) zamienia wektor kolumnowy w wierszowy, więc $w_i^{\top}\tilde{w}_j$ to po prostu iloczyn skalarny dwóch wektorów. Tylda nad $\tilde{w}_j$ oznacza **drugi**, osobny zestaw wektorów (dla słów występujących jako kontekst). Funkcja wagowa $f$ tłumi wpływ bardzo częstych par (jak „the"), żeby nie zdominowały uczenia. Suma $\sum$ (sigma) biegnie po wszystkich parach słów.

</details>

### Statyczne vs kontekstowe - i co jest *naprawdę* w LLM

word2vec i GloVe mają jedno fundamentalne ograniczenie: są **statyczne**. Jedno słowo = jeden wektor, niezależnie od zdania. Słowo „zamek" dostaje ten sam wektor w „zamek królewski" i w „zamek błyskawiczny" - choć to dwa różne znaczenia. Przełomem były reprezentacje **kontekstowe**: **ELMo**[^elmo] i potem **BERT**[^bert] generują wektor słowa **zależny od całego zdania**. „Zamek" dostaje inny wektor zależnie od sąsiadów. To właśnie ta zdolność jest jednym z fundamentów dzisiejszych LLM-ów.

I tu kluczowe sprostowanie, bo łatwo o nieporozumienie: **w LLM nie wczytuje się gotowych word2vec**. Warstwa embeddingów to po prostu **macierz parametrów**, trenowana razem z resztą modelu - dokładnie tak, jak wagi z poprzedniego wpisu. Każdy z $V$ tokenów słownika ma swój wiersz w macierzy $E$ o tylu kolumnach, ile wynosi wymiar modelu $d_{\text{model}}$ (czytamy „de model"). Te wektory startują losowo i są szlifowane gradientem podczas treningu - sieć sama wymyśla sobie geometrię znaczeń najwygodniejszą do przewidywania następnego tokenu.

Jak duże są te wektory w prawdziwych modelach? Bazowy Transformer z 2017 roku miał $d_{\text{model}} = 512$[^vaswani]. GPT-3 (175 mld parametrów) - już $d_{\text{model}} = 12288$[^gpt3]. LLaMA skalowała od 4096 (wariant 7B) do 8192 (wariant 65B)[^llama]. Każdy token jest więc reprezentowany przez tysiące liczb.

<details>
<summary>📐 Dla dociekliwych: macierz embeddingów i weight tying</summary>

Macierz embeddingów to $E \in \mathbb{R}^{V \times d_{\text{model}}}$ - $V$ wierszy (po jednym na token słownika) i $d_{\text{model}}$ kolumn. „Embedding tokenu" to dosłownie wyciągnięcie odpowiedniego wiersza. Przy słowniku $V \approx 50\,000$ i $d_{\text{model}} = 12288$ sama ta macierz ma setki milionów parametrów.

**Weight tying** (współdzielenie wag). Press i Wolf (2017) zauważyli, że macierz, której model używa na **wyjściu** (do zamiany wektorów z powrotem na prawdopodobieństwa tokenów), jest sama w sobie poprawnym embeddingiem słów[^press-wolf]. Zaproponowali więc **współdzielenie** jednej macierzy na wejściu ($E$) i na wyjściu (jako $E^{\top}$, czyli transpozycja). Oszczędza to setki milionów parametrów i zwykle poprawia jakość (niższą perplexity - „zdziwienie" z poprzedniego wpisu). Stąd powszechne w GPT-2.

</details>


## 🧭 Skąd model wie, w jakiej kolejności padły słowa

Jest jeszcze jeden problem, który elementarze zwykle przemilczają, a który jest absolutnie kluczowy. Mechanizm uwagi - serce Transformera, do którego dojdziemy w następnym wpisie - ma zaskakującą właściwość: jest **niewrażliwy na kolejność**. Sam z siebie nie odróżnia „pies pogryzł listonosza" od „listonosza pogryzł pies". Patrzy na zbiór tokenów, nie na ich szyk. A przecież kolejność słów niesie znaczenie.

Trzeba więc informację o **pozycji** wstrzyknąć osobno. Powstało kilka pomysłów, jak to zrobić.

**Kodowanie sinusoidalne (absolutne).** Oryginalny Transformer dodawał do każdego embeddingu stały wektor zbudowany z sinusów i cosinusów o różnych częstotliwościach[^vaswani] - coś jak unikalny „odcisk palca" pozycji. Każda pozycja w zdaniu dostaje swój charakterystyczny wzór, a model uczy się go odczytywać.

**Kodowanie uczone.** Prostsza alternatywa: osobna trenowana tabela wektorów, po jednym na każdą pozycję (tak robi BERT i GPT-2). Jakość wychodzi niemal identyczna jak przy sinusoidach[^vaswani], ale jest wada: model nie radzi sobie naturalnie z sekwencjami **dłuższymi** niż te, które widział w treningu - dla pozycji, której nigdy nie trenował, po prostu nie ma wektora.

**RoPE (Rotary Position Embedding).** Dzisiejszy faworyt (Su i in., 2021)[^rope], używany m.in. w LLaMA. Zamiast **dodawać** pozycję, RoPE **obraca** wektory zapytań i kluczy o kąt proporcjonalny do pozycji. Pomysł jest elegancki: po obrocie iloczyn skalarny dwóch wektorów zależy już tylko od **różnicy** ich pozycji, a nie od pozycji bezwzględnych. Model koduje więc pozycję **względną** („o ile dalej"), co lepiej oddaje, jak naprawdę działa język.

**ALiBi (Attention with Linear Biases).** Inny sprytny pomysł (Press, Smith, Lewis, 2021)[^alibi]: w ogóle nie ruszać embeddingów, tylko do wyników uwagi dodać **liniową karę** rosnącą z odległością między tokenami. Im dalej, tym mocniejsze tłumienie. Główna zaleta: model trenowany na krótkich sekwencjach potrafi **ekstrapolować** na znacznie dłuższe podczas użycia.

<details>
<summary>📐 Dla dociekliwych: wzór sinusoidalny i intuicja RoPE</summary>

Kodowanie sinusoidalne dla pozycji $pos$ i wymiaru $i$:

$$ PE_{(pos,\,2i)}=\sin\!\Big(\frac{pos}{10000^{2i/d_{\text{model}}}}\Big),\qquad PE_{(pos,\,2i+1)}=\cos\!\Big(\frac{pos}{10000^{2i/d_{\text{model}}}}\Big) $$

Parzyste wymiary dostają sinus, nieparzyste cosinus. Różne wymiary mają różne częstotliwości (przez dzielnik $10000^{2i/d_{\text{model}}}$) - niskie wymiary „kręcą się" szybko, wysokie wolno. To jak zegar z wieloma wskazówkami: kombinacja ich położeń jednoznacznie koduje pozycję, a sąsiednie pozycje mają podobne wzory.

RoPE robi to inaczej: dzieli wektor na pary współrzędnych i każdą parę **obraca** o kąt zależny od pozycji (jak wskazówkę na tarczy). Ponieważ iloczyn skalarny dwóch obróconych wektorów zależy tylko od różnicy kątów - czyli od **różnicy pozycji** $m-n$ - model dostaje informację o odległości względnej za darmo, bez dodawania niczego do embeddingu.

</details>


## 🌗 Geometria, której nikt nie zaprojektował

Zatrzymajmy się na moment nad tym, co właśnie opisaliśmy - bo w technicznym natłoku łatwo przeoczyć rzecz zdumiewającą. Zaczęliśmy od **dyskretnych symboli**: token to po prostu numer w słowniku, etykieta bez treści. A skończyliśmy na **ciągłej przestrzeni**, w której kierunki odpowiadają pojęciom, bliskość znaczy podobieństwo, a relacje (przynajmniej z grubsza) układają się w geometryczne przesunięcia. Nikt tej geometrii nie zaprojektował ręcznie. Wyłoniła się sama - jako produkt uboczny jedynego nacisku, który znamy z poprzedniego wpisu: „przewiduj następny token jak najlepiej".

To dlatego trzymałem w tym wpisie uczciwą krytykę słynnych analogii wektorowych - nie po to, by tej geometrii ująć niezwykłości, lecz by nie dopisywać jej *więcej*, niż widać w danych: „król - mężczyzna + kobieta ≈ królowa" sprawdza się rzadziej i mniej czysto, niż głosi legenda. A i tak zostaje rzecz zdumiewająca bez cienia przesady - że **dyskretne** symbole, etykiety bez treści, w ogóle dają się zanurzyć w przestrzeni, w której odległość zaczyna *przypominać* podobieństwo, a kierunek - relację.

I tu pojawia się hipoteza najśmielsza z całej serii, a zarazem najlepiej pasująca akurat do tego wpisu - bo dotyczy wprost **geometrii reprezentacji**. Głosi ona, że opisana wyżej przestrzeń nie jest przypadkowym artefaktem jednego modelu: że sieci o różnej budowie, trenowane na różnych danych, a może i różne **substraty** (w tym mózg), zbiegają ku **tej samej** strukturze. Nazwano ją Hipotezą Platońskiej Reprezentacji; rozwijam ją - z należną ostrożnością - w [osobnym eseju o rezonansie człowiek-LLM](/posty/rezonans-czlowiek-llm-kwantowe-lustro).


## 🎯 Co dalej

Zbudowaliśmy most między tekstem a liczbami. Tekst rozpada się na **tokeny** (subword - nie słowa, nie litery), a każdy token dostaje **wektor** z trenowanej macierzy embeddingów - wektor, który z czasem nabiera geometrii znaczeń (z należnym sceptycyzmem wobec słynnej analogii „król - mężczyzna + kobieta"). Dorzuciliśmy też kodowanie **pozycji**, bez którego model byłby ślepy na kolejność słów.

Mamy więc ciąg wektorów, każdy ze świadomością swojego miejsca w zdaniu. Ale wektory wciąż siedzą obok siebie osobno - nie „rozmawiają" ze sobą. A przecież znaczenie słowa zależy od sąsiadów: „korek" to co innego na drodze niż przy butelce szampana, a w zdaniu „nóż nie przeciął chleba, bo był tępy" słówko „był" wskazuje na nóż - lecz po zmianie „tępy" na „czerstwy" wskazuje już na chleb. W następnym przystanku serii dochodzimy do serca Transformera - **mechanizmu uwagi**: jak każdy token „rozgląda się" po pozostałych i bierze od nich to, czego potrzebuje, by doprecyzować swoje znaczenie.

Jeśli wolisz teraz **dotknąć** zamiast czytać dalej, [interaktywna strona „Anatomia LLM"](/llm/anatomia#tokeny) pozwala zobaczyć, jak tekst dzieli się na tokeny i jak wektory układają się w przestrzeni. A jeśli kusi cię to, co naprawdę *wyłania się* z opisanej tu geometrii - i dlaczego różne umysły zdają się zbiegać ku wspólnej strukturze znaczeń - [pisałem o tym osobno](/posty/rezonans-czlowiek-llm-kwantowe-lustro).


[^gage]: P. Gage (1994). *A New Algorithm for Data Compression*. The C Users Journal (BPE jako algorytm kompresji). <http://www.pennelynn.com/Documents/CUJ/HTML/94HTML/19940045.HTM>
[^sennrich]: R. Sennrich, B. Haddow, A. Birch (2016). *Neural Machine Translation of Rare Words with Subword Units*. ACL. arXiv:1508.07909. <https://arxiv.org/abs/1508.07909>
[^gpt2]: A. Radford et al. (2019). *Language Models are Unsupervised Multitask Learners* (GPT-2; byte-level BPE), OpenAI. <https://cdn.openai.com/better-language-models/language_models_are_unsupervised_multitask_learners.pdf>
[^schuster]: M. Schuster, K. Nakajima (2012). *Japanese and Korean Voice Search* (WordPiece). ICASSP. <https://doi.org/10.1109/ICASSP.2012.6289079>
[^gnmt]: Y. Wu et al. (2016). *Google's Neural Machine Translation System* (GNMT; ~32 000 word-pieces). arXiv:1609.08144. <https://arxiv.org/abs/1609.08144>
[^bert]: J. Devlin et al. (2019). *BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding*. NAACL. arXiv:1810.04805. <https://arxiv.org/abs/1810.04805>
[^kudo-unigram]: T. Kudo (2018). *Subword Regularization: Improving NMT Models with Multiple Subword Candidates* (model Unigram). ACL. arXiv:1804.10959. <https://arxiv.org/abs/1804.10959>
[^sentencepiece]: T. Kudo, J. Richardson (2018). *SentencePiece: A simple and language independent subword tokenizer*. EMNLP. arXiv:1808.06226. <https://arxiv.org/abs/1808.06226>
[^tiktoken-vocab]: OpenAI, `tiktoken` - rozmiary słowników z pliku `tiktoken_ext/openai_public.py`. <https://github.com/openai/tiktoken/blob/main/tiktoken_ext/openai_public.py>
[^tiktoken-readme]: OpenAI, `tiktoken` - README (reguła „each token corresponds to about 4 bytes"). <https://github.com/openai/tiktoken>
[^mikolov-arch]: T. Mikolov et al. (2013). *Efficient Estimation of Word Representations in Vector Space* (CBOW, Skip-gram). arXiv:1301.3781. <https://arxiv.org/abs/1301.3781>
[^mikolov-neurips]: T. Mikolov et al. (2013). *Distributed Representations of Words and Phrases and their Compositionality* (negative sampling, analogie wektorowe). NeurIPS. arXiv:1310.4546. <https://arxiv.org/abs/1310.4546>
[^linzen]: T. Linzen (2016). *Issues in evaluating semantic spaces using word analogies*. RepEval. arXiv:1606.07736. <https://arxiv.org/abs/1606.07736>
[^drozd]: A. Drozd, A. Gladkova, S. Matsuoka (2016). *Word Embeddings, Analogies, and Machine Learning: Beyond king - man + woman = queen*. COLING. <https://aclanthology.org/C16-1332/>
[^glove]: J. Pennington, R. Socher, C. D. Manning (2014). *GloVe: Global Vectors for Word Representation*. EMNLP. <https://aclanthology.org/D14-1162/>
[^elmo]: M. E. Peters et al. (2018). *Deep contextualized word representations* (ELMo). NAACL. arXiv:1802.05365. <https://arxiv.org/abs/1802.05365>
[^vaswani]: A. Vaswani et al. (2017). *Attention Is All You Need* ($d_{\text{model}}$, kodowanie sinusoidalne i uczone). arXiv:1706.03762. <https://arxiv.org/abs/1706.03762>
[^gpt3]: T. B. Brown et al. (2020). *Language Models are Few-Shot Learners* (GPT-3; $d_{\text{model}}=12288$, Tab. 2.1). arXiv:2005.14165. <https://arxiv.org/abs/2005.14165>
[^llama]: H. Touvron et al. (2023). *LLaMA: Open and Efficient Foundation Language Models* (wymiary 4096-8192; RoPE). arXiv:2302.13971. <https://arxiv.org/abs/2302.13971>
[^press-wolf]: O. Press, L. Wolf (2017). *Using the Output Embedding to Improve Language Models* (weight tying). EACL. arXiv:1608.05859. <https://arxiv.org/abs/1608.05859>
[^rope]: J. Su et al. (2021). *RoFormer: Enhanced Transformer with Rotary Position Embedding* (RoPE). arXiv:2104.09864. <https://arxiv.org/abs/2104.09864>
[^alibi]: O. Press, N. A. Smith, M. Lewis (2022). *Train Short, Test Long: Attention with Linear Biases Enables Input Length Extrapolation* (ALiBi). ICLR. arXiv:2108.12409. <https://arxiv.org/abs/2108.12409>