Собесов

Сценарий ML: BPE vs WordPiece vs SentencePiece

ML / Data ScienceNLP и эмбеддингиСредняяMiddle

Условие

Объясните BPE, WordPiece, SentencePiece. Почему subword tokenization лучше word-level?

Решение

Подход

Word-level проблемы: out-of-vocabulary (OOV) слова, huge vocabulary (миллионы), редкие формы слов (рус. падежи), невозможность handle опечатки.

Subword: разделяем слова на части, на которых учим vocabulary. «токенизация» → «токен» + «иза» + «ция».

BPE (Byte Pair Encoding)

Алгоритм:

  1. Initial vocab = все символы.
  2. Подсчитаем частоту bigram пар в корпусе.
  3. Самую частую merge в новый token.
  4. Повтор до vocab_size.
def learn_bpe(corpus, n_merges=10000):
    vocab = list(corpus_to_chars(corpus))  # initial
    pairs = count_pairs(corpus)
    for _ in range(n_merges):
        best = max(pairs, key=pairs.get)
        vocab.append(''.join(best))
        corpus = merge_pair(corpus, best)
        pairs = count_pairs(corpus)
    return vocab

Используется в GPT-2, GPT-3, RoBERTa.

WordPiece

Похож на BPE, но выбирает merge максимизирующий likelihood корпуса:

score(pair) = freq(pair) / (freq(left) · freq(right))

Используется в BERT.

SentencePiece

Не предполагает pre-tokenization (нет split по пробелу). Работает на raw bytes, что важно для языков без пробелов (CJK).

Поддерживает 2 алгоритма:

  • BPE: как выше.
  • Unigram: вероятностная модель, выбирает best segmentation через Viterbi.

Используется в T5, mBART, ALBERT.

Byte-level BPE

GPT-2 / GPT-3: работает на bytes (256 символов), а не Unicode. Никогда не OOV.

Сравнение

BPE WordPiece SentencePiece (Unigram)
Pre-tokenization По пробелу По пробелу Нет
Merge critirea Freq Likelihood Likelihood global
Decode Concat Concat (## prefix) Concat
Reversible Не всегда Не всегда Lossless

Реализация (huggingface tokenizers)

from tokenizers import Tokenizer, models, trainers, pre_tokenizers
 
tokenizer = Tokenizer(models.BPE())
tokenizer.pre_tokenizer = pre_tokenizers.Whitespace()
trainer = trainers.BpeTrainer(vocab_size=30000, special_tokens=['<pad>','<unk>','<s>','</s>'])
tokenizer.train(files=['corpus.txt'], trainer=trainer)

Эффект на multilingual

Англоязычный BERT-Tokenizer на русском split на много мелких частей → длинные последовательности → плохое модели и большой compute. Для русского лучше rubert-tokenizer или multilingual model (XLM-R) с большим vocab.

Подводные камни

  1. Vocab size: малый → длинные последовательности, медленно. Большой → больше параметров embedding, overfit на rare tokens. Стандарт 30k-50k.
  2. Pre-tokenization влияет: BPE на пробелах не справляется с китайским; нужен SentencePiece.
  3. Numbers: tokenizer часто разбивает «12345» на «12» «345» → плохо для math reasoning. Решение — special number tokens или digit-level split.
  4. Token economics: payment по tokens. Языки с плохим vocab (русский) платят больше — счёт может быть в 1.5-2× выше английского.
  5. Truncation max_len: BERT 512, GPT-3 4k, GPT-4o 128k. Длинные документы — chunking.

Эталонный ответ

Subword: BPE (greedy merge по частоте, GPT), WordPiece (merge по likelihood, BERT), SentencePiece + Unigram (без pre-tokenization, T5/mBART). Byte-level BPE никогда не OOV. Vocab 30-50k стандарт. Для русского — выбрать tokenizer обученный на русском, иначе плохой compression.

Хочешь увидеть разбор?

Зарегистрируйся бесплатно — откроется развёрнутое решение этой задачи и ещё 4 на выбор.

Зарегистрироваться и увидеть разбор
Уже есть аккаунт? Войти