Технологии

«GPU не должны простаивать в ожидании CPU»: Hugging Face ускорила tokenizers в 3–30 раз, не меняя токены

Hugging Face выпустила release candidate tokenizers v1: движок переписан так, что на десяти семействах моделей кодирование идёт в 3–30 раз быстрее, чем в v0.23, при том же результате — те же API, словарь и токен-ID. Главные изменения — замена регулярного выражения на битстримы с SIMD в crate bitcannon, потоковый кэш слов и цикл слияний, который вообще не трогает аллокатор; размер crate уменьшился в шесть раз. Декодирование ускорилось в 5,4–8,8 раза, а на восьми воркерах масштабирование доходит до 76% от линейного.

«GPU не должны простаивать в ожидании CPU»: Hugging Face ускорила tokenizers в 3–30 раз, не меняя токены

Токенизатор перестал успевать за моделью

Исторически токенизация не была узким местом в ML-конвейере: по вычислениям она лёгкая на фоне самой модели. Но баланс сдвигается, когда модели ускоряются, а нагрузки растут: обучение на огромных датасетах, обслуживание множества одновременных запросов или повторная обработка длинных входов дают такую нагрузку на токенизатор, что он перестаёт подавать данные модели.

Hugging Face описывает это как смену ролей: библиотека tokenizers вышла семь лет назад, когда узким местом было выполнение модели, а экосистема с тех пор ушла настолько вперёд, что узким местом стал сам tokenizers. Цель v1 сформулирована в релизе буквально как «эталонная библиотека токенизации — те же API, те же токен-ID, те же стандарты».

Практическая цена — time to first token: каждый промпт нужно разбить на токены прежде, чем инференс вернёт первый токен, и на длинных агентских контекстах это заметно. Авторы отдельно благодарят экосистему — gigatoken, tiktoken, kitoken, tokie, fastokens, wordchipper и ai-tokenizer — и отмечают патчи от IBM, NVIDIA и команды ExecuTorch, которые помогли протестировать сборку на разном железе.

Тот же результат, другой путь внутри

Ключевое обещание: v1 выдаёт те же токен-ID, что и v0.23, потому что целью было сохранить выход, API, словарь и ранги слияний, а улучшать только то, что можно улучшить без изменения результата. Библиотека при этом остаётся общей для разных семейств токенизаторов, а не специализируется на BPE.

Конвейер токенизации состоит из четырёх стадий: нормализация, пре-токенизация, модель и постобработка. Основная работа идёт на стадии модели, и восемь из десяти измеренных семейств используют BPE, где слияние никогда не переходит границу пре-токена, поэтому именно разбиение определяет всё, что видит дальше конвейер.

Первое изменение — структурное: единый crate разложен на workspace, где tk-encode остаётся обязательным рантаймом, а tk-serialize, tk-convert и tk-train линкуются только тогда, когда приложению они нужны. Смысл практический — сервисный бинарник больше не тянет тренер, читалку корпусов и легаси-конвертеры. В релизе названа и причина переписывания: прежний стек был настолько устаревшим, что внешним контрибьюторам было некуда входить.

bitcannon: вместо регулярного выражения — битстримы

BPE-модели делят вход регулярным выражением, и это фиксированный параметр модели: шаблон не меняется во время работы, поэтому полноценный regex-движок в каждом вызове не нужен. Вместо него подходит написанная один раз функция на SIMD-инструкциях, которые применяют одну операцию сразу к множеству байтов и хорошо ложатся на UTF-8.

Новый crate bitcannon трактует байты входа как параллельные потоки битов: границы получаются булевыми операциями по целым регистрам, и за одну операцию обрабатывается 64 байта. Тяжёлые таблицы Unicode при этом не нужны: символы сначала классифицируются по «тегам» из разреженной таблицы, которая собирается при компиляции. Идея опирается на статью MICRO'25 о многопаттерновом regex-матчинге на GPU, но с собственным алгоритмом, чтобы не тянуть Parabix-движок.

Ограничение встроено в сам дизайн и объясняет разброс результатов: в таблице изменений сказано, что путь зависит от распознавания шаблона — несколько грамматик покрывают большинство byte-level BPE-моделей, а токенизатор с незнакомым шаблоном остаётся на regex и ускорения не получает. В README перечислены byte-exact грамматики: gpt2 / ByteLevel, cl100k, o200k, tekken, deepseek и kimi-k2, и там же заявлено, что это самая быстрая реализация каждого пре-токенизаторного regex на CPU.

Кэш слов и цикл слияний без аллокатора

Второй крупный выигрыш — кэш слов: потоковый memo от байтов пре-токена к готовым ID, поэтому повторяющееся слово сливается один раз, а не заново при каждом появлении. Кэш лучше всего работает на текстах с повторами: если пре-токены почти не повторяются, лукапы стоят дороже, чем приносят пользы.

