Obsah
1. Tokenizace textu: základní operace při zpracování přirozeného jazyka
5. Instalace knihovny tiktoken
6. Ukázka tokenizace s využitím kódování cl100k_base
8. Složená slova a kódování cl100k_base
9. Složená slova zakódovaná jediným tokenem
11. Kódování dalších speciálních znaků
12. Zpětný převod tokenů na text
13. Od cl100k_base k dalším enkodérům a modulům
14. Porovnání kódování cl100k_base s dalšími kodéry a moduly
16. Rychlost zpětného převodu sekvence tokenů na text
19. Repositář s demonstračními příklady
1. Tokenizace textu: základní operace při zpracování přirozeného jazyka
V současnosti se obor IT poměrně důrazně zaměřuje na problematiku zpracování přirozeného jazyka (Natural language processing, NLP), která byla zpopularizována i mezi širokou veřejností mj. i díky úspěšně nasazeným rozsáhlým jazykovým modelům (Large Language Model, LLM), mezi něž patří například GPT (OpenAI), PaLM, Gemini, LLaMA apod. Při zpracování přirozeného jazyka se používá několik standardních postupů a algoritmů, s nimiž se postupně seznámíme v navazující sérii článků. Na samotném začátku zpracování textu, ale i při ukládání „znalosti“ informací (jazykový korpus), se využívá takzvaná tokenizace. V dnešním článku se seznámíme se základními principy, na nichž je tato operace postavena a ukážeme si ji na příkladu knihovny tiktoken (i když dnes existuje celá řada podobně koncipovaných knihoven, ostatně o některých dalších knihovnách, které jsou používány, se dnes ještě zmíníme).
2. Převod slov na tokeny
Tokenizace má sice v informatice různý význam, ale v kontextu jazykových modelů se tímto slovem označuje převod textu (tedy sekvence znaků) na tokeny (tedy na sekvenci celočíselných hodnot), přičemž výsledek by měl být jednoznačný. Typicky také předpokládáme existenci opačné operace, tj. možnost převodu sekvence tokenů na běžný text. Existuje větší množství algoritmů pro konstrukci tokenů, ovšem mnoho algoritmů převádí jednodušší slova nebo velmi často používaná slova (popř. slova s mezerou) na jediný token. Tento postup uvidíme v praktických příkladech, které využívají enkodér nazvaný cl100k_base. Tento název je odvozen od faktu, že obsahuje slovník s přibližně 100000 tokeny reprezentujícími jednotlivá slova, slova s oddělovači, slovní předpony, přípony, speciální znaky atd.
Tokenizaci si můžete vyzkoušet na stránce https://tiktokenizer.vercel.app/. Pro jednoduchá slova a věty dostaneme:
Obrázek 1: Tokenizace jednoduché anglické věty.
3. Tokenizace složených slov
Některá delší slova, která jsou složena z prefixu, základu, suffixu atd., jsou ovšem (pokud se nejedná o velmi často používaná slova), převedena na několik tokenů, kde typicky jeden z tokenů představuje základ slova a další pak prefix či suffix. Ovšem u složitějších slov, například chemických názvů, názvů léků atd., se slova skládají z menších celků (2–4 znaky). Opět si to můžeme ukázat na příkladu:
Obrázek 2: Tokenizace věty se složenými slovy.
4. Knihovna tiktoken
Pro tokenizaci a popř. i pro zpětný převod tokenů na text lze využít větší množství knihoven. Tyto knihovny se od sebe odlišují jak svou implementací, tak i tím, zda jsou (či naopak nejsou) součástí větších programových celků pro realizaci systémů pro zpracování přirozeného jazyka (dnes typicky založených na LLM). Dnes se budeme primárně zabývat knihovnou nazvanou tiktoken, jejíž výhodou je fakt, že je velmi snadno použitelná a lze ji nainstalovat a používat samostatně, bez nutnosti instalace frameworků pro LLM. Navíc tato knihovna podporuje několik enkodérů textu na tokeny i několik specifických modelů (například GPT-4 atd.), což je problematika, k níž se ještě několikrát vrátíme.
5. Instalace knihovny tiktoken
Vzhledem k tomu, že knihovna tiktoken je dostupná na PyPI, je její instalace snadná. Buď je možné provést instalaci pro všechny uživatele:
$ pip3 install tiktoken
Nebo pouze pro aktivního uživatele:
$ pip3 install --user tiktoken
V průběhu instalace se stáhnou i další tranzitivní závislosti, ale není jich mnoho:
Collecting tiktoken Downloading tiktoken-0.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (6.6 kB) Collecting regex>=2022.1.18 (from tiktoken) Downloading regex-2023.12.25-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (40 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 40.9/40.9 kB 839.4 kB/s eta 0:00:00 Collecting requests>=2.26.0 (from tiktoken) Downloading requests-2.31.0-py3-none-any.whl.metadata (4.6 kB) Collecting charset-normalizer<4,>=2 (from requests>=2.26.0->tiktoken) Downloading charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (33 kB) Requirement already satisfied: idna<4,>=2.5 in /usr/lib/python3/dist-packages (from requests>=2.26.0->tiktoken) (2.8) Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/lib/python3/dist-packages (from requests>=2.26.0->tiktoken) (1.25.8) Requirement already satisfied: certifi>=2017.4.17 in /usr/lib/python3/dist-packages (from requests>=2.26.0->tiktoken) (2019.11.28) Downloading tiktoken-0.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.8 MB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.8/1.8 MB 4.9 MB/s eta 0:00:00 Downloading regex-2023.12.25-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (777 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 777.0/777.0 kB 2.7 MB/s eta 0:00:00 Downloading requests-2.31.0-py3-none-any.whl (62 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 62.6/62.6 kB 2.1 MB/s eta 0:00:00 Downloading charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (141 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 141.1/141.1 kB 3.2 MB/s eta 0:00:00 Installing collected packages: regex, charset-normalizer, requests, tiktoken Successfully installed charset-normalizer-3.3.2 regex-2023.12.25 requests-2.31.0 tiktoken-0.6.0
Samotná knihovna tiktoken zabere po instalaci cca 6,5 megabajtu, přičemž největší soubor tvoří nativní knihovna s realizací algoritmu tokenizace a zpětného převodu tokenů na text (tato nativní knihovna je naprogramována v Rustu, výsledkem jsou velmi rychlé realizace všech operací):
~/.local/lib/python3.12/site-packages/tiktoken$ ls -sh1h total 6,5M 24K core.py 20K _educational.py 12K __init__.py 16K load.py 12K model.py 4,0K __pycache__ 8,0K py.typed 12K registry.py 6,4M _tiktoken.cpython-312-x86_64-linux-gnu.so
6. Ukázka tokenizace s využitím kódování cl100k_base
Podívejme se nyní na způsob tokenizace jednoduchého textu, konkrétně klasické zprávy „Hello world“, na tokeny. Pro tokenizaci bude využito kódování (resp. možná přesněji řečeno enkodér) cl100k_base. Toto jméno je odvozeno od faktu, že obsahuje přibližně sto tisíc tokenů, resp. přesněji řečeno mapování sekvence znaků na tokeny (z toho plyne, že neobsahuje všechna slova, to však nevadí, jak uvidíme dále).
Samotný skript, který tokenizaci provede, je až triviálně jednoduchý, což je ostatně jedna z dobrých vlastností knihovny tiktoken. Nejprve získáme potřebný enkodér a poté provedeme tokenizaci zavoláním metody encode. Výsledkem je seznam s tokeny, tj. s celočíselnými hodnotami:
import tiktoken encoder = tiktoken.get_encoding("cl100k_base") tokens = encoder.encode("Hello world") print(tokens)
A takto vypadá výsledek:
[9906, 1917]
Na tomto místě je vhodné upozornit na to, že pokud například nahradíme slovo „Hello“ za „hello“, bude se z pohledu enkodéru jednat o odlišné slovo, které bude zakódováno do odlišné sekvence tokenů. Ostatně si to můžeme velmi snadno ověřit:
import tiktoken encoder = tiktoken.get_encoding("cl100k_base") tokens = encoder.encode("Hello world") print(tokens) tokens = encoder.encode("hello world") print(tokens) tokens = encoder.encode("hello World") print(tokens) tokens = encoder.encode("Hello World") print(tokens)
Výsledky naznačují, jaké tokeny odpovídají slovům „Hello“, „hello“, „World“ i „world“:
[9906, 1917] [15339, 1917] [15339, 4435] [9906, 4435]
7. Interpunkční znaménka
Ve skutečnosti má být zpráva „Hello world“ správně zapsána jako „Hello, world!“. To nás vede k problematice kódování interpunkčních znamének. Zkusme si tedy nechat tokenizovat zprávu i s oběma interpunkčními znaménky:
import tiktoken encoder = tiktoken.get_encoding("cl100k_base") tokens = encoder.encode("Hello, world!") print(tokens)
Výsledkem v tomto případě již nebude sekvence dvou tokenů, ale tokenů čtyř, což znamená, že pokud sekvenci tokenů použijeme v systému pro zpracování přirozeného jazyka, může jazykový model „rozumět“ i těmto důležitým znakům:
[9906, 11, 1917, 0]
Jen pro zajímavost – poslední token má hodnotu 0. Jedná se o token reprezentující samotný vykřičník, o čemž se můžeme velmi snadno přesvědčit:
import tiktoken encoder = tiktoken.get_encoding("cl100k_base") tokens = encoder.encode("!") print(tokens)
Výsledkem bude v tomto případě sekvence obsahující jediný token s hodnotou 0:
[0]
8. Složená slova a kódování cl100k_base
Mnohá jednoduchá anglická slova jsou transformována do jediného tokenu. Ovšem u slov delších, popř. u slov, která obsahují často používaný základ, je tomu jinak. Taková slova jsou složena z tokenů odpovídajících slovům (či části slov), z nichž jsou složena. Opět si to ukažme, a to například na slovech „black“, „blue“, „bird“, „blackbird“ a „bluebird“:
import tiktoken encoder = tiktoken.get_encoding("cl100k_base") compound_words = ( "bird", "black", "blue", "blackbird", "bluebird", ) for word in compound_words: tokens = encoder.encode(word) print(f"{word:12}", tokens)
Výsledek ukazuje, jak slova „blackbird“ a „bluebird“ vznikla složením jednodušších slov:
bird [23414] black [11708] blue [12481] blackbird [11708, 23414] bluebird [12481, 23414]
Další příklad, tentokráte slov se stejným prefixem:
import tiktoken encoder = tiktoken.get_encoding("cl100k_base") compound_words = ( "inter", "intermedial", "intermediate", "intermediaries", "intermediation", ) for word in compound_words: tokens = encoder.encode(word) print(f"{word:14}", tokens)
U posledních dvou slov prostřední token 4503 znamená „medi“:
inter [2295] intermedial [2295, 2106, 532] intermediate [2295, 14978] intermediaries [2295, 4503, 5548] intermediation [2295, 4503, 367]
Známé dlouhé slovo je „internationalization“, ale zkusme si tokenizovat ještě delší slovo „counterrevolutionaries“:
import tiktoken encoder = tiktoken.get_encoding("cl100k_base") compound_words = ( "unprofessionally", "internationalization", "counterrevolutionaries", ) for word in compound_words: tokens = encoder.encode(word) print(f"{word:22}", tokens)
Kupodivu jsou tato slova stále reprezentována relativně malým množstvím tokenů:
unprofessionally [359, 97235, 750] internationalization [98697, 2065] counterrevolutionaries [8456, 96822, 5548]
[17757, 587, 437, 822, 7141, 327, 1247, 546, 1494, 327, 1366, 41163]
9. Složená slova zakódovaná jediným tokenem
Některá složená slova jsou používána tak často, že jsou reprezentována jediným tokenem. Příkladem takového slova je (v námi používaném enkodéru!) „firefox“ zatímco slovo „fireplace“ je používáno méně často a proto je zakódováno dvojicí tokenů. Ostatně si to můžeme velmi snadno ověřit spuštěním následujícího skriptu:
import tiktoken encoder = tiktoken.get_encoding("cl100k_base") compound_words = ( "fire", "fox", "place", "fireplace", "firefox", ) for word in compound_words: tokens = encoder.encode(word) print(f"{word:12}", tokens)
Slova „fire“, „fox“ a „place“ jsou reprezentována jediným tokenem, zatímco slovo „fireplace“ vzniklo (podle očekávání) spojením „fire+place“. Ovšem „firefox“ má vlastní token:
fire [11029] fox [15361] place [2050] fireplace [11029, 2050] firefox [99012]
10. Kódování mezer
Většinou se setkáme i s tím, že existují vyhrazené tokeny pro sekvence mezer, které v automaticky zpracovávaných textech taktéž často nalezneme (i když se mnohdy tyto mezery odstraňují při preprocessingu). Jedna mezera mezi slovy je součástí tokenů slov, ale více mezer již potřebuje svůj vlastní token (či tokeny, pokud je mezer opravdu hodně). Opět si to otestujme, a to na známém příkladu textu „Hello world“, do něhož budeme vkládat mezery mezi obě slova:
import tiktoken encoder = tiktoken.get_encoding("cl100k_base") spaces = ( "Hello world", "Hello world", "Hello world", "Hello world", "Hello world", ) for word in spaces: tokens = encoder.encode(word) print(f"{word:16}", tokens)
Z výsledků je patrné, že větší množství mezer je zakódováno jediným tokenem (samozřejmě s nějakým limitem):
Hello world [9906, 1917] Hello world [9906, 220, 1917] Hello world [9906, 256, 1917] Hello world [9906, 262, 1917] Hello world [9906, 257, 1917]
Dosažení limitu:
Hello world
Nyní bude tokenizace odlišná:
[9906, 5351, 5218, 1917]
hello [15339] world [14957] world [1917] hello world [15339, 1917] <- zde se používá token slova " world" s mezerou
11. Kódování dalších speciálních znaků
Enkodér cl100k_base je primárně určen pro anglické texty, ale měl by zvládnout i použití různých speciálních znaků. Vyzkoušejme si tedy poněkud extrémní případ (který je ovšem taktéž nutné v praxi řešit), a to konkrétně tokenizaci části zdrojového kódu. Výsledek pravděpodobně nebude úsporný, ale minimálně by měl být korektní:
import tiktoken encoder = tiktoken.get_encoding("cl100k_base") source_code = ''' """Ackermannova funkce.""" if m == 0: return n + 1 if n == 0: return A(m - 1, 1) return A(m - 1, A(m, n - 1)) ''' tokens = encoder.encode(source_code) print("Tokens: ", len(tokens)) print(tokens)
Získáme sekvenci 57 tokenů, což je pro tak malý vstup poměrně vysoká hodnota naznačující, že tokenizér není pro tento vstup určen:
Tokens: 57 [198, 262, 4304, 56659, 92550, 12949, 69392, 346, 14781, 262, 422, 296, 624, 220, 15, 512, 286, 471, 308, 489, 220, 16, 198, 262, 422, 308, 624, 220, 15, 512, 286, 471, 362, 1278, 482, 220, 16, 11, 220, 16, 340, 262, 471, 362, 1278, 482, 220, 16, 11, 362, 1278, 11, 308, 482, 220, 16, 1192]
12. Zpětný převod tokenů na text
Knihovna Tiktoken umožňuje provádět i zpětný převod tokenů na text. Může se přitom jednat o libovolnou sekvenci tokenů – ovšem ne vždy je (pochopitelně) výsledkem čitelný a gramaticky správný text. Ukažme si tedy jednoduchou de-tokenizaci:
import tiktoken encoder = tiktoken.get_encoding("cl100k_base") tokens = [9906, 1917] text = encoder.decode(tokens) print(text) tokens = [9906, 11, 1917, 0] text = encoder.decode(tokens) print(text) tokens = [9906, 11, 1917, 0, 0, 0, 0] text = encoder.decode(tokens) print(text) tokens = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] text = encoder.decode(tokens) print(text) tokens = [1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010] text = encoder.decode(tokens) print(text)
Výsledky vypsané po spuštění tohoto skriptu:
Hello world Hello, world! Hello, world!!!! !"#$%&'()*+ indowlementpectash[i use.Fpec adoveception
Poslední dva řádky ukazují obsah tokenů 0–10 (běžné znaky, které v textu nalezneme) a 1000 až 1010 (což jsou části slov, takže výsledek nedává smysl).
13. Od cl100k_base k dalším enkodérům a modulům
cl100k_base je jen jedním z enkodérů umožňujících tokenizaci textu. Těchto enkodérů existuje více a některé jsou ve výchozím nastavení používány určitými modely. cl100k_base je používán v modelech GPT-3.4 i GPT-4. Naproti tomu modely DaVinci a Babbage (pro větší zmatek se tyto modely navíc číslují/verzují) používají buď taktéž cl100k_base nebo p50k_base či r50k_base, na základě zvolené konfigurace. Jak uvidíme v dalším článku, může být využití dekodérů s menším celkovým množstvím tokenů v některých případech výhodné (ostatně i proto se také nepoužívají enkodéry s naprosto všemi anglickými slovy reprezentovanými unikátními tokeny, i když je to teoreticky možné), to však již poněkud předbíháme.
14. Porovnání kódování cl100k_base s dalšími kodéry a moduly
Jednotlivé kodéry si pochopitelně můžeme mezi sebou snadno porovnat. V následujícím skriptu, který byl inspirován přímo dokumentací ke knihovně Tiktoken, je tokenizována věta a následně slovo „firefox“, a to s využitím různých „slovníků tokenů“. Ten nejčastěji používaný cl100k_base již známe (obsahuje cca 100000 tokenů pro slova i jejich části), ale zajímavé bude zjistit, jak vypadá tokenizace v případě použití r50k_base a p50k_base s menším množstvím tokenů ve slovníku. Lze předpokládat, že pro menší slovníky budou některá slova rozdělena na více tokenů:
import tiktoken def compare_encodings(example_string: str) -> None: print(f'\nExample string: "{example_string}"') for encoding_name in ["r50k_base", "p50k_base", "cl100k_base"]: encoding = tiktoken.get_encoding(encoding_name) tokens = encoding.encode(example_string) num_tokens = len(tokens) bytes = [encoding.decode_single_token_bytes(token) for token in tokens] print() print(f"{encoding_name}: {num_tokens} tokens") print(f"token integers: {tokens}") print(f"token bytes: {bytes}") print() compare_encodings("The quick brown fox jumps over the lazy dog.") compare_encodings("firefox")
Výsledky pro anglickou větu vypadají stejně (co slovo, to token, následuje token pro tečku), ovšem hodnoty některých tokenů se od sebe odlišují:
r50k_base: 10 tokens token integers: [464, 2068, 7586, 21831, 18045, 625, 262, 16931, 3290, 13] token bytes: [b'The', b' quick', b' brown', b' fox', b' jumps', b' over', b' the', b' lazy', b' dog', b'.'] p50k_base: 10 tokens token integers: [464, 2068, 7586, 21831, 18045, 625, 262, 16931, 3290, 13] token bytes: [b'The', b' quick', b' brown', b' fox', b' jumps', b' over', b' the', b' lazy', b' dog', b'.'] cl100k_base: 10 tokens token integers: [791, 4062, 14198, 39935, 35308, 927, 279, 16053, 5679, 13] token bytes: [b'The', b' quick', b' brown', b' fox', b' jumps', b' over', b' the', b' lazy', b' dog', b'.']
U slova „firefox“ je však patrné, že toto slovo jako celek existuje pouze v cl100k_base, zatímco v případě menších slovníků muselo být slovo reprezentováno dvěma tokeny pro „fire“ a „fox“ (bez mezery):
Example string: "firefox" r50k_base: 2 tokens token integers: [6495, 12792] token bytes: [b'fire', b'fox'] p50k_base: 2 tokens token integers: [6495, 12792] token bytes: [b'fire', b'fox'] cl100k_base: 1 tokens token integers: [99012] token bytes: [b'firefox']
15. Rychlost tokenizace
V některých oblastech je důležitá i rychlost tokenizace, i když v případě jazykových modelů jsou časově mnohem náročnější odlišné operace. Knihovna Tiktoken je z větší části naprogramována v Rustu a tak by rychlost tokenizace či zpětné tokenizace měla být poměrně vysoká (záleží ovšem na vnitřní struktuře slovníku tokenů). Ovšem i tento předpoklad si můžeme ověřit. Budeme opakovaně tokenizovat větu, která se převede na deset tokenů. Celkem tedy provedeme tokenizaci textu s výsledkem 1 milion tokenů a budeme přitom měřit dosažený čas:
from time import perf_counter import tiktoken encoder = tiktoken.get_encoding("cl100k_base") start_time = perf_counter() token_count = 0 for i in range(100000): tokens = encoder.encode("The quick brown fox jumps over the lazy dog.") token_count += len(tokens) end_time = perf_counter() seconds = end_time-start_time print("Tokens:", token_count) print("Time:", seconds, "seconds") speed = int(token_count / seconds) print(speed, "tokens per second")
Na počítači s mikroprocesorem řady i7 lze dosáhnout rychlosti větší než milion tokenů za sekundu:
Tokens: 1000000 Time: 0.7104394719935954 seconds 1407579 tokens per second
16. Rychlost zpětného převodu sekvence tokenů na text
Zajímat nás může i rychlost zpětného převodu sekvence tokenů (celých čísel) na text. Teoreticky by se mělo jednat o rychlejší operaci, protože se jedná o přímé mapování. Ale vyzkoušejme si to v praxi:
from time import perf_counter import tiktoken encoder = tiktoken.get_encoding("cl100k_base") start_time = perf_counter() tokens = encoder.encode("The quick brown fox jumps over the lazy dog.") characters_count = 0 for i in range(100000): text = encoder.decode(tokens) characters_count += len(text) end_time = perf_counter() seconds = end_time-start_time print("Characters:", characters_count) print("Time:", seconds, "seconds") speed = int(characters_count / seconds) print(speed, "characters per second")
Rychlost je skutečně vyšší, než v případě tokenizace (i když vlastně měříme dvě navzájem inverzní operace). Nicméně tokenizace 100000 vět trvala mnohem déle, než de-tokenizace stejné věty, opět 100000×:
Characters: 4400000 Time: 0.14141017908696085 seconds 31115157 characters per second
17. Další tokenizéry
V praxi se nepoužívá pouze knihovna Tiktoken, ale i relativně velké množství dalších knihoven určených pro tokenizaci. Velmi často se setkáme s knihovnou nazvanou BertTokenizer, která je součástí známého jazykového modelu Bidirectional Encoder Representations from Transformers (BERT). Jak pravděpodobně správně tušíte, je tokenizace BERTem stejně snadnou operací, jako tomu je v případě Tiktokenu:
from transformers import BertTokenizer tokenizer = BertTokenizer.from_pretrained("cesta") text = "Hello, world!" encoding = tokenizer.encode(text) print(encoding) print(tokenizer.convert_ids_to_tokens(encoding))
18. Speciální tokeny
Do textu, který je tokenizován, lze vkládat i různé značky, které jsou zpracovány specifickým způsobem souvisejícím s jazykovými modely. S tímto důležitým konceptem se seznámíme příště, ovšem alespoň zmínit se o něm musíme již dnes.
19. Repositář s demonstračními příklady
Zdrojové kódy všech popsaných demonstračních příkladů určených pro programovací jazyk Python 3 a knihovnu tiktoken byly uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/most-popular-python-libs:
20. Odkazy na Internetu
- tiktoken na GitHubu
https://github.com/openai/tiktoken - tiktoken na PyPi
https://pypi.org/project/tiktoken/ - Byte pair encoding (Wikipedie)
https://en.wikipedia.org/wiki/Byte_pair_encoding - A Beginner’s Guide to Tokens, Vectors, and Embeddings in NLP
https://medium.com/@saschametzger/what-are-tokens-vectors-and-embeddings-how-do-you-create-them-e2a3e698e037 - 5 Simple Ways to Tokenize Text in Python
https://towardsdatascience.com/5-simple-ways-to-tokenize-text-in-python-92c6804edfc4 - How to count tokens with Tiktoken
https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken - An Explanatory Guide to BERT Tokenizer
https://www.analyticsvidhya.com/blog/2021/09/an-explanatory-guide-to-bert-tokenizer/ - Tiktokenizer
https://tiktokenizer.vercel.app/ - Mastering BERT Tokenization and Encoding
https://albertauyeung.github.io/2020/06/19/bert-tokenization.html - The amazing power of word vectors
https://blog.acolyer.org/2016/04/21/the-amazing-power-of-word-vectors/ - Which embedding tokenizer should I use?
https://community.openai.com/t/which-embedding-tokenizer-should-i-use/82483 - Getting Started With Embeddings
https://huggingface.co/blog/getting-started-with-embeddings - Lexical analysis (Wikipedia)
https://en.wikipedia.org/wiki/Lexical_analysis#Token - Lexikální analýza (Wikipedia)
https://cs.wikipedia.org/wiki/Lexik%C3%A1ln%C3%AD_anal%C3%BDza - Jazykový korpus
https://cs.wikipedia.org/wiki/Jazykov%C3%BD_korpus - AP8, IN8 Regulární jazyky
http://statnice.dqd.cz/home:inf:ap8 - AP9, IN9 Konečné automaty
http://statnice.dqd.cz/home:inf:ap9 - AP10, IN10 Bezkontextové jazyky
http://statnice.dqd.cz/home:inf:ap10 - AP11, IN11 Zásobníkové automaty, Syntaktická analýza
http://statnice.dqd.cz/home:inf:ap11 - PaLM 2 (Pathways Language Model)
https://ai.google/discover/palm2/ - Gemini
https://deepmind.google/technologies/gemini/#introduction - LLaMA (Large Language Model Meta AI)
https://en.wikipedia.org/wiki/LLaMA - GPT-4
https://openai.com/gpt-4