Přeskočit na obsah
coden

Tokenizace: jak se text rozseká na kousky pro model

Znaky proti slovům, algoritmus BPE napsaný od nuly a naučený na článcích tohoto webu, velikost slovníku, proč je čeština s cizím tokenizátorem dražší, bajty UTF-8 a podivné dělení čísel.

11 minut Matěj Žalmánek 2026-10-16

Série Základy AI Díl 71 z 83
  1. Mapa umělé inteligence: co je co a jak to do sebe zapadá
  2. Stručná historie umělé inteligence: od Turinga po jazykové modely
  3. Data, model, trénink, inference: základní pojmy na jednom příkladu
  4. Jak číst matematický zápis: symboly, indexy, sumy a kvantifikátory
  5. Množiny a relace: stavebnice, ze které se skládají definice v AI
  6. Funkce a zobrazení: proč je každý model v AI funkce
  7. Logika a důkazy: pravidla, podle kterých se v AI uvažuje
  8. Grafy a stromy: struktura, na které stojí hledání i neuronové sítě
  9. Lineární algebra pro strojové učení: vektory, matice a proč AI hlavně násobí
  10. Derivace, gradient a řetízkové pravidlo: jak model zjistí, kterým směrem se učit
  11. Gradientní sestup: jak se model učí
  12. Co je pravděpodobnost: od hodu kostkou ke Kolmogorovovým axiomům
  13. Podmíněná pravděpodobnost a Bayesova věta: jak změnit odhad, když se dozvíte něco nového
  14. Náhodná veličina a distribuční funkce: jedna funkce, která o rozdělení řekne všechno
  15. Funkce hustoty a pravděpodobnostní funkce: proč má spojitá veličina v bodě pravděpodobnost nula
  16. Střední hodnota, rozptyl a kovariance: kde rozdělení leží, jak je široké a co s čím souvisí
  17. Přehled pravděpodobnostních rozdělení: Bernoulli, binomické, Poisson, rovnoměrné, normální a exponenciální
  18. Zákon velkých čísel a centrální limitní věta: proč se průměry chovají tak předvídatelně
  19. Statistika a odhady parametrů: maximální věrohodnost, MAP a intervaly spolehlivosti
  20. Teorie informace: entropie, křížová entropie a KL divergence — odkud se berou ztrátové funkce
  21. Prohledávání stavového prostoru: BFS, DFS, UCS a A* s animacemi
  22. Hry a protivník: minimax, alfa-beta ořezávání a Monte Carlo tree search
  23. Splňování omezujících podmínek: backtracking, propagace omezení a AC-3 na sudoku a mapě krajů
  24. Logika a znalostní systémy: dopředné a zpětné řetězení, rezoluce a expertní systémy
  25. Plánování: STRIPS, svět kostek, heuristiky z relaxace a plánování v AI agentech
  26. Lokální hledání a simulované žíhání: obchodní cestující přes krajská města
  27. Genetické algoritmy: populace, křížení, mutace a výběr na batohu na výlet
  28. Evoluční strategie a genetické programování: od pravidla jedné pětiny po Keplerův zákon
  29. Optimalizace mravenčí kolonií: jak feromonová stopa najde krátkou cestu
  30. Optimalizace hejnem částic: setrvačnost, vlastní zkušenost a zkušenost hejna
  31. Neuroevoluce: evoluce vah i tvaru neuronových sítí a algoritmus NEAT
  32. Fuzzy množiny a funkce příslušnosti: jak zapsat „trochu teplo“
  33. Fuzzy logika a pravděpodobnost: proč „trochu teplo“ neznamená „pravděpodobně teplo“
  34. Fuzzy logika: t-normy, implikace a pravidla KDYŽ–PAK
  35. Fuzzy řízení: Mamdani a Sugeno od ventilátoru po kyvadlo na vozíku
  36. Fuzzy shlukování: algoritmus fuzzy c-means a body mezi shluky
  37. Neuro-fuzzy systémy (ANFIS): fuzzy pravidla, která se učí z dat
  38. Markovovy řetězce: přechodová matice, stacionární rozdělení a PageRank
  39. Skryté Markovovy modely: Viterbiho algoritmus a nepoctivé kasino
  40. Bayesovské sítě: proč je tráva mokrá a co z toho plyne pro postřikovač
  41. Kalmanův filtr: jak z nepřesných měření odhadnout, kde auto je a jak rychle jede
  42. Druhy strojového učení: s učitelem, bez učitele, s částečným učitelem a další
  43. Přeučení a regularizace: proč model, který zná data nazpaměť, selže
  44. Vyhodnocení modelu: křížová validace, F1 a křivka ROC
  45. Shlukování a snížení dimenze: k-means, PCA a t-SNE
  46. Klasifikace a regrese: dvě úlohy učení s učitelem
  47. Lineární regrese: nejmenší čtverce geometricky i maticově
  48. Polynomiální a nelineární regrese: jak přímku ohnout
  49. Logistická regrese: sigmoida, šance a křížová entropie
  50. Vícetřídní klasifikace a softmax: od dvou tříd k mnoha
  51. Naivní Bayesův klasifikátor: spamový filtr, který funguje lépe, než by měl
  52. Ztrátové funkce: co přesně model minimalizuje
  53. Rozhodovací stromy a k nejbližších sousedů: modely bez vzorců
  54. Ansámbly: náhodný les a gradient boosting
  55. SVM a jádrový trik: nejširší hranice a jak ji ohnout
  56. Signál a vzorkování: proč platí Nyquistův teorém
  57. Fourierova transformace: rozklad signálu na frekvence
  58. Filtry a konvoluce: vyhlazení, hrany a odstranění šumu
  59. Zvuk a řeč: spektrogram, melová škála a MFCC
  60. Obraz jako signál: pixely, barvy, konvoluce a hrany
  61. Perceptron a umělý neuron: nejjednodušší neuronová síť a co neumí
  62. Neuronová síť od nuly: zpětné šíření chyby krok za krokem
  63. Aktivace, inicializace a normalizace: drobnosti, na kterých hluboká síť stojí
  64. Konvoluční sítě: jak síť poznává obrázky
  65. Rekurentní sítě: paměť pro posloupnosti a mizející gradient
  66. LSTM a GRU: brány, které rozhodují, co si síť zapamatuje
  67. Autoenkodéry: síť, která se učí data stlačit a zase rozbalit
  68. Embeddingy a word2vec: jak se slovo stane vektorem
  69. Mechanismus pozornosti: jak se model naučí, kam se dívat
  70. Transformery a velké jazykové modely: architektura krok za krokem
  71. Tokenizace: jak se text rozseká na kousky pro model
  72. Předtrénování a škálování: proč větší model a víc dat funguje
  73. Doladění a RLHF: jak se z doplňovače textu stane asistent
  74. Prompty, kontext a RAG: jak modelu dát správné informace
  75. Variační autoenkodéry (VAE): nové obrázky ze spojitého latentního prostoru
  76. Generativní adversariální sítě (GAN): padělatel proti detektivovi
  77. Difúzní modely: jak se z čistého šumu stane obrázek
  78. Markovovy rozhodovací procesy: stavy, akce, odměny a Bellmanovy rovnice
  79. Q-learning a DQN: učení hodnoty akcí od tabulky po neuronovou síť
  80. Policy gradient a PPO: učení přímo strategie
  81. Jak funguje AI agent: jazykový model ve smyčce s nástroji
  82. Programování s AI agenty: zadání, testy a kontrola
  83. Vyhodnocení a bezpečnost AI systémů: jak měřit a jak hlídat

