mcpField
H
huggingface-tokenizers

huggingface-tokenizers

github.com/orchestra-research開発14.1k967 回インストール19 週間前に更新
リポジトリ

huggingface-tokenizers について

HuggingFace Tokenizersは、Rustを基盤とし、PythonとNode.jsのバインディングを備えたテキストトークナイザーライブラリです。独自学習やバッチエンコード、トークンと原文の位置合わせに対応します。

主な機能

  1. 01BPE、WordPiece、Unigramモデル
  2. 02独自トークナイザーの学習
  3. 03パディング付きバッチエンコード
  4. 04トークンとテキスト位置の対応
  5. 05テキストの正規化と処理

活用シーン

  1. 01大規模コーパスでのトークナイザー学習
  2. 02NLPモデル用バッチの準備
  3. 03予測結果を原文の範囲に対応付け

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/orchestra-research/ai-research-skills --skill huggingface-tokenizers

インストール後、Claude Code で/huggingface-tokenizersを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
algorithms.md
integration.md
pipeline.md
training.md

詳細

HuggingFace Tokenizers - NLP 向けの高速トークナイゼーション

Rust による高いパフォーマンスと Python の使いやすさを兼ね備えた、高速で本番環境に対応したトークナイザーです。

HuggingFace Tokenizers を使うべき場面

HuggingFace Tokenizers を使うとよい場合:

  • 極めて高速なトークナイズが必要な場合(テキスト 1GB あたり 20 秒未満)
  • カスタムトークナイザーをゼロから学習させる場合
  • アライメントの追跡(トークン → 元テキストの位置)が必要な場合
  • 本番環境の NLP パイプラインを構築する場合
  • 大規模なコーパスを効率的にトークナイズする必要がある場合

パフォーマンス:

  • 速度: CPU で 1GB のトークナイズに 20 秒未満
  • 実装: Rust コアと Python/Node.js バインディング
  • 効率: 純粋な Python 実装より 10〜100 倍高速

代わりに使用できるもの:

  • SentencePiece: 言語非依存で、T5/ALBERT で使用
  • tiktoken: GPT モデル向けの OpenAI の BPE トークナイザー
  • transformers AutoTokenizer: 学習済みのものを読み込むだけの場合(内部でこのライブラリを使用)

クイックスタート

インストール
# Install tokenizers
pip install tokenizers

# With transformers integration
pip install tokenizers transformers
学習済みトークナイザーの読み込み
from tokenizers import Tokenizer

# Load from HuggingFace Hub
tokenizer = Tokenizer.from_pretrained("bert-base-uncased")

# Encode text
output = tokenizer.encode("Hello, how are you?")
print(output.tokens)  # ['hello', ',', 'how', 'are', 'you', '?']
print(output.ids)     # [7592, 1010, 2129, 2024, 2017, 1029]

# Decode back
text = tokenizer.decode(output.ids)
print(text)  # "hello, how are you?"
カスタム BPE トークナイザーの学習
from tokenizers import Tokenizer
from tokenizers.models import BPE
from tokenizers.trainers import BpeTrainer
from tokenizers.pre_tokenizers import Whitespace

# Initialize tokenizer with BPE model
tokenizer = Tokenizer(BPE(unk_token="[UNK]"))
tokenizer.pre_tokenizer = Whitespace()

# Configure trainer
trainer = BpeTrainer(
    vocab_size=30000,
    special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"],
    min_frequency=2
)

# Train on files
files = ["train.txt", "validation.txt"]
tokenizer.train(files, trainer)

# Save
tokenizer.save("my-tokenizer.json")

学習時間: 100MB のコーパスで約 1〜2 分、1GB で約 10〜20 分

パディングを使ったバッチエンコーディング
# Enable padding
tokenizer.enable_padding(pad_id=3, pad_token="[PAD]")

# Encode batch
texts = ["Hello world", "This is a longer sentence"]
encodings = tokenizer.encode_batch(texts)

for encoding in encodings:
    print(encoding.ids)
# [101, 7592, 2088, 102, 3, 3, 3]
# [101, 2023, 2003, 1037, 2936, 6251, 102]

トークナイゼーションのアルゴリズム

BPE(Byte-Pair Encoding)

仕組み:

  1. 文字レベルの語彙から開始する
  2. 最も頻出する文字ペアを見つける
  3. それを新しいトークンとしてマージし、語彙に追加する
  4. 語彙サイズに達するまで繰り返す

使用例: GPT-2、GPT-3、RoBERTa、BART、DeBERTa

from tokenizers import Tokenizer
from tokenizers.models import BPE
from tokenizers.trainers import BpeTrainer
from tokenizers.pre_tokenizers import ByteLevel

tokenizer = Tokenizer(BPE(unk_token="<|endoftext|>"))
tokenizer.pre_tokenizer = ByteLevel()

trainer = BpeTrainer(
    vocab_size=50257,
    special_tokens=["<|endoftext|>"],
    min_frequency=2
)

tokenizer.train(files=["data.txt"], trainer=trainer)