Цикл слияний переписан так, чтобы не трогать аллокатор: рабочее множество живёт в scratch-буфере, которым владеет вызывающая сторона, а символы хранятся в плоском массиве и ссылаются друг на друга позициями, поэтому слияние обновляет два индекса вместо перемещения данных. Пары-кандидаты упакованы в одно 64-битное значение, где ранг слияния лежит в старших битах: сравнение кандидатов превращается в сравнение двух целых, а вариант «сливать нечего» — просто наибольшее значение, поэтому следующий шаг находится без ветвлений.

К этому добавлены плоский кэш FlatCache, MPHF-хранилище рангов, инкрементальные слияния и BucketVocabStore, а также переиспользуемая память модели, чтобы кодирование не выделяло память на каждый вызов. Пре-токены обрабатываются батчем за один вызов модели, а декодирование пишет байты прямо в переиспользуемый буфер.

Что показали замеры

На десяти семействах моделей кодирование в v1 идёт в 3–30 раз быстрее, чем в v0.23, на одном потоке Apple M4 Max: нижняя граница — t5-base, верхняя — gpt2. На восьми воркерах масштабирование доходит до 76% от линейного, и результат на выходе остаётся прежним: на всём пути изменений v1 выдаёт точно те же токен-ID, что и выпущенная библиотека.

Обратный путь ускорился тоже: на шести семействах, для которых измерялось декодирование, v1 работает в 5,4–8,8 раза быстрее tokenizers 0.23 на M4 Max. Потребление памяти измерялось на токенизаторе gpt-oss с 1,024 МБ английского текста, а размер crate, по словам авторов релиза, стал в шесть раз меньше при снижении пиковой памяти.

Методика прописана жёстко, чтобы сравнение не разъезжалось: один и тот же цикл для всех движков без ускоренных путей, загрузка исключена из замера, хеш FNV-1a по выходным ID обязан совпасть с базовым, медианы считаются только по ячейкам, которые прошли все движки, каждый процесс выполняет полный прогон, а воркеры пришпилены к восьми физическим ядрам, а не к SMT-соседям.

Нелатинские языки для v1 — часть цели, а не побочный эффект: UTF-8 тратит больше байтов на символ вне латиницы, и v1 считает такие языки частью задачи по производительности. Для WordPiece добавлены double-array trie, путь кодирования без аллокаций и общий кэш слов, но выигрыш там меньше, чем на BPE, и именно на этих двух семействах авторы сосредоточатся дальше.

Числа получены на открытом стенде: репозиторий tokbench под лицензией Apache-2.0, в README которого сказано, что он во многом написан агентными средствами, а перезапуск замеров на своём железе доступен отдельной командой.

Что ставить сейчас и что осталось до 1.0

Release candidate уже опубликован: 21 сентября 2026 года вышел пре-релиз Release candidate v1.0.0.rc.2, тег подписан ключом коммиттера. Ставится он как обычная версия — cargo add tokenizers --pre; если обучение не нужно, из сборки можно исключить тренер флагами --no-default-features --features http, а в Python работает pip install --pre tokenizers.

Вызовы не меняются, и это часть обещания: «API, который вы вызываете, — тот же», меняется только сборка, которую вы ставите. Кодирование остаётся прежним вызовом с теми же ID, а для пакетов по ядрам масштабируется именно encode_batch — его и измеряет график масштабирования; в release candidate появились и биндинги для Node.js.

До 1.0 остаётся вернуть полный Python API в стиле transformers: обучение, пакетное кодирование с zero-copy-представлениями, dlpack-интероп, работу с парами входов, сохранение и композицию компонентов конвейера. В списке для 1.0.0 — одна реализация кодирования, чтобы обучение и инференс не могли дать разную токенизацию, опциональные офсеты и маски, переработка нормализаторов, упрощённые Python-биндинги и inference-only биндинги на C и C++ для ExecuTorch и llama.cpp; после 1.0.0 планируется tok-devices — эксперименты с кодированием и пакетным декодированием на GPU.

Первоисточники

  1. Hugging Face — Arthur Zucker, Simon Brandeis, Luc Georges, Lysandre, «tokenizers v1: encode, decode and scaling, measured» (21 сентября 2026)
  2. Hugging Face — «tokenizers v1 benchmarks»: официальная страница замеров релиз-кандидата (21 сентября 2026)
  3. GitHub — huggingface/tokenizers, пре-релиз «Release candidate v1.0.0.rc.2» (21 сентября 2026)
  4. GitHub — huggingface/tokenizers: официальный репозиторий библиотеки, README и план v1.0.0
  5. GitHub — huggingface/tokbench: официальный стенд для сравнения токенизаторов, на котором получены замеры