Celá osnova série 83 z 83 témat hotovo

Co si odnesete
  • Proč modely nečtou ani znaky, ani celá slova.
  • Jak funguje BPE a co se na češtině naučí.
  • Proč stejný text stojí v různých jazycích různě tokenů a proč modely klopýtají v počítání.

Co se hodí znát předem: Transformery a velké jazykové modely: architektura krok za krokem, Embeddingy a word2vec: jak se slovo stane vektorem

Jazykový model nečte písmena ani slova. Čte tokeny — kousky textu, na které ho rozseká tokenizátor, ještě než model vůbec začne počítat. Z tohohle nenápadného kroku plyne překvapivě mnoho: kolik stojí dotaz (platí se za tokeny), kolik textu se vejde do kontextu, proč modely občas neumějí spočítat písmena ve slově nebo sečíst dvě dlouhá čísla — a proč je čeština u mnoha modelů dražší než angličtina. V tomhle dílu naprogramujeme nejpoužívanější metodu, BPE, a naučíme ji na textu článků z tohoto webu.

Navazuje na díly Transformery a velké jazykové modely a Embeddingy a word2vec.

1. Znaky, nebo slova?

Definice — token a tokenizátor

Nechť Σ je konečná neprázdná abeceda (množina znaků, které se v textu mohou objevit). Slovník je konečná množina V neprázdných řetězců znaků z Σ; jejím prvkům říkáme tokeny a jsou očíslované čísly 0, 1, …, |V| − 1. Tokenizátor je postup, který

  1. každý text s (konečný řetězec znaků z Σ) rozloží na posloupnost tokenů v1, …, vn ∈ V,
  2. každý token nahradí jeho číslem (indexem do tabulky embeddingů, viz díl Embeddingy a word2vec),
  3. je obratitelný: zřetězení v1v2…vn je přesně původní text s.