利点:

  • OOV 単語をうまく扱える(サブワードに分割される)
  • 語彙サイズを柔軟に設定できる
  • 形態論的に豊かな言語に適している

トレードオフ:

  • トークナイズ結果がマージの順序に依存する
  • 一般的な単語が予想外に分割されることがある
WordPiece

仕組み:

  1. 文字の語彙から開始する
  2. マージ候補のペアを frequency(pair) / (frequency(first) × frequency(second)) でスコア付けする
  3. 最もスコアの高いペアをマージする
  4. 語彙サイズに達するまで繰り返す

使用例: BERT、DistilBERT、MobileBERT

from tokenizers import Tokenizer
from tokenizers.models import WordPiece
from tokenizers.trainers import WordPieceTrainer
from tokenizers.pre_tokenizers import Whitespace
from tokenizers.normalizers import BertNormalizer

tokenizer = Tokenizer(WordPiece(unk_token="[UNK]"))
tokenizer.normalizer = BertNormalizer(lowercase=True)
tokenizer.pre_tokenizer = Whitespace()

trainer = WordPieceTrainer(
    vocab_size=30522,
    special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"],
    continuing_subword_prefix="##"
)

tokenizer.train(files=["corpus.txt"], trainer=trainer)

利点:

  • 意味のあるマージを優先する(スコアが高いほど意味的に関連が強い)
  • BERT で良好な結果(最先端の性能)を達成するのに使用された

トレードオフ:

  • サブワードに一致しない場合、未知語は [UNK] になる
  • マージルールではなく語彙を保存するため、ファイルが大きくなる
Unigram

仕組み:

  1. 大きな語彙(すべての部分文字列)から開始する
  2. 現在の語彙でコーパスの損失を計算する
  3. 損失への影響が最も小さいトークンを削除する
  4. 語彙サイズに達するまで繰り返す

使用例: ALBERT、T5、mBART、XLNet(SentencePiece 経由)

from tokenizers import Tokenizer
from tokenizers.models import Unigram
from tokenizers.trainers import UnigramTrainer

tokenizer = Tokenizer(Unigram())

trainer = UnigramTrainer(
    vocab_size=8000,
    special_tokens=["<unk>", "<s>", "</s>"],
    unk_token="<unk>"
)

tokenizer.train(files=["data.txt"], trainer=trainer)

利点:

  • 確率的である(最も尤もらしいトークナイズを見つける)
  • 単語の境界がない言語でもうまく機能する
  • 多様な言語的文脈を扱える

トレードオフ:

  • 学習の計算コストが高い
  • 調整すべきハイパーパラメータが多い

トークナイゼーションのパイプライン

完全なパイプライン: 正規化 → 事前トークン化 → モデル → 後処理

正規化

テキストをクリーニングして標準化します:

from tokenizers.normalizers import NFD, StripAccents, Lowercase, Sequence

tokenizer.normalizer = Sequence([
    NFD(),           # Unicode normalization (decompose)
    Lowercase(),     # Convert to lowercase
    StripAccents()   # Remove accents
])

# Input: "Héllo WORLD"
# After normalization: "hello world"

一般的な正規化器:

  • NFD、NFC、NFKD、NFKC - Unicode 正規化形式
  • Lowercase() - 小文字に変換
  • StripAccents() - アクセント記号を削除(é → e)
  • Strip() - 空白を削除
  • Replace(pattern, content) - 正規表現による置換
事前トークン化

テキストを単語らしい単位に分割します:

from tokenizers.pre_tokenizers import Whitespace, Punctuation, Sequence, ByteLevel

# Split on whitespace and punctuation
tokenizer.pre_tokenizer = Sequence([
    Whitespace(),
    Punctuation()
])

# Input: "Hello, world!"
# After pre-tokenization: ["Hello", ",", "world", "!"]

一般的な事前トークナイザー:

  • Whitespace() - スペース、タブ、改行で分割
  • ByteLevel() - GPT-2 スタイルのバイトレベル分割
  • Punctuation() - 句読点を分離
  • Digits(individual_digits=True) - 数字を 1 桁ずつ分割
  • Metaspace() - スペースを ▁ に置換(SentencePiece スタイル)
後処理

モデル入力用に特殊トークンを追加します:

from tokenizers.processors import TemplateProcessing

# BERT-style: [CLS] sentence [SEP]
tokenizer.post_processor = TemplateProcessing(
    single="[CLS] $A [SEP]",
    pair="[CLS] $A [SEP] $B [SEP]",
    special_tokens=[
        ("[CLS]", 1),
        ("[SEP]", 2),
    ],
)

一般的なパターン:

# GPT-2: sentence <|endoftext|>
TemplateProcessing(
    single="$A <|endoftext|>",
    special_tokens=[("<|endoftext|>", 50256)]
)

# RoBERTa: <s> sentence </s>
TemplateProcessing(
    single="<s> $A </s>",
    pair="<s> $A </s> </s> $B </s>",
    special_tokens=[("<s>", 0), ("</s>", 2)]
)

