{"id":22582,"date":"2004-08-22T14:01:28","date_gmt":"2004-08-22T14:01:28","guid":{"rendered":"https:\/\/scannn.com\/marcelroed-gigatoken-language-model-tokenization-at-gb-s-%c2%b7-github\/"},"modified":"2004-08-22T14:01:28","modified_gmt":"2004-08-22T14:01:28","slug":"marcelroed-gigatoken-language-model-tokenization-at-gb-s-%c2%b7-github","status":"publish","type":"post","link":"https:\/\/scannn.com\/lv\/marcelroed-gigatoken-language-model-tokenization-at-gb-s-%c2%b7-github\/","title":{"rendered":"marcelroed\/gigatoken: Language model tokenization at GB\/s \u00b7 GitHub"},"content":{"rendered":"\n<div id=\"\">\n<div align=\"center\" dir=\"auto\">\n<p dir=\"auto\">~1000x faster than HuggingFace&#8217;s tokenizers, drop-in replacement.<\/p>\n<p dir=\"auto\"><em>Tokenize your text data at GB\/s!<\/em><\/p>\n<p dir=\"auto\"><a target=\"_blank\" rel=\"noopener noreferrer nofollow\" href=\"https:\/\/raw.githubusercontent.com\/marcelroed\/gigatoken\/main\/assets\/throughput_owt_train_gpt-2.svg\"><\/a><\/p>\n<p dir=\"auto\">Note that both HF tokenizers and tiktoken are already running multithreaded Rust!<\/p>\n<\/div>\n<p dir=\"auto\">Gigatoken is the fastest tokenizer for language modeling.<br \/>\nIt supports a wide range of CPU hardware, and nearly all commonly used tokenizers.<br \/>\nSee the <a href=\"#benchmarks\">Benchmarks<\/a> section for detailed throughput numbers across tokenizers and CPUs.<\/p>\n<p dir=\"auto\">Gigatoken can be used with its own API, or in compatibility mode with HuggingFace Tokenizers or Tiktoken.<\/p>\n<div class=\"markdown-heading\" dir=\"auto\">\n<h3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\">Compatibility Mode (Easiest)<\/h3>\n<p><a id=\"user-content-compatibility-mode-easiest\" class=\"anchor\" aria-label=\"Permalink: Compatibility Mode (Easiest)\" href=\"#compatibility-mode-easiest\"><svg data-component=\"Octicon\" class=\"octicon octicon-link\" viewbox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"><path d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\/><\/svg><\/a><\/div>\n<div class=\"highlight highlight-source-python notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"import gigatoken as gt&#10;&#10;# Minimum change from existing HuggingFace tokenizers usage (compatibility mode)&#10;hf_tokenizer = ...&#10;tokenizer = gt.Tokenizer(hf_tokenizer).as_hf()&#10;&#10;# tokenizer can be used in the same contexts as hf_tokenizer&#10;tokens = tokenizer.encode_batch([&quot;This is a test string&quot;, &quot;And here is another&quot;])&#10;&#10;# OR with tiktoken&#10;tiktokenizer = ...&#10;tokenizer = gt.Tokenizer(tiktokenizer).as_tiktoken()&#10;&#10;# Now works like existing tiktoken tokenizers&#10;tokens = tokenizer.encode_batch([&quot;This is a test string&quot;, &quot;And here is another&quot;])\">\n<pre><span class=\"pl-k\">import<\/span> <span class=\"pl-s1\">gigatoken<\/span> <span class=\"pl-k\">as<\/span> <span class=\"pl-s1\">gt<\/span>\n\n<span class=\"pl-c\"># Minimum change from existing HuggingFace tokenizers usage (compatibility mode)<\/span>\n<span class=\"pl-s1\">hf_tokenizer<\/span> <span class=\"pl-c1\">=<\/span> ...\n<span class=\"pl-s1\">tokenizer<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-s1\">gt<\/span>.<span class=\"pl-c1\">Tokenizer<\/span>(<span class=\"pl-s1\">hf_tokenizer<\/span>).<span class=\"pl-c1\">as_hf<\/span>()\n\n<span class=\"pl-c\"># tokenizer can be used in the same contexts as hf_tokenizer<\/span>\n<span class=\"pl-s1\">tokens<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-s1\">tokenizer<\/span>.<span class=\"pl-c1\">encode_batch<\/span>([<span class=\"pl-s\">\"This is a test string\"<\/span>, <span class=\"pl-s\">\"And here is another\"<\/span>])\n\n<span class=\"pl-c\"># OR with tiktoken<\/span>\n<span class=\"pl-s1\">tiktokenizer<\/span> <span class=\"pl-c1\">=<\/span> ...\n<span class=\"pl-s1\">tokenizer<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-s1\">gt<\/span>.<span class=\"pl-c1\">Tokenizer<\/span>(<span class=\"pl-s1\">tiktokenizer<\/span>).<span class=\"pl-c1\">as_tiktoken<\/span>()\n\n<span class=\"pl-c\"># Now works like existing tiktoken tokenizers<\/span>\n<span class=\"pl-s1\">tokens<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-s1\">tokenizer<\/span>.<span class=\"pl-c1\">encode_batch<\/span>([<span class=\"pl-s\">\"This is a test string\"<\/span>, <span class=\"pl-s\">\"And here is another\"<\/span>])<\/pre>\n<\/div>\n<p dir=\"auto\">A substantial amount of effort has been put into making sure the outputs match exactly with what you would get with HuggingFace Tokenizers in this setting, but this is at a non-negligible cost to performance.<br \/>\nYou can still expect way faster performance across the board, but not quite the 1000x you will get with the Gigatoken API.<\/p>\n<div class=\"highlight highlight-source-python notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"import gigatoken as gt&#10;&#10;tokenizer = gt.Tokenizer(&quot;Qwen\/Qwen3-8B&quot;)  # Accepts HF model names&#10;file_source = gt.TextFileSource([&quot;owt_train.txt&quot;], separator=b&quot;&lt;|endoftext|&gt;&quot;)&#10;tokens = tokenizer.encode_files(file_source)\">\n<pre><span class=\"pl-k\">import<\/span> <span class=\"pl-s1\">gigatoken<\/span> <span class=\"pl-k\">as<\/span> <span class=\"pl-s1\">gt<\/span>\n\n<span class=\"pl-s1\">tokenizer<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-s1\">gt<\/span>.<span class=\"pl-c1\">Tokenizer<\/span>(<span class=\"pl-s\">\"Qwen\/Qwen3-8B\"<\/span>)  <span class=\"pl-c\"># Accepts HF model names<\/span>\n<span class=\"pl-s1\">file_source<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-s1\">gt<\/span>.<span class=\"pl-c1\">TextFileSource<\/span>([<span class=\"pl-s\">\"owt_train.txt\"<\/span>], <span class=\"pl-s1\">separator<\/span><span class=\"pl-c1\">=<\/span><span class=\"pl-s\">b\"&lt;|endoftext|&gt;\"<\/span>)\n<span class=\"pl-s1\">tokens<\/span> <span class=\"pl-c1\">=<\/span> <span class=\"pl-s1\">tokenizer<\/span>.<span class=\"pl-c1\">encode_files<\/span>(<span class=\"pl-s1\">file_source<\/span>)<\/pre>\n<\/div>\n<p dir=\"auto\">Using the Gigatoken API lets the Rust implementation read data directly, and skips as much overhead as possible while allowing for maximum parallelism.<br \/>\nKeep in mind that passing Python data structures through this API still incurs the overhead of reading from Python.<\/p>\n<details>\n<summary><b>Encoding throughput on owt_train.txt (11.9 GB) \u2014 AMD EPYC 9565 72-Core Processor x 2 sockets (144 cores)<\/b><\/summary>\n<p><markdown-accessiblity-table><\/p>\n<table>\n<thead>\n<tr>\n<th>Tokenizer<\/th>\n<th align=\"right\">gigatoken<\/th>\n<th align=\"right\">HF tokenizers<\/th>\n<th align=\"right\">tiktoken<\/th>\n<th align=\"right\">vs HF<\/th>\n<th align=\"right\">vs tiktoken<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>GPT-2<\/td>\n<td align=\"right\">24.53 GB\/s<\/td>\n<td align=\"right\">24.8 MB\/s<\/td>\n<td align=\"right\">36.0 MB\/s<\/td>\n<td align=\"right\">989\u00d7<\/td>\n<td align=\"right\">681\u00d7<\/td>\n<\/tr>\n<tr>\n<td>Phi-4<\/td>\n<td align=\"right\">24.00 GB\/s<\/td>\n<td align=\"right\">29.9 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">801\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>GPT-OSS<\/td>\n<td align=\"right\">23.96 GB\/s<\/td>\n<td align=\"right\">49.7 MB\/s<\/td>\n<td align=\"right\">42.8 MB\/s<\/td>\n<td align=\"right\">482\u00d7<\/td>\n<td align=\"right\">560\u00d7<\/td>\n<\/tr>\n<tr>\n<td>OLMo 2 \/ 3<\/td>\n<td align=\"right\">23.06 GB\/s<\/td>\n<td align=\"right\">27.7 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">833\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Nemotron 3<\/td>\n<td align=\"right\">22.79 GB\/s<\/td>\n<td align=\"right\">49.4 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">462\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Qwen 3<\/td>\n<td align=\"right\">22.16 GB\/s<\/td>\n<td align=\"right\">34.2 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">648\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Llama 3 \/ 3.1 \/ 3.2<\/td>\n<td align=\"right\">22.15 GB\/s<\/td>\n<td align=\"right\">48.5 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">457\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>GLM 5<\/td>\n<td align=\"right\">20.97 GB\/s<\/td>\n<td align=\"right\">74.8 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">280\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Llama 3.3<\/td>\n<td align=\"right\">20.82 GB\/s<\/td>\n<td align=\"right\">48.3 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">431\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Llama 4<\/td>\n<td align=\"right\">20.77 GB\/s<\/td>\n<td align=\"right\">72.7 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">286\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>GLM 4<\/td>\n<td align=\"right\">20.61 GB\/s<\/td>\n<td align=\"right\">72.3 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">285\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Phi-4-mini<\/td>\n<td align=\"right\">20.05 GB\/s<\/td>\n<td align=\"right\">27.6 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">726\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>DeepSeek V3 \/ R1 \/ V4<\/td>\n<td align=\"right\">19.69 GB\/s<\/td>\n<td align=\"right\">26.2 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">750\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Qwen 2 \/ 2.5<\/td>\n<td align=\"right\">19.12 GB\/s<\/td>\n<td align=\"right\">27.7 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">691\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Kimi K2<\/td>\n<td align=\"right\">18.85 GB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Qwen 3.5 \/ 3.6<\/td>\n<td align=\"right\">15.49 GB\/s<\/td>\n<td align=\"right\">27.7 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">558\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Gemma 4<\/td>\n<td align=\"right\">4.82 GB\/s<\/td>\n<td align=\"right\">334.1 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">14\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>ModernBERT<\/td>\n<td align=\"right\">4.18 GB\/s<\/td>\n<td align=\"right\">26.9 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">155\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Mistral 7B v0.3<\/td>\n<td align=\"right\">3.57 GB\/s<\/td>\n<td align=\"right\">354.7 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">10\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>TinyLlama \/ Phi-3 (Llama 2)<\/td>\n<td align=\"right\">3.48 GB\/s<\/td>\n<td align=\"right\">323.6 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">11\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>CodeLlama<\/td>\n<td align=\"right\">3.47 GB\/s<\/td>\n<td align=\"right\">347.4 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">10.0\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Gemma 3<\/td>\n<td align=\"right\">3.43 GB\/s<\/td>\n<td align=\"right\">357.2 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">9.6\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Gemma 1<\/td>\n<td align=\"right\">2.51 GB\/s<\/td>\n<td align=\"right\">342.2 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">7.3\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><\/markdown-accessiblity-table><br \/>\n<\/details>\n<details>\n<summary><b>Encoding throughput on owt_train.txt (11.9 GB) \u2014 Apple M4 Max (16 cores)<\/b><\/summary>\n<p><markdown-accessiblity-table><\/p>\n<table>\n<thead>\n<tr>\n<th>Tokenizer<\/th>\n<th align=\"right\">gigatoken<\/th>\n<th align=\"right\">HF tokenizers<\/th>\n<th align=\"right\">tiktoken<\/th>\n<th align=\"right\">vs HF<\/th>\n<th align=\"right\">vs tiktoken<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>GPT-2<\/td>\n<td align=\"right\">8.79 GB\/s<\/td>\n<td align=\"right\">6.9 MB\/s<\/td>\n<td align=\"right\">62.8 MB\/s<\/td>\n<td align=\"right\">1,268\u00d7<\/td>\n<td align=\"right\">140\u00d7<\/td>\n<\/tr>\n<tr>\n<td>Nemotron 3<\/td>\n<td align=\"right\">7.82 GB\/s<\/td>\n<td align=\"right\">10.9 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">715\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Phi-4<\/td>\n<td align=\"right\">7.76 GB\/s<\/td>\n<td align=\"right\">7.7 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">1,012\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Llama 3 \/ 3.1 \/ 3.2<\/td>\n<td align=\"right\">7.60 GB\/s<\/td>\n<td align=\"right\">11.2 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">676\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>OLMo 2 \/ 3<\/td>\n<td align=\"right\">7.56 GB\/s<\/td>\n<td align=\"right\">5.8 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">1,299\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Llama 3.3<\/td>\n<td align=\"right\">7.50 GB\/s<\/td>\n<td align=\"right\">15.7 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">479\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Phi-4-mini<\/td>\n<td align=\"right\">6.97 GB\/s<\/td>\n<td align=\"right\">7.2 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">964\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Kimi K2<\/td>\n<td align=\"right\">6.88 GB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Llama 4<\/td>\n<td align=\"right\">6.81 GB\/s<\/td>\n<td align=\"right\">11.6 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">590\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Qwen 2 \/ 2.5<\/td>\n<td align=\"right\">6.37 GB\/s<\/td>\n<td align=\"right\">5.8 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">1,105\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Qwen 3<\/td>\n<td align=\"right\">6.36 GB\/s<\/td>\n<td align=\"right\">6.9 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">918\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Qwen 3.5 \/ 3.6<\/td>\n<td align=\"right\">6.31 GB\/s<\/td>\n<td align=\"right\">6.3 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">994\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>GPT-OSS<\/td>\n<td align=\"right\">6.20 GB\/s<\/td>\n<td align=\"right\">20.2 MB\/s<\/td>\n<td align=\"right\">87.2 MB\/s<\/td>\n<td align=\"right\">306\u00d7<\/td>\n<td align=\"right\">71\u00d7<\/td>\n<\/tr>\n<tr>\n<td>GLM 4<\/td>\n<td align=\"right\">6.17 GB\/s<\/td>\n<td align=\"right\">15.8 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">392\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>DeepSeek V3 \/ R1 \/ V4<\/td>\n<td align=\"right\">5.68 GB\/s<\/td>\n<td align=\"right\">7.2 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">788\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>GLM 5<\/td>\n<td align=\"right\">5.55 GB\/s<\/td>\n<td align=\"right\">12.2 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">456\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>ModernBERT<\/td>\n<td align=\"right\">2.64 GB\/s<\/td>\n<td align=\"right\">5.8 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">452\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Mistral 7B v0.3<\/td>\n<td align=\"right\">1.99 GB\/s<\/td>\n<td align=\"right\">95.1 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">21\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Gemma 4<\/td>\n<td align=\"right\">1.82 GB\/s<\/td>\n<td align=\"right\">85.2 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">21\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>CodeLlama<\/td>\n<td align=\"right\">1.73 GB\/s<\/td>\n<td align=\"right\">80.2 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">22\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>TinyLlama \/ Phi-3 (Llama 2)<\/td>\n<td align=\"right\">1.69 GB\/s<\/td>\n<td align=\"right\">80.1 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">21\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Gemma 1<\/td>\n<td align=\"right\">1.42 GB\/s<\/td>\n<td align=\"right\">85.7 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">17\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Gemma 3<\/td>\n<td align=\"right\">1.38 GB\/s<\/td>\n<td align=\"right\">82.2 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">17\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><\/markdown-accessiblity-table><br \/>\n<\/details>\n<details>\n<summary><b>Encoding throughput on owt_train.txt (11.9 GB) \u2014 AMD Ryzen 7 9800X3D 8-Core Processor (16 cores)<\/b><\/summary>\n<p><markdown-accessiblity-table><\/p>\n<table>\n<thead>\n<tr>\n<th>Tokenizer<\/th>\n<th align=\"right\">gigatoken<\/th>\n<th align=\"right\">HF tokenizers<\/th>\n<th align=\"right\">tiktoken<\/th>\n<th align=\"right\">vs HF<\/th>\n<th align=\"right\">vs tiktoken<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>GPT-2<\/td>\n<td align=\"right\">6.27 GB\/s<\/td>\n<td align=\"right\">59.0 MB\/s<\/td>\n<td align=\"right\">92.1 MB\/s<\/td>\n<td align=\"right\">106\u00d7<\/td>\n<td align=\"right\">68\u00d7<\/td>\n<\/tr>\n<tr>\n<td>Phi-4<\/td>\n<td align=\"right\">6.09 GB\/s<\/td>\n<td align=\"right\">55.4 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">110\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>OLMo 2 \/ 3<\/td>\n<td align=\"right\">6.06 GB\/s<\/td>\n<td align=\"right\">55.4 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">109\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Phi-4-mini<\/td>\n<td align=\"right\">5.80 GB\/s<\/td>\n<td align=\"right\">54.6 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">106\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>GPT-OSS<\/td>\n<td align=\"right\">5.68 GB\/s<\/td>\n<td align=\"right\">79.6 MB\/s<\/td>\n<td align=\"right\">112.7 MB\/s<\/td>\n<td align=\"right\">71\u00d7<\/td>\n<td align=\"right\">50\u00d7<\/td>\n<\/tr>\n<tr>\n<td>Qwen 3<\/td>\n<td align=\"right\">5.34 GB\/s<\/td>\n<td align=\"right\">54.4 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">98\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Qwen 2 \/ 2.5<\/td>\n<td align=\"right\">5.30 GB\/s<\/td>\n<td align=\"right\">51.7 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">103\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Llama 3.3<\/td>\n<td align=\"right\">5.26 GB\/s<\/td>\n<td align=\"right\">79.9 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">66\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Llama 3 \/ 3.1 \/ 3.2<\/td>\n<td align=\"right\">5.24 GB\/s<\/td>\n<td align=\"right\">79.5 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">66\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Kimi K2<\/td>\n<td align=\"right\">5.23 GB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Qwen 3.5 \/ 3.6<\/td>\n<td align=\"right\">5.22 GB\/s<\/td>\n<td align=\"right\">51.6 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">101\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Nemotron 3<\/td>\n<td align=\"right\">5.20 GB\/s<\/td>\n<td align=\"right\">79.0 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">66\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>GLM 5<\/td>\n<td align=\"right\">5.05 GB\/s<\/td>\n<td align=\"right\">79.5 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">63\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>GLM 4<\/td>\n<td align=\"right\">5.04 GB\/s<\/td>\n<td align=\"right\">79.5 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">63\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Llama 4<\/td>\n<td align=\"right\">5.03 GB\/s<\/td>\n<td align=\"right\">78.2 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">64\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>DeepSeek V3 \/ R1 \/ V4<\/td>\n<td align=\"right\">4.21 GB\/s<\/td>\n<td align=\"right\">51.6 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">82\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>ModernBERT<\/td>\n<td align=\"right\">2.84 GB\/s<\/td>\n<td align=\"right\">52.1 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">54\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Mistral 7B v0.3<\/td>\n<td align=\"right\">1.47 GB\/s<\/td>\n<td align=\"right\">91.6 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">16\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Gemma 4<\/td>\n<td align=\"right\">1.45 GB\/s<\/td>\n<td align=\"right\">78.8 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">18\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>CodeLlama<\/td>\n<td align=\"right\">1.38 GB\/s<\/td>\n<td align=\"right\">85.2 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">16\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>TinyLlama \/ Phi-3 (Llama 2)<\/td>\n<td align=\"right\">1.37 GB\/s<\/td>\n<td align=\"right\">84.9 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">16\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Gemma 1<\/td>\n<td align=\"right\">1.14 GB\/s<\/td>\n<td align=\"right\">84.9 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">13\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<tr>\n<td>Gemma 3<\/td>\n<td align=\"right\">1.12 GB\/s<\/td>\n<td align=\"right\">83.0 MB\/s<\/td>\n<td align=\"right\">\u2014<\/td>\n<td align=\"right\">13\u00d7<\/td>\n<td align=\"right\">\u2014<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><\/markdown-accessiblity-table><br \/>\n<\/details>\n<details>\n<summary><b>Benchmark details<\/b><\/summary>\n<p dir=\"auto\">OWT (openwebtext) was chosen because it&#8217;s roughly representative of the text you get after extraction from CommonCrawl documents.<br \/>\nGigatoken encodes the whole file un-split, and is thus doing more work than the other tokenizers to find the split boundaries and automatically parallelize.<br \/>\nHuggingFace tokenizers (<code>encode_batch_fast<\/code>) gets the first 100 MB and tiktoken (<code>encode_ordinary_batch<\/code>) the first 1 GB, both presplit on <code>&lt;|endoftext|&gt;<\/code>.<br \/>\nThis is fair because neither of the compared tokenizers do caching, meaning the speed is roughly uniform throughout processing.<br \/>\nTiktoken rows are currently only filled in for tokenizers with official support.<\/p>\n<p dir=\"auto\">The slowest rows are the SentencePiece-based tokenizers, which are not well optimized in Gigatoken.<\/p>\n<p dir=\"auto\">Each row is one distinct tokenizer (identical vocab\/merges\/pretokenizer), measured on a representative repo.<br \/>\nIf you don&#8217;t see your tokenizer here, it&#8217;s likely based on some existing one.<br \/>\nFor instance:<\/p>\n<ul dir=\"auto\">\n<li><strong>Llama 3 \/ 3.1 \/ 3.2<\/strong> \u2014 Llama 3 \/ 3.1 \/ 3.2, DeepSeek-R1-Distill-Llama, Hermes 3, Saiga, and other Llama-3 finetunes<\/li>\n<li><strong>Llama 3.3<\/strong> \u2014 Llama 3.3, Llama-3.1-Nemotron-Nano-VL, SmolLM3, Kanana 1.5, jina-embeddings-v5, Ultravox<\/li>\n<li><strong>Qwen 2 \/ 2.5<\/strong> \u2014 Qwen 2 and 2.5 (incl. Coder and VL), Qwen3-Coder, Qwen3-VL, DeepSeek-R1 Qwen distills, MiMo V2.5, MiniCPM-o 2.6, InternVL3<\/li>\n<li><strong>Qwen 3<\/strong> \u2014 Qwen 3 (incl. Embedding and Reranker), Qwen2.5-Omni, Qwen3-VL-Embedding, MiMo V2.5 Pro, jina-reranker-m0, pplx-embed, MOSS-TTS, Zeta<\/li>\n<li><strong>DeepSeek V3 \/ R1 \/ V4<\/strong> \u2014 DeepSeek V3 \/ V3.1 \/ V3.2, R1, V4 Flash and Pro, DeepSeek-VL2<\/li>\n<li><strong>GLM 4<\/strong> \u2014 GLM 4.1V, 4.5, and 4.7<\/li>\n<li><strong>GLM 5<\/strong> \u2014 GLM 5 \/ 5.2 and GLM-4.7-Flash<\/li>\n<li><strong>Nemotron 3<\/strong> \u2014 Nemotron 3 Nano, Super, and Ultra<\/li>\n<li><strong>Kimi K2<\/strong> \u2014 Kimi K2 \/ K2.5 \/ K2.6 \/ K2.7, Kimi-Linear, Kimi-VL, Moonlight<\/li>\n<li><strong>Phi-4-mini<\/strong> \u2014 Phi-4-mini and Phi-4-multimodal<\/li>\n<li><strong>TinyLlama \/ Phi-3 (Llama 2)<\/strong> \u2014 TinyLlama, Phi-3-mini, Phi-3.5-mini and Phi-3.5-vision (the Llama 2 vocab)<\/li>\n<li><strong>Gemma 3<\/strong> \u2014 Gemma 3 (270M\u201327B) and EmbeddingGemma<\/li>\n<li><strong>Gemma 4<\/strong> \u2014 Gemma 4 (dense, MoE, and E-series) and DiffusionGemma<\/li>\n<\/ul>\n<\/details>\n<div class=\"markdown-heading\" dir=\"auto\">\n<h3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\">Q: Did you just way over-optimize for a specific CPU and tokenizer? How is it so fast?<\/h3>\n<p><a id=\"user-content-q-did-you-just-way-over-optimize-for-a-specific-cpu-and-tokenizer-how-is-it-so-fast\" class=\"anchor\" aria-label=\"Permalink: Q: Did you just way over-optimize for a specific CPU and tokenizer? How is it so fast?\" href=\"#q-did-you-just-way-over-optimize-for-a-specific-cpu-and-tokenizer-how-is-it-so-fast\"><svg data-component=\"Octicon\" class=\"octicon octicon-link\" viewbox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"><path d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\/><\/svg><\/a><\/div>\n<p dir=\"auto\">No, I way over-optimized for every combination of these!<br \/>\nThe results are very consistent across CPUs (modern x86 and ARM), and across specific tokenizers.<\/p>\n<p dir=\"auto\">The major improvements are in optimizing heavily an implementation that usually is outsourced to a Regex engine (pretokenization) using SIMD, minimizing branching and other tricks, as well as heavily optimizing caching of pretoken mappings (if a word has been seen before, look it up its encoded tokens efficiently).<br \/>\nCaching is a very hard problem in this domain since the cache grows very quickly, and pretoken distributions are very long-tailed.<\/p>\n<p dir=\"auto\">Some gains are also achieved from minimizing interactions with Python, and avoiding communication between threads.<\/p>\n<div class=\"markdown-heading\" dir=\"auto\">\n<h3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\">Q: How can I quickly check if my tokenizer is supported?<\/h3>\n<p><a id=\"user-content-q-how-can-i-quickly-check-if-my-tokenizer-is-supported\" class=\"anchor\" aria-label=\"Permalink: Q: How can I quickly check if my tokenizer is supported?\" href=\"#q-how-can-i-quickly-check-if-my-tokenizer-is-supported\"><svg data-component=\"Octicon\" class=\"octicon octicon-link\" viewbox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"><path d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\/><\/svg><\/a><\/div>\n<p dir=\"auto\">You can try it out without installing anything! The following command will validate and time tokenization for a given HuggingFace model repo:<\/p>\n<div class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"# Download your data&#10;wget https:\/\/huggingface.co\/datasets\/stanford-cs336\/owt-sample\/resolve\/main\/owt_train.txt.gz  # Just an example!&#10;gunzip owt_train.txt.gz\">\n<pre><span class=\"pl-c\"><span class=\"pl-c\">#<\/span> Download your data<\/span>\nwget https:\/\/huggingface.co\/datasets\/stanford-cs336\/owt-sample\/resolve\/main\/owt_train.txt.gz  <span class=\"pl-c\"><span class=\"pl-c\">#<\/span> Just an example!<\/span>\ngunzip owt_train.txt.gz<\/pre>\n<\/div>\n<div class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"uvx --with tokenizers gigatoken bench 'openai-community\/gpt2' owt_train.txt \\&#10;    --validate --doc-separator &quot;&lt;|endoftext|&gt;&quot;\">\n<pre>uvx --with tokenizers gigatoken bench <span class=\"pl-s\"><span class=\"pl-pds\">'<\/span>openai-community\/gpt2<span class=\"pl-pds\">'<\/span><\/span> owt_train.txt \\\n    --validate --doc-separator <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>&lt;|endoftext|&gt;<span class=\"pl-pds\">\"<\/span><\/span><\/pre>\n<\/div>\n<div class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"      cpu: Apple M4 Max, 16 cores&#10;gigatoken:    1.432 s |   11920.51 MB at  8327.05 MB\/s |  2701.65 Mtok at 1887.23 Mtok\/s&#10;       hf:   16.250 s |     100.00 MB at     6.15 MB\/s |    22.76 Mtok at    1.40 Mtok\/s&#10;gigatoken is 1353.13x faster than hf&#10;validation OK: 20401 documents match\">\n<pre>      cpu: Apple M4 Max, 16 cores\ngigatoken:    1.432 s <span class=\"pl-k\">|<\/span>   11920.51 MB at  8327.05 MB\/s <span class=\"pl-k\">|<\/span>  2701.65 Mtok at 1887.23 Mtok\/s\n       hf:   16.250 s <span class=\"pl-k\">|<\/span>     100.00 MB at     6.15 MB\/s <span class=\"pl-k\">|<\/span>    22.76 Mtok at    1.40 Mtok\/s\ngigatoken is 1353.13x faster than hf\nvalidation OK: 20401 documents match<\/pre>\n<\/div>\n<div class=\"highlight highlight-source-shell notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"      cpu: AMD EPYC 9565 72-Core Processor, 144 cores, 2 sockets&#10;gigatoken:    0.486 s |   11920.51 MB at 24532.45 MB\/s |  2701.65 Mtok at 5564.94 Mtok\/s&#10;       hf:    4.033 s |     100.00 MB at    24.80 MB\/s |    22.76 Mtok at    5.63 Mtok\/s&#10;gigatoken is 989.21x faster than hf&#10;validation OK: 20401 documents match\">\n<pre>      cpu: AMD EPYC 9565 72-Core Processor, 144 cores, 2 sockets\ngigatoken:    0.486 s <span class=\"pl-k\">|<\/span>   11920.51 MB at 24532.45 MB\/s <span class=\"pl-k\">|<\/span>  2701.65 Mtok at 5564.94 Mtok\/s\n       hf:    4.033 s <span class=\"pl-k\">|<\/span>     100.00 MB at    24.80 MB\/s <span class=\"pl-k\">|<\/span>    22.76 Mtok at    5.63 Mtok\/s\ngigatoken is 989.21x faster than hf\nvalidation OK: 20401 documents match<\/pre>\n<\/div>\n<p dir=\"auto\">At the rates we see on the EPYC CPU, you could tokenize the <a href=\"https:\/\/arxiv.org\/pdf\/2211.04325\" rel=\"nofollow\">entirety of Common Crawl<\/a> (often considered to be the entire internet, 130 trillion tokens) in just under 6.5 hours!<\/p>\n<p dir=\"auto\">This example uses the train sample from <a href=\"https:\/\/huggingface.co\/datasets\/stanford-cs336\/owt-sample\" rel=\"nofollow\">this dataset<\/a>, and the CLI by default subsets to the first 100MB of the file for validation and comparison with HF.<br \/>\nYou can see help for these flags with <code>uvx gigatoken bench --help<\/code>.<br \/>\nYou might need to run your commands twice on macOS to get a good reading, since the first run will always perform a security scan, which will slow down the Rust code.<\/p>\n<div class=\"markdown-heading\" dir=\"auto\">\n<h3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\">Q: I&#8217;ve found a mismatch\/slow use-case, is this expected?<\/h3>\n<p><a id=\"user-content-q-ive-found-a-mismatchslow-use-case-is-this-expected\" class=\"anchor\" aria-label=\"Permalink: Q: I've found a mismatch\/slow use-case, is this expected?\" href=\"#q-ive-found-a-mismatchslow-use-case-is-this-expected\"><svg data-component=\"Octicon\" class=\"octicon octicon-link\" viewbox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"><path d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\/><\/svg><\/a><\/div>\n<p dir=\"auto\">Most likely not! Despite reasonably wide testing I don&#8217;t have every use-case on hand, so please report anything you find in a <a href=\"https:\/\/github.com\/marcelroed\/gigatoken\/issues\">GitHub Issue<\/a> so I can address it as soon as possible.<\/p>\n<p dir=\"auto\">If you use Gigatoken in your research, please cite it as:<\/p>\n<div class=\"highlight highlight-text-bibtex notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"@software{roed2026gigatoken,&#10;  author = {Marcel R{\\o}d},&#10;  title = {{G}igatoken: SIMD and Cache Hierarchies for 1000x Faster Byte-Pair Encoding Tokenization on Modern CPUs},&#10;  url = {https:\/\/github.com\/marcelroed\/gigatoken},&#10;  year = {2026},&#10;}\">\n<pre><span class=\"pl-k\">@software<\/span>{<span class=\"pl-en\">roed2026gigatoken<\/span>,\n  <span class=\"pl-s\">author<\/span> = <span class=\"pl-s\"><span class=\"pl-pds\">{<\/span>Marcel R{\\o}d<span class=\"pl-pds\">}<\/span><\/span>,\n  <span class=\"pl-s\">title<\/span> = <span class=\"pl-s\"><span class=\"pl-pds\">{<\/span>{G}igatoken: SIMD and Cache Hierarchies for 1000x Faster Byte-Pair Encoding Tokenization on Modern CPUs<span class=\"pl-pds\">}<\/span><\/span>,\n  <span class=\"pl-s\">url<\/span> = <span class=\"pl-s\"><span class=\"pl-pds\">{<\/span>https:\/\/github.com\/marcelroed\/gigatoken<span class=\"pl-pds\">}<\/span><\/span>,\n  <span class=\"pl-s\">year<\/span> = <span class=\"pl-s\"><span class=\"pl-pds\">{<\/span>2026<span class=\"pl-pds\">}<\/span><\/span>,\n}<\/pre>\n<\/div>\n<ul dir=\"auto\">\n<li>Python iteration is handled in Rust, but uses ABI3, which is slower than using internal version-specific CPython APIs. In the future I intend to specialize for each Python version to cut this overhead. Early experiments show a 2x speed improvement for overhead-bound cases.<\/li>\n<li>File sinks are not yet implemented in the Gigatoken API.<\/li>\n<li>WordPiece is not yet supported.<\/li>\n<li>SentencePiece-based tokenization is not nearly as optimized as the more common BPE tokenizers. This is low priority for now since mostly Google models\/BERT style models use SentencePiece.<\/li>\n<li>Windows has not been tested much, so for now prefer using WSL.<\/li>\n<\/ul>\n<hr\/>\n<details>\n<summary>AI Use Disclosure<\/summary>\n<p>A majority of this code base was crafted by hand without any use of AI (which can be seen from the project&#8217;s Git history).<br \/>\nIn the final stages of the project, AI was used to assist:<\/p>\n<ul dir=\"auto\">\n<li>Implementing the user-facing API<\/li>\n<li>Widening of compatibility, for instance generalizing and porting the pretokenizer implementations to support more tokenizers, less interesting features like padding\/truncation\/unicode normalization<\/li>\n<li>Porting SIMD strategies between AVX512\/AVX2\/NEON<\/li>\n<li>Final profiling stages and the last ~4x worth of performance from eliminating branching and improving the pretoken cache hierarchy<\/li>\n<li>Refactoring and code reuse<\/li>\n<\/ul>\n<\/details>\n<\/div>\n<p><a href=\"https:\/\/github.com\/marcelroed\/gigatoken\/#benchmarks?utm_source=tldrai\">Source link <\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>~1000x faster than HuggingFace&#8217;s tokenizers, drop-in replacement. Tokenize your text data at GB\/s! Note that both HF tokenizers and tiktoken are already running multithreaded Rust! Gigatoken is the fastest tokenizer for language modeling. It supports a wide range of CPU hardware, and nearly all commonly used tokenizers. See the Benchmarks section for detailed throughput numbers [&hellip;]<\/p>\n","protected":false},"author":16,"featured_media":22583,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[143],"tags":[],"class_list":["post-22582","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ai"],"_links":{"self":[{"href":"https:\/\/scannn.com\/lv\/wp-json\/wp\/v2\/posts\/22582","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/scannn.com\/lv\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/scannn.com\/lv\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/scannn.com\/lv\/wp-json\/wp\/v2\/users\/16"}],"replies":[{"embeddable":true,"href":"https:\/\/scannn.com\/lv\/wp-json\/wp\/v2\/comments?post=22582"}],"version-history":[{"count":0,"href":"https:\/\/scannn.com\/lv\/wp-json\/wp\/v2\/posts\/22582\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/scannn.com\/lv\/wp-json\/wp\/v2\/media\/22583"}],"wp:attachment":[{"href":"https:\/\/scannn.com\/lv\/wp-json\/wp\/v2\/media?parent=22582"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/scannn.com\/lv\/wp-json\/wp\/v2\/categories?post=22582"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/scannn.com\/lv\/wp-json\/wp\/v2\/tags?post=22582"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}