Model tedy místo textu dostane posloupnost čísel tokenů. Přesný zápis je v definici „tokenizátor formálně“ níže.

Laicky řečeno

Dvě krajní možnosti. Po znacích: slovník je malý (v našich českých článcích 185 různých znaků), ale texty jsou dlouhé — každé písmeno je jeden krok modelu. Po slovech: texty jsou krátké, ale slovník obrovský, a hlavně neúplný. Čeština má ke každému slovu desítky tvarů: model, modelu, modelem, modely, modelům…

Definice — tokenizátor formálně

Nechť Σ je konečná neprázdná abeceda a Σ* množina všech konečných řetězců nad Σ (včetně prázdného). Nechť V ⊆ Σ* ∖ {prázdný řetězec} je konečný slovník a V* množina všech konečných posloupností tokenů z V. Pro s ∈ Σ* značí |s| jeho délku ve znacích, pro posloupnost tokenů |·| jejich počet. Tokenizátor je dvojice zobrazení

enc : Σ* → V*,   dec : V* → Σ*,   dec(v1, v2, …, vn) = v1v2…vn (zřetězení),

pro která platí

∀ s ∈ Σ* : dec(enc(s)) = s.

Číslování tokenů je bijekce V → {0, 1, …, |V| − 1}; model vidí jen posloupnost čísel tokenů délky |enc(s)|. Aby šel zakódovat každý text, musí slovník obsahovat aspoň všechny jednotlivé znaky (Σ ⊆ V) — slovní tokenizátor tuhle podmínku nesplňuje, a proto potřebuje značku „neznámé slovo“, po které už text zpátky složit nejde.

Data: 21 starších článků tohoto webu česky a v anglickém překladu. Na 14 článcích se tokenizátory učí, na zbylých 7 se zkoušejí. Slovník slov z 14 článků má 4 365 položek, a přesto v nových článcích 15 % slov chybí — nový text je plný tvarů, které model nikdy neviděl, a slovní tokenizátor by je musel nahradit značkou „neznámé slovo“.

Definice — podíl neznámých slov

Nechť S je konečná množina různých slov, která se vyskytla v trénovacích textech (slovník slov), a w1, …, wn, n ≥ 1, posloupnost všech výskytů slov v testovacích textech v pořadí, jak jdou za sebou (u nás vše převedené na malá písmena; v testu se počítají jen slova z písmen, bez čísel a interpunkce). Podíl neznámých slov (out-of-vocabulary rate) je číslo

OOV = |{ i ∈ {1, …, n} : wi ∉ S }|/n ∈ [0, 1],

tedy podíl výskytů, ne různých slov: slovo, které chybí a v testu stojí pětkrát, se počítá pětkrát. U nás S má 4 365 slov a OOV = 0,153 ≈ 15 %: ze sta slov nového textu by slovní tokenizátor asi 15 neznal.