アライメントの追跡

元テキスト中のトークンの位置を追跡します:

output = tokenizer.encode("Hello, world!")

# Get token offsets
for token, offset in zip(output.tokens, output.offsets):
    start, end = offset
    print(f"{token:10} → [{start:2}, {end:2}): {text[start:end]!r}")

# Output:
# hello      → [ 0,  5): 'Hello'
# ,          → [ 5,  6): ','
# world      → [ 7, 12): 'world'
# !          → [12, 13): '!'

ユースケース:

  • 固有表現認識(予測結果を元テキストに対応付ける)
  • 質問応答(回答の範囲を抽出する)
  • トークン分類(ラベルを元の位置に対応付ける)

transformers との統合

AutoTokenizer での読み込み
from transformers import AutoTokenizer

# AutoTokenizer automatically uses fast tokenizers
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")

# Check if using fast tokenizer
print(tokenizer.is_fast)  # True

# Access underlying tokenizers.Tokenizer
fast_tokenizer = tokenizer.backend_tokenizer
print(type(fast_tokenizer))  # <class 'tokenizers.Tokenizer'>
カスタムトークナイザーを transformers に変換
from tokenizers import Tokenizer
from transformers import PreTrainedTokenizerFast

# Train custom tokenizer
tokenizer = Tokenizer(BPE())
# ... train tokenizer ...
tokenizer.save("my-tokenizer.json")

# Wrap for transformers
transformers_tokenizer = PreTrainedTokenizerFast(
    tokenizer_file="my-tokenizer.json",
    unk_token="[UNK]",
    pad_token="[PAD]",
    cls_token="[CLS]",
    sep_token="[SEP]",
    mask_token="[MASK]"
)

# Use like any transformers tokenizer
outputs = transformers_tokenizer(
    "Hello world",
    padding=True,
    truncation=True,
    max_length=512,
    return_tensors="pt"
)

よくあるパターン

イテレーターからの学習(大規模データセット)
from datasets import load_dataset

# Load dataset
dataset = load_dataset("wikitext", "wikitext-103-raw-v1", split="train")

# Create batch iterator
def batch_iterator(batch_size=1000):
    for i in range(0, len(dataset), batch_size):
        yield dataset[i:i + batch_size]["text"]

# Train tokenizer
tokenizer.train_from_iterator(
    batch_iterator(),
    trainer=trainer,
    length=len(dataset)  # For progress bar
)

パフォーマンス: 1GB を約 10〜20 分で処理

切り詰めとパディングの有効化
# Enable truncation
tokenizer.enable_truncation(max_length=512)

# Enable padding
tokenizer.enable_padding(
    pad_id=tokenizer.token_to_id("[PAD]"),
    pad_token="[PAD]",
    length=512  # Fixed length, or None for batch max
)

# Encode with both
output = tokenizer.encode("This is a long sentence that will be truncated...")
print(len(output.ids))  # 512
マルチプロセッシング
from tokenizers import Tokenizer
from multiprocessing import Pool

# Load tokenizer
tokenizer = Tokenizer.from_file("tokenizer.json")

def encode_batch(texts):
    return tokenizer.encode_batch(texts)

# Process large corpus in parallel
with Pool(8) as pool:
    # Split corpus into chunks
    chunk_size = 1000
    chunks = [corpus[i:i+chunk_size] for i in range(0, len(corpus), chunk_size)]

    # Encode in parallel
    results = pool.map(encode_batch, chunks)

高速化: 8 コアで 5〜8 倍

パフォーマンスベンチマーク

学習速度
コーパスサイズBPE(30k 語彙)WordPiece(30k)Unigram(8k)
10 MB15 秒18 秒25 秒
100 MB1.5 分2 分4 分
1 GB15 分20 分40 分

ハードウェア: 16 コア CPU、英語版 Wikipedia でテスト

トークナイズ速度
実装1 GB コーパススループット
純粋な Python約 20 分約 50 MB/分
HF Tokenizers約 15 秒約 4 GB/分
高速化率80 倍80 倍

テスト: 英語テキスト、平均文長 20 語

メモリ使用量
タスクメモリ
トークナイザーの読み込み約 10 MB
BPE の学習(30k 語彙)約 200 MB
100 万文のエンコード約 500 MB

対応モデル

from_pretrained() で利用できる事前学習済みトークナイザー:

BERT ファミリー:

  • bert-base-uncased, bert-large-cased
  • distilbert-base-uncased
  • roberta-base, roberta-large

GPT ファミリー:

  • gpt2, gpt2-medium, gpt2-large
  • distilgpt2

T5 ファミリー:

  • t5-small, t5-base, t5-large
  • google/flan-t5-xxl

その他:

  • facebook/bart-base, facebook/mbart-large-cc25
  • albert-base-v2, albert-xlarge-v2
  • xlm-roberta-base, xlm-roberta-large

すべてを閲覧: https://huggingface.co/models?library=tokenizers

参考資料

リソース

コメント