Gigatoken: tokenizer BPE oparty na Rust osiągający 24,53 GB/s, do 989x szybciej niż HuggingFace Tokenizers
Najważniejsze informacje
- •Gigatoken 0.9.0 to oparty na Rust tokenizer BPE z wiązaniami dla Pythona, wydany na licencji MIT i dostępny na PyPI.
- •Na 144-rdzeniowym systemie AMD EPYC 9565 Gigatoken przetworzył workload GPT-2 z szybkością 24,53 GB/s, w porównaniu z 36,0 MB/s dla tiktoken i 24,8 MB/s dla HuggingFace tokenizers.
- •Główne usprawnienia wydajności biblioteki wynikają z ręcznie napisanego pretokenizera, optymalizacji opartej na SWAR, równoległości na poziomie instrukcji z dwoma kursorami, cache’owania pretokenów i ograniczonej interakcji z Pythonem.
- •Gigatoken obsługuje 23 rodziny tokenizerów i pokazuje mocne wyniki na systemach x86 i ARM, ale przyspieszenia dla SentencePiece są niższe, a WordPiece nie jest obsługiwany.
- •Niezależna reprodukcja KrabArena wykazała, że Gigatoken 0.9.0 był 26,2x szybszy niż tiktoken i 83,4x szybszy niż HuggingFace tokenizers na maszynie wirtualnej Intel Xeon VM z 4 vCPU.