2. BPE: slučuj, co chodí spolu

Definice — byte-pair encoding (BPE)

Byte-pair encoding (BPE) je algoritmus učení tokenizátoru.

Vstup: trénovací text rozdělený na slova w s četnostmi n(w) ∈ ℕ (kolikrát slovo v textu stojí), abeceda Σ všech znaků těchto slov a největší počet sloučení K ∈ ℕ.
Výstup: uspořádaný seznam sloučení (a1, b1), …, (ak, bk), k ≤ K, a slovník V = Σ ∪ {a1b1, …, akbk}, takže |V| ≤ |Σ| + k.

Kroky:

  1. Každé slovo w rozděl na jednotlivé znaky (každý znak je jeden symbol); polož j = 0.
  2. Pro každou dvojici symbolů (a, b) spočti její četnost ∑w n(w) · cab(w), kde cab(w) je počet míst, kde v aktuálním dělení slova w stojí symbol a hned před symbolem b.
  3. Zastavení: je-li j = K, nebo má-li každá dvojice četnost nejvýš 1, skonči.
  4. Vyber dvojici (aj+1, bj+1) s největší četností (při shodě rozhodne pevné pořadí, u nás abecední) a připiš ji na konec seznamu sloučení.
  5. V dělení každého slova nahraď zleva doprava každý výskyt „aj+1 hned před bj+1“ jediným novým symbolem aj+1bj+1 (zřetězení); zvyš j o 1 a pokračuj krokem 2.

Tokenizace nového textu: každé slovo se rozdělí na znaky a dokud v jeho dělení stojí vedle sebe dvojice ze seznamu sloučení, provede se sloučení té z nich, která je v seznamu nejdřív. Původně kompresní algoritmus (Philip Gage, 1994), na tokenizaci ho použili Rico Sennrich a kol. v roce 2016.

Laicky řečeno

Kdo si píše poznámky, začne zkracovat, co se opakuje. Nejdřív dvojice písmen, pak slabiky, pak celá častá slova. Vzácná slova zůstanou rozložená na kousky, které se ale vždycky dají složit — žádné „neznámé slovo“ nikdy nenastane, nejhůř se slovo napíše po písmenech.

(a*, b*) = argmax(a, b) ∑w n(w) · cab(w)

(a, b)
kandidát na sloučení: dva symboly, které v aktuálním dělení nějakého slova stojí hned za sebou. Jen sousedé — token má být souvislý kus textu, aby ho šlo zřetězením složit zpátky
∑w
součet přes různá slova trénovacího textu. Text se předem rozdělí na slova (s mezerou ␣ na začátku), takže dvojice nikdy nepřeskočí přes hranici slova a tokeny nespojí konec jednoho slova se začátkem dalšího
n(w)
kolikrát slovo w stojí v textu. Každé různé slovo se rozdělí jen jednou a jeho dvojice se vynásobí četností — časté slovo jako „␣je“ se nemusí procházet znovu při každém výskytu, stačí slovník četností
cab(w)
kolikrát dvojice ab stojí v aktuálním dělení slova w. Dělení se po každém sloučení mění, proto se dvojice musí po každém kroku spočítat znovu
argmax
vezme se nejčastější dvojice: každý její výskyt se po sloučení zapíše o symbol kratší, takže nejčastější dvojice zkrátí trénovací text nejvíc (až na překryvy jako „aaa“). BPE je tedy hladová komprese — v každém kroku nejlepší jednotlivý krok, ne nejlepší slovník celkově. Při shodě četností rozhodne pevné pořadí (u nás abecední), aby byl výsledek pokaždé stejný
Krok učení BPE: tahle dvojice se stane novým tokenem ab a ve všech slovech se nahradí.
Příklad — BPE ručně na pěti slovech

Text o 16 slovech, zapsaný jako slovník četností: „model“ 5×, „modelu“ 3×, „modely“ 2×, „modelem“ 2×, „den“ 4×. Symboly v dělení odděluje tečka.

