SentencePieceライブラリに実装されたByte Pair Encodingアルゴリズムで、空白を「▁」記号として扱う前処理不要の設計により、LLaMA・Mistral・CodeLlama等のデコーダー系LLMで標準的に使用されている。
SentencePiece BPEモードは、SentencePieceライブラリ内でByte Pair Encoding(BPE)アルゴリズムを実行するトークン化方式である。オリジナルのBPE(Sennrich et al., 2016)は空白で事前分割された単語単位で動作するが、SentencePiece BPEは空白を「▁」(U+2581)に変換して文字列全体を一括処理する点が決定的に異なる。これにより、日本語や中国語のように空白を使わない言語でも前処理なしでBPEを適用できる。
| 項目 | オリジナルBPE | SentencePiece BPE |
|---|---|---|
| 前処理 | 空白分割 + 単語末尾マーカー | 不要(「▁」自動付与) |
| 入力形式 | 事前トークン化済みテキスト | 生のUnicodeテキスト |
| 空白の扱い | 分割境界として除外 | 「▁」としてトークンに含む |
| 可逆性 | 不完全(空白情報の損失) | 完全(ロスレス復元) |
| 日本語対応 | 形態素解析器が必要 | そのまま処理可能 |
| Unicode正規化 | 外部処理 | 内蔵(NFKC等) |
| 実装言語 | Python | C++(Pythonバインディング) |
| 処理速度 |
| 低速 |
| 高速(10〜50倍) |
import sentencepiece as spm
spm.SentencePieceTrainer.train(
input='corpus.txt',
model_prefix='bpe_model',
vocab_size=32000,
model_type='bpe',
byte_fallback=True,
character_coverage=0.9995,
split_digits=True,
num_threads=16
)
学習済みのマージルール(結合順序テーブル)を上から順に適用し、入力テキストを分割する:
sp = spm.SentencePieceProcessor()
sp.load('bpe_model.model')
text = '深層学習モデルの推論最適化'
tokens = sp.encode(text, out_type=str)
# ['▁深', '層', '学習', 'モデル', 'の', '推論', '最適', '化']
ids = sp.encode(text, out_type=int)
decoded = sp.decode(ids)
assert decoded == text # 完全復元を保証
| モデル | 語彙サイズ | byte_fallback | split_digits | 特記事項 |
|---|---|---|---|---|
| LLaMA | 32,000 | Yes | Yes | Meta初のオープンLLM |
| LLaMA 2 | 32,000 | Yes | Yes | 商用利用可能 |
| Code Llama | 32,000 | Yes | Yes | コード特化 |
| Mistral 7B | 32,000 | Yes | Yes | LLaMA互換語彙 |
| Mixtral 8x7B | 32,000 | Yes | Yes | MoEアーキテクチャ |
| Baichuan 2 | 125,696 | Yes | No | 中国語強化 |
LLaMA系モデルで重要なbyte_fallback=Trueは、語彙に含まれない文字をUTF-8のバイト列に分解して処理する仕組みである。これによりUNKトークンが発生しないことが保証される。例えば珍しい絵文字や特殊記号も、バイト単位のトークン(<0xE2>, <0x9C>, <0x85>等)として表現できる。
GPT-4で使用されるtiktokenもBPEベースだが、SentencePiece BPEとは実装が大きく異なる:
| 項目 | SentencePiece BPE | tiktoken |
|---|---|---|
| 前処理 | なし(「▁」変換のみ) | 正規表現による事前分割 |
| 実装 | C++ + protobuf | Rust + 正規表現 |
| バイトフォールバック | オプション | 標準 |
| マージファイル形式 | .model(protobuf) | .tiktoken(テキスト) |
| 処理速度 | 高速 | 最高速 |
| カスタム学習 | 可能 | 困難 |
SentencePiece BPEの学習品質はコーパスの質に大きく依存する:
| 用途 | 推奨語彙サイズ | 理由 |
|---|---|---|
| 小規模単言語 | 16,000〜32,000 | パラメータ効率重視 |
| 大規模単言語 | 32,000〜64,000 | カバレッジと効率のバランス |
| 多言語 | 64,000〜256,000 | 言語間の公平性確保 |
| コード特化 | 32,000〜100,000 | プログラミング記号の網羅 |
Q1: SentencePiece BPEの学習にはどのくらいの時間がかかりますか?
A: 32,000語彙をGBクラスのコーパスから学習する場合、16スレッドで30分〜2時間程度である。語彙サイズとcharacter_coverageの設定が計算時間に大きく影響する。
Q2: LLaMA 3はなぜSentencePiece BPEからtiktokenに移行したのですか?
A: LLaMA 3は語彙サイズを128,256に拡張し、多言語トークン効率を大幅に改善するためtiktokenベースに移行した。tiktokenの正規表現ベースの前処理がコードや数式のトークン化で有利だった点も理由の一つである。
Q3: byte_fallbackを無効にするとどうなりますか?
A: 語彙に含まれない文字がUNK(未知語)トークンになり、情報が失われる。LLM用途では常にbyte_fallback=Trueを推奨する。唯一の例外は、対象言語の文字セットが完全に既知で限定される場合(例:ASCII英語のみ)である。