Přeskočit na obsah
AI Základy

Tokenizace — BPE, WordPiece a zpracování textu

8 min čtení
TokenizaceBPENLP

Tokenizace je klíčový proces přípravy textu pro AI modely, který rozděluje text na menší jednotky. Seznamte se s algoritmy BPE a WordPiece a pochopte, jak funguje zpracování textu v moderních jazykových modelech.

Tokenizace v moderním NLP: od slov k subwords

Tokenizace je základním krokem každého NLP systému. Zatímco tradiční přístupy rozdělují text na slova podle mezer, moderní modely jako GPT nebo BERT využívají pokročilejší techniky jako Byte-Pair Encoding (BPE) a WordPiece. Tyto algoritmy dokážou elegantně řešit problém out-of-vocabulary (OOV) slov a efektivně reprezentovat rozsáhlé slovníky.

Proč klasická tokenizace nestačí

Představte si, že trénujete model na anglických textech a narazíte na slovo "unhappiness". Klasický word-based tokenizer by toto slovo buď zařadil do slovníku (pokud se vyskytuje dostatečně často), nebo by ho označil jako neznámé token <UNK>. Oba přístupy mají zásadní nevýhody:

  • Velký slovník zabírá více paměti a zpomaluje trénink
  • Neznámé tokeny způsobují ztrátu informace
  • Model se nedokáže naučit morfologii a slovotvorbu

Moderní subword tokenizace řeší tyto problémy rozdělením slov na menší významové jednotky.

Byte-Pair Encoding (BPE)

BPE původně vzniklo jako kompresní algoritmus, ale našlo uplatnění v NLP. Algoritmus funguje následovně:

# Jednoduchá implementace BPE
def get_pairs(vocab):
    """Získá všechny páry sousedních symbolů"""
    pairs = {}
    for word, freq in vocab.items():
        symbols = word.split()
        for i in range(len(symbols) - 1):
            pair = (symbols[i], symbols[i + 1])
            pairs[pair] = pairs.get(pair, 0) + freq
    return pairs

def merge_vocab(pair, vocab):
    """Sloučí nejčastější pár symbolů"""
    new_vocab = {}
    bigram = ' '.join(pair)
    replacement = ''.join(pair)
    
    for word in vocab:
        new_word = word.replace(bigram, replacement)
        new_vocab[new_word] = vocab[word]
    return new_vocab

BPE začíná s vocabulářem jednotlivých znaků a iterativně slučuje nejčastější páry. Pro slovo "unhappiness" by proces mohl vypadat takto:

# Původní stav
"u n h a p p i n e s s"

# Po několika iteracích
"un hap p i ness"

# Finální tokenizace
["un", "hap", "pi", "ness"]

WordPiece algoritmus

WordPiece, používané v BERT, je podobné BPE, ale s důležitým rozdílem. Místo výběru nejčastějších párů vybírá páry, které maximalizují likelihood trénovacích dat. Používá také speciální prefix "##" pro označení sub-tokenů, které neznačují začátek slova:

# WordPiece tokenizace
"unhappiness" → ["un", "##hap", "##pi", "##ness"]
"playing" → ["play", "##ing"]
"hello" → ["hello"]  # časté slovo zůstane celé

Praktická implementace s Hugging Face

V praxi většinou využijeme hotové implementace. Hugging Face Transformers poskytuje jednoduché API:

from transformers import AutoTokenizer

# GPT-2 používá BPE
gpt2_tokenizer = AutoTokenizer.from_pretrained("gpt2")
text = "Tokenizace je důležitá pro NLP"
tokens = gpt2_tokenizer.tokenize(text)
print(tokens)
# ['Token', 'iz', 'ace', ' je', ' d', 'ů', 'ležitá', ' pro', ' NL', 'P']

# BERT používá WordPiece
bert_tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
tokens = bert_tokenizer.tokenize("unhappiness")
print(tokens)
# ['un', '##hap', '##pi', '##ness']

Trénování vlastního BPE tokenizeru

Pro specializované domény často potřebujeme vlastní tokenizer. SentencePiece je populární knihovna pro tento účel:

import sentencepiece as spm

# Trénování BPE modelu
spm.SentencePieceTrainer.train(
    input='training_data.txt',
    model_prefix='my_bpe',
    vocab_size=32000,
    model_type='bpe',
    character_coverage=0.9995,
    split_by_unicode_script=True,
    split_by_number=True
)

# Načtení a použití
sp = spm.SentencePieceProcessor(model_file='my_bpe.model')
tokens = sp.encode('Vlastní tokenizer pro česká data')
print(tokens)
print(sp.decode(tokens))

Optimalizace pro konkrétní jazyky

Čeština má specifika, která ovlivňují tokenizaci. Bohatá morfologie, diakritika a relativně volný slovosled vyžadují pozornost:

# Příklad problémů s češtinou
text = "Programování, programuju, naprogramoval"

# Špatně nastavený tokenizer může vytvořit:
# ["Program", "ování", ",", " program", "uju", ",", " na", "program", "oval"]

# Lepší tokenizace by rozpoznala kořen:
# ["programo", "##vání", ",", " programo", "##ju", ",", " na", "##programo", "##val"]

Pro lepší výsledky s češtinou doporučujeme:

  • Vyšší character_coverage (0.9999) kvůli diakritice
  • Předtrénované modely jako czert-b-base-cased
  • Preprocessing pro normalizaci diakritiky pokud to úkol dovoluje

Výkon a paměťové nároky

Volba velikosti slovníku je kompromis mezi výkonem a kvalitou. Větší slovník znamená:

  • Kratší sekvence tokenů → rychlejší inference
  • Větší embedding matice → vyšší paměťové nároky
  • Více parametrů → pomalejší trénink
# Analýza tokenizace
def analyze_tokenization(tokenizer, texts):
    total_tokens = 0
    total_chars = 0
    
    for text in texts:
        tokens = tokenizer.tokenize(text)
        total_tokens += len(tokens)
        total_chars += len(text)
    
    compression_ratio = total_chars / total_tokens
    print(f"Kompresní poměr: {compression_ratio:.2f} znaků/token")
    return compression_ratio

# Porovnání různých tokenizérů
gpt2_ratio = analyze_tokenization(gpt2_tokenizer, sample_texts)
bert_ratio = analyze_tokenization(bert_tokenizer, sample_texts)

Shrnutí

Tokenizace je kritický první krok každého NLP pipeline. BPE a WordPiece algoritmy elegantně řeší problém OOV slov a umožňují efektivní reprezentaci textů. Při výběru tokenizeru je třeba zvážit specifika cílového jazyka, velikost dat a výkonnostní požadavky. Pro češtinu doporučujeme využít předtrénované modely nebo pečlivě nastavit parametry při trénování vlastního tokenizeru.

CORE SYSTEMS tým

Enterprise architekti a AI inženýři.