kroksloučí sečetnostdělení slov po krokusymbolů v textu
0——m·o·d·e·l, m·o·d·e·l·u, m·o·d·e·l·y, m·o·d·e·l·e·m, d·e·n81
1d + e → de16m·o·de·l, m·o·de·l·u, m·o·de·l·y, m·o·de·l·e·m, de·n65
2de + l → del12m·o·del, m·o·del·u, m·o·del·y, m·o·del·e·m, de·n53
3m + o → mo12mo·del, mo·del·u, mo·del·y, mo·del·e·m, de·n41
4mo + del → model12model, model·u, model·y, model·e·m, de·n29
5de + n → den4model, model·u, model·y, model·e·m, den25
6model + u → modelu3model, modelu, model·y, model·e·m, den22

krok 1: dvojice d + e je ve všech slovech, cde(w) = 1 pro každé: 5 · 1 + 3 · 1 + 2 · 1 + 2 · 1 + 4 · 1 = 16 (barvy podle vzorce výše); ostatní dvojice (m + o, o + d, e + l …) chybí ve slově „den“, mají nejvýš 12

krok 2: de + l, m + o i o + de mají shodně 12 — vyhraje abecedně první, de + l

krok 5: de + n (4) předběhne model + u (3), model + y a model + e (po 2)

délka textu: 81 − (16 + 12 + 12 + 12 + 4 + 3) = 81 − 59 = 22 symbolů — každé sloučení ubere přesně tolik, kolik je jeho četnost

Po šesti krocích je „model“ jeden token, „modelu“ taky, ale „modelem“ zůstalo „model·e·m“ — koncovka -em byla moc vzácná. Přesně tohle se děje i se 4 000 sloučeními, jen ve větším.

def nauc_bpe(text, k):
    cetnost = Counter(rozdel_na_slova(text))      # slovo → kolikrát je v textu
    deleni = {w: list(w) for w in cetnost}         # začínáme po znacích
    slouceni = []
    for _ in range(k):
        pary = Counter()
        for w, n in cetnost.items():
            for a, b in sousedni_dvojice(deleni[w]):
                pary[a, b] += n                      # ∑ n(w) · c_ab(w)
        if not pary or max(pary.values()) < 2: break   # nic se už neopakuje
        a, b = nejcastejsi(pary)                     # při shodě abecedně první
        slouceni.append((a, b))
        for w in deleni:                             # nahraď všechny výskyty
            deleni[w] = sluc(deleni[w], a, b)
    return slouceni

def tokenizuj(text, slouceni):
    poradi = {par: i for i, par in enumerate(slouceni)}
    tokeny = []
    for w in rozdel_na_slova(text):
        s = list(w)
        while True:                                  # vždy nejdřív to sloučení,
            kandidati = [p for p in sousedni_dvojice(s) if p in poradi]
            if not kandidati: break                  # které vzniklo při učení nejdřív
            s = sluc(s, *min(kandidati, key=poradi.get))
        tokeny += s
    return tokeny

Prvních dvacet sloučení na českých článcích (␣ označuje mezeru před slovem): ␣p ␣s ␣j ␣n ␣v en ro ␣k st od ␣a ␣je ␣d no te ␣m ra ní ch in. Na anglických: ␣t ␣a he ␣i ␣the on ␣s re in ti er ␣w ␣o ␣p es ␣c nd ␣f at ␣is. Tokenizátor objeví jazyk sám: v češtině předložky a předpony (s, v, k, na, je), koncovku „ní“, v angličtině „the“ a „is“.

0 sloučení (po znacích) · 60 tokenů Nejpravděpodobnější␣vysvětlení␣je,␣že␣model␣nepřeučený␣není.
250 sloučení · 29 tokenů Nejpravděpodobnější␣vysvětlení␣je,␣že␣model␣nepřeučený␣není.
1 000 sloučení · 23 tokenů Nejpravděpodobnější␣vysvětlení␣je,␣že␣model␣nepřeučený␣není.
4 000 sloučení · 16 tokenů Nejpravděpodobnější␣vysvětlení␣je,␣že␣model␣nepřeučený␣není.
4 000 sloučení naučených na angličtině · 45 tokenů Nejpravděpodobnější␣vysvětlení␣je,␣že␣model␣nepřeučený␣není.
Jedna věta při různém počtu sloučení BPE

