Токенизаторы в LLM: BPE, SentencePiece и почему один и тот же текст занимает разное число токенов

Что делает токенизатор и почему это важно​


LLM не работает с текстом напрямую. Перед подачей в модель строка разбивается на токены — целочисленные идентификаторы, каждый из которых соответствует фрагменту текста: символу, части слова или целому слову. От того, как именно происходит это разбиение, зависят три практические вещи:

  • Расход контекстного окна. Лимит модели задаётся в токенах, а не в символах. Один и тот же абзац может занять 80 токенов в одной модели и 140 в другой.
  • Стоимость инференса. API-провайдеры тарифицируют запросы по числу токенов на входе и выходе.
  • Качество генерации. Если токенизатор плохо представляет язык (например, разбивает кириллицу посимвольно), модель тратит ёмкость на «склейку» фрагментов вместо семантики.

Конвейер токенизации: три этапа​


Прежде чем текст превратится в последовательность ID, он проходит три стадии:

1. Нормализация​


Общая очистка входной строки. Конкретные операции зависят от модели:

  • Удаление лишних пробельных символов.
  • Приведение к нижнему регистру (например, bert-base-uncased).
  • Удаление диакритических знаков (ударений, умляутов).
  • Unicode-нормализация (NFC, NFKC).

Нормализация определяет, будет ли токенизация обратимой. bert-base-uncased приводит всё к нижнему регистру и убирает ударения — восстановить исходную строку из токенов невозможно.

2. Претокенизация​


Разбиение текста на мелкие фрагменты, которые станут границами для дальнейшего дробления на подтокены. Правила различаются:

ТокенизаторРазбиениеОбработка пробеловДвойные пробелы
BERTпо пробелам и пунктуацииудаляетигнорирует
GPT-2по пробелам и пунктуациизаменяет на Ġсохраняет
T5 (SentencePiece)только по пробеламзаменяет на игнорирует

Пример для строки "Hello, how are you?":

  • BERT: ['Hello', ',', 'how', 'are', 'you', '?'] — пунктуация отделена, пробелы выброшены.
  • GPT-2: ['Hello', ',', 'Ġhow', 'Ġare', 'Ġ', 'Ġyou', '?'] — пробелы закодированы префиксом Ġ, двойной пробел сохранён как отдельный токен.
  • T5: ['▁Hello,', '▁how', '▁are', '▁you?'] — пунктуация остаётся внутри фрагмента, пробелы закодированы .

3. Алгоритм подтокенизации​


На этом этапе фрагменты из претокенизации дробятся дальше — на подтокены, которые присутствуют в словаре модели. Три основных алгоритма:

  • BPE (Byte-Pair Encoding) — GPT-2, LLaMA, Mistral и большинство decoder-only моделей.
  • WordPiece — BERT и модели на его архитектуре.
  • Unigram — T5, ALBERT.

Как работает BPE​


BPE — итеративный алгоритм слияния пар. Обучение происходит на корпусе текстов:

  1. Инициализация. Словарь начинается с отдельных символов (или байтов, в зависимости от реализации). Каждый символ — базовый токен.
  2. Подсчёт пар. Алгоритм считает, какие пары соседних токенов встречаются в корпусе чаще всего.
  3. Слияние. Самая частая пара объединяется в новый токен и добавляется в словарь.
  4. Повторение. Шаги 2–3 повторяются, пока словарь не достигнет заданного размера.

В результате словарь содержит как отдельные символы, так и часто встречающиеся последовательности: целые слова (the, function), распространённые аффиксы (ing, tion), характерные биграммы.

При инференсе токенизатор применяет выученные слияния в том же порядке, в котором они были созданы при обучении. Слово, которое встречалось в корпусе целиком, останется одним токеном. Редкое или неизвестное слово будет разбито на знакомые подтокены.

Ключевое свойство BPE: алгоритм детерминирован и жаден — для данного входа результат всегда одинаков, но он не гарантирует глобально оптимальное разбиение с точки зрения вероятности.

SentencePiece: не алгоритм, а фреймворк​


SentencePiece часто путают с конкретным алгоритмом токенизации. На деле это фреймворк предобработки, который можно комбинировать с BPE, Unigram или другими методами. Его отличительные черты:

  • Текст рассматривается как последовательность символов Unicode. Нет отдельного шага претокенизации по пробелам или пунктуации. Это критично для языков без пробельного разделения слов: китайского, японского, тайского.
  • Пробелы заменяются специальным символом (U+2581, lower one eighth block). Это позволяет отличить начало слова от продолжения.
  • Обратимая токенизация. Декодирование — простая конкатенация токенов с заменой на пробел. Никакой информации не теряется.
  • Пробел добавляется в начало предложения по умолчанию, поэтому первый токен обычно начинается с .

