Ce qui se passe
Hugging Face publie une version candidate de tokenizers v1, la bibliothèque
Rust qui transforme le texte en identifiants de tokens pour une large part de
l'écosystème. La tokenisation pesait peu face au calcul du modèle ; avec des
entraînements sur des corpus massifs, beaucoup de requêtes concurrentes et de
longs contextes, elle finit par laisser le GPU attendre le processeur. Le billet
du 21 septembre 2026 mesure la réponse.
Les chiffres
Sur les dix familles de modèles couvertes par le nouveau chemin d'encodage, et sur un Apple M4 Max :
- 3 à 30 fois plus rapide que la v0.23 sur un seul thread — t5-base en bas de l'échelle, gpt2 en haut ;
- 76 % d'un passage à l'échelle linéaire sur 8 cœurs physiques ;
- mêmes identifiants de tokens que la version publiée, contrôlés par une empreinte FNV-1a sur chaque sortie.
Le protocole est publié avec l'outil tokbench : même boucle de mesure pour tous les moteurs, chargement du vocabulaire exclu, cœurs épinglés, un processus neuf par répétition. Le billet insiste sur un piège : réencoder un même document profite entièrement du cache et gonfle les résultats ; les chiffres annoncés portent sur des documents distincts, sur un corpus trop grand pour tenir en cache.
D'où vient le gain
Le travail porte surtout sur l'étape du modèle, où se font les fusions BPE — huit des dix familles mesurées utilisent BPE, les deux autres WordPiece et Unigram.
- Découpage sans expression régulière. Le motif qui coupe le texte en pré-tokens est fixe pour un modèle donné. Plutôt qu'un moteur de regex généraliste, bitcannon traite les octets comme des flux de bits et trouve les frontières par opérations booléennes SIMD, 64 octets à la fois — l'idée de simdjson. Motifs couverts : GPT-2, cl100k, o200k, Tekken et DeepSeek.
- Cache de mots. Un même pré-token donne toujours les mêmes identifiants : un cache par thread évite de refaire les fusions d'un mot déjà vu.
- Boucle de fusion sans allocation. Tampon de travail réutilisé, liste chaînée dans un tableau préalloué, et chaque paire candidate codée sur un entier de 64 bits, rang en poids fort : comparer deux candidats revient à comparer deux entiers.
- Appels par lots au modèle, et un tokenizer partagé entre threads sans verrou unique.
La crate est aussi découpée : tk-encode suffit à l'exécution, tk-serialize,
tk-convert et tk-train ne sont liés qu'au besoin.
La limite
C'est une préversion Rust. Les liaisons Python enveloppent le même code mais
ajoutent un coût par appel qu'aucune mesure n'inclut, et leur simplification
est prévue pour la 1.0.0, comme des liaisons C et C++ destinées à ExecuTorch
et llama.cpp. Des liaisons Node.js figurent parmi les travaux déjà faits. Un
tokenizer dont le motif de découpage n'est pas reconnu garde l'ancien chemin
regex, et le gain qui va avec. L'intégration dans transformers viendra une fois
les versions candidates stabilisées.
Comment s'y prendre
cargo add tokenizers --pre
# encodage seul, sans le code d'entraînement et sa dépendance C++
cargo add tokenizers --pre --no-default-features --features httpL'API ne change pas : Tokenizer::from_pretrained, encode, et
encode_batch pour répartir sur plusieurs cœurs. Mesurer ensuite sur son propre
corpus avec tokbench, en distinguant documents répétés et documents distincts.
Source : tokenizers v1: encode, decode and scaling, measured, blog Hugging Face, 21 septembre 2026.