Se 4 000 sloučeními je „pravděpodobnější“ jeden token — v článcích o pravděpodobnosti je to časté slovo. Předpona „Nej“ s velkým písmenem ale v datech skoro nebyla, a tak zůstala rozložená na písmena. Tokenizátor nerozumí slovům, jen četnostem. Poslední řádek je stejná věta v tokenizátoru naučeném na angličtině: písmena s háčky a čárkami zůstávají samostatně a tokenů je skoro třikrát víc.

3. Kolik tokenů a jak velký slovník

020 00040 00060 000 01 0002 0003 0004 000 sloučení BPE (počet) délka textu (počet tokenů)
Počet tokenů sedmi testovacích článků podle počtu sloučení čeština (český tokenizátor) angličtina (anglický tokenizátor)

Po znacích má sedm testovacích článků v češtině 51 682 tokenů. Prvních 250 sloučení počet skoro způlí (28 416), dalších 3 750 už ubere jen čím dál méně, na 16 997. To je 3,04 znaku na token. Větší slovník znamená kratší texty (levnější výpočet, delší dosah kontextu), ale větší tabulku embeddingů a vzácnější tokeny, které se model hůř naučí. Velké jazykové modely mají slovníky o desítkách tisíc až kolem 200 000 tokenech.

|V| = |Σ| + k,   ρ = |s|/|enck(s)|

|Σ|
počet znaků, se kterými BPE začíná (u nás 185, mezera v podobě ␣). Zůstávají ve slovníku i po všech sloučeních — jsou pojistkou, že jde zakódovat každý text
k
počet sloučení; každé přidá jeden token (obecně nejvýš jeden — dvě sloučení jako „a + bc“ a „ab + c“ mohou dát týž řetězec; u nás je všech 4 000 různých) a staré tokeny nemaže (i „mo“ zůstane, i když se z něj stalo „model“). U nás 185 + 4 000 = 4 185 tokenů. Velikost slovníku si tedy volíme předem a k je jediný „knoflík“ BPE
|s|
délka textu ve znacích — nezávisí na tokenizátoru, proto je to dobrý jmenovatel pro srovnání různých tokenizátorů na stejném textu
|enck(s)|
počet tokenů po k sloučeních — tolik kroků musí model udělat a tolik místa text zabere v kontextu
ρ
kompresní poměr, znaků na token: čím víc, tím je text pro model „kratší“. Pro k = 0 je ρ = 1
Testovací české články (k = 4 000): ρ = 51 682/16 997 = 3,04 znaku na token; po 250 sloučeních 51 682/28 416 = 1,82.
Příklad — kolik stojí velký slovník

Každý token má v modelu vlastní řádek tabulky embeddingů o šířce d, takže tabulka má |V| · d parametrů. Llama 3 (Meta, 2024) má slovník o 128 256 tokenech a šířku d = 4 096:

128 256 · 4 096 = 525 336 576 parametrů, u modelu s 8 miliardami parametrů 525 336 576/8 · 109 ≈ 6,6 %

A stejný tvar má i výstupní vrstva, která z posledního vektoru počítá pravděpodobnosti všech tokenů. Zdvojnásobit slovník tedy znamená o stovky milionů parametrů víc — a každý vzácný token v nich má řádek, který se učí jen z mála výskytů.

4. Daň za jazyk

Teď to nejzajímavější. Testovací články máme v obou jazycích — stejný obsah. Kolik tokenů zabere s různými tokenizátory (všechny po 4 000 sloučeních)?

Tokenizátor naučený načeská verzeanglická verze
české texty16 99731 293
anglické texty31 07217 212
obojí dohromady18 03018 220

Se „svým“ tokenizátorem vyjdou oba jazyky skoro stejně draze (16 997 a 17 212 tokenů). Česká verze tokenizovaná anglickým tokenizátorem ale zabere 1,83krát víc tokenů — anglické sloučení „ti“ nebo „er“ češtině moc nepomůže, a slova s háčky se rozpadnou na písmena. Totéž obráceně. Společný tokenizátor je kompromis: každý jazyk stojí asi o 6 % víc než se svým.

