gigatoken 検証:トークナイザを GB/s で回す Rust 実装とその代償
Language model tokenization at GB/s
ひと目でわかる
- これは何?
- gigatoken は HuggingFace tokenizers と比較して約1000倍を主張する Rust 製トークナイザ。互換モードとネイティブAPIの速度差、ライセンス、そして採用前に確認すべき境界を README の記述だけから整理する。
- 誰に向いている?
- 大量のテキストを前処理する学習パイプラインを持ち、トークナイズがボトルネックになっているチームは gigatoken のネイティブAPIを試す価値がある。逆に、トークナイズが全体の数パーセントしか占めない推論サービスの開発者や、HuggingFace の全機能(特殊トークンの追加、truncation、padding など)に依存しているコードベースには向かない。
- 商用利用できる?
- できます。MIT は寛容なライセンスで、著作権表示とライセンス表示を残せば、使用・改変・販売が可能です。
- 今もメンテナンスされている?
- されています。最後のコミットは 14 日前です。
- 何の言語で書かれている?
- 主に Rust です(GitHub の言語統計による)。
回答はプロジェクトの GitHub データ(最終同期:2026年9月15日)と当サイトの分析に基づくもので、法的助言ではありません。
オープンソース詳細解説
gigatoken が埋めようとしている穴
言語モデルの学習では、数GBから数十GBのテキストをトークン列に変換する前処理が必ず走る。この処理はGPUを使わず、CPUとメモリ帯域だけで完結する。README は HuggingFace の tokenizers と tiktoken が「すでにマルチスレッドの Rust で動いている」とわざわざ断ったうえで、それでもなお約1000倍を主張している。つまり対象は、トークナイズが明らかにボトルネックになっている大規模コーパスの前処理である。11.9 GB の owt_train.txt を丸ごと符号化するベンチマークが同梱されており、想定ユースケースは「ファイルを読んでトークンIDの列を吐く」という一方向のバッチ処理だ。対話型の推論サーバのように、1リクエスト数十トークンを何度も符号化する用途は想定されていない。
速度差が生まれる2つの経路
gigatoken には使い方が2つある。1つは gt.Tokenizer(hf_tokenizer).as_hf() のように既存のトークナイザを包む互換モード、もう1つは gt.Tokenizer("Qwen/Qwen3-8B") のようにモデル名を直接渡すネイティブAPIだ。README は互換モードについて「出力を HuggingFace Tokenizers と完全に一致させるために相当な労力が払われたが、その代償として性能が無視できないほど落ちる」と明記している。1000倍という数字はネイティブAPIのもので、互換モードではそこまで出ない。ネイティブAPIが速い理由も README が説明している。Rust 側がファイルを直接読み、Python のデータ構造を経由するオーバーヘッドを可能な限り飛ばす。逆に言えば、Python のリストをネイティブAPIに渡すと、その時点で Python 側の読み出しコストが乗る。速度はデータの入口がファイルか Python オブジェクトかで決まる。
インストールと最小の実行例
導入は pip install gigatoken の一語で済む。ネイティブAPIの例は README にこうある。tokenizer = gt.Tokenizer("Qwen/Qwen3-8B") でモデルを指定し、file_source = gt.TextFileSource(["owt_train.txt"], separator=b"<|endoftext|>") でファイルと区切りバイト列を渡し、tokens = tokenizer.encode_files(file_source) で符号化する。separator に bytes を渡す点が特徴で、ドキュメントの境界をバイト列として指定する設計だ。互換モード側は hf_tokenizer = ... のあとに tokenizer = gt.Tokenizer(hf_tokenizer).as_hf() とし、tokens = tokenizer.encode_batch(["This is a test string", "And here is another"]) を呼ぶ。tiktoken を使っている場合は .as_tiktoken() に切り替える。既存コードの変更点はこの1行に収まる。
ベンチマーク表は万能ではない
README の表は3つのCPU(AMD EPYC 9565 の2ソケット144コア、Apple M4 Max 16コア、AMD Ryzen 7 9800X3D 16コア)で、モデルごとに速度を並べている。注目すべきは最下段の傾向だ。M4 Max では Mistral 7B v0.3 が 1.99 GB/s で HF 比21倍、Gemma 1 が 1.42 GB/s で17倍にとどまる。EPYC では Gemma 1 が 2.51 GB/s で7.3倍、Mistral 7B v0.3 が 3.57 GB/s で10倍だ。GPT-2 の989倍や OLMo 2 の833倍と比べると桁が2つ違う。つまり「約1000倍」はトークナイザの種類に強く依存し、SentencePiece 系のモデルでは1桁台の倍率になる。自分のモデルが表のどこに位置するかを確認せずに期待値を決めると外す。なお、この表は README に記載された数値であり、本記事では追試していない。
互換モードという安全弁とそのコスト
互換モードの存在は、採用のハードルを下げる。既存の HuggingFace パイプラインを丸ごと書き換えずに、トークナイザの生成箇所だけ差し替えて速度を測れる。ただし README は、完全一致を優先した結果として性能が落ちると明言している。ここから読み取れる設計判断はこうだ。互換モードは移行と検証のための足場であり、最終的な性能を引き出す経路ではない。本番でネイティブAPIに切り替えるなら、encode_files の入力がファイルである必要があるため、データの流れそのものをファイル前提に組み替えることになる。ストリーミングで生成したテキストをその場で符号化する用途には、この入口の設計が合わない。
採用を見送るべきケース
第一に、トークナイズが処理時間のごく一部しか占めないシステム。推論APIのようにモデル実行が支配的な場面では、符号化を何倍速くしても全体はほとんど変わらない。第二に、HuggingFace tokenizers の付随機能に依存しているコード。互換モードは encode_batch の例が示されているが、README が一致を保証しているのは符号化の出力であり、truncation や padding、特殊トークンの動的な追加といった周辺APIの網羅性は記述からは確認できない。第三に、モデルの対応状況。Kimi K2 は3つの表すべてで HF 側の数値が空欄であり、比較対象が存在しない。自分のモデルが表にない場合、対応しているかどうかを別途確かめる必要がある。ライセンスは MIT で、派生物の再配布や商用利用の条件はこの表示から読み取れる範囲では緩い。ただし依存するトークナイザ定義やモデル重みのライセンスは別問題であり、そちらは各モデルの配布元で確認する必要がある。
tiktoken との違いは何か
比較対象として README が繰り返し挙げるのは tiktoken だ。両者は同じ問題を別の角度から解いている。tiktoken は OpenAI 系モデルのトークナイザを Python から使うための実装で、README の表でも GPT-2 と GPT-OSS の列にだけ数値が入っている。対応するモデル群が限られる。gigatoken は逆に、Qwen、Llama、Gemma、DeepSeek、GLM、Phi、OLMo、Nemotron、Kimi といった幅広い系列を1つのAPIで扱うことを狙っている。表の列が空欄なのは tiktoken 側であり、これは対応範囲の差がそのまま現れたものだ。速度でも GPT-2 で tiktoken の 36.0 MB/s に対し gigatoken は 24.53 GB/s、M4 Max では 62.8 MB/s に対し 8.79 GB/s と、README の数値上は大きく開く。ただし tiktoken は推論時の符号化に向いた軽量な道具で、大量コーパスの一括変換を主目的にはしていない。用途が違う。
編集部の結論
大量のテキストを前処理する学習パイプラインを持ち、トークナイズがボトルネックになっているチームは gigatoken のネイティブAPIを試す価値がある。逆に、トークナイズが全体の数パーセントしか占めない推論サービスの開発者や、HuggingFace の全機能(特殊トークンの追加、truncation、padding など)に依存しているコードベースには向かない。採用前に確認すべきは、自分の使うモデルのトークナイザが README のベンチマーク表に載っているか、そして互換モードの出力が既存パイプラインと完全に一致するかである。
コミュニティノート