Aivaro
  • Оглавление
  • Вопросы
  • Практика
  • Вики
  • Материалы сообщества
  • Тесты
  • Поиск
✈Telegram @ai_varo
RUEN中文
…
Оглавление/Вопросы/#928

Что такое SentencePiece и чем он отличается от BPE (например, в модели T5)? Как обрабатывает пробелы?

Краткий тезис

SentencePiece — это библиотека для создания субсловных токенизаторов от Google, которая работает с сырым текстом без предварительного разделения на слова. В отличие от стандартного BPE, SentencePiece рассматривает пробел как обычный символ, заменяя его на специальный токен (обычно _ или ▁). Это позволяет обучиться границам слов в процессе токенизации, что критически важно для языков без чётких word boundaries, например для русского. SentencePiece поддерживает два алгоритма: Unigram (используется в T5) и собственно BPE (применяется в Llama).

2. Отличие от BPE: работа с сырым текстом (пробел = символ _)

Классическая процедура BPE (например, в GPT или RoBERTa) предполагает следующие шаги:

  1. Разделить текст на слова по пробелам и знакам препинания (pre-tokenization).
  2. Заменить каждое слово последовательностью символов (например, с добавлением ## или </w> для отметки конца слова).
  3. Итеративно объединять самые частые пары символов.

Таким образом, BPE работает с уже выделенными словами — пробелы теряются на этапе pre-tokenization. Это означает, что модель не может обучиться межсловным отношениям (например, что пробел обычно предшествует началу нового слова).

SentencePiece, наоборот, не делает предварительного разбиения по пробелам. Вместо этого:

  • Пробел преобразуется в специальный символ (например, _ в ранних версиях или ▁ в современных).
  • Вся последовательность символов, включая пробелы, обрабатывается как единый поток.
  • Токенизатор учится объединять символы, включая пары, содержащие пробел. Например, последовательность _м может стать отдельным токеном, который будет означать "пробел + символ 'м'".

Сравнение подходов на примере предложения "Hello world":

ЭтапКлассический BPESentencePiece (c пробелом как _)
Исходный текст"Hello world""Hello world"
Pre-tokenization["Hello", "world"]["_Hello", "_world"] (только для демонстрации, на самом деле не нужно)
Вход для BPE"Hello", "world""▁Hello▁world" (как одна строка с символом ▁)
Возможные токены"He", "llo", "wor", "ld""▁He", "llo", "▁wor", "ld"
Обратная конвертация"He" + "llo" + " " + "wor" + "ld" (нужен отдельный шаг)"▁He" → "He", "▁wor" → "wor" → на выходе "Hello world"

Таким образом, SentencePiece инкапсулирует границу слова прямо в токене, что делает декодирование тривиальным: достаточно заменить все ▁ на пробелы (кроме первого, если токенизатор не добавляет ▁ в начало текста).


3. Поддерживает Unigram (T5) и BPE (Llama)

SentencePiece не привязан к одному алгоритму. Параметр model_type может быть:

  • 'bpe' — стандартный BPE, но реализованный на последовательности символов, включая пробел.
  • 'unigram' — алгоритм на основе Unigram Language Model.

Unigram (используется в T5):

  • Обучает вероятностную модель, которая для каждого входа находит токенизацию с максимальной правдоподобностью.
  • Начинает с большого словаря (например, всех символов и их частых биграмм) и рекурсивно удаляет наименее вероятные субслова.
  • Подробнее: каждый субсловный токен имеет вероятность, произведение вероятностей всех токенов в последовательности даёт общую вероятность. Оптимизация ведётся через EM-алгоритм.
  • Преимущество: естественная регуляризация, возможность обучения токенизатора с заданным размером словаря.

BPE (используется в Llama и многих других):

  • Итеративное слияние: на каждом шаге объединяется наиболее частая пара соседних символов (или токенов) во всём корпусе.
  • Процесс продолжается, пока не будет достигнут желаемый размер словаря.
  • В SentencePiece BPE работает на уровне байтов (дополнительно поддерживается опция byte_fallback).

Сравнение подходов:

АспектBPEUnigram
ПринципДетерминированное слияние парВероятностная модель
ОбучаемостьЖадный алгоритмEM-оптимизация
СловарьФиксируется последовательностью слиянийВыбирается из большего начального набора
Использование в моделяхGPT, RoBERTa, LlamaT5, ALBERT

4. Обработка пробелов: кодируется как токен, без word boundaries

Ключевое следствие: токенизатор SentencePiece не имеет понятия "граница слова" в классическом смысле. Токен может начинаться с символа пробела (▁), содержать несколько слов, или наоборот — разбивать одно слово с учётом пробела внутри (например, дефис или перенос строки).

Пример токенизации русского текста с помощью модели Unigram (аналог T5):

text = "Привет мир! Я изучаю NLP."
sp = ...  # обученная модель SentencePiece
tokens = sp.encode(text, out_type=str)
print(tokens)
# ['▁Привет', '▁мир', '!', '▁Я', '▁изучаю', '▁N', 'LP', '.']

Обратите внимание: N и LP — это два разных токена, потому что заглавные буквы после пробела считаются разными символами. Символ ▁ (метка пробела) стоит только перед первым символом каждого "слова", но не в середине. Если бы текст содержал дефис, например "NLP-модель", то токенизатор мог бы выдать ['▁N', 'LP', '-', '▁модель'].

Как происходит обратное преобразование:

  1. Получить последовательность токенов-строк.
  2. Склеить их без разделителей.
  3. Заменить все вхождения ▁ на пробел.
  4. Если строка начинается с пробела (первый токен начинался с ▁), удалить его (обычно это настраиваемый параметр).

Пример кода для декодирования:

tokens = ['▁Привет', '▁мир', '!']
decoded = sp.decode(tokens)
print(repr(decoded))
# 'Привет мир!'
# (если модель обучена добавлять ▁ только между словами, то пробел между 'Привет' и 'мир' есть)

Важная деталь: в моделях на основе SentencePiece (например, T5) токенизатор не знает, что такое слово — он оперирует только субсловами с маркерами пробелов. Это упрощает обработку многоязычных текстов и текстов без пробелов (китайский, японский), но может приводить к неожиданным разбиениям для языков с составными словами (немецкий, русский сложные приставки).


Пет-проект для закрепления

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

Инструменты:

  • Python 3.8+
  • sentencepiece (PyPI)
  • transformers или tokenizers для визуализации
  • Любой русский текстовый корпус (можно взять подмножество «Толока» или Lenta.ru)

Шаги:

  1. Подготовить корпус: очистить от лишних символов, оставить только текст (одно предложение на строку).
  2. Обучить две модели с одинаковым размером словаря (например, 32000):
    spm.SentencePieceTrainer.train('--input=corpus.txt --model_prefix=bpe_model --vocab_size=32000 --model_type=bpe')
    spm.SentencePieceTrainer.train('--input=corpus.txt --model_prefix=unigram_model --vocab_size=32000 --model_type=unigram')
    
  3. Загрузить обе модели и протестировать на одном предложении:
    • Вывести токены (как строки) для фразы «Привет, мир! Я изучаю токенизаторы».
    • Посчитать среднюю длину токенизации на тестовом корпусе.
  4. Сравнить результат:
    • Какая модель даёт меньше токенов на одно предложение? (BPE обычно даёт более короткие последовательности, но это зависит от корпуса).
    • Влияние алгоритма на покрытие редких слов.
  5. Попробовать декодировать обратно и проверить, восстановился ли пробел.

Ожидаемый результат:

  • Понимание разницы между BPE и Unigram на практике.
  • Умение объяснить, почему T5 использует Unigram, а Llama — BPE.
  • Навык работы с SentencePiece и визуализации токенизации.

Связь с другими вопросами

ВопросТема
284BPE vs WordPiece — сравнение алгоритмов субсловной токенизации
927WordPiece — ещё один метод, близкий к BPE, но с вероятностной оценкой слияния

Навигация

  • Предыдущий: 927
  • Следующий: 929
  • Индекс: 00. Индекс разборов