daň = |encen(scs)|/|enccs(scs)|

scs
tentýž český text v čitateli i jmenovateli — proto se v podílu obsah textu zkrátí a zbude jen vliv tokenizátoru
|encen(scs)|
tokeny s tokenizátorem naučeným na angličtině (modře v grafu výše) — tak dopadne čeština u modelu, jehož slovník vznikl hlavně z anglických textů
|enccs(scs)|
tokeny s tokenizátorem naučeným na češtině (zeleně) — nejlepší, čeho jde se stejně velkým slovníkem dosáhnout, proto je ve jmenovateli jako měřítko
U nás daň = 31 072/16 997 = 1,83. Za stejnou cenu za token tedy český dotaz stojí 1,83krát víc, a do kontextu o 1 000 tokenech se vejde jen asi 1 660 znaků české verze místo asi 3 040 (1 000 · ρ, kde ρ = 1,66, resp. 3,04 znaku na token).
Laicky řečeno

Skutečné tokenizátory se učí na textu, kde výrazně převažuje angličtina. Čeština tak bývá dražší: stejná otázka stojí víc tokenů, je pomalejší, dražší a do kontextu se jí vejde méně. Aleksandar Petrov a kolegové v roce 2023 změřili, že u některých jazyků je rozdíl až patnáctinásobný. Novější modely mají slovníky větší a vícejazyčnější, a rozdíl se proto zmenšuje.

5. Bajty, háčky a čísla

Definice — bajtové BPE

Nechť 𝔹 = {0, 1, …, 255} je množina všech 256 hodnot bajtu a pro text s označme utf8(s) ∈ 𝔹* posloupnost bajtů jeho zápisu v kódování UTF-8 (definice níže). Bajtové BPE (GPT-2, 2019) je BPE (definice výše), ve kterém roli abecedy hraje 𝔹 místo znaků:

  1. učí se na posloupnostech utf8(w) slov w trénovacího textu, výchozí slovník je 𝔹 (|𝔹| = 256) a sloučení spojují sousední posloupnosti bajtů;
  2. text s se tokenizuje tak, že se BPE použije na utf8(s), a dekóduje se zřetězením bajtů tokenů a jejich převodem zpět z UTF-8.

Protože 𝔹 je ve slovníku vždy celé, jde zakódovat libovolný text, včetně emoji a cizích písem — v nejhorším případě bajt po bajtu.

Laicky řečeno

V UTF-8 má písmeno bez diakritiky jeden bajt, „ž“ nebo „ř“ dva. Česká testovací verze má 51 682 znaků, ale 58 260 bajtů (o 13 % víc), anglická jen o 3 % víc. Když tokenizátor češtinu moc neviděl, rozpadne se slovo s háčkem i na půlky písmen.

Definice — kódování UTF-8

Každý znak c má v Unicode číslo, kódový bod cp(c) ∈ {0, 1, …, 10FFFF16} (píše se šestnáctkově s předponou U+, „ž“ je U+017E = 382). Mimo zůstávají jen kódové body D80016 až DFFF16, které znakům nepatří. UTF-8 je kódování, které znak c zapíše posloupností b(c) bajtů, kde

  1. b(c) = 1, právě když cp(c) ≤ 7F16;
  2. b(c) = 2, právě když 8016 ≤ cp(c) ≤ 7FF16;
  3. b(c) = 3, právě když 80016 ≤ cp(c) ≤ FFFF16;
  4. b(c) = 4, právě když 1000016 ≤ cp(c) ≤ 10FFFF16;

a bity bajtů jsou určené tabulkou:

kódové bodybajtůbitypříklad
U+0000 – U+007F10xxxxxxxe, 7, mezera (ASCII)
U+0080 – U+07FF2110xxxxx 10xxxxxxž, ř, á, ü, cyrilice
U+0800 – U+FFFF31110xxxx 10xxxxxx 10xxxxxx„ (U+201E), €, čínské znaky
U+10000 – U+10FFFF411110xxx 10xxxxxx 10xxxxxx 10xxxxxxemoji