Когда SentencePiece комбинируется с Unigram, претокенизация не требуется вовсе: алгоритм сам определяет оптимальное разбиение на основе языковой модели, обученной на корпусе.

Почему один текст даёт разное число токенов​


Разница в количестве токенов для одной и той же строки между моделями объясняется несколькими факторами:

Размер и состав словаря​


Словарь BPE обучается на конкретном корпусе. Если в корпусе доминировал английский, частые английские слова станут едиными токенами, а кириллица будет разбита на мелкие фрагменты. Модель с мультиязычным корпусом (например, mBERT, XLM-R) имеет более сбалансированное покрытие.

Правила претокенизации​


Как показано выше, GPT-2 сохраняет двойные пробелы как отдельные токены, а T5 их игнорирует. Пунктуация в BERT отделяется от слов, а в T5 остаётся внутри фрагмента. Это напрямую влияет на число итоговых токенов.

Нормализация​


Модель с lowercasing и удалением диакритики может дать меньше токенов для текста с ударениями, но потеряет информацию. Модель без нормализации сохранит каждый вариант написания как отдельную последовательность.

Базовые единицы​


Некоторые реализации BPE работают на уровне байтов (byte-level BPE, как в GPT-2). Это гарантирует, что любой Unicode-символ может быть представлен, но для не-ASCII текстов увеличивает число токенов: один символ UTF-8 может занимать 2–4 байта, каждый из которых — отдельный базовый токен до слияния.

Практические следствия​


Контекстное окно и стоимость​


Если модель A токенизирует русский текст в 1.8 раза плотнее, чем модель B, то при одинаковом лимите контекста модель A обработает почти вдвое больше текста. При тарификации по токенам разница напрямую конвертируется в деньги.

Качество генерации на не-английских языках​


Когда токенизатор разбивает слово на 5–7 подтокенов, модели сложнее уловить его семантику за один шаг внимания. Это одна из причин, почему модели с англоцентричным словарем хуже генерируют на русском, китайском или арабском — не из-за архитектуры, а из-за представления входа.

Structured output и парсинг​


Токенизация влияет на генерацию JSON и других структурированных форматов. Если ключ или значение разбиты на несколько токенов, модели сложнее гарантировать синтаксическую корректность. Подробнее об этом — в материале Structured Output: как получать от LLM валидный JSON и не парсить ответ регулярками.

Как проверить число токенов для конкретной модели​


Самый надёжный способ — использовать токенизатор целевой модели напрямую:

Python:
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3-8B")
text = "Пример текста для проверки токенизации."
tokens = tokenizer.encode(text)
print(f"Токенов: {len(tokens)}")
print(f"ID: {tokens}")

Для визуализации разбиения на подтокены:

Python:
print(tokenizer.tokenize(text))

Это покажет, на какие фрагменты разбивается каждое слово. Если кириллическое слово распадается на 4–6 кусков — словарь модели плохо покрывает русский язык.

Сравнение нескольких моделей​


Python:
from transformers import AutoTokenizer

models = ["gpt2", "t5-small", "bert-base-uncased"]
text = "Hello, how are you?"

for name in models:
    tok = AutoTokenizer.from_pretrained(name)
    ids = tok.encode(text)
    print(f"{name:25s} → {len(ids)} токенов")

Для одного и того же текста результаты будут различаться из-за разных словарей и правил претокенизации.

Типичные ошибки при оценке токенов​


  • Оценка по символам или словам. Деление числа символов на 4 — грубая эвристика для английского текста в GPT-подобных моделях. Для русского, китайского или кода она даёт ошибку в 1.5–3 раза.
  • Использование токенизатора одной модели для оценки другой. Словари несовместимы. tiktoken (OpenAI) не подходит для LLaMA, и наоборот.
  • Игнорирование специальных токенов. [CLS], [SEP], <s>, </s> и системные промпты тоже занимают токены. При расчёте доступного контекста их нужно учитывать.
  • Предположение, что токенизация обратима. Для BERT-подобных токенизаторов с нормализацией это не так: исходный регистр и диакритику восстановить невозможно.

Что учитывать при выборе модели под задачу​


КритерийНа что смотреть
Основной язык контентаПокрытие языка в словаре: проверить tokenize() на типичных строках
Лимит контекстаРеальная ёмкость в токенах с учётом системного промпта и специальных токенов
Стоимость APIТариф за 1K токенов × средний объём запроса
Structured outputЧем плотнее токенизация целевого формата, тем надёжнее генерация Structured Output: как получать от LLM валидный JSON и не парсить ответ регулярками
МультиязычностьПредпочтение моделям с мультиязычным корпусом обучения

Токенизатор — не вспомогательная деталь, а часть архитектуры, которая определяет, как модель «видит» текст. Понимание его механики позволяет точнее оценивать стоимость, выбирать модель под язык задачи и диагностировать проблемы с качеством генерации.

Источники​


 

Похожие темы

Назад
Верх Низ