Tokenizacja — etap wstępnego przetwarzania, który przekształca surowy tekst w numeryczne sekwencje tokenów faktycznie używane przez modele językowe — pozostaje jednym z najrzadziej profilowanych komponentów stosu ML. Wraz ze wzrostem zbiorów treningowych do skali terabajtów i petabajtów czas poświęcony na tę konwersję może stać się praktycznym wąskim gardłem w potokach przygotowania danych, choć rzadko jest głównym celem optymalizacji. Gigatoken, nowa biblioteka wydana przez Marcela Røda, doktoranta Stanfordu, na licencji MIT, pokazuje, że to przeoczenie ma koszt. Biblioteka osiąga kodowanie tekstu z szybkością gigabajtów na sekundę na pojedynczej maszynie, przewyższając punkty odniesienia, które już są zaimplementowane w wielowątkowym Rust.
Wyniki benchmarków
W benchmarku tokenizera GPT-2 z użyciem korpusu owt_train.txt o wielkości 11,9 GB na 144-rdzeniowym, dwuprocesorowym systemie AMD EPYC 9565, Gigatoken przetwarza dane z szybkością 24,53 GB/s. Na tym samym sprzęcie OpenAI's tiktoken — biblioteka używana do kodowania tekstu dla modeli GPT — osiąga 36,0 MB/s, a HuggingFace tokenizers — de facto standard tokenizacji w ekosystemie open-source ML — rejestruje 24,8 MB/s, co przekłada się odpowiednio na przewagę wydajności 681x i 989x.
Przyspieszenie jest spójne między architekturami. Na Apple M4 Max z 16 rdzeniami ten sam workload GPT-2 działa z szybkością 8,79 GB/s — 1,268x szybciej niż HuggingFace tokenizers i 140x szybciej niż tiktoken. Na konsumenckim AMD Ryzen 7 9800X3D Gigatoken osiąga 6,27 GB/s, co oznacza przyspieszenia 106x i 68x względem odpowiednich punktów odniesienia.
Czym jest Gigatoken
Gigatoken to tokenizer byte-pair encoding (BPE) napisany w Rust, z wiązaniami dla Pythona. BPE jest dominującym algorytmem tokenizacji podwyrazowej dla współczesnych LLM, używanym m.in. przez rodziny GPT, Llama, Qwen i Mistral. Jest dostępny na PyPI jako gigatoken (wersja 0.9.0, wydana 21 July 2026) i można go zainstalować przez pip install gigatoken. Baza kodu składa się w 66,2% z Rust i w 33,3% z Pythona. Opublikowane benchmarki obejmują 23 odrębne rodziny tokenizerów, w tym GPT-2, GPT-OSS, Llama 3 through 4, Qwen 2 through 3.6, DeepSeek V3/R1/V4, GLM 4 and 5, Kimi K2, Nemotron 3, Phi-4, OLMo 2/3, ModernBERT, Gemma i Mistral.
Gigatoken oferuje dwa tryby użycia. Tryb zgodności opakowuje istniejący tokenizer HuggingFace lub tiktoken, zachowując dokładną zgodność wyników kosztem przepustowości. Rød stwierdził na Hacker News, że tryb zgodności zapewnia przyspieszenie rzędu 200–300x w zależności od sposobu użycia, ponieważ nadal ponosi narzut Pythona związany z tworzeniem list i konwersją stringów na bajty. Natywne API Gigatoken, które pozwala Rust bezpośrednio odczytywać pliki, jest źródłem opublikowanych wyników benchmarków.
Podejście techniczne
Zyski wydajności nie wynikają z szybszej pętli łączenia BPE. Zamiast tego pochodzą z dwóch obszarów, które większość tokenizerów traktuje jako już rozwiązane.
Optymalizacja pretokenizacji
Większość implementacji deleguje pretokenizację do silnika regex. Gigatoken zapisuje cały pretokenizer ręcznie. dziennik optymalizacji pretokenizera śledzi jednowątkową przepustowość pretokenizera GPT-2 na 100 MB OpenWebText, pokazując szczegółową progresję:
- Punkt odniesienia
fancy-regexdziała z szybkością około 47 MiB/s. - Ręcznie napisana maszyna stanów osiąga około 380 MiB/s.
- Implementacja kombinatorowa
winnowz intrinsics NEON SIMD osiąga 462 MiB/s.
Dalsza optymalizacja polegała na zastąpieniu winnow bezpośrednim Iteratorem, dodaniu 256-bajtowej tabeli wyszukiwania klas dla dyspozycji pierwszego bajtu w O(1) oraz przejściu z intrinsics NEON na SWAR (SIMD Within A Register). SWAR ładuje 8 bajtów jako u64 i sprawdza wszystkie 8 pod kątem właściwości litery przy użyciu arytmetyki bez rozgałęzień, bez wymagania intrinsics specyficznych dla architektury. To podniosło przepustowość do 830 MiB/s.
Ostatni etap optymalizacji obejmował wykorzystanie równoległości na poziomie instrukcji (ILP) z dwoma kursorami, osiągając 1,049 MiB/s. Kluczową obserwacją było to, że wąskim gardłem przy około 840 MiB/s była latencja, a nie przepustowość. Pozycja końcowa każdego tokenu zależy od poprzedniego, tworząc szeregową sekwencję około 25–27 cykli. Uruchomienie dwóch niezależnych kursorów z bezpiecznego punktu podziału pozwala silnikowi wykonywania poza kolejnością przeplatać oba strumienie na niewykorzystywanych portach wykonawczych.
Efekt netto dla samego pretokenizera: 2,27x względem punktu odniesienia winnow + NEON oraz 22,3x względem implementacji regex.
Cache’owanie pretokenów
Gdy słowo pojawiło się wcześniej, jego zakodowane tokeny są pobierane zamiast ponownie obliczane. Rød zauważa, że w praktyce jest to trudne, ponieważ cache szybko rośnie, a rozkłady pretokenów mają długi ogon. Dodatkowo interakcje z Pythonem są minimalizowane, a wątki zaprojektowano tak, by wchodziły ze sobą w jak najmniejszą interakcję.
Dziennik optymalizacji dokumentuje również podejścia, które nie zadziałały. Podział hot/cold z użyciem #[cold] i #[inline(never)] cofnął wydajność do 580 MiB/s i został wycofany, ponieważ bariera inline uniemożliwiała LLVM optymalizację połączonej pętli ASCII i unicode. Dwupassowy bufor klasyfikacji ze zliczaniem przejść SWAR był poprawny algorytmicznie, ale działał z szybkością 354 MiB/s, ponieważ dodatkowy ruch w pamięci przeważył nad oszczędnościami z rozgałęzień. Optymalizacja kierowana profilowaniem nie miała mierzalnego efektu, ponieważ pętla wewnętrzna jest już bezrozgałęzieniowa, a rozgałęzienie granicy słowa zależy od danych.
Metodologia benchmarków
Porównanie nie jest ściśle apples-to-apples. Gigatoken koduje całe, niepodzielone pliki, samodzielnie wykrywa granice dokumentów i automatycznie równolegli pracę. HuggingFace (encode_batch_fast) jest oceniany na pierwszych 100 MB, podczas gdy tiktoken (encode_ordinary_batch) na pierwszym 1 GB, oba wstępnie podzielone po <|endoftext|>. Ponieważ punkty odniesienia nie implementują cache’owania, ich przepustowość pozostaje jednolita. Wszystkie pomiary raportują najlepszy wynik z trzech przeplatanych rund z użyciem świeżych procesów i włączoną równoległością.
Typ słownika również wprowadza ograniczenia. Tokenizery SentencePiece są zoptymalizowane tylko częściowo. Na EPYC, Gemma 1 przetwarza z szybkością 2,51 GB/s (przyspieszenie 7,3x), Gemma 3 z szybkością 3,43 GB/s (9,6x), a CodeLlama z szybkością 3,47 GB/s (10,0x). Choć są to znaczące zyski, są one o rząd wielkości niższe niż nagłówkowe wyniki wydajności BPE.
Niezależna reprodukcja na KrabArena zweryfikowała wyniki. Na maszynie wirtualnej Intel Xeon VM z 4 vCPU (2,20 GHz) i fragmentem OpenWebText o wielkości 174 MB, Gigatoken 0.9.0 osiągnął medianę 277,8 MB/s, przewyższając tiktoken 0.13.0 (10,62 MB/s) o 26,2x oraz tokenizers 0.23.1 (3,33 MB/s) o 83,4x. Wszystkie próby pomyślnie zwalidowały 35,356 dokumentów, potwierdzając, że trend wydajności skaluje się wraz z liczbą rdzeni.
Zakres i ograniczenia
Przyspieszenie Gigatoken utrzymuje się zarówno na architekturach x86, jak i ARM oraz we wszystkich 23 obsługiwanych rodzinach tokenizerów, zamiast ograniczać się do jednej dostrojonej konfiguracji. Jednak słowniki SentencePiece osiągają przyspieszenia 7–22x zamiast zysków rzędu 1,000x, a WordPiece nie jest obsługiwany. Tryb zgodności zachowuje dokładną zgodność wyników HuggingFace przy około 200–300x, a nie przy pełnym natywnym przyspieszeniu.
Repozytorium GitHub oraz eksplorator benchmarków są publicznie dostępne.