Kódový bod zapsaný dvojkově se zleva doplní nulami na počet míst x v daném řádku (7, 11, 16, nebo 21) a jeho bity se zleva doprava rozepíšou do míst x. Text s = c1c2…cm se zakóduje zřetězením kódů jeho znaků, takže jeho délka v bajtech je

B(s) = ∑i=1m b(ci),   b(ci) ∈ {1, 2, 3, 4}.

ž = U+017E → 11000101 10111110 = C5 BE

00101 111110
samotné číslo znaku: 0x17E = 382 = 1 0111 1110 dvojkově, doplněné na 11 bitů, které se do dvou bajtů vejdou (5 + 6). Proto dva bajty stačí až po U+07FF = 211 − 1
110
úvodní bajt: počet jedniček na začátku říká, z kolika bajtů se znak skládá (zde dvou). Dekodér tak ví, kolik bajtů má přečíst, bez jakékoli tabulky
10
pokračovací bajt: začíná vždy 10, a to žádný úvodní bajt ani ASCII znak nedělá. Kdo začne číst uprostřed, pozná, že je uprostřed znaku. Pro tokenizátor to znamená, že token z jediného bajtu C5 je „půlka ž“ — sama o sobě žádný znak
Česká testovací verze: 58 260 − 51 682 = 6 578 bajtů navíc, každý od znaku mimo ASCII (dvoubajtový přidá jeden, tříbajtový, třeba dolní uvozovka U+201E, dva).
český tokenizátor, čísla · 20 tokenů Rok␣2026␣má␣365␣dní␣a␣123456␣sekund.
anglický tokenizátor, anglická věta · 16 tokenů The␣most␣probable␣explanation␣is␣that␣the␣model␣is␣not␣overfitted.
český tokenizátor, anglická věta · 33 tokenů The␣most␣probable␣explanation␣is␣that␣the␣model␣is␣not␣overfitted.
Čísla a angličtina v našem tokenizátoru

Čísla se dělí podle toho, které kousky byly v textu časté: „2026“ na „20|2|6“, „123456“ na „12|3|4|5|6“. Model pak nevidí číslice na stejných místech, a to je jeden z důvodů, proč jazykové modely dlouho chybovaly v počítání. A protože „jahoda“ je pro model třeba jeden nebo dva tokeny, ne šest písmen, je pro něj spočítat písmena ve slově překvapivě těžké. Novější tokenizátory proto čísla rozdělují vždy po jedné až třech číslicích.

# předzpracování čísel, ještě než na text pustíme BPE
# náš tokenizátor: číslo = jedno „slovo“ [\p{N}]+, BPE z něj sloučí, co bylo časté
"2026"   → "20" | "2" | "6"           # podle četností v trénovacích textech
# GPT-3.5 a GPT-4 (cl100k_base, OpenAI): regulární výraz \p{N}{1,3}, skupiny po třech zleva
"2026"   → "202" | "6"
"123456" → "123" | "456"
# LLaMA (Meta 2023): každá číslice zvlášť, model vidí vždy stejné jednotky
"2026"   → "2" | "0" | "2" | "6"

6. Shrnutí

  • Model čte tokeny; tokenizátor převádí text na čísla a musí jít přesně obrátit.
  • Po slovech chybí v nových článcích 15 % slov; po znacích jsou texty dlouhé. BPE je kompromis, který žádné „neznámé slovo“ nezná.
  • BPE opakovaně slučuje nejčastější dvojici; 4 000 sloučení zkrátilo české texty z 51 682 na 16 997 tokenů.
  • Stejný obsah: se svým tokenizátorem čeština 16 997 tokenů, angličtina 17 212; český text s anglickým tokenizátorem 1,83krát víc.
  • Dělení čísel a slov na tokeny vysvětluje, proč modely klopýtají v počítání a hláskování.

Chcete si to osahat? Nechte AI agenta načíst tokenizátor nějakého otevřeného modelu (třeba přes knihovnu tiktoken) a porovnat, kolik tokenů stojí tenhle odstavec česky a jeho anglický překlad.

Máte na to jiný názor? Napište na support@coden-app.com.

Agent na vašem počítači, ovládaný z telefonu